1. Introduction

CI/CD (Continuous Integration and Continuous Deployment) helps automate the software delivery process, reducing manual errors and improving reliability. In this guide, we'll build a complete CI/CD pipeline using Docker and GitHub Actions.

Our pipeline will automatically:

  • Build a Docker image
  • Run tests
  • Push the image to Docker Hub
  • Deploy to a server

2. Project Structure

Here's a simple structure of our project:

my-app/
├── .github/
│ └── workflows/
│ └── deploy.yml
├── Dockerfile
├── app.py
├── requirements.txt
└── README.md

3. Dockerfile

Create a Dockerfile in the root directory:

# FROM python:3.11-slim
WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .
CMD ["python", "app.py"]

This Dockerfile creates a lightweight image for our Python application.

4. GitHub Actions Workflow

Next, set up a workflow file that builds the image, runs the test suite, and pushes to your registry on every push to main. Keep secrets such as registry credentials in GitHub's encrypted repository secrets rather than committing them.

5. Secrets Configuration

Store your Docker Hub token, SSH deploy key, and any environment variables under Settings → Secrets and variables → Actions so the workflow can reference them without exposing sensitive values in the repo.

6. Deployment

The final job in the workflow connects to your server over SSH, pulls the freshly built image, and restarts the container — giving you a zero-touch deploy on every merge.

7. Best Practices

  • Pin base image versions instead of using latest
  • Cache dependencies between workflow runs to speed up builds
  • Run your test suite before the build/push steps, not after
  • Use a non-root user inside the container

8. Conclusion

With this setup, every push to your repository automatically builds, tests, and deploys your application — no manual steps required. From here, you can extend the pipeline with staging environments, rollback steps, or notifications to Slack.