Container Image Creation

Container images in Fedora are built using a Dockerfile much in the same way an RPM is built using a spec file. In this section are Fedora Guidelines for creating Container images using a Dockerfile.

Dockerfile Example

FROM registry.fedoraproject.org/fedora:rawhide

ENV NAME=mycontainer VERSION=0 ARCH=x86_64
LABEL   com.redhat.component="$NAME" \
        name="$FGC/$NAME" \
        version="$VERSION" \
        architecture="$ARCH" \
        run="podman run -p 1337:1337 IMAGE" \
        summary="mycontainer exposes something on port 1337." \
        maintainer="Christian Glombek <lorbus@fedoraproject.org>"

EXPOSE 1337

RUN dnf -y --setopt=tsflags=nodocs install mypackage && \
    dnf clean all

COPY root/help.1 /
COPY script.sh /usr/bin/

CMD ["/usr/bin/script.sh"]

FROM

As defined by the Dockerfile reference, the FROM instruction '''must''' be the first line of a Dockerfile. The FROM instruction '''must''' be fully-qualified with the fedora registry name, image name, and tag as shown in this example:

This provides a guarantee of where the base image is coming from when being built by the build service or when rebuilt by a user.

For most layered images built by the https://docs.pagure.org/releng/layered_image_build_service.html[Fedora Layered Docker Image Build Service], the FROM line will use one of the Fedora base images that exist on the https://registry.fedoraproject.org/[Fedora Container Registry]:

``` FROM registry.fedoraproject.org/fedora:latest ```

It is also possible to use another layered image as the base layer, as in this example:

``` FROM registry.fedoraproject.org/f25/kubernetes-master:latest ```


=== Labels

Dockerfiles have a concept of a https://docs.docker.com/engine/reference/builder/#label[LABEL] which can add arbitrary metadata to an image as a key-value pair. Fedora Guidelines on the topic of LABELs follows the http://www.projectatomic.io/[Project Atomic] https://github.com/projectatomic/ContainerApplicationGenericLabels[Container Application Generic Labels] standards for LABEL definition.

'''Required''' LABELs for a Fedora Layered Image are as follows:

[cols="2*", options"header"]
|===
|Name
|Description

|com.redhat.component
|The Bugzilla component name where bugs against this container should be reported by users.

|name
|Name of the Image

|version
|Version of the image

|architecture
|Architecture the software in the image should target (Optional: if omitted, it will be built for all supported Fedora Architectures)

|maintainer
|The name and email of the maintainer (usually the submitter)

|run or usage
|Either provides an Atomic run line, or a human readable example of container execution

|summary
|A short description of the image.
|===

'''Optional''' labels for Fedora Layered Images

[cols="2*", options"header"]
|===
|Name
|Description

|install
|Powers "atomic install" command. Not used for system containers.

|uninstall
|Powers "atomic uninstall" command.  Required if Install is present.

|url
|A URL where the user can find more information about the image.

|help
|A runnable command which results in display of Help information.

|atomic.type
|Used for system containers, see below.

|Generics
|Any of the https://github.com/projectatomic/ContainerApplicationGenericLabels[Container Application Generic Labels] which are appropriate to the container, such as "stop", "debug", or "changelog-url"
|===

See LABEL SPECIFICATION below for more details on what's required for each of these labels.

{{admon/note|Dockerfile Label Guidelines Upstream| The LABELs used here are meant to be a Fedora adaptation of the upstream https://projectatomic.io[Project Atomic] effort to define https://github.com/projectatomic/ContainerApplicationGenericLabels[Container Application Generic Labels] as well as http://docs.projectatomic.io/container-best-practices/[Container Best Practices]. }}

In the past these LABELs had to be defined in a single line of the Dockerfile so they would not lead to additional layers in the build. Recent OSBS versions squash all layers built on top of the parent image into a single layer, meaning there is no need to have all LABELs or RUN commands in a single line.

The following is a very simple Dockerfile example containing the required LABELs:

[source]
----
FROM registry.fedoraproject.org/fedora:rawhide

ENV NAME=mycontainer VERSION=0 ARCH=x86_64
LABEL   com.redhat.component="$NAME" \
        name="$FGC/$NAME" \
        version="$VERSION" \
        architecture="$ARCH" \
        run="podman run -p 1337:1337 IMAGE" \
        summary="mycontainer exposes something on port 1337." \
        maintainer="Christian Glombek <lorbus@fedoraproject.org>"

EXPOSE 1337

RUN dnf -y --setopt=tsflags=nodocs install mypackage && \
    dnf clean all

COPY root/help.1 /
COPY script.sh /usr/bin/

CMD ["/usr/bin/script.sh"]
----


=== LABEL SPECIFICATION

Some additional details about how each label is to be populated.

'''com.redhat.component''': Existing Bugzilla component against which bugs in this image should be reported.

'''name''': Name of the image. If the image replaces a standard RPM, it should have the exact same name of that RPM. Otherwise, please see naming guidelines above.

'''version''': Usually 0. Populated from the ENV variable. See "VERSIONING" below for explanation.

'''architecture''': usually "x86_64", unless the container image supports other/all architectures.

'''usage''': a human-readable example command line for invoking the container. Required if run is not present. Should include all likely options, such as ports, volumes, and any required command-line parameters. You may use any container runtime as your example. Example from the OwnCloud container:

    usage="docker run -d -P -v owncloud-data:/var/lib/owncloud -v owncloud-config:/etc/owncloud owncloud"

'''summary''': A short description of the image, intended to be searchable once we have a registry with search functionality. Please include relevant keywords.

'''run''': a command line to invoke the container, suitable for use by the https://github.com/projectatomic/atomic[Atomic CLI], including placeholders and the embedded atomic-run code. Must successfully execute on a suitable Fedora Atomic system. Required if "usage" is not present. Example for the Cockpit container:

    run="/usr/bin/docker run -d --privileged --pid=host -v /:/host IMAGE /container/atomic-run --local-ssh"

'''install''': A container may require preparation of the host system before the container can be run. In this case the install label is useful for defining what operations should be performed on the host to prepare it. The set of operations should be as minimal as possible and should not include any operation that is not useful for preparing the host to run the container. If an install label is provided then it must be tested and work with the https://github.com/projectatomic/atomic[Atomic CLI]. Optionally an uninstall label should also be provided that will allow for cleaning up any operations done by install. Please refer to the https://github.com/projectatomic/atomic#atomic-install[upstream documentation] for more information. Example for the Cockpit container:

    install="/usr/bin/docker run --rm --privileged -v /:/host IMAGE /container/atomic-install"

'''uninstall''': If a container has an install label then most likely an uninstall label will be needed in order to delete any files and/or to clean up any configuration that was done or to the host system. It is not required to delete files that may contain user data. In unusual cases there may be no files or configuration to clean up from the install label so the uninstall label might not be needed. If an uninstall label is provided then it must be tested and work with the https://github.com/projectatomic/atomic[Atomic CLI]. Please refer to the https://github.com/projectatomic/atomic#atomic-uninstall[upstream documentation] for more information.

    uninstall="/usr/bin/docker run --rm --privileged -v /:/host IMAGE /container/atomic-uninstall"

'''url''': A URL where users can get more information about the image, such as a github or pagure repository, or software documentation.

'''help''': A runnable command which outputs a man page or other "help" information. If supplied, must be tested with `atomic help`. If you have a help command, you do not need to also supply a Help File (see below).


=== Versioning

In the previous section there was coverage of LABELs, one of those is the Version that is set in the example using the `ENV` variable `VERSION` which at this time needs to be `0`. OSBS handle automatically the increase of the release number for a given version of the container image.

At this time there is no way to automatically populate the `Version`/`VERSION` value with the same value of the latest version of the primary RPM belonging to the container image. This is something that is currently https://pagure.io/atomic-wg/issue/249[on the roadmap].

Why is this needed?

If we set the `Version` LABEL to the version of it's respective RPM at the time of the Container Image Review, then the maintainer will constantly have to update it by hand every time there is a RPM update which is inconvenient and error prone. Beyond that, there's a possibility that the version of the RPM could be updated by the layered image automatic rebuilds and the maintainer isn't able to update the `Dockerfile` in a timely manner (Automatic Rebuilds are done by https://docs.pagure.org/releng/[Release Engineering] in order to pull in security updates for all layered images). If this were to happen, then the version of the container image will not match the version of the software it's meant to deliver which would lead to confusion and potentially unexpected negative side effects for users. Therefore, for the time being we're saying that the version number of the container is not meaningful but it will be as soon as possible.


=== CMD / ENTRYPOINT

Another item required is a CMD or ENTRYPOINT entry so that when an user were run perform the following command (for example), expected behavior occurs.:

``` docker run registry.fedoraproject.org/f25/myawesomecontainer ```

For more information on these entries, please reference the upstream https://docs.docker.com/engine/reference/builder/[Dockerfile documentation].


=== Volumes

The use of container volumes for persistent data is permitted and encouraged, but the following guidelines need to be followed:

* Any user data that would be at risk of loss on update '''must''' be in a volume.
* Any application configuration data that requires persistence '''must''' be in a volume. Configuration by environment variables instead is also allowed, either together or instead of configuration volumes.
* All volumes listed in the Dockerfile '''must''' be listed in the Help File.
* The example run command '''should''' have the volume with a persistent name (e.g. "docker run -d -v owncloud-data:/var/lib/owncloud -v owncloud-config:/etc/owncloud owncloud")
* Volumes '''must''' be defined as narrowly as possible. Specifically, unless the image is intended for use as a system container intended for system administration, volumes must be defined so as to mount system directories which are exclusive to the container. For example, the container must mount /etc/application-name/ for config files, ''not'' /etc/.

Each volume in the Help File '''must''' have the following:
* The full path of the volume
* Why it is marked a volume (such as why this config needs persistence or indicating user data lives there)

Volumes listed in the Help File '''should''' also include information about space, permissions, and performance requirements.

The readme '''may''' contain suggested additional volumes that aren't made mandatory by the Dockerfile, such as locations for generated, rather than self signed, ssl certificates.