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]
Found this in 2023, useful way of setting runtime vars in a scratch image thanks ❤️