While I often utilize Docker as part of a hosting and deployment system, I also use it locally for all sorts of exploration, spikes, and development. There are a couple of especially useful patterns and invocations that I show to people when I am introducing them to Docker and its usage.
The following tips are not comprehensive, but they do cover some of the most common operations that beginning users are likely to need when first working with containers. All of the following tips work with the standard Docker CLI from version
18.06.0-ce. I’ve organized them by sub-commands to the main
build creates Docker images from Dockerfiles.
The anatomy of a Dockerfile is beyond the scope of this post, but looking at examples from official repositories on Docker Hub and the Docker documentation can be helpful.
You can easily build a new image from a Dockerfile and tag it with:
docker build PATH -f FILE -t NAME:TAG
docker build . -f docker/Dockefile -t my-rails-app:latest
-f specifies the path to the actual Dockerfile, whereas the
. in the example) tells Docker what to use for its context or current directory when building the image. (This is important when considering commands specifying files and paths within the Dockerfile.)
-t will tag the image built by Docker.
All Docker images have an image identifier (a generated, 12-character alphanumeric string). They may also be given a name and a tag. If only a name is provided, the default tag of “latest” is used. Image names and tags help tremendously to readily (and unambiguously) reference specific images.
run is for creating containers. It is important to differentiate it from
exec, which is used to interact with containers that are already running.
Sometimes, it’s useful to just start a container to poke around, and then discard it afterwards. The following will start a new container, drop into a shell, and then destroy the container after you exit:
docker run -it --rm IMAGE COMMAND
docker run -it --rm ruby:latest bash
-it runs Docker interactively (so you get a pseudo-TTY with STDIN). The
--rm causes Docker to automatically remove the container when it exits.
The image being used to create the container is generally specified as
: such as
ruby:latest. If the specified image is not available locally, Docker will attempt to retrieve it from Docker Hub (or any connected Docker registry).
If you need to find Docker images available locally, you can run:
docker images or
docker image ls.
The following will start a container with specified environment variables and forwarding ports from your local computer into the Docker container:
docker run -p HOST_PORT:CONTAINER_PORT -e ENV_VAR=VALUE IMAGE COMMAND
docker run -p 8080:3000 -e RACK_ENV=development my-rails-app:latest rails s
-p defines the port mapping from the host to the container, and the
-e defines key value pairs to set in the container’s environment when it starts up. Multiple parameters can be provided:
docker run -it -—rm -p 8080:3000 -p 8081:3001 -e RACK_ENV=development -e HOSTNAME=my-container my-rails-app:latest rackup
As mentioned earlier, Docker
exec only interacts with containers that are actively running.
If there is an existing container that was started headless (such as by
docker-compose), you can easily drop into a shell to check on the state of things:
docker exec -it CONTAINER COMMAND
docker exec -it 90cdc54358fa bash
As in the earlier example, the
-it allows an interactive session. The container to run
exec can either be specified by the container ID or the more friendly name that is generated or specified when the container is created.
If you do not know the name of the container, you can easily find it with:
docker ps or
docker container ls.
The main resources used for local containers are images, containers, and volumes. Containers are the basic unit of execution. Images are the basis for containers, and volumes are mounted by containers.
Docker has sub-commands which allow you to examine and interact with these resources. While there are many dozens of sub-commands (and sub-sub commands), I find that these are the ones I use most frequently:
docker container allows you to manage containers, for example:
- `docker container ls` to list all running containers
- `docker container kill CONTAINER` to forcefully stop a running container
- `docker container rm CONTAINER` to remove a container
- `docker inspect CONTAINER` to view detailed information about a running container
docker images allows you to manage images, for example:
- `docker image ls` to list all locally available images
- `docker image rm IMAGE` to remove an image
- `docker image prune` to remove dangling images (those not attached to a container, or a dependency for an image that is)
- `docker image prune -a` to remove all images
- `docker image tag IMAGE IMAGE` to tag an image from one image id or tag, to a new tag. (e.g. `my-app:latest` to `my-app:1.0.0`)
I hope this post will encourage you to experiment with Docker.