💎

Gitlab CI/CD を用いて prefect をデプロイする

2024/02/23に公開

はじめに

今回は、Gitlab の CI/CD を用いて、prefect のデプロイをやってみたいと思います。

具体的には、prefect の workflow のエントリとなる Deployment を CI/CD を使って自動デプロイする方法についてみていきます。

動作環境

リポジトリの管理は SaaS 版の Gitlab ( gitlab.com ) を用い、CI/CD の Job 実行用の Gitlab-Runner はローカル環境に docker コンテナで用意します。

また、prefect-server や、そのバックエンドにあたる DB も同様に docker コンテナで用意します。

ローカルに用意する各 docker コンテナは、docker-compose でまとめて起動させます。
そのため、以下のような docker-compose.yml を作成します。

docker-compose.yml
services:
  prefect_server:
    image: prefecthq/prefect:2-python3.11
    restart: always
    volumes:
      - prefect:/root/.prefect
    entrypoint:
      [
        "/opt/prefect/entrypoint.sh",
        "prefect",
        "server",
        "start"
      ]
    environment:
      - PREFECT_UI_URL=http://127.0.0.1:4200/api
      - PREFECT_API_URL=http://127.0.0.1:4200/api
      - PREFECT_SERVER_API_HOST=0.0.0.0
      - PREFECT_API_DATABASE_CONNECTION_URL=postgresql+asyncpg://postgres:postgres@database:5432/prefect
    ports:
      - 4200:4200
    depends_on:
      - database

  database:
    image: postgres:latest
    restart: always
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
      - POSTGRES_DB=prefect
    expose:
      - 5432
    ports:
      - 5432:5432
    volumes:
      - db:/var/lib/postgresql/data

  gitlab-runner:
    image: gitlab/gitlab-runner:latest
    restart: always
    volumes:
      - "runner:/etc/gitlab-runner"
      - /var/run/docker.sock:/var/run/docker.sock

volumes:
  prefect:
  db:
  runner:
networks:
  default:
    name: prefect-network

また、Gitlab-Runner が実行する CI/CD Job はローカル環境の docker コンテナとして起動できるようにします。そのため、上記 docker-compose.yml 内の gitlab-runner の設定にて、/var/run/docker.sock:/var/run/docker.sock の volumes を定義し、ローカル環境で動作している Docker Engine と通信が出来るようにしています。

Gitlab リポジトリに Runner を登録

docker-compose.yml で gitlab-runner の起動が完了したら、この Runner を Gitlab リポジトリに登録します。登録方法は Gitlab リポジトリの CI/CD Settings > Runner から実施します。以下のような Project Runner の項目にて「New project runner」をクリックします。

以下のようなページになるので、 Platform は Linux 、 Tags は dev としておきます。

「Create runner」をクリックすると、登録用のコマンドが表示されます。このコマンドには、登録時に必要となる認証トークンが記載されているため、コマンド一式をコピーしておきます。

その後、ローカル環境で起動しておいた gitlab-runner に対してこのコマンドを実行します。

docker compose exec gitlab-runner gitlab-runner register --url https://gitlab.com  --token XXXXXXXXXXXXXXXXXXXXXX

コマンドを実行すると、 CI/CD Job を実行する環境について聞かれるので、 docker と入力します。これで docker コンテナを用いて Job を実行できるようになります。

.gitlab-ci.yml の作成

Gitlab-Runner の登録が完了したら、次に .gitlab-ci.yml を作成します。このファイルは、CI/CD Pipeline を定義するファイルです。

.gitlab-ci.yml
default:
  tags:
    - dev

stages:
  - build
  - deploy

build:
  stage: build
  image:
    name: gcr.io/kaniko-project/executor:v1.14.0-debug
    entrypoint: [""]
  script:
    - /kaniko/executor
      --context "${CI_PROJECT_DIR}"
      --dockerfile "${CI_PROJECT_DIR}/Dockerfile"
      --destination "${CI_REGISTRY_IMAGE}:${CI_COMMIT_TAG}"
  rules:
      - if: $CI_COMMIT_TAG

deploy:
  stage: deploy
  image:
    name: registry.gitlab.com/<username>/<repository_name>:$CI_COMMIT_TAG
  script:
    - python deploy.py $CI_COMMIT_TAG
  rules:
      - if: $CI_COMMIT_TAG

tagsdev をセットすることで、先ほど登録した Gitlab-Runner を使ってくれるようになります。

また、今回は build と deploy という 2 つのステージを用意しました。

build ステージでは、kaniko という docker image ビルド用のツールを用いて、prefect の flow 用 docker image をビルドしています。今回 prefect の flow はローカル環境の docker コンテナで実行するためです。
https://docs.gitlab.com/ee/ci/docker/using_kaniko.html

deploy ステージでは、prefect の deployment を登録します。このステージの script で実行している deploy.py は以下のようになっており、これで flow を deployment として prefect-server に登録しています。

deploy.py
import asyncio
import sys

from prefect import flow


@flow(log_prints=True)
async def sample_flow():
    print("This is sample_flow!")


async def deploy(tag: str):
    await sample_flow.deploy(
        name="sample-flow-deployment",
        work_pool_name="docker-pool",
        image=f"registry.gitlab.com/<username>/<repository_name>:{tag}",
        push=False,
        build=False,
    )


if __name__ == "__main__":
    if len(sys.argv) != 2:
        print("Docker image tag must be set.")
        exit(1)

    asyncio.run(deploy(sys.argv[1]))

それぞれのステージは、rules にて Tag が作成された時に Pipeline が生成されるようにしています。また、ビルドした docker image に対してその Tag で Push するようにしました。

環境変数の登録

CICD から ローカル環境の prefect-server に flow を deploy するには、PREFECT_API_URL の環境変数を Gitlab リポジトリに登録しておく必要があります。登録方法は Gitlab リポジトリの CI/CD Settings > Variables から実施します。

今回は、ローカル環境で動作している prefect-server に deploy が出来ればいいので、PREFECT_API_URL には http://gateway.docker.internal:4200/api を設定します。gateway.docker.internal を使っているのは、Gitklab-Runner が起動した CI/CD Job 用の docker コンテナ内から、ホスト経由で prefect-server の docker コンテナに通信できるようにするためです。
https://docs.docker.jp/v19.03/docker-for-mac/networking.html#mac-i-want-to-connect-from-a-container-to-a-service-on-the-host

環境変数の登録が出来れば、以下のように表示されるはずです。

Dockerfile と work-pool の作成

最後に prefect flow の実行に必要な Dockerfile と work-pool を作成しておきます。Dockerfile は、kaniko を用いた build ステージで flow 用の docker image をビルドするためのものです。以下のような Dockerfile を用意します。

FROM prefecthq/prefect:2-python3.11

COPY requirements.txt .
RUN pip install -r requirements.txt --trusted-host pypi.python.org --no-cache-dir

COPY <repository_name> ./<repository_name>
COPY deploy.py .

また、prefect flow を docker コンテナで起動するために docker 用の work-pool を用意します。以下のコマンドを実行します。

prefect work-pool create --type docker docker-pool

CI/CD から Deploy

それでは Gitlab リポジトリから CI/CD Pipeline を通してデプロイ( deployment の登録)を行なってみます。Gitlab リポジトリの Tags から以下のように Tag を作成します。

Tag 作成後、Pipelines をみると、自動的に CI/CD Job の実行が始まっているはずです。

build Job にて prefect flow 用の docker image の push、 deploy Job にて deployment の最新化を行なっています。

これらの Job 完了後、最新のコードで prefect flow を実行することができます。

終わりに

今回は、Gitlab CI/CD を用いて prefect flow を自動デプロイしてみました。prefect flow を docker コンテナで動作させる場合、事前にコンテナ用の docker image の用意と deployment の最新化を行う必要があります。CI/CD を通してこれらを自動化することで、煩雑な手作業が減り、継続的な開発がやりやすくなるかと思います。

参考

https://docs.prefect.io/latest/guides/ci-cd/
https://github.com/kevingrismore/cicd-example
https://docs.gitlab.com/ee/ci/docker/using_kaniko.html

Discussion