GitLab Container Registry
The GitLab Container Registry is a built-in storage location for Docker images. Instead of pushing images to Docker Hub or a separate registry, you store them directly inside GitLab alongside your code, pipelines, and issues.
What a Container Image Is
A container image is a packaged snapshot of your application and everything it needs to run — the code, runtime, libraries, and settings — bundled into one portable file. Run the image anywhere using Docker and your app works identically, regardless of the host machine.
Traditional deployment: Container deployment: ───────────────────────── ────────────────────────────── App needs: Node 18, PostgreSQL 14 App packaged in one image Server A has: Node 16 → breaks ❌ Server A runs image → works ✅ Server B has: Node 18 → works ✅ Server B runs image → works ✅ Server C has: Node 20 → breaks ❌ Server C runs image → works ✅
Enabling the Container Registry
On GitLab.com, the Container Registry is enabled by default for every project. Access it at Deploy → Container Registry in your project sidebar. Self-hosted GitLab instances may need an admin to enable it at the instance level first.
The Dockerfile — Blueprint for Your Image
A Dockerfile is a text file with instructions that Docker reads to build an image. Place it in the root of your repository.
Dockerfile ───────────────────────────────────────────── FROM node:20-alpine ← start from official Node.js image WORKDIR /app ← set the working directory COPY package*.json ./ ← copy package files first RUN npm ci ← install dependencies COPY . . ← copy all other source files RUN npm run build ← build the production app EXPOSE 3000 ← the app listens on port 3000 CMD ["node", "dist/server.js"] ← command to start the app
Building and Pushing an Image From Your Terminal
Step 1 — Log In to the Registry
docker login registry.gitlab.com -u YOUR_USERNAME -p YOUR_TOKEN
Use a Personal Access Token (not your password) with the read_registry and write_registry scopes. Create one at Preferences → Access Tokens.
Step 2 — Build the Image
docker build -t registry.gitlab.com/acme/my-webapp:latest .
The image tag format is always: registry.gitlab.com/NAMESPACE/PROJECT:TAG
Step 3 — Push the Image
docker push registry.gitlab.com/acme/my-webapp:latest
The image now appears in Deploy → Container Registry inside your GitLab project.
Automating Image Builds in CI/CD
The most common pattern is to build and push images automatically in your pipeline whenever code is merged to main.
stages:
- test
- build-image
run-tests:
stage: test
image: node:20
script:
- npm test
build-and-push:
stage: build-image
image: docker:24
services:
- docker:24-dind ← Docker-in-Docker service
variables:
IMAGE: registry.gitlab.com/$CI_PROJECT_PATH
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build -t $IMAGE:$CI_COMMIT_SHORT_SHA .
- docker build -t $IMAGE:latest .
- docker push $IMAGE:$CI_COMMIT_SHORT_SHA
- docker push $IMAGE:latest
only:
- main
GitLab automatically provides $CI_REGISTRY_USER, $CI_REGISTRY_PASSWORD, and $CI_REGISTRY — no manual secret setup needed for your own project's registry.
Image Tags — Labelling Versions
Tags identify different versions of the same image. Using clear tags makes it easy to roll back to a previous version if a new release causes issues.
registry.gitlab.com/acme/my-webapp:latest ← most recent build registry.gitlab.com/acme/my-webapp:a1b2c3d ← specific commit registry.gitlab.com/acme/my-webapp:v2.1.0 ← release version registry.gitlab.com/acme/my-webapp:staging ← staging environment
Pulling an Image for Deployment
On any server that has Docker installed and access to your registry:
docker login registry.gitlab.com -u USERNAME -p TOKEN docker pull registry.gitlab.com/acme/my-webapp:v2.1.0 docker run -d -p 3000:3000 registry.gitlab.com/acme/my-webapp:v2.1.0
Registry Storage and Cleanup
Every image push consumes storage. Old images accumulate quickly. Set up cleanup policies to delete images automatically.
Go to Settings → Packages and registries → Container registry → Cleanup policy. Configure rules like:
Cleanup policy example: ───────────────────────────────────────────────────────────── Run cleanup: Every week Remove tags older than: 90 days Keep the most recent: 10 tags Exclude tags matching: latest, v*.*.* (keep release tags) ─────────────────────────────────────────────────────────────
Viewing Images in the Registry
Go to Deploy → Container Registry. You see each image repository, its tags, the digest (a unique fingerprint), size, and when it was last pushed.
Container Registry — acme/my-webapp ────────────────────────────────────────────────────────────────── Tag Digest Size Pushed ────────────────────────────────────────────────────────────────── latest sha256:ab12 245 MB 2 hours ago a1b2c3d sha256:ab12 245 MB 2 hours ago v2.0.0 sha256:cd34 238 MB 1 week ago v1.9.5 sha256:ef56 231 MB 3 weeks ago ──────────────────────────────────────────────────────────────────
Using Registry Images as CI/CD Job Images
You can use your own registry images as the base image for CI/CD jobs. This is useful when you build a custom image with all your tools pre-installed, speeding up job startup time.
Custom base image: registry.gitlab.com/acme/ci-tools:latest
(contains node, python, kubectl, and aws-cli pre-installed)
run-tests:
image: registry.gitlab.com/acme/ci-tools:latest
script:
- npm test
- python -m pytest
Jobs start in seconds because all tools are already in the image instead of being installed fresh each run.
