πŸš€ Day 40: CI/CD with Flask + Docker + GitHub Actions | #100DaysOfDevOps

Ritesh SinghRitesh Singh
5 min read

Welcome to Day 40 of my #100DaysOfDevOps! Today, I built a CI/CD pipeline for a Python Flask application, containerized it with Docker, and automated the build and deployment process using GitHub Actions. Let’s dive into this exciting journey! 🐍🐳πŸ’₯ #DevOps #CI/CD


πŸ”§ Project Overview: Flask App with Docker CI/CD

The goal of this project is to create a simple Flask application, containerize it using Docker, and set up a GitHub Actions workflow to automatically build and push the Docker image to Docker Hub whenever code is pushed to the main branch. #Flask #Docker #GitHubActions


πŸ—‚ Project Structure

Here’s the structure of the project:

flask-ci-cd-demo/
β”œβ”€β”€ app/
β”‚   β”œβ”€β”€ app.py           # Flask app logic
β”‚   └── requirements.txt # Python dependencies
β”œβ”€β”€ Dockerfile           # Docker configuration
β”œβ”€β”€ .dockerignore        # Ignore unnecessary files in Docker context
β”œβ”€β”€ .gitignore           # Ignore local dev/config files
β”œβ”€β”€ .github/
β”‚   └── workflows/
β”‚       └── ci-cd.yml    # GitHub Actions workflow file
└── README.md            # Project details

πŸ› οΈ Step 1: Set Up the Project

Create the project directory and initialize a Python environment:

mkdir flask-ci-cd-demo && cd flask-ci-cd-demo
mkdir app

🐍 Step 2: Create the Flask Application

app/app.py

Create a simple Flask app:

from flask import Flask
app = Flask(__name__)

@app.route("/")
def home():
    return "πŸš€ Hello from Flask CI/CD Pipeline!"

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000)

This code sets up a Flask server that responds with a message at http://localhost:5000. #Python #Flask

app/requirements.txt

List the dependencies:

flask

🐳 Step 3: Create the Dockerfile

Create a Dockerfile to containerize the Flask app:

# Use official Python image
FROM python:3.10-slim

# Set work directory
WORKDIR /app

# Copy files and install dependencies
COPY app/requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copy source code
COPY app/ .

# Run the Flask app
CMD ["python", "app.py"]

Why this structure?

  • Using python:3.10-slim keeps the image lightweight.

  • Copying requirements.txt first allows Docker to cache the dependency layer, speeding up builds if only app.py changes. #Docker #Optimization


πŸ“¦ Step 4: Optimize with .dockerignore and .gitignore

.dockerignore

Prevent unnecessary files from being included in the Docker image:

# Git and version control
.git
.gitignore

# Python bytecode
__pycache__/
*.pyc

# Virtual environments
env/
venv/
ENV/

# Editor settings
.vscode/
.idea/

# System files
.DS_Store

# GitHub Actions config
.github/

.gitignore

Ignore local development and temporary files:

# Python
__pycache__/
*.pyc
*.pyo
*.pyd
env/
venv/
ENV/
*.env

# Editor settings
.vscode/
.idea/

# System files
.DS_Store
Thumbs.db

# Logs
*.log

# Docker artifacts
*.tar

These files ensure clean builds and repositories by excluding irrelevant files. #BestPractices


βš™οΈ Step 5: Set Up GitHub Actions Workflow

Create the workflow file at .github/workflows/ci-cd.yml:

name: Flask CI/CD

on:
  push:
    branches:
      - main

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest

    steps:
      - name: πŸ“₯ Checkout code
        uses: actions/checkout@v4

      - name: 🐍 Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.10'

      - name: πŸ“¦ Install dependencies
        run: pip install -r app/requirements.txt

      - name: βœ… Run tests
        run: echo "No tests yet"

      - name: 🐳 Build Docker image
        run: docker build -t ritesh355/flask-ci-cd-demo .

      - name: πŸ“€ Push to Docker Hub
        run: |
          echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin
          docker tag ritesh355/flask-ci-cd-demo ritesh355/flask-ci-cd-demo:latest
          docker push ritesh355/flask-ci-cd-demo:latest

Key Points:

  • Triggers on pushes to the main branch.

  • Sets up Python 3.10 and installs dependencies.

  • Builds the Docker image and pushes it to Docker Hub.

  • Uses GitHub Secrets for secure Docker Hub authentication. #GitHubActions #Automation


πŸ” Step 6: Configure Docker Hub Secrets

To enable Docker Hub pushes, add these secrets to your GitHub repository:

  • DOCKER_USERNAME: Your Docker Hub username (ritesh355).

  • DOCKER_PASSWORD: Your Docker Hub access token (not your password).

Add them via:

  1. Go to GitHub Repo β†’ Settings β†’ Secrets and variables β†’ Actions.

  2. Click New repository secret and add DOCKER_USERNAME and DOCKER_PASSWORD. #Security #DockerHub


πŸš€ Step 7: Push to GitHub

Push your project to GitHub:

git init
git remote add origin https://github.com/ritesh355/flask-ci-cd-demo.git
git add .
git commit -m "Add Flask CI/CD demo with Docker and GitHub Actions"
git push -u origin main

βœ… Step 8: Verify the CI/CD Pipeline

  1. Go to your GitHub repo β†’ Actions tab.

  2. Watch the Flask CI/CD workflow run. It will:

    • Install Python dependencies.

    • Build the Docker image.

    • Push the image to ritesh355/flask-ci-cd-demo:latest on Docker Hub.

  3. Visit Docker Hub to confirm the image is published.


πŸ§ͺ Step 9: Test the Docker Image Locally

To verify the image, run it locally (if you have Docker installed):

docker pull ritesh355/flask-ci-cd-demo:latest
docker run -p 5000:5000 ritesh355/flask-ci-cd-demo

Open your browser and visit http://localhost:5000. You should see:

"πŸš€ Hello from Flask CI/CD Pipeline!"


πŸ“Œ Learnings from Day 13

  • Built an end-to-end CI/CD pipeline for a Flask app using GitHub Actions.

  • Used .dockerignore and .gitignore to optimize Docker builds and keep the repository clean.

  • Secured Docker Hub credentials with GitHub Secrets.

  • Automated Docker image builds and pushes to Docker Hub. #Learning #DevOpsJourney


πŸ“ˆ Benefits

  • Automation: Push code, and GitHub Actions handles the rest.

  • Efficiency: .dockerignore reduces image size and build time.

  • Security: Sensitive credentials are safely stored in GitHub Secrets.

  • Scalability: Ready to extend with tests or deployment steps.


#Portfolio #Networking


πŸŽ‰ Congratulations!

You’ve successfully built a CI/CD pipeline for a Flask app with Docker and GitHub Actions! Keep rocking your #100DaysOfDevOps journey! πŸ’ͺ #KeepLearning

Need help? Drop a comment or question, and I’ll guide you through any issues!

0
Subscribe to my newsletter

Read articles from Ritesh Singh directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Ritesh Singh
Ritesh Singh

Hi, I’m Ritesh πŸ‘‹ I’m on a mission to become a DevOps Engineer β€” and I’m learning in public every single day.With a full-time commitment of 8–10 hours daily, I’m building skills in: βœ… Linuxβœ… Git & GitHubβœ… Docker & Kubernetesβœ… AWS EC2, S3βœ… Jenkins, GitHub Actionsβœ… Terraform, Prometheus, Grafana I post daily blogs on Hashnode, push projects to GitHub, and stay active on LinkedIn and Twitter/X. Let’s connect, collaborate, and grow together πŸš€ #100DaysOfDevOps #LearningInPublic #DevOps