Here’s a complete step-by-step guide for:
โ
Building a Docker image
โ
Storing (pushing) it to GitLab’s Container Registry
โ
Using GitLab CI/CD pipeline with GitLab SaaS 18.x
๐ Use Case
You want to:
- Build a Docker image from your code
- Push it to GitLabโs Container Registry
- Use it later for deployment or as base image
๐งฑ Prerequisites
- A GitLab project on GitLab.com (SaaS)
- GitLab CI/CD enabled
.gitlab-ci.ymlfile created- Dockerfile at the root of your project
๐ Step 1: Create a Dockerfile
Hereโs an example Dockerfile for a Java app:
# syntax=docker/dockerfile:1
FROM openjdk:17-jdk-slim
COPY ./target/myapp.jar /app/myapp.jar
CMD ["java", "-jar", "/app/myapp.jar"]
Code language: PHP (php)
Make sure your JAR is built to ./target/myapp.jar via Maven or Gradle.
๐ฆ Step 2: Understand Your GitLab Container Registry URL
GitLab automatically enables a private container registry for every project:
registry.gitlab.com/<namespace>/<project>
Code language: HTML, XML (xml)
๐ Example:
registry.gitlab.com/yourusername/myapp
You can view it in:
Project โ Deploy โ Container Registry
- โ
<namespace>can be:- A personal username (
yourusername) - A GitLab group (
yourgroup) - A GitLab subgroup path (
yourgroup/subgroup)
- A personal username (
- โ
<project>is always the project name
โ๏ธ Step 3: Configure .gitlab-ci.yml
Hereโs a full working example:
stages:
- build
- dockerize
- push
variables:
IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
# Build your app (optional if using compiled files)
build-job:
stage: build
image: maven:3.8.7-openjdk-17
script:
- mvn clean package -DskipTests
dockerize-job:
stage: dockerize
image: docker:latest
services:
- docker:dind
before_script:
- echo $CI_JOB_TOKEN | docker login -u gitlab-ci-token --password-stdin $CI_REGISTRY
script:
- docker build -t $IMAGE_TAG .
- docker push $IMAGE_TAG
only:
- main
Code language: PHP (php)
๐ง Explanation of Important Variables
| Variable | Purpose |
|---|---|
$CI_REGISTRY | Points to registry.gitlab.com |
$CI_REGISTRY_IMAGE | Your project-specific Docker registry path |
$CI_JOB_TOKEN | GitLabโs built-in token for authenticating CI jobs |
gitlab-ci-token | Required user for registry auth inside CI/CD |
๐ Step 4: CI/CD Authentication
GitLab uses:
- Username:
gitlab-ci-token - Password:
$CI_JOB_TOKEN
Docker login is done via:
echo $CI_JOB_TOKEN | docker login -u gitlab-ci-token --password-stdin $CI_REGISTRY
Code language: PHP (php)
๐ Step 5: View Container in Registry
After pushing:
- Go to your GitLab project
- Navigate to Deploy > Container Registry
- You’ll see the image like:
registry.gitlab.com/yourusername/myapp:abcdef1
๐ ๏ธ Step 6: Pull and Use the Image Anywhere
From any machine (with Docker installed):
docker login registry.gitlab.com
docker pull registry.gitlab.com/yourusername/myapp:<tag>
Code language: HTML, XML (xml)
๐ Optional: Use latest Tag and Versioning
variables:
IMAGE_TAG: $CI_REGISTRY_IMAGE:latest
Code language: PHP (php)
Or for versioning:
IMAGE_TAG: $CI_REGISTRY_IMAGE:${CI_COMMIT_REF_NAME//\//-}
Code language: PHP (php)
โ Summary
| Step | Description |
|---|---|
| 1 | Write a Dockerfile |
| 2 | Identify your GitLab container registry path |
| 3 | Configure .gitlab-ci.yml to build & push |
| 4 | Use docker login with CI_JOB_TOKEN |
| 5 | View in Deploy โ Container Registry |
Great observation! The line:
services:
- docker:dind
Code language: CSS (css)
is critical when using Docker inside GitLab CI/CD pipelines โ especially when building or pushing Docker images.
๐ What is docker:dind?
**dind**stands for Docker-in-Docker.docker:dindis a Docker image that runs the Docker daemon as a background service inside your CI/CD job.- This allows the main job container to use Docker commands (
docker build,docker push, etc.), even though it’s running in an isolated environment.
๐ง Why is It Needed?
GitLab CI/CD runs your job steps inside a container (e.g., docker:latest), which doesn’t have the Docker daemon running by default.
So you need to add:
services:
- docker:dind
Code language: CSS (css)
This launches a background Docker daemon, which your main container can talk to (usually via the socket on localhost or Docker host networking).
๐งช Example Use in Context
dockerize-job:
stage: dockerize
image: docker:latest # Main container with Docker CLI
services:
- docker:dind # Side container with Docker daemon
script:
- docker build -t $IMAGE_TAG .
- docker push $IMAGE_TAG
Code language: PHP (php)
docker:latestโ contains the Docker CLIdocker:dindโ provides the Docker daemon to executedockercommands
๐ Important: Secure Docker-in-Docker
For security and performance:
- GitLab runs Docker-in-Docker in privileged mode automatically when using their Docker executor.
- You may explicitly add (if self-hosted):
tags:
- docker
variables:
DOCKER_TLS_CERTDIR: ""
Code language: JavaScript (javascript)
This disables TLS cert enforcement (GitLab-specific tweak for dind).
โ ๏ธ Alternatives to docker:dind
- Kaniko: A rootless, safer Docker image builder (good for Kubernetes-based runners)
- Buildah + Podman: For more secure container builds without daemon
- GitLab CI with remote Docker host
โ Summary
docker:dind | Explanation |
|---|---|
| Docker-in-Docker | Runs Docker daemon inside CI/CD service |
| Required for | docker build, docker push, etc. in pipeline |
| Used alongside | Docker CLI image (docker:latest) |
| Daemon runs in | Background, accessible to main job container |
I’m Rajesh Kumar, a DevOps, SRE, DevSecOps, Cloud, and Platform Engineering expert passionate about sharing practical knowledge, real-world experiences, and industry best practices. I have worked at Cotocus and regularly write about technology, travel, investing, health, product reviews, and digital marketing through my various platforms.
I publish technical articles at DevOps School, travel stories at Holiday Landmark, stock market insights at Stocks Mantra, health and fitness guidance at My Medic Plus, product reviews at TrueReviewNow, and SEO and digital marketing strategies at Wizbrand.
Find Trusted Cardiac Hospitals
Compare heart hospitals by city and services โ all in one place.
Explore Hospitals