Docker Cheatsheet
Chances are that Docker is new to you. While this isn’t going to be an exhaustive article on what Docker is and what we use it for, here are some helpful hints for getting around how our projects are constructed.
High Level Concepts
There are a few things to know about Docker to do development work inside them. Unless you’re building containers for serving applications in production, this is probably enough:
- Images - Images are software packaged for your consumption and are the basis for Containers. They should be purpose-built for handling one particular portion of your application, whether it be to serve the application, run a database or cache, or perform some background tasks.
- Container - Containers are the Image turned into an operational construct. While the Image is a static asset, a Container is the packaged software in an operational state. You will connect to one or more Containers to view and execute your application. We generally orchestrate their creation through
docker compose
. They are built, executed, and destroyed at will and should be considered ephemeral. - Volumes - Volumes are persistent storage that we utilize so that application data can persist outside of the lifecycle of a Container. Data for a database, image and document uploads through the application are typically stored in a volume. They can be removed if you no longer need the data contained therein in order to completely reset an environment.
Basic Commands
Here are a few basic Docker commands that may help you navigate your new project. Note that we generally use Docker Compose to run our projects, and its usage is explained later.
docker ps
- Shows all currently running containers
% docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e276a11d8098 nginx:latest "/docker-entrypoint.…" 38 seconds ago Up 37 seconds 0.0.0.0:8080->80/tcp wordpress-template-web-1
9ad9b547f1d5 php:7-fpm "docker-php-entrypoi…" 38 seconds ago Up 37 seconds 9000/tcp, 9003/tcp wordpress-template-php-1
1e61b569bb53 mariadb "docker-entrypoint.s…" 39 seconds ago Up 38 seconds 0.0.0.0:3306->3306/tcp wordpress-template-database-
docker image ls
- Shows all downloaded Docker images
% docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
php 7-fpm 72f2a68f9ca2 2 months ago 423MB
nginx latest 63eb316dc556 3 months ago 134MB
mariadb latest 7eda4c38372f 4 months ago 394MB
docker volume ls
- Shows all persistent volumes living outside of the containers.
% docker volume ls
DRIVER VOLUME NAME
local wordpress-template_database
At any time you can use docker [subcommand] --help
to get help doing things within Docker.
Docker Compose
We try to use Docker Compose to help spin up our development environments, especially since it makes for a nice, self-contained, consistent experience for everyone. It’s also super easy to implode and leave almost nothing behind when it’s done.
Many of our projects come with a docker-compose.yml
file, or coordinate with another project which does. Look for one when you’re checking out a new project. At this time, this is mostly our PHP-based projects and a few older Ruby on Rails projects.
Commands
docker compose up
- Spins up a full infrastructure stack, as defined in docker-compose.yml
for running an application. You can add the command line option -d
if you don’t want to watch the logs. We do not recommend this in a development environment. Just open another terminal window.
docker compose down
or docker compose kill
- Either nicely brings a stack down or violently brings the stack down, depending on your preference. If you wish to reuse the containers and volumes again, the former is preferred over the latter.
docker compose build
- If your stack depends on a custom built image (and a few of ours do), you will want to first start with this command to build the images that the containers will use later. Normally a README will direct you to do this if necessary.
Executing Commands within a Container
Sometimes we need to execute one-off tasks or troubleshoot an application and therefore need to be inside the application’s running context (the Container) in order to do it. There are two ways to execute commands under a Docker context and understanding the difference is key:
docker compose run --rm [container service name] [command]
- Using run
will instantiate a new Container using the image defined by container service name
and run your command. This is good for when you need to run a rake
task or composer install
as the output of those commands are persisted outside of the Container in question to either a database or to a Volume. --rm
saves you an extra step by removing the newly instantiated Container for you instead of leaving it out there and cluttering your environment.
docker compose exec -it [container service name] [command]
- If you really need to be inside of the current Container running your application for some reason, exec
will connect you to the current Container. This is useful if you need to look at an internal application or application server (e.g. Apache or Nginx) log that doesn’t appear in the terminal when you started Docker Compose.
Starting up a Project New
While we recommend checking out each project’s README file first, lacking that, you can use
docker compose up
to start up most new projects. This should roll out an infrastructure, usually in multiple containers, which will get the project rolling.
Sometimes you may need to perform some side tasks like running Composer. This is common in our WordPress stacks. In those cases, look for a composer.json
file and run
docker compose run --rm php composer install
This will instantiate a second php
Container, run composer install
within it, and install all of the PHP dependencies you need. In these cases, run
is normally appropriate because Composer will put the installed files in the application’s current working directory which is likely shared to your host OS (macOS) so that you can work with them in your code editor/IDE of choice.
If all else fails…
Assuming the project was stood up with docker compose
, you can execute
docker compose down --volumes
This command is extremely destructive and will remove not only the containers, but any persistent volumes instantiated as part of Docker Compose. This should be considered ‘last resort’, or used in a situation where you know you won’t be working on an application for a long time and will likely need to set it up from scratch the next time.