Build Docker Image

Wednesday, Mar 19, 2025| Tags: Perl, Docker

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 !!

SO WHAT DO YOU THINK ?

If you have any suggestions or ideas then please do share with us.

Contact with me