Docker
Intro
Docker was pretty intimidating to me at first. After upgrading to Windows 10, installing Docker Desktop, and playing around with some of the tutorials it has started to make a bit more sense. First, there is a great cheat sheet available here:
This includes a useful description of the docker run command and its main parameters:
docker run--rm remove container automatically after it exits-it connect the container to terminal--name web name the container-p 5000:80 expose port 5000 from the container as port 80 on the local machine-v ~/dev:/code create a host mapped volume inside the containeralpine:3.4 the image from which the container is instantiated/bin/sh the command to run inside the container
I've also seen some tutorials use the "-w" (as in "-w /opt") command. This specifies the working directory.
Terminology
I keep confusing docker terminology (especially "container" versus "image" and "repository" versus "registry"). Here are some key terms to keep me straight:
- Container - A running instance of an image
- Image - The basis for a running container. An image is an "ordered collection of file system changes" and execution parameters for running the image in a container
- Registry - A Registry is a hosted service containing repositories of images which responds to the Registry API.
- Repository - A repository is a set of Docker images. A repository can be shared by pushing it to a registry server. The different images in the repository can be labeled using tags.
For a complete docker glossary, see: https://docs.docker.com/glossary/.
Namespaces
Large companies might organize the repositories inside their registry into namespaces. This is a logical grouping that just uses part of the repository path to group repositories. As an example, a team's repository paths might look like:
docker-prod.registry.mycompanycom/myteam/awesome-image:1.2
This breaks down into:
registry/namespace/repository:tag
Online Articles
Here are some online tutorials to help get started:
Level | Link/Description |
---|---|
Beginner | Docker: have a Ubuntu development machine within seconds, from Windows or Mac Quick intro to running Ubuntu on Windows and mounting a local drive. |
Beginner | 2.5 Ways to Update a Container How to make changes to a container (manually and through Dockerfiles, but it doesn't go deep into Dockerfiles) |
Easy | Behind the Corporate Proxy Information on how to run docker behind a corporate proxy. (With some good humor thrown in) |
Easy | 10 Myths About Docker That Stop Developers Cold Good article with tips for making docker a great development experience. Good info on how to mount local folders into your container so you can develop locally in our favorite IDE but run everything in your docker environment. |
Easy | Put Your Dev Env in GitHub Article that suggests doing development in docker and committing your development Dockerfile along with your code. This is separate from the production Dockerfile that will run your app. It instead intended to make sure all the developers have the same tools, compilers, and libraries installed for development. The author recommends using VSCode, but you can do this without VSCode as well. |
Medium | Using Docker Behind a Proxy Another article on using docker behind a proxy. This one gets into some more advanced usage and assumes a fairly good understanding of docker. |
Medium | Why you don't need to run SSHd in your docker containers Explains why you shouldn't need to SSH into containers to do work there (but also tells you how to do it, just in case) |
? | Patterns and antipatterns in docker image lifecycle (YouTube, slides only) Interesting looking presentation about how to manage docker images in an enterprise so you get consistent, reliable builds with high security. |
Medium | How to Create Optimized Docker Images for Production Tips on using multi-stage builds to create smaller docker images for productions. The main advice is to avoid adding all the build tools to your production image. Instead, create a build step that can be big and bloated with all these tools, build your app, and then just copy your final executable over to a minimal Alpine docker image. He shows how a 1 GB Ubuntu image can be used for building an app but your deployment can be as small as 11 MB. |
Useful Commands
Connect to a Running Container
docker container exec -it [container_name] /bin/bash
This command assumes that "/bin/bash" is installed on the container. If present, it will be invoked. "-it" connects interactively to the terminal. Otherwise, the command would just exit.
Using Docker behind a Proxy
If your Dockerfile build scripts need to access the internet, they will need to do so through the proxy. Usually, it is enough to set the http_proxy and https_proxy environmental variables while building the image. This can be done as shown:
http_proxy=http://user:password@proxy.domain.com:port/https_proxy=$http_proxydocker build \--build-arg http_proxy=$http_proxy \--build-arg https_proxy=$https_proxy \-t <tag> \.
This can be helpful when building docker images on your laptop using public repositories. However, this isn't really what you're supposed to do. Instead, most companies will setup internal registries and repositories (such as Artifactory) to serve dependencies in the internet in a safer manner. These can be setup to proxy public repositories and serve the same content, but in a way that allows the company to see what artifacts are being pulled in from the internet, scan them to make sure they are safe, and sleep a little more soundly at night.
Automated Builds
The GitLab build script below is one example of how you can automate the compilation and pushing of docker images to a repository:
APP_NAME="docker-test"BUILD_NUMBER=$(git describe --tags)NAMESPACE="my-team"DOCKER_REGISTRY="docker-prod.registry.my-company.com"DOCKER_NAME=$NAMESPACE/$APP_NAMEDOCKER_IMAGE=$DOCKER_REGISTRY/$DOCKER_NAMEdocker logout ${DOCKER_REGISTRY}docker build --build-arg version=${BUILD_NUMBER} --file Dockerfile --tag ${DOCKER_IMAGE} .docker tag ${DOCKER_IMAGE} ${DOCKER_IMAGE}:latestdocker tag ${DOCKER_IMAGE} ${DOCKER_IMAGE}:${BUILD_NUMBER}docker images --alldocker login -u ${DOCKER_USERNAME} -p ${DOCKER_PASSWORD} ${DOCKER_REGISTRY}docker push ${DOCKER_IMAGE}:${BUILD_NUMBER}docker push ${DOCKER_IMAGE}:latest