When containers initially made their big splash into the industry via Docker,
users were almost required to use the docker
CLI and daemon to create and
manage their container images. But a lot has happened since then and now it
is easier than ever to create a container image without using docker
at all,
since the Docker image format has been standardized as the
OCI Image format.
In this post, we’ll review some of the ways you can create and manage your
container images without ever having to start the docker
daemon.
We’ll explore these alternative ways to build container images using a privileged user, but most of the approaches also have a way to build images using a non-privileged user. We’ll cover using a non-privileged user in a future blog post.
orca-build
The project that was probably first to build container images without docker
is the orca-build project from
Aleksa Sarai of SUSE. He’s created a simple
Python3 script which leverages runC,
skopeo, and the
umoci library to build container images.
Let’s see how it works with this simple Dockerfile that I’ve created to build
an httpd
container.
$ cat fedora27-httpd/Dockerfile
FROM registry.fedoraproject.org/fedora:27
LABEL maintainer='Micah Abbott <miabbott@redhat.com>' \
version='1.0'
ENV container=docker
COPY Dockerfile /root/
RUN dnf -y install httpd && \
dnf clean all && \
echo "SUCCESS fedora27_httpd" > /var/www/html/index.html
EXPOSE 80
ENTRYPOINT [ "/usr/sbin/httpd" ]
CMD [ "-D", "FOREGROUND" ]
Using a Fedora 27 system, I’ll install the dependencies for using orca-build
and then build the container image from the Dockerfile. (But obviously, I
won’t be installing docker
).
# rpm -q docker
package docker is not installed
# systemctl status docker
Unit docker.service could not be found.
# dnf -y install git golang runc skopeo
# export GOPATH=$HOME/go
# export PATH=$PATH:$GOPATH/bin
# go get -d github.com/openSUSE/umoci
# cd $GOPATH/src/github.com/openSUSE/umoci/
# make
# cp $GOPATH/src/github.com/openSUSE/umoci/umoci $GOPATH/bin/
# cd $HOME
# git clone https://github.com/cyphar/orca-build.git
# cd orca-build
# python3 orca-build -t fedora27-httpd:orca $HOME/fedora27-httpd/
orca-build[INFO] Created new image for build: /tmp/orca-build.y3n_2i0m
orca-build[INFO] BUILD[1 of 8]: from ['registry.fedoraproject.org/fedora:27'] [json=False]
---> [skopeo]
Getting image source signatures
Copying blob sha256:d445b8c354cc48e75ed621cb6783a80c29ac24135cdd98fd02ae70e1f18345bc
80.81 MB / 80.81 MB [=====================================================] 10s
Copying config sha256:400ec4f003634cb31d8b37d68ac56c41c6bbd8eb02eb7d7151b0ade59e513594
424 B / 424 B [============================================================] 0s
Writing manifest to image destination
Storing signatures
<--- [skopeo]
orca-build[INFO] BUILD[2 of 8]: label ['maintainer=Micah Abbott <miabbott@redhat.com>', 'version=1.0'] [json=False]
---> [umoci]
<--- [umoci]
---> [umoci]
<--- [umoci]
orca-build[INFO] BUILD[3 of 8]: env ['container=docker'] [json=False]
---> [umoci]
<--- [umoci]
---> [umoci]
<--- [umoci]
orca-build[INFO] BUILD[4 of 8]: copy ['Dockerfile', '/root/'] [json=False]
---> [umoci]
<--- [umoci]
---> [umoci]
<--- [umoci]
---> [umoci]
<--- [umoci]
orca-build[INFO] BUILD[5 of 8]: run ['dnf', '-y', 'install', 'httpd', '&&', 'dnf', 'clean', 'all', '&&', 'echo', 'SUCCESS fedora27_httpd', '>', '/var/www/html/index.html'] [json=False]
---> [umoci]
<--- [umoci]
---> [runc]
Error: Failed to synchronize cache for repo 'updates'
<--- [runc]
orca-build[CRITICAL] Error executing subprocess: runc --root=/tmp/orca-runcroot.un2g__rz run --bundle=/tmp/orca-bundle.dw5x64x0 orca-build-6bE2dWZlNxyZELMtkmHjObCb9fAkvMbq failed with error code 1
Hmmm…I believe runc
doesn’t have network access to allow dnf
to install
packages. That is disappointing. But I don’t want to spend too much time on
any one way of building an image, so let’s move on to another method.
jessfraz/img
Jessie Frazelle recently announced her own
project called img that handles building
OCI images without docker
. Her approach uses a Go binary that leverages
buildkit from the Moby project to build
images.
Using the same Dockerfile and Fedora 27 system, let’s try to build the image.
# go get github.com/jessfraz/img
# img build -t fedora27-httpd:img $HOME/fedora27-httpd/
Building fedora27-httpd:img
Setting up the rootfs... this may take a bit.
INFO[0001] resolving docker.io/tonistiigi/copy@sha256:476e0a67a1e4650c6adaf213269a2913deb7c52cbc77f954026f769d51e1a14e
INFO[0001] resolving registry.fedoraproject.org/fedora:27@sha256:3a75aec3625da0c80dcedda6a0321f997f812e24336a1c06d8b402afffc55450
INFO[0010] unpacking registry.fedoraproject.org/fedora:27@sha256:3a75aec3625da0c80dcedda6a0321f997f812e24336a1c06d8b402afffc55450
RUN [copy /src-0/Dockerfile /dest/root/]
--->
<--- e70rtudliv77emdm70tc5m027 0 <nil>
RUN [/bin/sh -c dnf -y install httpd && dnf clean all && echo "SUCCESS fedora27_httpd" > /var/www/html/index.html]
--->
Fedora 27 - x86_64 - Updates 8.8 MB/s | 20 MB 00:02
Fedora 27 - x86_64 6.1 MB/s | 58 MB 00:09
Last metadata expiration check: 0:00:05 ago on Sat Mar 3 21:06:25 2018.
Dependencies resolved.
================================================================================
Package Arch Version Repository Size
================================================================================
Installing:
httpd x86_64 2.4.29-1.fc27 updates 1.3 M
Installing dependencies:
apr x86_64 1.6.3-1.fc27 updates 121 k
apr-util x86_64 1.6.1-2.fc27 updates 102 k
fedora-logos-httpd noarch 28.0.2-1.fc27 updates 33 k
httpd-filesystem noarch 2.4.29-1.fc27 updates 25 k
httpd-tools x86_64 2.4.29-1.fc27 updates 89 k
mailcap noarch 2.1.48-2.fc27 fedora 37 k
mod_http2 x86_64 1.10.13-1.fc27 updates 151 k
Transaction Summary
================================================================================
Install 8 Packages
Total download size: 1.9 M
Installed size: 5.0 M
Downloading Packages:
(1/8): httpd-filesystem-2.4.29-1.fc27.noarch.rp 66 kB/s | 25 kB 00:00
(2/8): mailcap-2.1.48-2.fc27.noarch.rpm 431 kB/s | 37 kB 00:00
(3/8): httpd-tools-2.4.29-1.fc27.x86_64.rpm 136 kB/s | 89 kB 00:00
(4/8): apr-1.6.3-1.fc27.x86_64.rpm 319 kB/s | 121 kB 00:00
(5/8): apr-util-1.6.1-2.fc27.x86_64.rpm 338 kB/s | 102 kB 00:00
(6/8): mod_http2-1.10.13-1.fc27.x86_64.rpm 728 kB/s | 151 kB 00:00
(7/8): fedora-logos-httpd-28.0.2-1.fc27.noarch. 332 kB/s | 33 kB 00:00
(8/8): httpd-2.4.29-1.fc27.x86_64.rpm 984 kB/s | 1.3 MB 00:01
--------------------------------------------------------------------------------
Total 857 kB/s | 1.9 MB 00:02
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
Preparing : 1/1
Installing : apr-1.6.3-1.fc27.x86_64 1/8
Running scriptlet: apr-1.6.3-1.fc27.x86_64 1/8
Installing : apr-util-1.6.1-2.fc27.x86_64 2/8
Running scriptlet: apr-util-1.6.1-2.fc27.x86_64 2/8
Installing : httpd-tools-2.4.29-1.fc27.x86_64 3/8
Installing : fedora-logos-httpd-28.0.2-1.fc27.noarch 4/8
Installing : mailcap-2.1.48-2.fc27.noarch 5/8
Running scriptlet: httpd-filesystem-2.4.29-1.fc27.noarch 6/8
Installing : httpd-filesystem-2.4.29-1.fc27.noarch 6/8
Installing : mod_http2-1.10.13-1.fc27.x86_64 7/8
Installing : httpd-2.4.29-1.fc27.x86_64 8/8
Running scriptlet: httpd-2.4.29-1.fc27.x86_64 8/8Failed to connect to bus: No such file or directory
Verifying : httpd-2.4.29-1.fc27.x86_64 1/8
Verifying : httpd-filesystem-2.4.29-1.fc27.noarch 2/8
Verifying : httpd-tools-2.4.29-1.fc27.x86_64 3/8
Verifying : mailcap-2.1.48-2.fc27.noarch 4/8
Verifying : apr-1.6.3-1.fc27.x86_64 5/8
Verifying : apr-util-1.6.1-2.fc27.x86_64 6/8
Verifying : mod_http2-1.10.13-1.fc27.x86_64 7/8
Verifying : fedora-logos-httpd-28.0.2-1.fc27.noarch 8/8
Installed:
httpd.x86_64 2.4.29-1.fc27 apr.x86_64 1.6.3-1.fc27
apr-util.x86_64 1.6.1-2.fc27 fedora-logos-httpd.noarch 28.0.2-1.fc27
httpd-filesystem.noarch 2.4.29-1.fc27 httpd-tools.x86_64 2.4.29-1.fc27
mailcap.noarch 2.1.48-2.fc27 mod_http2.x86_64 1.10.13-1.fc27
Complete!
18 files removed
<--- rx3j12yy3t0ea0shbimrgxtdx 0 <nil>
INFO[0063] exporting layers
INFO[0066] exporting manifest sha256:1fd9c488a4f116e3d02c5ea0d9277994bc8145ea7bb5021442b348b257b7b6e6
INFO[0066] exporting config sha256:ae05d003b8ec6d046eb73ca8d3333a9d6e10bac332af7591a101f6f118f2bf7c
INFO[0066] naming to fedora27-httpd:img
Successfully built fedora27-httpd:img
We can also use img
to list the container image that was just built.
# img ls
NAME SIZE CREATED AT UPDATED AT DIGEST
docker.io/tonistiigi/copy@sha256:476e0a67a1e4650c6adaf213269a2913deb7c52cbc77f954026f769d51e1a14e 1.333KiB 7 days ago 7 days ago sha256:476e0a67a1e4650c6adaf213269a2913deb7c52cbc77f954026f769d51e1a14e
fedora27-httpd:img 754B 7 days ago 43 hours ago sha256:1fd9c488a4f116e3d02c5ea0d9277994bc8145ea7bb5021442b348b257b7b6e6
That was pretty easy and successful! There are more things that img
can
do, but let’s continue to expore other ways to build container images.
DIY Docker using Skopeo+OStree+Runc
Muayyad Alsadi recently shared his blog
post called DIY Docker using Skopeo+OStree+Runc
to the atomic-devel
mailing list. In his post, he describes using skopeo
and ostree
to pull
down existing Docker images and building out a rootfs that can be used by
runc
. It is not exactly the same operation as building a container image
from a Dockerfile, but it is a useful exercise to show off some of the gory
details of working with OCI images.
But what if you don’t want to have to run multiple skopeo
and ostree
commands to pull down content and prep a container image? Or maybe you don’t
really care about the details of OCI images and you just want to pull a
container image without docker
?
All of those operations are neatly wrapped up in the atomic CLI and can be reduced to a single command!
# atomic pull --storage=ostree docker.io/redis:alpine
Getting image source signatures
Copying blob sha256:ff3a5c916c92643ff77519ffa742d3ec61b7f591b6b7504599d95a4a41134e28
1.97 MB / 1.97 MB [========================================================] 0s
Copying blob sha256:aae70a2e60279ffae89150a59b81fe10d1d81f341ef6f31b9714ea6cc3418577
1.22 KB / 1.22 KB [========================================================] 0s
Copying blob sha256:87c655da471c9a7d8f946ec7b04a6a72a98ae8c1734bddf4b950861b5638fe20
8.35 KB / 8.35 KB [========================================================] 0s
Copying blob sha256:a0bd51ac7350a7048a0bd85a83d87181a0b851952e94f70e18c1ddb6ff96e66e
7.73 MB / 7.73 MB [========================================================] 0s
Copying blob sha256:755565c3ea2b1335705a21024b1bdb607f85492b284e8dec37eb759c0d601f57
99 B / 99 B [==============================================================] 0s
Copying blob sha256:8bf100ea488d16d4401a9af72879db0c1ab56045b42670ebf64fe1f8d90568fc
397 B / 397 B [============================================================] 0s
Copying config sha256:d3117424aaee14ab2b0edb68d3e3dcc1785b2e243b06bd6322f299284c640465
4.68 KB / 4.68 KB [========================================================] 0s
Writing manifest to image destination
Storing signatures
And soon, you’ll be able to use the very same atomic
command to run the
container image via runc
. Keep your eyes open for new versions of atomic
that will include this pull request
from Giuseppe Scrivano.
There’s one more way to build container images that we’ll cover before wrapping up this post.
Use This One Weird Command to Build OCI Images!
Maybe you are thinking, Gee, it’s great that we have all these ways to build
container images without Docker, but I’d really like a tool that highlights my
Boston accent.
Enter buildah!
You’ve probably already seen this tool mentioned on this blog a few times, but it’s worth showing off another time just how easy it is to install and use. We’ll continue to use the same Dockerfile and Fedora 27 system to build our image.
# dnf install buildah
# buildah bud -t fedora27_httpd:buildah $HOME/fedora27-httpd/
STEP 1: FROM registry.fedoraproject.org/fedora:27
Getting image source signatures
Copying blob sha256:d445b8c354cc48e75ed621cb6783a80c29ac24135cdd98fd02ae70e1f18345bc
80.81 MiB / 80.81 MiB [===================================================] 32s
Copying config sha256:99b71991af6eef73e85e3a657641cf2447929f37fff1f9570d525a6ef485a4a8
1.27 KiB / 1.27 KiB [======================================================] 0s
Writing manifest to image destination
Storing signatures
STEP 2: LABEL maintainer='Micah Abbott <miabbott@redhat.com>' version='1.0'
STEP 3: ENV container=docker
STEP 4: COPY Dockerfile /root/
STEP 5: RUN dnf -y install httpd && dnf clean all && echo "SUCCESS fedora27_httpd" > /var/www/html/index.html
Fedora 27 - x86_64 - Updates 3.0 MB/s | 20 MB 00:06
Fedora 27 - x86_64 1.6 MB/s | 58 MB 00:35
Last metadata expiration check: 0:00:08 ago on Mon Mar 5 16:02:41 2018.
Dependencies resolved.
================================================================================
Package Arch Version Repository Size
================================================================================
Installing:
httpd x86_64 2.4.29-1.fc27 updates 1.3 M
Installing dependencies:
apr x86_64 1.6.3-1.fc27 updates 121 k
apr-util x86_64 1.6.1-2.fc27 updates 102 k
fedora-logos-httpd noarch 28.0.2-1.fc27 updates 33 k
httpd-filesystem noarch 2.4.29-1.fc27 updates 25 k
httpd-tools x86_64 2.4.29-1.fc27 updates 89 k
mailcap noarch 2.1.48-2.fc27 fedora 37 k
mod_http2 x86_64 1.10.13-1.fc27 updates 151 k
Transaction Summary
================================================================================
Install 8 Packages
Total download size: 1.9 M
Installed size: 5.0 M
Downloading Packages:
(1/8): httpd-filesystem-2.4.29-1.fc27.noarch.rp 107 kB/s | 25 kB 00:00
(2/8): httpd-tools-2.4.29-1.fc27.x86_64.rpm 208 kB/s | 89 kB 00:00
(3/8): mailcap-2.1.48-2.fc27.noarch.rpm 127 kB/s | 37 kB 00:00
(4/8): apr-util-1.6.1-2.fc27.x86_64.rpm 452 kB/s | 102 kB 00:00
(5/8): apr-1.6.3-1.fc27.x86_64.rpm 305 kB/s | 121 kB 00:00
(6/8): fedora-logos-httpd-28.0.2-1.fc27.noarch. 355 kB/s | 33 kB 00:00
(7/8): mod_http2-1.10.13-1.fc27.x86_64.rpm 699 kB/s | 151 kB 00:00
(8/8): httpd-2.4.29-1.fc27.x86_64.rpm 1.1 MB/s | 1.3 MB 00:01
--------------------------------------------------------------------------------
Total 933 kB/s | 1.9 MB 00:02
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
Preparing : 1/1
Installing : apr-1.6.3-1.fc27.x86_64 1/8
Running scriptlet: apr-1.6.3-1.fc27.x86_64 1/8
Installing : apr-util-1.6.1-2.fc27.x86_64 2/8
Running scriptlet: apr-util-1.6.1-2.fc27.x86_64 2/8
Installing : httpd-tools-2.4.29-1.fc27.x86_64 3/8
Installing : fedora-logos-httpd-28.0.2-1.fc27.noarch 4/8
Installing : mailcap-2.1.48-2.fc27.noarch 5/8
Running scriptlet: httpd-filesystem-2.4.29-1.fc27.noarch 6/8
Installing : httpd-filesystem-2.4.29-1.fc27.noarch 6/8
Installing : mod_http2-1.10.13-1.fc27.x86_64 7/8
Installing : httpd-2.4.29-1.fc27.x86_64 8/8
Running scriptlet: httpd-2.4.29-1.fc27.x86_64 8/8
Failed to connect to bus: No such file or directory
Verifying : httpd-2.4.29-1.fc27.x86_64 1/8
Verifying : httpd-filesystem-2.4.29-1.fc27.noarch 2/8
Verifying : httpd-tools-2.4.29-1.fc27.x86_64 3/8
Verifying : mailcap-2.1.48-2.fc27.noarch 4/8
Verifying : apr-1.6.3-1.fc27.x86_64 5/8
Verifying : apr-util-1.6.1-2.fc27.x86_64 6/8
Verifying : mod_http2-1.10.13-1.fc27.x86_64 7/8
Verifying : fedora-logos-httpd-28.0.2-1.fc27.noarch 8/8
Installed:
httpd.x86_64 2.4.29-1.fc27 apr.x86_64 1.6.3-1.fc27
apr-util.x86_64 1.6.1-2.fc27 fedora-logos-httpd.noarch 28.0.2-1.fc27
httpd-filesystem.noarch 2.4.29-1.fc27 httpd-tools.x86_64 2.4.29-1.fc27
mailcap.noarch 2.1.48-2.fc27 mod_http2.x86_64 1.10.13-1.fc27
Complete!
18 files removed
STEP 6: EXPOSE 80
STEP 7: ENTRYPOINT [ "/usr/sbin/httpd" ]
STEP 8: CMD [ "-D", "FOREGROUND" ]
STEP 9: COMMIT containers-storage:[overlay@/var/lib/containers/storage+/var/run/containers/storage:overlay.override_kernel_check=true]docker.io/library/fedora27_httpd:buildah
[root@fedora27cloud-dev ~]# buildah images
IMAGE ID IMAGE NAME CREATED AT SIZE
99b71991af6e registry.fedoraproject.org/fedora:27 Mar 1, 2018 07:48 234.9 MB
c3fddc394f81 docker.io/library/fedora27_httpd:buildah Mar 5, 2018 16:03 252 MB
On my Fedora 27 host, I just needed two commands to install buildah
and
build the container image! When you pair buildah
with atomic
, you have
a powerful combination of tools that will allow you to build, manage, and run
your container images without ever having to run the Docker daemon.