For many years, I have run several containers within my Homelab, such as Uptime Kuma, Librespeed, and Pihole. One thing that always intrigued me was building my own container. Now that I was attempting my first Kubernetes deployment, I thought this would be a good time to understand how to do the process from the beginning.
First, I installed the docker client for my OS. For the desktop OS’s, these are branded Docker Desktop.
Container Registry
Before you create a container image, you must decide where to store it. This is because docker/kubernetes expect images to come from a container registry. For my learning and own development, I use Gitea self-hosted.
There were not really any prerequisites, other than it seemed to be the Gitea instance needed to have https enabled to execute all the docker commands. Myself being lazy and using it locally anyways, I had mine only on HTTP, but this finally got me to have Gitea behind my HAProxy instance to have a valid SSL frontend. Docs for Gitea and container registry are here, and once below the image is built I will show the instructions to push it to the registry.
Docker file
The docker file is a list of commands/instructions to build the Docker image. It is executed top down, and builds layers to make a full image. Of course, Docker themselves can explain it best.
Fair warning: my example I am sure this is not efficient, nor lightweight but I wanted to try to use something I was at most familiar with to get started. I’m interested as time goes on and my learning grows to better shape these with smaller images, and more efficient commands.
My Dockfile is linked on my personal github. I will step through the important parts:
First I choose to use Ubuntu 22.04 as the base as it is a distribution I am most familiar with.
FROM ubuntu:22.04
Next, I refreshed package repositories and then installed the various packages needed for Librespeed to work with a mysql backend. The DEBIAN_FRONTEND=noninteractive instructions php to install non interactivity, as it will ask for a timezone on default install and not let the command ever finish:
RUN apt-get -y update
RUN DEBIAN_FRONTEND=noninteractive apt-get -y install tzdata apache2 curl php php-image-text php-gd git mysql-client inetutils-ping php-mysql
Then from the librespeed package maintainers, there were several configuration changes to be made to PHP, which cloned the package locally:
#Set post max size to 0
RUN sed -i 's/post_max_size = 8M/post_max_size = 0/' /etc/php/8.1/apache2/php.ini
#Enable Extensions
RUN sed -i 's/;extension=gd/extension=gd/' /etc/php/8.1/apache2/php.ini
RUN sed -i 's/;extension=pdo_mysql/extension=pdo_mysql/' /etc/php/8.1/apache2/php.ini
#Prep directory for web root
RUN rm -rf /var/www/html/index.html
#Clone
RUN git clone https://github.com/librespeed/speedtest.git /var/www/html
Next, as I wanted to save results to permanent storage, I changed the telemetry_settings.php file with the various db username/password, db name:
RUN sed -i 's/USERNAME/speedtest/' /var/www/html/results/telemetry_settings.php
RUN sed -i 's/PASSWORD/speedtest/' /var/www/html/results/telemetry_settings.php
RUN sed -i 's/DB_HOSTNAME/mysql/' /var/www/html/results/telemetry_settings.php
RUN sed -i 's/DB_NAME/kptspeedtest/' /var/www/html/results/
telemetry_settings.php
If not clear, my values are: username = speedtest, password = speedtest = dbhostname = mysql (important note here: this is the Kubernetes service name I create later!) and db_name = kptspeedtest.
Skipping some of the basic cleanup/permission settings which you can see in the file, in the end I instructed the container to list on port 80, and to run Apache server as the foreground so the container does not just stop after it is started. There is also a health check for the container to simply see if the Apache service is running.
EXPOSE 80
CMD ["apachectl", "-D", "FOREGROUND"]
HEALTHCHECK --timeout=3s \
CMD curl -f http://localhost/ || exit 1
Building the image
With the file saved as “Dockerfile” I could build the image. First, I logged in to the container registry (in my case my Gitea instance):
docker login git."your_domain_name".com
Next, it would normally be as simple as running docker build -t and name of the repo, and image such as:
# build an image with tag
docker build -t {registry}/{owner}/{image}:{tag} .
I ran into some errors with the next step of uploading, and searching around found that adding the flag “–provenance=false” does not include certain metadata about the build and makes it compatible with Gitea. Depending on the container registry, it may or may not be needed. Full example:
docker build -t git."domain_name"/kweevuss/speedtest:latest . --provenance=false
Since the file is named Dockerfile, docker build tried to find that file in the directory. My user is “kweevuss” and this image is being called speedtest and using the “latest” tag.
Then I pushed the image to the registry:
docker push git.internal.keepingpacetech.com/kweevuss/speedtest:latest
Within Gitea then, I could see the image related to my user:
Now on any docker install, I simply pulled the image as:
docker pull git.internal.keepingpacetech.com/kweevuss/speedtest:latest
Or, instead, in a kubernetes deployment/pod manifest simply point to the image:
spec:
containers:
- name: prdkptspeedtestkube
image: git."domain_name"/kweevuss/speedtest:latest
Next installment will finally be setting up this custom image along with another container, mysql, to store the data!