WhatsApp

🔄 CI/CD · Docker

CI/CD Docker Deployment Pipeline — From Git Push to Production

Every DevOps engineer talks about CI/CD. Fewer actually build one end-to-end from scratch. This project is a complete CI/CD pipeline that takes code from a Git push, builds a Docker image, runs tests, pushes to a registry, and deploys to a server — fully automated, zero manual steps.

The Problem CI/CD Solves

Without a pipeline, deployment looks like this: developer finishes code, SSHes into the server, pulls the repo, manually builds the image, restarts the container, hopes nothing breaks. It works once. It breaks the tenth time when someone forgets a step, deploys the wrong branch, or pushes untested code.

A CI/CD pipeline removes humans from the deployment path. Code that passes tests ships automatically. Code that fails never touches production.

Pipeline Architecture

git push → mainGitHub Actions triggered ├── Checkout code ├── Run tests (pytest) ├── Build Docker image ├── Push to Docker Hub / GHCR └── SSH deploy to server ↓ docker pull → docker compose up -d # Zero-downtime rolling update

GitHub Actions Workflow

name: CI/CD Pipeline

on:
  push:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Run tests
        run: |
          pip install -r requirements.txt
          pytest tests/ -v

  build-and-deploy:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - name: Build Docker image
        run: docker build -t ${{ secrets.REGISTRY }}/app:${{ github.sha }} .

      - name: Push to registry
        run: |
          echo ${{ secrets.REGISTRY_TOKEN }} | docker login -u ${{ secrets.REGISTRY_USER }} --password-stdin
          docker push ${{ secrets.REGISTRY }}/app:${{ github.sha }}

      - name: Deploy to server
        uses: appleboy/ssh-action@v0.1.10
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: |
            docker pull ${{ secrets.REGISTRY }}/app:${{ github.sha }}
            docker compose up -d --no-deps app

Secrets Management

No credentials in code. Ever. All sensitive values — registry tokens, SSH keys, server addresses — live in GitHub Actions Secrets and are injected at runtime as environment variables. The workflow file in the repo contains zero plaintext secrets.

Docker Image Strategy

Each build produces an image tagged with the Git commit SHA. This means every deployed version is traceable back to an exact commit — rollback is as simple as deploying a previous tag.

# Multi-stage build — keeps final image lean
FROM python:3.11-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --user -r requirements.txt

FROM python:3.11-slim
WORKDIR /app
COPY --from=builder /root/.local /root/.local
COPY . .
CMD ["python", "-m", "uvicorn", "main:app", "--host", "0.0.0.0"]

Key Lessons

What's Next

Work With Me

Need help implementing any of this?

I offer consulting for Linux, AWS, CI/CD, Docker, Terraform, and monitoring setup. Let's talk.

Book Free Consultation WhatsApp →