How do you set up a continuous deployment pipeline using GitLab CI for a Python Flask project?

12 June 2024

In today's fast-paced software development environment, continuous integration and continuous deployment (CI/CD) are essential practices. They ensure that your application is always in a deployable state, providing rapid feedback on the quality of your code. This article will guide you through setting up a continuous deployment pipeline for a Python Flask project using GitLab CI, Docker, and other key technologies. By the end, you'll have a robust pipeline that automates the build, test, and deployment processes.

GitLab CI (Continuous Integration) is a powerful tool that integrates with your GitLab repositories. It allows you to define a pipeline using a .gitlab-ci.yml file, which specifies the steps required to build, test, and deploy your application. This tutorial will focus on setting up a Python Flask project and deploying it using a continuous deployment pipeline in GitLab CI.

Flask is a lightweight WSGI web application framework in Python. It’s perfect for small to medium projects and is widely used for creating RESTful APIs. Combining Flask with GitLab CI allows you to streamline your development and deployment workflow, ensuring that your application is always up-to-date and performing well.

Setting Up Your GitLab Project and Docker

Before diving into the pipeline configuration, ensure you have a GitLab project set up. Push your existing Flask project to a GitLab repository or create a new one directly on GitLab. Next, install Docker on your development machine. Docker allows you to create and manage lightweight, portable containers for your applications.

  1. Initialize GitLab Project: Create a GitLab project by logging into your GitLab account and clicking on "New Project". Select "Create from template", "Import project", or "Create blank project" based on your needs.

  2. Install Docker: Follow the instructions on the official Docker website to install Docker on your system.

  3. Create Dockerfile: In your Flask project directory, create a Dockerfile to define the environment in which your application will run. Here's a basic example:

    FROM python:3.8-slim-buster
    
    WORKDIR /app
    
    COPY requirements.txt requirements.txt
    RUN pip install -r requirements.txt
    
    COPY . .
    
    CMD ["python", "app.py"]
    

This Dockerfile does the following:

  • Uses the official Python 3.8 Docker image.
  • Sets the working directory to /app.
  • Copies the requirements.txt file and install Python dependencies using pip install.
  • Copies the rest of the application files.
  • Defines the command to run the Flask application.

Configuring .gitlab-ci.yml for Continuous Integration

The heart of GitLab CI/CD is the .gitlab-ci.yml file. This file defines the various stages and jobs in your pipeline. Below is an example configuration for a Python Flask project:

image: docker:latest

services:
  - docker:dind

variables:
  DOCKER_DRIVER: overlay2

stages:
  - build
  - test
  - deploy

before_script:
  - docker info
  - pip install docker-compose

build:
  stage: build
  script:
    - docker build -t registry.gitlab.com/your-username/your-project:latest .
  only:
    - main

test:
  stage: test
  script:
    - docker-compose -f docker-compose.test.yml up --abort-on-container-exit
  only:
    - main

deploy:
  stage: deploy
  script:
    - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN registry.gitlab.com
    - docker push registry.gitlab.com/your-username/your-project:latest
  only:
    - main

Let's break down this configuration:

  1. Docker Image and Services: The pipeline uses the latest Docker image and the docker:dind (Docker in Docker) service to build Docker images within the pipeline.

  2. Variables: The DOCKER_DRIVER variable is set to overlay2 for better performance.

  3. Stages: Define three stages: build, test, and deploy.

  4. Before Script: Runs commands before any job. Here, it checks Docker information and installs docker-compose.

  5. Build Job: The build job builds the Docker image from the Dockerfile and tags it with the GitLab Container Registry.

  6. Test Job: The test job uses docker-compose to run tests defined in docker-compose.test.yml.

  7. Deploy Job: The deploy job logs into the GitLab Container Registry and pushes the Docker image.

Docker Compose and Test Configuration

To facilitate testing, we'll use Docker Compose. Create a docker-compose.test.yml file in your project directory with the following content:

version: '3.8'

services:
  web:
    image: registry.gitlab.com/your-username/your-project:latest
    build:
      context: .
      dockerfile: Dockerfile
    command: python -m unittest discover -s tests
    environment:
      - FLASK_ENV=testing
    depends_on:
      - db

  db:
    image: postgres:13
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: test_db

This configuration does the following:

  • Defines two services: web and db.
  • The web service uses the image built from the Dockerfile and runs unit tests using unittest.
  • The db service uses a PostgreSQL image as the database.
  • Specifies environment variables for the web service.

Deploying to Heroku

To deploy your Flask application to Heroku, you'll need to add a deploy job in the .gitlab-ci.yml file. This job will use the Heroku CLI to deploy the Docker image.

  1. Install Heroku CLI: First, install the Heroku CLI on your development machine by following the instructions here.

  2. Login to Heroku: Authenticate with Heroku on your local machine using heroku login.

  3. Create Heroku App: Create a new Heroku app using heroku create your-app-name.

  4. Add Deploy Job: Add the following deploy job to your .gitlab-ci.yml file:

deploy:
  stage: deploy
  script:
    - docker login -u _ -p $HEROKU_API_KEY registry.heroku.com
    - docker tag registry.gitlab.com/your-username/your-project:latest registry.heroku.com/your-app-name/web
    - docker push registry.heroku.com/your-app-name/web
    - heroku container:release web --app your-app-name
  only:
    - main

This deploy job does the following:

  • Logs into the Heroku Container Registry using the $HEROKU_API_KEY.
  • Tags the Docker image for Heroku.
  • Pushes the image to the Heroku Container Registry.
  • Releases the image on Heroku.

Setting up a continuous deployment pipeline using GitLab CI for a Python Flask project involves several steps, from creating and building Docker images to configuring pipelines and deploying to Heroku. By following this guide, you ensure that your application is always in a deployable state, automating the build, test, and deployment processes. This not only saves time but also provides rapid feedback on the quality of your code.

By using GitLab CI, Docker, and Flask in combination with a well-configured .gitlab-ci.yml file, you can create a seamless CI/CD pipeline. This setup allows you to focus more on developing features and less on managing deployments. Embrace the power of continuous deployment and elevate your Flask projects to the next level.

Copyright 2024. All Rights Reserved