Weâll go over some every-day commands and files youâll use as part of your development workflow with docker.
Letâs start by tying together the concepts from the previous post, with the ones we are about to see:
One builds and image (which might share a volume with the host machine) based on the definition found in a Dockerfile, runs it in a container and optionally composes multiple images together.
To make sense of this, letâs take a closer look.
Dockerfile
A file that defines a docker Image, a blueprint of sorts. It will look something like this:
It contains a series of commands of the format INSTRUCTION arguments
.
Keep in mind that every line is a new layer in the Image. So the order does matter.
Common Instructions
FROM
Sets the Base Image for subsequent instructions. In its most basic form, youâll see here what OS the Image is based on (Alpine Linux in our example).
A valid Dockerfile must start with a FROM
instruction. Most commonly, this will be done by pulling an already existing image from the public repos.
RUN
Executes a command within the Container.
Create a directory? RUN mkdir
. Update your system? RUN apk update
. Install a dependency? RUN apk add dependency
.
Plain and simple.
CMD
Default command to execute when running an image, âwhat the image doesâ.
Only one is allowed per Dockerfile and whatever command we append to the docker run
command will override this instruction. Weâll take a closer look at the run command further down.
ENV
Sets environment variables, quite like you would in your .bashrc
or .zshrc
.
Useful if you need information to be set at build time, for later modification or reference at run time.
COPY
Copy files or directories from the host to the Container.
It works pretty much as you would expect:
ADD
Pretty much like COPY
, with the remarkable difference that ADD
can also unpack tarballs and fetch files from remote URLs.
So you could say
Pretty handy, but if you donât need the added functionality, prefer COPY
.
VOLUME
Creates a sort of shared directory between host and Container.
So an instruction like:
Would make the Containerâs /opt
directory accessible from the host. In fact, it will actually âmount the volumeâ somewhere under the hostâs /var/lib/docker/volumes/
directory.
Docker Build
Used to build an Image, use -f
to specify the Image path (optional if itâs located in the cwd
) and -t
to give it a name.
Those are options you can (but donât have to) pass. It does however need to get a context as parameter.
A buildâs context is the set of files located outside the Container (local path or URL) that it will be able to refer to at build time.
This is more or less like the COPY
instruction we saw before, with the difference being that the COPY
command makes the hosts files available at run time, while the context makes them available only at build time.
Example
A build command usually looks something like this:
Which is to say: âBuild an Image called my-docker-image
based on the file src/Dockerfile
with .
(or cwd
) as its build contextâ.
Docker Run
Tells Docker to execute the image as defined in the Dockerfile. If a command (or script) is appended, it will override the CMD
instruction (if set). Its more or less like spinning up a VM.
It must take an Image as parameter, although its options make it possible to override nearly all the commands specified in the Dockerfile. This allows for a lot of flexibility.
Common options
-it
It allocates a âpseudo-ttyâ and keeps STDIN open during execution. Useful if you want to be able to interact with your Container through command line.
ârm
Removes the Container from the hosts file system after execution.
-u
Changes the user and group (both of which are root
by default) for the specific execution. Useful if your docker Image outputs files to the hosts file system (which can get a bit unwieldy if done so as root
).
One neat thing you can do is make the docker Image run as the current host user (the one executing the command). You would do so by passing "$(id -u "$USER"):$(id -g "$USER")"
as the parameter for -u
.
âvolume
Allows you to bind or mount directories from the hosts file system to the Container, or from one Container to another.
Takes an argument of the structure host-source:container-destination
(container-destination
must be an absolute path).
Example
Run the Image tagged as my-docker-image
in a Container and execute useful-script.sh
at startup. Keep STDIN open with a âpseudo-ttyâ while running and remove the Container when done.
Also, mount the cwd
($PWD
) of the host into the /data
directory in the Container, and operate as the current host user (and group) instead of root
.
Docker Compose
Utility for managing the build and run of one or more Images, and the relations (or dependencies) between them.
You might be able to achieve similar results by just running the Images separately from the command line. This is however a really easy and convenient way of building complex systems of interconnected and/or interdependent Containers in a reproducible manner.
So just like you would build an Image from a Dockerfile, you can compose a bunch of Services from a docker-compose.yml
like:
As you might be able to tell by the general structure of the file, it is quite literally a sequence of âDockerfile-likeâ instructions enclosed within a sequence of âServicesâ (which for simplicity weâll consider equivalent to Containers).
How it works
- Define your app Image with a Dockerfile (and point to it from
docker-compose.yml
). - Define the Images for the rest of the Containers (Services) you need in
docker-compose.yml
. - Run
docker compose up
to start and run the Containers (docker compose down
will stop and remove the ongoing processes gracefully).
You can pass it the -d
flag to detach the process from the terminal and, just like with the build
command, you can use -f
to tell it where the docker-compose.yml
is located.