Skip to content

Create GitHub Actions CI/CD pipeline including Docker #19

Description

@MRD2F

✅ 1. Does the Dockerfile contain environment AND code information?

Yes — and that's intentional.

A Dockerfile usually contains:

🔹 Environment Definition

  • Base image (python:3.11-slim)
  • System dependencies (ffmpeg, build-essential, etc.)
  • Python version / runtime behavior
  • Package manager (pip, uv, conda)

🔹 Application Code Instructions

  • Where the code will live: WORKDIR /app
  • COPY instructions (COPY src ./src)
  • Install app dependencies (uv sync or pip install)
  • API entrypoint (CMD ["uv", "run", "src/app/main.py"])

Why?
Because a Docker image is meant to be a fully self-contained runtime for your application.

It needs everything required to execute the code, not just the environment.


✅ 2. How do you keep the Dockerfile updated while still developing the project?

You don’t update the Dockerfile every time you change the code.

Instead:

👍 Good practice

You design the Dockerfile to remain stable while development changes happen normally.

Only update the Dockerfile when:

  • You add new system dependencies
  • You modify Python version
  • You change the application entrypoint
  • You adopt a new package manager
  • You add/remove tooling (e.g., ffmpeg, libs for Whisper)

Most changes during development will be within src/ — and Docker simply rebuilds with the updated code.

💡 Docker caching keeps builds fast

Your Dockerfile should be structured so that:

  1. Dependencies install first
  2. Code is copied later

Example:

COPY pyproject.toml uv.lock ./
RUN uv sync --no-dev

COPY src ./src

This means:

  • Dependencies are cached
  • Rebuilding after code changes is fast

✅ 3. Should Dockerfile creation be part of a pipeline?

Yes — this is a standard DevOps best practice.

In a good pipeline:

  1. Dockerfile is version-controlled

    • It's part of the repo.
  2. CI builds the Docker image automatically

    • On every pull request
    • OR on every push to dev and main
    • Using GitHub Actions, GitLab CI, Jenkins, etc.
  3. CI runs tests inside the Docker container

    • Ensures the container works
    • Catches environment-related bugs early
  4. If tests pass → publish image to registry

    • DockerHub
    • GitHub Container Registry (GHCR)
    • AWS ECR
    • GCP Artifact Registry
    • Azure Container Registry
  5. CD deploys it

    • Kubernetes
    • Cloud Run
    • ECS/Fargate
    • AKS
    • etc.

🧱 4. Best Practices for Dockerfiles in DevOps

These are widely accepted industry rules:


1. Use slim or minimal base images

FROM python:3.11-slim

Lean, secure, fewer dependencies, smaller attack surface.


2. Install only necessary system packages

Avoid:
apt-get install -y --no-install-recommends python3-dev build-essential everything-big

Instead:
apt-get install -y --no-install-recommends ffmpeg (for Whisper)
✔ No GUI or unnecessary libs.


3. Use layer caching intelligently

This is crucial:

COPY pyproject.toml uv.lock ./
RUN uv sync --no-dev  # cached unless dependencies change

COPY src ./src         # changes frequently

This makes development builds fast.


4. Use .dockerignore

Example:

*.pyc
__pycache__/
tests/
.env
.git

This prevents sending unnecessary files to the Docker build context and speeds things up massively.


5. Don't run as root

Add:

RUN useradd -m appuser
USER appuser

Security best practice.


6. Use HEALTHCHECK

Example:

HEALTHCHECK CMD curl --fail http://localhost:8000/health || exit 1

Monitors service health inside Docker or Kubernetes.


7. Keep container ephemeral and stateless

Never write state inside the container filesystem.
Use:

  • Cloud storage
  • Volumes
  • Databases

8. Use multi-stage builds when needed

To reduce size:

FROM builder AS builder
RUN uv build

FROM python:3.11-slim AS runtime
COPY --from=builder /app/dist /app/

🏗 5. Typical Docker Workflow in DevOps Lifecycle

Below is the usual sequence:


🔹 Local Development

  • Write code
  • Run app locally with uv run
  • Occasionally test docker build .

🔹 Dev Branch

  • Developer pushes to dev

  • GitHub Actions automatically:

    • builds image
    • runs tests
    • scans for vulnerabilities (Trivy/Grype)

🔹 Testing/Staging

  • Docker image deployed to staging Kubernetes/CloudRun/ECS
  • QA & integration tests performed

🔹 Production Deployment

  • When PR merged to main:

    • GitHub Actions builds final docker image
    • Tags image with version + commit hash
    • Pushes to container registry
    • Deploys automatically (CD)

🎯 In Short: The Dockerfile Should Be Stable and Version Controlled

Even while the project is under development, the Dockerfile:

  • lives in the repo
  • is updated rarely
  • is used automatically by CI/CD
  • ensures everyone runs the same environment
  • prevents “works on my machine” bugs

If you want…

I can generate:

✔ A complete GitHub Actions CI/CD pipeline that:

  • Builds the Docker image
  • Runs pytest inside Docker
  • Publishes the image to GHCR

✔ A .dockerignore optimized for uv projects
✔ A production-ready Flask / FastAPI template with Docker

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions