This post focuses on me being lazy. In the previous post, I talked about building a custom image and posting it to the Docker Hub. I have also talked about creating a Git repo and storing everything in it thus far. What if we could make a commit rebuild our image for us? As luck would have it, you can do this!
This post is going to focus on making that very simple change to your Docker Hub repository so that every commit causes the image to be rebuilt to the latest. How fun!
Connecting Docker Hub to Your Git Account
The major thing to accomplish here is configuring Docker Hub to monitor Git. In order to do that, you’ll need to first sign into your Docker Hub account. This should bring you to the main page where you see the list of repos you maintain:
From there, click on the repo that you plan to configure. In my case, it’s the testnginximage repo. On the resulting screen, click on the Builds link to reveal the below page:
Click on the Link to GitHub button, to open your preferences to configure linked accounts.
Click the Connect link on this screen, to link to your GitHub account. If you are already signed into GitHub, Docker Hub will automatically connect to whatever account you are signed in with. If you are not already signed into GitHub, you’ll see the below login to GitHub screen:
Login to the GitHub account you used to store your Dockerfile we created in the previous post. Once connected, you’ll return to your Docker Hub profile with your GitHub account connected and the account name used listed:
At this point, you now have your Docker Hub and GitHub accounts connected. The next step will be to enable automatic builds.
Enabling Automatic Builds in Docker Hub
With Docker Hub and GitHub connected, the next step is to tell Docker Hub which repo to use and where the Dockerfile is located. In order to do that, go back to your repo and once again, click on the Build link. Within the Build screen, again, click on the Link to GitHub button. This time, the button should say “Connected” on it as shown below:
On the resulting page, configure the username and repo you would like to use as your source. Since I have been building everything in my mysamplerepo repo, I’m choosing this from the drop down:
In my prior examples, I created the Dockerfile in the nginxdocker directory within my mysamplerepo. Assuming you have done the same, scroll down the page and set the Build Context to be the nginxdocker in the Build Rules. This Build Context would be the path from the root of your repo that contains the Dockerfile. If you’ve placed your Dockerfile in a different path within your repo, make sure you have Build Context configured for that particular path.
Once you have this all configured, click on the Save and Build button at the bottom of the page. This should take you back to the Build page where you can monitor the status of the build.
Monitor the progress to make sure everything builds correctly. Once done, you should see a success status for the build.
Use a Commit to Generate a Build
Now that we have everything connected and working, let’s see if we can do a commit to our repo and confirm that the commit makes a build trigger. Let’s just make a simple change and no longer expose port 443 from for the image:
$ git commit -a
[master 0e01193] Removing port 443
Committer: Scott <scott@iMacs-iMac.local>
2 files changed, 2 deletions(-)
$ git push origin master
Counting objects: 6, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (6/6), done.
Writing objects: 100% (6/6), 499 bytes | 499.00 KiB/s, done.
Total 6 (delta 3), reused 0 (delta 0)
remote: Resolving deltas: 100% (3/3), completed with 3 local objects.
1d4d448..0e01193 master -> master
After performing the commit, refresh your Build page in Docker Hub and you should see a build trigger:
This means that you’ll be able to simply use your GitHub to generate a new image anytime you like! This also means that with every commit, you’ll be exposing the latest version of your image on Docker Hub.
In case you want to make sure you have the correct file, here would be the only file I referenced in this post:
Welcome to 2020! I hope the new year finds everyone in good spirits and ready to continue listening to me babble about my struggles with technology.
So far, the focus has been on using default Docker images for our builds. This is great if you plan to deploy stock instances and only need to serve custom content with some minor configuration tweaks. Note that we were able to make configuration changes using a configMap yaml. What if you needed Nginx modules that weren’t already installed in the base image? Sure, you could come up with some funky CMD statement in your yaml file that tells Kubernetes to install the modules. Of course, that’ll take some time for the pod to be available while it boots up and runs through the install steps. This will also defeat the purpose of what I’m attempting to show you too 🙂
The focus of this article is simple. We’re going to setup a Docker Hub account and build a custom Nginx image to post there. From there, there are some future articles to help us use this new found knowledge to do some cool stuff.
Let’s stop the babble and start the fun!
Creating a Docker Hub Account
This is pretty straight forward so we’ll cover it briefly.
Now that you have a Docker Hub account, you’ll want to create a repo to be able to store your custom docker image. Assuming that you are still signed in from the steps above, you should see a Create a Repository button:
If you don’t see the Create a Repository button, worry not, you can get there by clicking on the Repositories link on the top menu and then the Create Repository button:
On the resulting Create Repository screen, let’s add in some details such as below:
You may call the repo whatever you want and feel free to give it a description. For now, we’re going to make this a public repo. Once you have this information filled out, scroll to the bottom and click Create. You should now see something similar to the below:
Make note of the docker push command in the black background box on the right. In my case, it is
docker push algattblog/testnginximage:tagname
We’ll need this later when we build our custom image.
Configuring Our Custom Nginx Docker Image
In order to keep everything in one place and keep things backed up, we’ll be building this out within our previously defined Git Repo. It’s a private repo so reasonably protected and Github is a really nice place to maintain our backup. So the first step will be to make sure we’re in the root of our repo and we’ll make a new directory to store this image.
$ mkdir nginxdocker
From there, we’ll change into the directory so that we can start with our Dockerfile
$ cd nginxdocker/
Now let’s create a new Dockerfile that looks like the following:
Let’s see what this does…First, we’re going to build this new Docker using ubuntu as our base image. From there, we’re going to install nginx, libnginx-mod-http-lua, libnginx-mod-http-subs-filter, and software-properties-common. We’re installing software-properties-common so that we can add the certbot repo and then add certbot. We’re going to also copy over some custom Nginx configuration files so we won’t need to leverage our configMap anymore. We make sure ports 80 and 443 are exposed to the running container. Finally, the container should run the “nginx” command to start the nginx server.
Next, we’ll want to create those files referenced by the COPY commands. We start by creating the conf directory with and then change into the directory:
$ mkdir conf
$ cd conf
Create the nginx.conf file with the following (Basically, we’re defining a custom log format):
The MOST important item at the bottom of this file would be the daemon off; statement. Without this, our container will start run nginx and then COMPLETE and stop. We want nginx to run in the foreground and not background as a daemon so this is why this is here. Now create the referenced site.conf file.
Next, we need to publish it on Docker Hub (remember that push command from earlier?):
$ docker push algattblog/testnginximage:latest
The push refers to repository [docker.io/algattblog/testnginximage]
918efb8f161b: Mounted from library/ubuntu
27dd43ea46a8: Mounted from library/ubuntu
9f3bfcc4a1a8: Mounted from library/ubuntu
2dc9f76fb25b: Mounted from library/ubuntu
latest: digest: sha256:4545730a7dd5b5818f0ce9a78666f40ea9a864198665022dc29000a34cc4b402 size: 1778
Testing the New Image in our Cluster
At this point, we’ve got our newly created image uploaded to Docker Hub. The next step is to test it out and see if it works in our cluster. In order to do that, we’ll want to change the image in our webserver.yaml file to reference the newly created image:
Wait for it to build the new webserver pod by keeping an eye on kubectl:
# kubectl get pod
NAME READY STATUS RESTARTS AGE
phpfpm-7b8d87955c-rps2w 2/2 Running 0 3d1h
webserver-6b577db595-wgwwb 2/2 Running 0 25s
Looks like it’s up and running so now let’s check and see if we can test to make sure everything looks good. We’ll start by connecting to the webserver, installing curl, and making sure everything works again.
# kubectl exec -it webserver-6b577db595-wgwwb /bin/bash -c webserver
groups: cannot find name for group ID 65533
root@webserver-6b577db595-wgwwb:/# apt update
Get:1 http://security.ubuntu.com/ubuntu bionic-security InRelease [88.7 kB]
Get:2 http://archive.ubuntu.com/ubuntu bionic InRelease [242 kB]
Setting up libcurl4:amd64 (7.58.0-2ubuntu3.8) ...
Setting up curl (7.58.0-2ubuntu3.8) ...
Processing triggers for libc-bin (2.27-3ubuntu1) ...
root@webserver-6b577db595-wgwwb:/# curl localhost
hello world! Everything must be cleaned up at this point
root@webserver-6b577db595-wgwwb:/# curl localhost/index.php
hello world from php
We can ignore the groups error for now. Some idiot left out instructions regarding fixing that but not a biggie. Looks we’re serving content properly. Let’s check our nginx configuration to confirm it’s also running the correct config:
root@webserver-6b577db595-wgwwb:/# cat /etc/nginx/nginx.conf
log_format graylog2_format '$remote_addr $request_method "$request_uri" $status $bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for" "$http_if_none_match"';
Confirmed! This looks great! You’ve now got a custom Docker image that you can use and expand upon. I know I left you hanging here but if I continued to build my attention span couldn’t tolerate typing anymore. More to come….