How to build a docker image from scratch

This Post covers the steps one will have to go through, to build ones own docker image.

First we’ll need to create a basic image from which we’ll go on.

I’ll use debian here, though I work on gentoo I like debian a lot and debootstrap is available on gentoo as well.

mkdir stretchimage

sudo debootstrap --arch amd64 stretch stretchimage http://deb.debian.org/debian/
 W: Cannot check Release signature; keyring file not available /usr/share/keyrings/debian-archive-keyring.gpg
 I: Retrieving InRelease 
 I: Retrieving Release 
 I: Retrieving Packages 
 I: Validating Packages 
 I: Resolving dependencies of required packages...
 
 [...]
 I: Configuring systemd...
 I: Base system installed successfully. 

First we create a folder in which to debootstrap our new installation. After some time this is done.

as root/sudo, do:

mount -t proc none /home/nkalle/stretchimage/proc/
mount -o bind sys /home/nkalle/stretchimage/sys/
mount -o bind /dev/ /home/nkalle/stretchimage/dev/
chroot /path/to/stretchimage/ /bin/bash 

We would like to change some things in our image, otherwise there would be no need for an individual image. So we create a chroot environment to work in.

apt-get remove vim-common nano
rm -rf /var/lib/apt/lists/* 

I’ll reduce the size of our installation here by removing vim and nano and also deleting some installation information. You may play around with this as you wish or even install more basic stuff that you need on every image, you get the idea. I do not recommend on installing additional stuff though, because one of docker’s strengths is saving resources by reusing the same image with different additional layers where your applications will be installed.

as root/sudo, do:

umount /home/nkalle/stretchimage/proc
umount /home/nkalle/stretchimage/sys
umount /home/nkalle/stretchimage/dev

don’t forget to unmount, before packaging.

cd stretchimage/
 sudo tar cvf /home/nkalle/stretchbase.tar *
 du -sh ../stretchbase.tar 
 259M    ../stretchbase.tar 

tar your installation (you may as well tar and zip it, as you wish)

docker import ../stretchbase.tar
 sha256:08ec830450cdacf33847bda7ad152f974eddbc69f01f92ba3800470184b64517
 
 nkalle@suse ~/stretchimage $ docker image ls
 REPOSITORY              TAG                 IMAGE ID            CREATED             SIZE
 <none>                  <none>              08ec830450cd        13 seconds ago      264MB 

docker import, imports our tarball as a dockerimage, this image has no name though, as “docker image ls” shows us.

nkalle@suse ~/stretchimage $ docker tag 08ec830450cd stretchbase
 nkalle@suse ~/stretchimage $ docker image ls
 REPOSITORY              TAG                 IMAGE ID            CREATED              SIZE
 stretchbase             latest              08ec830450cd        About a minute ago   264MB

docker tag allows us to name the image which is convenient, especially when searching, etc.

docker run -i -t stretchbase bash
 root@90c298cbb08e:/# ps faxww
   PID TTY      STAT   TIME COMMAND
     1 pts/0    Ss     0:00 bash
     6 pts/0    R+     0:00 ps faxww

to test if the new image is working we run it from the commandline and tell docker to execute a bash and attach us to a terminal (-i = inputstream, -t terminal).

You may now push your new image on dockerhub, use it locally or push it to a private hub (e.g. harbor or a github project, etc.).

If you choose to only use it locally, you’re done

https://www.docker.com/products/docker-hub

If you want to publish your image, create an account on docker-hub and then:

docker tag stretchbase dockerhubusername/stretchbase
docker login
docker push dockerhubusername/stretchbase

You now have build and published your own dockerimage.

How to WordPress with docker

I’m experimenting with docker at the moment and built this simple wordpress setup in about 5 minutes.

It consists of:

  • a mariadb container
  • a phpmyadmin container (used for testing the mariabd container and not really required)
  • the wordpress container itself
mysql container: 
docker run -d --name mariadb-test -e MYSQL_ROOT_PASSWORD=geheim --network test-net -v /home/nkalle/varlibmysql/:/var/lib/mysql -p 13306:3306 mariadb 

The above command will spawn a mariabd container from the official image (if you are interested in building your own image, check this out) with a root password (change it), in a network called test-net, with persistent storage on the local filesystem mapped to /var/lib/mysql (so we won’t lose all our data when the conatiner is stopped) and a portbinding of 13306 on localhost (mapping 3306, the standard port for mysql).

phpmyadmin container: docker run -d --name pma -p 8080:80 --network test-net -e PMA_HOST=mariadb-test phpmyadmin/phpmyadmin 

Next we’ll spawn a phpmyadmin container from the official image, in the same virtual net and again with persistent storage. Also we define the mysql host phpmyadmin shall bind to.

Try it with: http://localhost:8080, after the next step you will see the wordpress database structure here.

wordpress container: docker run -d --name "wp-test" --network test-net -v /home/nkalle/wp-html:/var/www/html -p 8081:80 -e WORDPRESS_DB_PASSWORD=geheim -e WORDPRESS_DB_HOST=mariadb-test wordpress

Finally we’ll spawn our wordpress container, referencing our database host and password.

Log in on http://localhost:8081 and complete the wordpress installation process with a few simple clicks (asking you to choose a language, and a password and you’re done).

How to stop/start the containers

When you are done playing around with your new conatiners, you may want to stop them and maybe re-use them again later.

docker stop wp-test
 wp-test
 docker stop pma
 pma
 docker stop mariadb-test
 mariadb-test
 docker start mariadb-test
 mariadb-test
 docker start pma
 pma
 docker start wp-test
 wp-test

stop the database last and start it first, so you don’t lose any data.

A few commands to remember

When you are working with docker (or some of the above didn’t went as expected), one will find the following commands to be useful:

docker ps

shows started containers (ps -a also shows a history of container already closed, exited, etc.)

docker image ls

shows all docker images on your host

 docker inspect <imagename/id>

shows data about the selected container (including status, network information, etc.)

docker logs <imagename/id>

show the logs for the selected container

docker exec <options> <command>

executes command in a running docker instance, e.g.:

docker exec -i -t mariadb-test bash

this starts a bash in our mariadb-test instance and opens an input stream (-i) that acts like a terminal (-t)


This post was largely inspired by reading “Docker. Das Praxisbuch für Entwickler und Dev-Ops Teams”
https://www.rheinwerk-verlag.de/docker_4599/