Docker FROM debian:latest

So in my last article I created a Docker container with nothing but a statically compiled helloworld in it. That demonstrated how it’s possible to define a very very (very very) simple container.

Here I define a similarly simple container with more complex dependencies – a hello world perl script requiring the Modern::Perl perl module. Now I don’t even need to build the executable binary, but all of a sudden I need to include enough of an environment to support my simple perl script.

As far as working with Docker this is not much more complex than changing “FROM scratch” to “FROM debian:latest”. The result is a much bigger container which will take more resources to run, but other than providing the computing resources to support that I really don’t have to care about it that much.

The Dockerfile now looks like this:

FROM debian:latest

# Get base module requirements
RUN apt-get --assume-yes update &&\
    apt-get --assume-yes install libmodern-perl-perl

# Copy the script in place and start running
COPY hello.pl /
CMD ["/hello.pl"]

But the container build process is no longer a couple of lines:

$ make docker
docker build --rm -t bradhelloperl .
Sending build context to Docker daemon 4.096 kB
Sending build context to Docker daemon 
Step 0 : FROM debian:latest
latest: Pulling from debian
902b87aaaec9: Already exists 
9a61b6b1315e: Already exists 
Digest: sha256:b42e664a14b4ed96f7891103a6d0002a6ae2f09f5380c3171566bc5b6446a8ce
Status: Downloaded newer image for debian:latest
 ---> 9a61b6b1315e
Step 1 : RUN apt-get --assume-yes update &&    apt-get --assume-yes install libmodern-perl-perl
 ---> Running in afe73c43d3a8
Get:1 http://security.debian.org jessie/updates InRelease [63.1 kB]
Get:2 http://security.debian.org jessie/updates/main amd64 Packages [165 kB]
Get:3 http://httpredir.debian.org jessie InRelease [134 kB]
Get:4 http://httpredir.debian.org jessie-updates InRelease [123 kB]
Get:5 http://httpredir.debian.org jessie/main amd64 Packages [9038 kB]
Get:6 http://httpredir.debian.org jessie-updates/main amd64 Packages [3614 B]
Fetched 9527 kB in 40s (237 kB/s)
Reading package lists...
Reading package lists...
Building dependency tree...
Reading state information...
The following extra packages will be installed:
  libalgorithm-c3-perl libarchive-extract-perl libcgi-fast-perl libcgi-pm-perl
  libclass-c3-perl libclass-c3-xs-perl libcpan-meta-perl libdata-optlist-perl
  libdata-section-perl libfcgi-perl libgdbm3 liblog-message-perl
  liblog-message-simple-perl libmodule-build-perl libmodule-pluggable-perl
  libmodule-signature-perl libmro-compat-perl libpackage-constants-perl
  libparams-util-perl libpod-latex-perl libpod-readme-perl
  libregexp-common-perl libsoftware-license-perl libsub-exporter-perl
  libsub-install-perl libterm-ui-perl libtext-soundex-perl
  libtext-template-perl perl perl-modules rename
Suggested packages:
  perl-doc libterm-readline-gnu-perl libterm-readline-perl-perl make
  libb-lint-perl libcpanplus-dist-build-perl libcpanplus-perl
  libfile-checktree-perl libobject-accessor-perl
Recommended packages:
  libarchive-tar-perl
The following NEW packages will be installed:
  libalgorithm-c3-perl libarchive-extract-perl libcgi-fast-perl libcgi-pm-perl
  libclass-c3-perl libclass-c3-xs-perl libcpan-meta-perl libdata-optlist-perl
  libdata-section-perl libfcgi-perl libgdbm3 liblog-message-perl
  liblog-message-simple-perl libmodern-perl-perl libmodule-build-perl
  libmodule-pluggable-perl libmodule-signature-perl libmro-compat-perl
  libpackage-constants-perl libparams-util-perl libpod-latex-perl
  libpod-readme-perl libregexp-common-perl libsoftware-license-perl
  libsub-exporter-perl libsub-install-perl libterm-ui-perl
  libtext-soundex-perl libtext-template-perl perl perl-modules rename
0 upgraded, 32 newly installed, 0 to remove and 1 not upgraded.
Need to get 6606 kB of archives.
After this operation, 37.3 MB of additional disk space will be used.
Get:1 http://httpredir.debian.org/debian/ jessie/main libgdbm3 amd64 1.8.3-13.1 [30.0 kB]
Get:2 http://httpredir.debian.org/debian/ jessie/main libalgorithm-c3-perl all 0.09-1 [11.9 kB]
Get:3 http://httpredir.debian.org/debian/ jessie/main libarchive-extract-perl all 0.72-1 [24.8 kB]
Get:4 http://httpredir.debian.org/debian/ jessie/main perl-modules all 5.20.2-3+deb8u1 [2551 kB]
Get:5 http://httpredir.debian.org/debian/ jessie/main perl amd64 5.20.2-3+deb8u1 [2629 kB]
Get:6 http://httpredir.debian.org/debian/ jessie/main libcgi-pm-perl all 4.09-1 [213 kB]
Get:7 http://httpredir.debian.org/debian/ jessie/main libparams-util-perl amd64 1.07-2+b1 [23.5 kB]
Get:8 http://httpredir.debian.org/debian/ jessie/main libclass-c3-perl all 0.26-1 [22.9 kB]
Get:9 http://httpredir.debian.org/debian/ jessie/main libsub-exporter-perl all 0.986-1 [49.9 kB]
Get:10 http://httpredir.debian.org/debian/ jessie/main libdata-optlist-perl all 0.109-1 [10.6 kB]
Get:11 http://httpredir.debian.org/debian/ jessie/main libclass-c3-xs-perl amd64 0.13-2+b1 [15.2 kB]
Get:12 http://httpredir.debian.org/debian/ jessie/main libmodern-perl-perl all 1.20140107-1 [9964 B]
Get:13 http://httpredir.debian.org/debian/ jessie/main libmodule-build-perl all 0.421000-2 [265 kB]
Get:14 http://httpredir.debian.org/debian/ jessie/main libmodule-signature-perl all 0.73-1+deb8u2 [30.4 kB]
Get:15 http://httpredir.debian.org/debian/ jessie/main libmodule-pluggable-perl all 5.1-1 [25.0 kB]
Get:16 http://httpredir.debian.org/debian/ jessie/main libpackage-constants-perl all 0.04-1 [5820 B]
Get:17 http://httpredir.debian.org/debian/ jessie/main libpod-latex-perl all 0.61-1 [34.7 kB]
Get:18 http://httpredir.debian.org/debian/ jessie/main libregexp-common-perl all 2013031301-1 [173 kB]
Get:19 http://httpredir.debian.org/debian/ jessie/main libpod-readme-perl all 0.11-1 [15.3 kB]
Get:20 http://httpredir.debian.org/debian/ jessie/main libfcgi-perl amd64 0.77-1+b1 [39.1 kB]
Get:21 http://httpredir.debian.org/debian/ jessie/main libsoftware-license-perl all 0.103010-3 [119 kB]
Get:22 http://httpredir.debian.org/debian/ jessie/main libcgi-fast-perl all 1:2.04-1 [10.9 kB]
Get:23 http://httpredir.debian.org/debian/ jessie/main libcpan-meta-perl all 2.142690-1 [125 kB]
Get:24 http://httpredir.debian.org/debian/ jessie/main rename all 0.20-3 [12.4 kB]
Get:25 http://httpredir.debian.org/debian/ jessie/main libsub-install-perl all 0.928-1 [11.4 kB]
Get:26 http://httpredir.debian.org/debian/ jessie/main libmro-compat-perl all 0.12-1 [13.2 kB]
Get:27 http://httpredir.debian.org/debian/ jessie/main libdata-section-perl all 0.200006-1 [13.4 kB]
Get:28 http://httpredir.debian.org/debian/ jessie/main liblog-message-perl all 0.8-1 [26.0 kB]
Get:29 http://httpredir.debian.org/debian/ jessie/main liblog-message-simple-perl all 0.10-2 [8126 B]
Get:30 http://httpredir.debian.org/debian/ jessie/main libtext-template-perl all 1.46-1 [53.1 kB]
Get:31 http://httpredir.debian.org/debian/ jessie/main libterm-ui-perl all 0.42-1 [19.1 kB]
Get:32 http://httpredir.debian.org/debian/ jessie/main libtext-soundex-perl amd64 3.4-1+b2 [13.7 kB]
debconf: delaying package configuration, since apt-utils is not installed
Fetched 6606 kB in 16s (395 kB/s)
Selecting previously unselected package libgdbm3:amd64.
(Reading database ... 7528 files and directories currently installed.)
Preparing to unpack .../libgdbm3_1.8.3-13.1_amd64.deb ...
Unpacking libgdbm3:amd64 (1.8.3-13.1) ...
Selecting previously unselected package perl-modules.
Preparing to unpack .../perl-modules_5.20.2-3+deb8u1_all.deb ...
Unpacking perl-modules (5.20.2-3+deb8u1) ...
Selecting previously unselected package perl.
Preparing to unpack .../perl_5.20.2-3+deb8u1_amd64.deb ...
Unpacking perl (5.20.2-3+deb8u1) ...
Selecting previously unselected package libalgorithm-c3-perl.
Preparing to unpack .../libalgorithm-c3-perl_0.09-1_all.deb ...
Unpacking libalgorithm-c3-perl (0.09-1) ...
Selecting previously unselected package libarchive-extract-perl.
Preparing to unpack .../libarchive-extract-perl_0.72-1_all.deb ...
Unpacking libarchive-extract-perl (0.72-1) ...
Selecting previously unselected package libcgi-pm-perl.
Preparing to unpack .../libcgi-pm-perl_4.09-1_all.deb ...
Unpacking libcgi-pm-perl (4.09-1) ...
Selecting previously unselected package libfcgi-perl.
Preparing to unpack .../libfcgi-perl_0.77-1+b1_amd64.deb ...
Unpacking libfcgi-perl (0.77-1+b1) ...
Selecting previously unselected package libcgi-fast-perl.
Preparing to unpack .../libcgi-fast-perl_1%3a2.04-1_all.deb ...
Unpacking libcgi-fast-perl (1:2.04-1) ...
Selecting previously unselected package libclass-c3-perl.
Preparing to unpack .../libclass-c3-perl_0.26-1_all.deb ...
Unpacking libclass-c3-perl (0.26-1) ...
Selecting previously unselected package libclass-c3-xs-perl.
Preparing to unpack .../libclass-c3-xs-perl_0.13-2+b1_amd64.deb ...
Unpacking libclass-c3-xs-perl (0.13-2+b1) ...
Selecting previously unselected package libcpan-meta-perl.
Preparing to unpack .../libcpan-meta-perl_2.142690-1_all.deb ...
Unpacking libcpan-meta-perl (2.142690-1) ...
Selecting previously unselected package libparams-util-perl.
Preparing to unpack .../libparams-util-perl_1.07-2+b1_amd64.deb ...
Unpacking libparams-util-perl (1.07-2+b1) ...
Selecting previously unselected package libsub-install-perl.
Preparing to unpack .../libsub-install-perl_0.928-1_all.deb ...
Unpacking libsub-install-perl (0.928-1) ...
Selecting previously unselected package libdata-optlist-perl.
Preparing to unpack .../libdata-optlist-perl_0.109-1_all.deb ...
Unpacking libdata-optlist-perl (0.109-1) ...
Selecting previously unselected package libmro-compat-perl.
Preparing to unpack .../libmro-compat-perl_0.12-1_all.deb ...
Unpacking libmro-compat-perl (0.12-1) ...
Selecting previously unselected package libsub-exporter-perl.
Preparing to unpack .../libsub-exporter-perl_0.986-1_all.deb ...
Unpacking libsub-exporter-perl (0.986-1) ...
Selecting previously unselected package libdata-section-perl.
Preparing to unpack .../libdata-section-perl_0.200006-1_all.deb ...
Unpacking libdata-section-perl (0.200006-1) ...
Selecting previously unselected package liblog-message-perl.
Preparing to unpack .../liblog-message-perl_0.8-1_all.deb ...
Unpacking liblog-message-perl (0.8-1) ...
Selecting previously unselected package liblog-message-simple-perl.
Preparing to unpack .../liblog-message-simple-perl_0.10-2_all.deb ...
Unpacking liblog-message-simple-perl (0.10-2) ...
Selecting previously unselected package libmodern-perl-perl.
Preparing to unpack .../libmodern-perl-perl_1.20140107-1_all.deb ...
Unpacking libmodern-perl-perl (1.20140107-1) ...
Selecting previously unselected package libmodule-build-perl.
Preparing to unpack .../libmodule-build-perl_0.421000-2_all.deb ...
Adding 'diversion of /usr/bin/config_data to /usr/bin/config_data.diverted by libmodule-build-perl'
Adding 'diversion of /usr/share/man/man1/config_data.1.gz to /usr/share/man/man1/config_data.diverted.1.gz by libmodule-build-perl'
Unpacking libmodule-build-perl (0.421000-2) ...
Selecting previously unselected package libmodule-pluggable-perl.
Preparing to unpack .../libmodule-pluggable-perl_5.1-1_all.deb ...
Unpacking libmodule-pluggable-perl (5.1-1) ...
Selecting previously unselected package libmodule-signature-perl.
Preparing to unpack .../libmodule-signature-perl_0.73-1+deb8u2_all.deb ...
Unpacking libmodule-signature-perl (0.73-1+deb8u2) ...
Selecting previously unselected package libpackage-constants-perl.
Preparing to unpack .../libpackage-constants-perl_0.04-1_all.deb ...
Unpacking libpackage-constants-perl (0.04-1) ...
Selecting previously unselected package libpod-latex-perl.
Preparing to unpack .../libpod-latex-perl_0.61-1_all.deb ...
Adding 'diversion of /usr/bin/pod2latex to /usr/bin/pod2latex.bundled by libpod-latex-perl'
Adding 'diversion of /usr/share/man/man1/pod2latex.1.gz to /usr/share/man/man1/pod2latex.bundled.1.gz by libpod-latex-perl'
Unpacking libpod-latex-perl (0.61-1) ...
Selecting previously unselected package libregexp-common-perl.
Preparing to unpack .../libregexp-common-perl_2013031301-1_all.deb ...
Unpacking libregexp-common-perl (2013031301-1) ...
Selecting previously unselected package libpod-readme-perl.
Preparing to unpack .../libpod-readme-perl_0.11-1_all.deb ...
Unpacking libpod-readme-perl (0.11-1) ...
Selecting previously unselected package libtext-template-perl.
Preparing to unpack .../libtext-template-perl_1.46-1_all.deb ...
Unpacking libtext-template-perl (1.46-1) ...
Selecting previously unselected package libsoftware-license-perl.
Preparing to unpack .../libsoftware-license-perl_0.103010-3_all.deb ...
Unpacking libsoftware-license-perl (0.103010-3) ...
Selecting previously unselected package libterm-ui-perl.
Preparing to unpack .../libterm-ui-perl_0.42-1_all.deb ...
Unpacking libterm-ui-perl (0.42-1) ...
Selecting previously unselected package libtext-soundex-perl.
Preparing to unpack .../libtext-soundex-perl_3.4-1+b2_amd64.deb ...
Unpacking libtext-soundex-perl (3.4-1+b2) ...
Selecting previously unselected package rename.
Preparing to unpack .../archives/rename_0.20-3_all.deb ...
Unpacking rename (0.20-3) ...
Setting up libgdbm3:amd64 (1.8.3-13.1) ...
Setting up perl-modules (5.20.2-3+deb8u1) ...
Setting up perl (5.20.2-3+deb8u1) ...
update-alternatives: using /usr/bin/prename to provide /usr/bin/rename (rename) in auto mode
Setting up libalgorithm-c3-perl (0.09-1) ...
Setting up libarchive-extract-perl (0.72-1) ...
Setting up libcgi-pm-perl (4.09-1) ...
Setting up libfcgi-perl (0.77-1+b1) ...
Setting up libcgi-fast-perl (1:2.04-1) ...
Setting up libclass-c3-perl (0.26-1) ...
Setting up libclass-c3-xs-perl (0.13-2+b1) ...
Setting up libcpan-meta-perl (2.142690-1) ...
Setting up libparams-util-perl (1.07-2+b1) ...
Setting up libsub-install-perl (0.928-1) ...
Setting up libdata-optlist-perl (0.109-1) ...
Setting up libmro-compat-perl (0.12-1) ...
Setting up libsub-exporter-perl (0.986-1) ...
Setting up libdata-section-perl (0.200006-1) ...
Setting up liblog-message-perl (0.8-1) ...
Setting up liblog-message-simple-perl (0.10-2) ...
Setting up libmodern-perl-perl (1.20140107-1) ...
Setting up libmodule-build-perl (0.421000-2) ...
Setting up libmodule-pluggable-perl (5.1-1) ...
Setting up libmodule-signature-perl (0.73-1+deb8u2) ...
Setting up libpackage-constants-perl (0.04-1) ...
Setting up libpod-latex-perl (0.61-1) ...
Setting up libregexp-common-perl (2013031301-1) ...
Setting up libpod-readme-perl (0.11-1) ...
Setting up libtext-template-perl (1.46-1) ...
Setting up libsoftware-license-perl (0.103010-3) ...
Setting up libterm-ui-perl (0.42-1) ...
Setting up libtext-soundex-perl (3.4-1+b2) ...
Setting up rename (0.20-3) ...
update-alternatives: using /usr/bin/file-rename to provide /usr/bin/rename (rename) in auto mode
Processing triggers for libc-bin (2.19-18) ...
 ---> 5df0148ab594
Removing intermediate container afe73c43d3a8
Step 2 : COPY hello.pl /
 ---> 73621b2beb17
Removing intermediate container 073772d52012
Step 3 : CMD /hello.pl
 ---> Running in 32701bc83e03
 ---> 2ba9eec0fbfa
Removing intermediate container 32701bc83e03
Successfully built 2ba9eec0fbfa

And in this case I’ve create a perl script which loops forever to show what happens when a container keeps running:

#!/usr/bin/env perl

use Modern::Perl;

# autoflush output
$| = 1;

my $loop = 0;
while (1) {
    say "[${loop}] Hello World!";
    $loop++;
    sleep 1;
}

Now I start the container and ask it to run in the background:

$ make run
docker run -d bradhelloperl
e4cb410b97f18b70f18ba1a4b4ded3e310bc63f85dbaf58b776463ec4a61ab64

And to see what is being printed I view the container log:

 $ docker logs e4cb410b97f18b70f18ba1a4b4ded3e310bc63f85dbaf58b776463ec4a61ab64
[0] Hello World!
[1] Hello World!
[2] Hello World!
[3] Hello World!
[4] Hello World!
[5] Hello World!
[6] Hello World!
[7] Hello World!

And finally, I’ll have to kill this container off now as it’s going to run forever. To show a different way this can be done I’ll look up the human readable ID and use it instead:

$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
e4cb410b97f1        bradhelloperl       "/hello.pl"         4 minutes ago       Up 4 minutes                            silly_sinoussi 

$ docker kill silly_sinoussi
silly_sinoussi

$ docker rm silly_sinoussi
silly_sinoussi

Note I needed to both kill and remove the container. While the container was killed but not removed I could still view the logs (and see the final stdout output before the kill was run).

Docker FROM scratch

Docker is a framework which makes it easy to wrap linux applications in “containers” – a sort chroot’d jail but with tools to take away the pain of setting up dependencies and also providing tools to help automate setting up dependencies between those containers.

The Docker Hub provides a bunch of pre-defined containers from major projects like Ubuntu, mysql, Redis, nginx, wordpress, postgres and java. It’s also a central store (like github, but for Docker) of publicly created and licensed Docker containers.

What’s the simplest quickest way to start? Well there is a special base container called SCRATCH, which is used in the Docker official hello world container. A container based on SCRATCH has nothing in it, so whatever you add has to be fully self sufficient. The Docker official hello world does this with some assembly code compiled by nasm which certainly covers the angle of a stand-alone executable but I think is arguably more complex than a statically compiled hello world – so here we go:

helloworld

Doesn’t really need much in the way of an explanation, but I’m going to write it in c and I’m including a bit of code to grab an environment variable to show how these can be passed into a Docker container to configure the way a container operates.

Here’s the helloworld c code:

#include<stdio.h>
#include<stdlib.h>

int main(int argc, char** argv) {
  // Vars
  char *envVar;

  // do it
  printf("Hello From Brad\n");

  // Check for special environment variable, print it present
  envVar = getenv("BJDTEST");
  if ( envVar == NULL ) {
    printf("No special environment variable set - set BJDTEST to see this work\n");
  }
  else {
    printf("Special environment BJDTEST set to [%s]\n", envVar);
  }

  return 0;
}

That’s built statically the usual way – with this bit of Makefile:

helloworld: helloworld.c
    gcc -static -o helloworld helloworld.c

Note that without the static build the Docker container will fail because the linked libraries will not exist inside the Docker container.

The simplest of containers – FROM scratch

To defined a docker container you write a Dockerfile – this is just about as simple as it gets:

FROM scratch
COPY helloworld /
CMD ["/helloworld"]

Basically, start with the no-op scratch container, copy our statically compiled binary to a known location and run it.

Building this with docker is very fast, because there’s not much there and scratch is very small. Here’s another Makefile snipped:

docker: helloworld
      docker build --rm -t bradhello .

And here’s how that looks:

$ make docker
docker build --rm -t bradhello .
Sending build context to Docker daemon 885.2 kB
Sending build context to Docker daemon 
Step 0 : FROM scratch
 ---> 
Step 1 : COPY helloworld /
 ---> Using cache
 ---> a4a757585183
Step 2 : CMD /helloworld
 ---> Using cache
 ---> b32df200f4ed
Successfully built b32df200f4ed

And here’s how that runs, deleting the container after running otherwise it will leave an empty container waiting around to be removed:

$ docker run --rm=true bradhello
Hello From Brad
No special environment variable set - set BJDTEST to see this work

And finally, as you can see above my environment variable was not set. But I can do that – either a bunch of variables defined in a file and used with –env-file=<filename> or individually with –env=”foo=bar”.

$ docker run --rm=true --env="BJDTEST=value for demo" bradhello
Hello From Brad
Special environment BJDTEST set to [value for demo]