Day 9 – GitLab CI/CD for Python + Container Registry + Kubernetes Deployment

Hey there! I'm currently working as an Associate DevOps Engineer, and I'm diving into popular DevOps tools like Azure Devops,Linux, Docker, Kubernetes,Terraform and Ansible. I'm also on the learning track with AWS certifications to amp up my cloud game. If you're into tech collaborations and exploring new horizons, let's connect!
Welcome to Day 8 of the Ramdan DevOps Bootcamp! Today, we dove into real-world DevOps practices by implementing CI/CD pipelines for a Python API using GitLab CI, building Docker images, pushing them to the GitLab Container Registry, and deploying them via Kubernetes.
Let’s break down what we accomplished 👇
🐍 Python App Setup with Docker
We containerized a basic FastAPI application using this Dockerfile:
# Base Python image
FROM python:3.12-slim
# Set working directory inside the container
WORKDIR /usr/local/app
# Copy requirements file and install dependencies
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
# Copy application source code
COPY src ./src
# Expose application port
EXPOSE 8000
# Switch to a non-root user for better security
RUN useradd app
USER app
# Run the application
CMD ["uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "8000"]
✅ Lightweight
✅ Secure (non-root user)
✅ Production-ready
⚙️ GitLab CI/CD Pipeline
We configured a GitLab CI/CD pipeline to automatically:
Build the Docker image.
Push it to the GitLab Container Registry.
Optionally trigger deployment (manual or automatic).
A sample .gitlab-ci.yml might look like this:
image: docker:latest
services:
- docker:build
stages:
- build
- push
variables:
IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG
before_script:
- echo "$CI_JOB_TOKEN" | docker login -u gitlab-ci-token --password-stdin $CI_REGISTRY
build:
stage: build
script:
- docker build -t $IMAGE_TAG .
- docker push $IMAGE_TAG
only:
- tags
💡 We trigger builds on Git tags like
1.2.0to produce versioned images.
🐳 Image Hosting with GitLab Container Registry
No need for Docker Hub or external registries. GitLab gives us a built-in container registry:
tgitlab.hassandevops.site:5050/ramdanbootcamp/multistage-python-cicd:1.2.0
You can access it under your project > Packages & Registries > Container Registry.
☸️ Kubernetes Deployment
After pushing our Docker image, we deployed it to Kubernetes using the following YAML configs:
✅ Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: mypythonapp
spec:
replicas: 1
selector:
matchLabels:
app: mypythonapp
template:
metadata:
labels:
app: mypythonapp
spec:
containers:
- name: mypythonapp
image: gitlab.hassandevops.site:5050/ramdanbootcamp/multistage-python-cicd:1.2.0
ports:
- containerPort: 8000
imagePullSecrets:
- name: gitlab-registry-secret
🔐
imagePullSecretshelps Kubernetes authenticate with GitLab's private registry.
✅ Service
apiVersion: v1
kind: Service
metadata:
name: mypythonapp-svc
spec:
selector:
app: mypythonapp
ports:
- protocol: TCP
port: 80
targetPort: 8000
✅ Ingress (with SSL)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: mypythonapp-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: "/"
spec:
rules:
- host: python.hassandevops.site
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: mypythonapp-svc
port:
number: 80
tls:
- hosts:
- python.hassandevops.site
secretName: hassandevops-tls
🌐 Our Python app is now live at https://python.hassandevops.site
🔐 Pro Tip: Creating the GitLab Registry Secret
To pull private images in Kubernetes, create a secret:
kubectl create secret docker-registry gitlab-registry-secret \
--docker-server=gitlab.hassandevops.site:5050 \
--docker-username=<your-username> \
--docker-password=<your-token> \
--docker-email=you@example.com




