Python Deployment: A Deep Dive into GitHub Actions and Docker



This content originally appeared on DEV Community and was authored by Hritik Raj

Cover image for a post about GitHub Actions and Python deployment

Hello everyone! 👋

I’m currently on a learning journey into the world of DevOps and SRE, and I’m excited to share my experience with the DevOps SRE Daily Challenge.

This week’s task was a big one: setting up a full CI/CD pipeline to deploy a Python application.

A huge shout-out to my mentor, Sagar Utekar, for guiding me through this. It was a fantastic learning experience, and I wanted to document the process for anyone else starting out.

👉 You can check out the final code on my GitHub repo: Hritikraj8804/devops-python-app

What are GitHub Actions? (The Brains of the Operation) 🧠

First things first, I had to understand the tool. GitHub Actions is a powerful CI/CD platform built right into GitHub. It lets you automate almost anything — from running tests on every commit to deploying your application to the cloud.

The key components I learned about are:

  • Workflow: The main YAML file in .github/workflows/ that defines the process.
  • Event: The trigger, like a push to the main branch.
  • Job: A set of steps that run on a server.
  • Step: An individual task, like running a command.
  • Action: A reusable piece of code, often from the Marketplace (like actions/checkout).
  • Runner: The virtual server that executes your job.

My Goal: Automate Pushing a Docker Image to Docker Hub

Instead of deploying directly to a server via SSH, I decided to containerize my app with Docker.

The goal: automatically build a Docker image and push it to Docker Hub every time I pushed new code.

Here’s how I achieved it. 🚀

Step 1: The Dockerfile – The Recipe for My App 📜

A Dockerfile is a script that tells Docker how to build your image. It’s the foundation of your container.

Here’s the Dockerfile I created for my simple Python Flask app:

# Use an official Python runtime as a parent image
FROM python:3.10-slim

# Set the working directory in the container
WORKDIR /app

# Copy the requirements file and install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copy the rest of the application's code
COPY . .

# Expose port 8000
EXPOSE 8000

# Command to run the application using Gunicorn
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "app:app"]

Step 2: Manual Build and Push (Practice Run) 🏗

Before automating, I verified the process manually.

  1. Build the image:

docker build -t my-python-app .

  1. Log in to Docker Hub:

docker login

  1. Tag for Docker Hub:

docker tag my-python-app hritikraj8804/my-python-app

  1. Push to Docker Hub:

docker push hritikraj8804/my-python-app

✅ Success! My image was on Docker Hub. Now it was time to make GitHub handle this automatically.

The Magic: Automating with GitHub Actions ✨

This is where it all came together. I created a workflow file at .github/workflows/docker-publish.yml.

The Secret Ingredient: Managing Secrets and Variables 🔑

You can’t just put your credentials directly in code! GitHub provides a secure way to manage this:

  • Secrets 🤫: For sensitive data like API keys and passwords. They’re encrypted and hidden once set. I used these for DOCKERHUB_TOKEN.
  • Variables 📝: For non-sensitive values you want to reuse, like project names.

I went to Settings → Secrets and variables → Actions in my repo and added:

  • DOCKERHUB_USERNAME
  • DOCKERHUB_TOKEN

The Workflow File (docker-publish.yml)

This YAML file tells GitHub Actions exactly what to do.

name: Build and Push Docker Image

on:
  push:
    branches: [ main ]
  workflow_dispatch:

jobs:
  build-and-push:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Log in to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Build and push Docker image
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ${{ secrets.DOCKERHUB_USERNAME }}/devops-python-app:latest

Once I pushed this file to my main branch, GitHub Actions automatically kicked in and pushed my image to Docker Hub. 🎉

What I Learned 💡

This challenge was a huge step forward for me.
Going from manual steps to a fully automated CI/CD pipeline felt like magic. ✨

Key takeaways:

  • GitHub Actions is powerful and flexible for automation.
  • Docker makes applications portable and deployment-ready.
  • Secrets management is essential for security in DevOps.

👉 If you’re starting your DevOps journey, I highly recommend building something like this yourself. Nothing beats hands-on learning!


This content originally appeared on DEV Community and was authored by Hritik Raj