Docker Image
Docker image is essential component of container infrastructure. It is an image that contains an application and all its required parts (libraries and other files).
Docker image is created usually using a Dockerfile
. The Dockerfile
contains commands that builds the image, environment variables, command to run when starting the container, entrypoint and many other items.
Docker images are named using the following schema: registry/name:tag
. If registry
is omitted, docker hub registry is used. Example of docker image name is: cerit.io/xserver:v1.0
.
Before building own docker image, it is strongly recommended to search public registry for an existing image that contains desired application, but also check what is the time stamp of last image, i.e., if someone makes new releases and bug fixes. We can recommend, e.g., bitnami
images. There some limitation of using external docker images on our infrastructure, see limitations.
Create Own Docker Image
If you find it necessary to create own image, you find below a brief guide. For full guide see official docker documentation. Knowledge of installing Linux applications and basics of Linux packaging systems is required.
Here you find most common Dockerfile commands:
FROM image
– defines image name you start your docker image from, e.g.ubuntu
.RUN cmd
– run command that modifies the starting image, more than oneRUN
command can be used.COPY localfile containerfile
– copy local files into docker image, you can use optional--chown=user:group
to change ownership during copy. Copy and changing ownership later usingRUN chown
is discouraged as resulting image is twice as big.USER uid
– switch user touid
(or name), from this line, all other commands will run under identity of specified user, if this command was not used, everything is done asroot
user. The lastUSER uid
directive also specifies as which user the container will run by default.CMD command
– runcommand
as default command when starting the container.- ‘WORKDIR dir` – specifies current working directory, last working directory will be used as initial directory in a running container.
Example of Dockerfile:
FROM debian:buster
RUN apt update -y && apt upgrade -y && apt install build-essential libssh-dev git -y
RUN git clone https://gitlab.con/zvon/iobench && cd iobench && make && make install
USER 1000
CMD /bin/bash -c "tail -f /dev/null"
Dockerfile Tips
- Container usually does not have any created user in
/etc/passwd
. In this case, you can seeI have no name
prompt. Also in this case, there is nohome
directory which defaults to/
, many applications fail here as/
will not be writable. It is recommended to create some default user that the container run as. Name of the user is not important. The following command will create group namedgroup
and user nameduser
, doubleuser
at the end of the command is not an error.RUN addgroup --gid 1000 group && \ adduser --gid 1000 --uid 1000 --disable-password --gecos User user
- Container defaults to UTC time zone. If it not desired, it should be set to proper default, e.g.
RUN echo 'Europe/Prague' > /etc/timezone
- Packaging tools must not be interactive. E.g., for
deb
systems:RUN DEBIAN_FRONTEND=noniteractive apt-get install -y curl
Do not forget to add
-y
to most of packaging tools. - Debian family systems usually install recommended packages by default which is not desired here, disable it:
RUN apt-get install -y --no-install-recommends curl
- Keep resulting image as small as possible. It is needed to clean temporary files. E.g. for
deb
:RUN apt-get update && apt-get -y install curl && apt-get clean && rm -rf /var/lib/apt/lists/*
for
conda
:RUN conda install package && conda clean --all -f -y && rm -rf "~/.cache
Cleaning must be done within a single
RUN
command. -
Each
RUN
command creates a new docker image layer. It is recommended to merge related commands into a singleRUN
command, e.g., install all required packages at once, not one by one. -
For Kubernetes, there is no need to use the
EXPOSE
command to publish network ports. See Exposing applications. -
Running
chown
orchmod
doubles the size of changes files in the docker file, i.e.,chown
on all files in the docker file doubles the size of the docker file. - If chaining commands, always chain with
&&
and never with just;
. If one of commands fails, chaining with&&
stops build of whole image which is mostly desired. Chaining with;
can hide some failing commands and makes it hard to debug why image is not as it should be.
Building Docker Image
Manual Build
Once the Dockerfile
is created, the docker image can be built. The following describes manual docker image building. Manual building can be useful for debugging build process.
To be able to build docker image locally, you need to have a computer with Linux and with installed docker. For docker installation, follow instruction for your Linux distribution, usually docker-ce
is the right package. You may need to become member of docker
group to be able to use docker.
Put the Dockerfile
to a directory, e.g., mydocker
and run the following replacing repo/name:tag
with proper name and tag.
docker build -t repo/name:tag mydocker
If the build has been successful, image is locally built and needs to be pushed to a registry. If you are not logged into the registry, issue docker login registry
replacing registry
with real registry name.
docker push repo/name:tag
The repo/name:tag
must be exactly the same as in build case.
Automated Build
Automated build can be done using so called CI/CD pipeline. Build is done using runner component which is a part of many github/gitlab installation. You can utilize gitlab.ics.muni.cz, see GitLab Containers how to do it. This gitlab also provides docker registry so once built image can be stored here for using from Kubernetes. Registry is public or private depending on the project settings, see GitLab Containers.
Automated build can be slow, so it is not best option for debugging build process.
Running Docker Images
It can be useful to run the built image manually before running it on Kubernetes, e.g., checking that all the files are in place, important directories are writable and so on. Manual running is fast and has no restriction on privileges. However, be careful to run unknown images on own computer. To run docker image locally, you need Linux computer with installed docker, see manual build above.
Local run can be also useful for inspecting image, e.g., for getting UID
of running user, if it is not known as UID
may be needed for running in Kubernetes.
For testing purposes, you can run docker image using:
docker run -it --rm registry/name:tag command
This command will run the registry/name:tag
image and runs the commend
inside it. You can add -u uid
to run the image as user uid
.
If used image has ENTRYPOINT
set, the command
will not be run but only is passed as an argument to the ENTRYPOINT
script. If you need to avoid running, you can pass --entrypoint /bin/bash
option to docker run
. However, not all images have /bin/bash
or even /bin/sh
available. In such a case, you need to rebuild the image and add/install bash
or sh
.
Hitting ctrl-c
or ctrl-d
terminates the running docker image. All modifications inside the container are lost unless you use docker commit
, see official docker documentation, in this case, do not use --rm
option that removes exited images automatically.