ProjectsImplementation project

Complete3 min read

Learning Container Deployment and GitLab CI/CD

An end-to-end learning project covering a minimal Node.js service, containerisation, local testing, registry publishing, managed deployment and GitLab CI/CD automation.

Container deployment pipeline showing source code moving through Git push, GitLab CI, a container build, a registry, deployment and into a running service.
The project follows the same build, publish and deployment path that was later automated through GitLab CI/CD.

This project was a deliberate end-to-end exercise in understanding the complete path between application source code and a running containerised service.

Rather than starting with an existing application or copying a CI/CD template, I built the smallest service I could and worked through each deployment layer manually before automating it.

Objective

The target workflow was:

Source code

Container image

Local validation

Container registry

Deployment platform

Running application

GitLab CI/CD

The goal was not the application itself.

The goal was understanding every transition in that chain.

Application

The application is a minimal Node.js HTTP service with two responses:

/health-check → OK
/             → Hello world

The service listens on:

0.0.0.0:8080

and runs as an unprivileged user inside the container.

This kept application complexity out of the deployment exercise.

Containerisation

The service was packaged into a small Linux container.

The image was built and tested locally before anything was published:

docker build -t hello-container:1.0.0 .

docker run --rm \
  --user nobody \
  -p 8080:8080 \
  hello-container:1.0.0

Health and application responses were then tested independently:

curl localhost:8080/health-check
curl localhost:8080/

This established a known-good artifact before introducing registry or platform dependencies.

Development environment

The container tooling runs through:

Windows

WSL2

Linux

Docker Engine

Working across Windows and WSL also highlighted the importance of treating them as distinct execution environments for credentials and CLI configuration.

Manual deployment

Before creating any CI/CD automation, I manually:

  1. built the image
  2. ran it locally
  3. tested the health endpoint
  4. authenticated to the container registry
  5. tagged the image
  6. pushed the image
  7. created the application environment
  8. deployed the service
  9. verified the resulting application

This proved the complete deployment path independently of GitLab.

DNS troubleshooting

One deployment also provided a useful DNS troubleshooting exercise.

The deployment itself succeeded, but the client resolver temporarily returned:

NXDOMAIN

Comparing responses from different DNS resolvers proved that the record existed and isolated the problem to negative caching in another resolver layer.

That became a useful reminder to establish which resolver is answering before assuming DNS itself is broken.

GitLab CI/CD

Once the manual workflow worked, it was converted into a two-stage GitLab pipeline:

BUILD

  ├── Build container
  └── Push immutable image


DEPLOY

  └── Deploy selected image

Container images are tagged using the Git commit identifier rather than continuously overwriting a generic tag.

The deployment stage remains manually triggered so a successful build does not automatically modify the target environment while the project is being used for learning.

What I learned

The project reinforced several practices that I will reuse elsewhere:

  • understand the target platform’s runtime contract before building the container
  • test health checks locally
  • treat Windows and WSL as separate configuration environments
  • prove a deployment manually before automating it
  • use immutable container image identifiers
  • separate CI/CD credentials from repository content
  • identify the actual DNS resolver during name-resolution troubleshooting
  • make the pipeline mirror an already understood manual process

I documented the broader experience in What Deploying My First Containerised Application Taught Me.

The CI/CD implementation is covered in From Manual Container Deployment to GitLab CI/CD.

I also extracted several smaller lessons: