Container Building

This document assumes you already read ContainerIntroduction.

Our tool to build images is podman together with a Containerfile describing the build.

Containerfile

The Containerfile contains all steps to create an image.

mkdir my-first-container
touch my-first-container/Containerfile
cd my-first-container

And then open the file in an editor of your choice.

FROM

Every Image needs a starting point. In theory we could start with

FROM scratch

With this we could tightly control what is part of the image and create very small images. For the time beeing we choose to start with something that is similiar to our "normal" server setup. Rocky8.

FROM library/rockylinux:8

This base image is about 220MB in size. For convenience a aco base image is available (aco/base:8). It is configured to use our in-house yum repositories and includes our certificate authority.

FROM aco/base:8

LABEL

Leave a note who is responsible for this
MAINTAINER my.name@gsi.de

COPY / ADD

copy in some local files The source can be a path relative to the Containerfile (best practice) or an absolute path

COPY somefile /somewhereinthecontainer
COPY lsa-server.zip /tmp/lsa-server.zip

ADD has additional magic. It can handle urls and automatic tarball expansion. For clarity most of the time copy is the better solution.

RUN

Run a command inside the container.

RUN mkdir /opt/lsa-server
RUN cd /opt/lsa-server && unzip /tmp/lsa-server.zip

CMD

If the image is run as a container, this command should be executed
CMD /opt/lsa-server/bin/lsa-server.sh --config=DEV

ARG

Arguments can be passed to the build process and used during image building. For example it would be nice we could specify the version of our product without changing the containerfile

ARG version=default
RUN curl -o my-app.zip "https://example.com/my-app-${version}.zip"; unzip my-app.zip; rm -f my-app.zip

Note: Why is this in one line? See layers below.

Note: Couldn't we just use a pipe to extract on the fly? Zipfiles are not realy pipeable as the main header is at the content index is at the end of the file.

ENV

Environment variables are the main option to configure a container image during runtime.

ENV CONFIG dev
CMD /my/app.sh --config ${CONFIG}

what is the difference to an argument? We can specify the value during runtime podman run -e CONFIG=pro lsa/server:version

USER

Even if containers are isolated, it is good practice to not run a process as root. The aco/base image includes a user alice which can be used for this. The instruction switches to the user. All commands after this are run as alice.

USER alice
CMD /my/app.sh

build

podman build -t lsa/server:version .

or if we have arguments

podman build -t lsa/server:13.0.1 --build-args version=13.0.1 .

if the base image (from) is present it is not pulled again. Images may follow a branch and have a stable tag. That is, their content changes, but the tag is stable. To update these images run

podman build --pull=always  .

inspect

once the build completed we can inspect the image with all it's layers

podman inspect lsa/server:version

layers

An image consists of layers. Every layer is a readonly set of files. Each layer can add, remove, overwrite files in the lower layers. Layers are referenced via checksums and can be reused.

By default each ADD or RUN will create a new layer. If you add a 100MB file and then run rm to remove it again, this results in an intermediate layer with 100MB which is not required. To avoid this, we can skip creating layers.

podman build -t lsa/server:version --layers=false .

All steps are still visible but don't use space. During development it makes sense to have layers so as long as nothing changed previous steps could be retrieved from the layer cache, but before publishing it makes sense to reduce the size.

Note: if you installed additional packages using yum, wipe the package cache before shipping by cleaning up

RUN dnf install -y something
RUN dnf clean all
# or
RUN dnf install -y something; dnf clean all
# and best practice, install everything in one go, alphabetical sorted
RUN dnf install -y \
   a \
   b \
   ; dnf clean all

tags

every image has a version tag. By default this is latest. If you want reproducibale builds never use latest in your from line. If you want to have a stable container, never use latest in your deployments.

publish

and finally we need to publish our image so everyone can use it. First we need to login to the ContainerRegistry, see Authentication how to get your clisecret.

podman login -u USERNAME -p CLISECRET registry.acc.gsi.de

so we can now push/deploy the image

podman push localhost/lsa/server:version registry.acc.gsi.de/lsa/server:version
Topic revision: r14 - 29 Jun 2022, ChristophHandel
This site is powered by FoswikiCopyright © by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding Foswiki? Send feedback