DISCLAIMER: Image is generated using FREE
version of ChatGPT
.
Build Docker Image
1. Introduction
2. Journey
3. Setup
Introduction
I know the post title is a little vague, what I meant is building docker image for the weekly challenge website
.
If you are new to The Weekly Challenge then this is the perfect platform for all geeks who want to use their favourite programming language to solve the two challenges we present every week. You don’t need to be an expert in the programming language, as there is always one simple challenge for beginners and a second, more advanced challenge for those with greater experience.
It was launched on March 25, 2019
.
Yes, it has been running for nearly 6 years
now.
The primary programming languages are Perl
and Raku
but you are free to choose your favourite programming language.
So far, we have received solutions in over 100
different programming languages.
We have a dedicated repository called Perl Weekly Challenge Club where member’s contributions are stored.
For the website, we maintain a separate GitHub repository.
The site is static, built using Hugo
, hosted as GitHub Page
.
Journey
In the past, I received complaints from users that they couldn’t run the site locally as it relies on a custom-built Hugo binary.
To solve this issue, Docker image
would have been an ideal solution.
However, I had never worked with Docker
in detail before, so my lack of experience with the tool held me back.
After a sudden change of heart, I started exploring Docker
and found myself enjoying it.
Here’s the Dockerfile
, I came up with initially:
FROM perl:5.38.0
EXPOSE 1414
CMD ["bin/hugo", "server", "-p", "1414", "-D"]
COPY . /theweeklychallenge
WORKDIR /theweeklychallenge
With this, I was able to build the image and start the container.
But, I had trouble accessing the site.
I knew that Dave Cross
, had extensive experience with Docker
as he had written a four-part series on it.
I decided to reach out to him for help.
He replied instantly but unfortunately, he was facing a similar issue.
In the meantime, I decided to switch the base image to alpine
as Dave
had suggested.
FROM alpine:latest
EXPOSE 1414
CMD ["bin/hugo", "server", "-p", "1414", "-D"]
COPY . /theweeklychallenge
WORKDIR /theweeklychallenge
However, changing the base image made things worse, as now I couldn’t even start the container.
Earlier, starting the container worked fine, but accessing it was the issue.
After few days, I contacted him again for help.
He instantly identified the issue and shared the solution as well.
These are his words:
It's because Alpine uses libc, not glibc. And your executable is built for glibc.
His advice was:
Just add this to your Dockerfile.
RUN apk add --no-cache libc6-compat
So as per his suggestion, my Dockerfile
now looks like below:
FROM alpine:latest
RUN apk add --no-cache libc6-compat
EXPOSE 1414
CMD ["bin/hugo", "server", "-p", "1414", "-D"]
COPY . /theweeklychallenge
WORKDIR /theweeklychallenge
This indeed solved the issue of not being able to run the container.
It was a huge relief, thank you Dave Cross
for your help.
However, I was still having trouble accessing the site.
A few moments later, I received another message from Dave Cross
.
This time he found the solution to the main issue.
His advice was:
Adding the "--bind" parameter to the Dockerfile seems to fix the problem.
So now my Dockerfile
looks like below:
FROM alpine:latest
RUN apk add --no-cache libc6-compat
WORKDIR /theweeklychallenge
COPY . /theweeklychallenge
EXPOSE 1414
CMD ["bin/hugo", "server", "-p", "1414", "-D", "--bind", "0.0.0.0"]
Finally I can now access the site: http://localhost:1414
I can’t thank Dave
enough for his help and support.
May be next time when I meet him, I will present him a box of chocolate.
Setup
I added the following Dockerfile
to the main repository
FROM alpine:latest
LABEL maintainer="mohammad.anwar@yahoo.com"
RUN apk add --no-cache libc6-compat
WORKDIR /theweeklychallenge
COPY . /theweeklychallenge
EXPOSE 1414
CMD ["bin/hugo", "server", "-p", "1414", "-D", "--bind", "0.0.0.0"]
Also added the configuration file, docker-compose.yml, as below:
version: '3.8'
services:
theweeklychallenge:
build:
context: .
dockerfile: Dockerfile
image: manwardock/theweeklychallenge:${IMAGE_TAG:-latest}
container_name: theweeklychallenge
restart: unless-stopped
ports:
- "1414:1414"
So now, I wanted to build the image and push it to Docker Hub
to make it available to general public.
I already had an account manwardock on Docker Hub
.
I created a new public repository theweeklychallenge on Docker Hub
.
Now, it’s just a matter of creating an image with a tag and pushing it to this repository.
Without any further issues, I successfully pushed the image.
As of today, we have v3.13
as the latest tag, which represents the current week 313
.
The plan is that every Monday
when I release a new challenge, I will also push the updated image.
[2025-03-23] UPDATE
As I shared my plan above, Dave Cross
suggested I can automate the process of building new image and pushing to Docker Hub
on tag push.
I used my Sunday
morning hours to figure out the process.
It took me few attempts to nail down the process, I must confess.
I created GitHub
repository just to try things: https://github.com/manwar/Test-Workflow
I have a simple Dockerfile
in the repository.
FROM alpine:latest
CMD echo "Hello, World!"
And then I created workflow configuration file: .github/workflow/dockerhub.yml
name: Docker Build and Push
on:
push:
tags:
- 'dhub*'
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Log in to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_TOKEN }}
- name: Build and Push
run: |
docker build -t ${{ secrets.DOCKER_HUB_USERNAME }}/my-app:${{ github.ref_name }} .
docker push ${{ secrets.DOCKER_HUB_USERNAME }}/my-app:${{ github.ref_name }}
[2025-03-23] UPDATE
Another quick suggestions from Dave Cross
with reference.
docker build -t ${{ secrets.DOCKER_HUB_USERNAME }}/my-app:${{ github.ref_name }} \
-t ${{ secrets.DOCKER_HUB_USERNAME }}/my-app:latest .
docker push -a ${{ secrets.DOCKER_HUB_USERNAME }}/my-app
For this, first I created token in Docker Hub
as below:
1. Once logged in, click on your profile icon in the top-right corner.
2. From the dropdown menu, select Account Settings.
3. In the left-hand menu, click on Personal access tokens.
4. Click on Generate new token.
5. Enter a description for your token (e.g., "GitHub Actions Token").
6. Choose expires: Never
7. Choose permission: read and write
Now time to create secrets in the GitHub
repository:
1. Go to repository settings page
2. Click: Secrets and variables
3. Click: Actions
4. Click: New repository secret
5. Give secret name: DOCKER_HUB_USERNAME
6. Give value: manwardock
7. Click: Add secret
Similarly add another secret, DOCKER_HUB_TOKEN
and set the token you created in Docker Hub
.
We are read to test the changed i.e tag the repository and push as below:
$ git tag dhubv1.0
$ git push origin dhubv1.0
Go to GitHub
repository and check if everything went OK.
When it is done without error, goto Docker Hub
check the repository, you should have the tag listed there.
From now on, if anyone wants to run the website locally, they can simply grab the configuration file and the job is done.
$ wget https://raw.githubusercontent.com/manwar/theweeklychallenge/refs/heads/master/docker-compose.yml
$ docker-compose up -d
You now have access to your local website: http://localhost:1414
And when done with it, simply do this:
$ docker-compose down
This journey has been amazing and great learning process, thanks to Dave Cross
.
Keep Hacking !!