Open23

GitLab CIしたい

shotakahashotakaha
  • リポジトリのルートに.gitlab-ci.ymlを作成する
  • .gitlab-ci.ymlにパイプラインを設定する
  • パイプラインはステージジョブで構成する
    • ステージ: build / test / deploy など
    • ジョブ: ステージごとの実行内容

https://docs.gitlab.com/ee/ci/

shotakahashotakaha
  • キーワード・リファレンス
  • グローバルキーワードとジョブキーワードがある
  • defaultというグローバルキーワードで、デフォルトのジョブを設定する

https://gitlab-docs.creationline.com/ee/ci/yaml/

  • poetryを使ったバージョンを考えてみた(未テスト)
.gitlab-ci.yml
default:
  image: python:latest
  before_script:
    - python --version
    - pip --version
    - pip install virtualenv
    - virtualenv venv
    - source venv/bin/activate
    - pip install -U pip
    - pip install -U poetry
    - which poetry
    - poetry env info --path
    - poetry install

variables:
  # mystmdのためにBASE_URLが必要
  BASE_URL: $CI_PAGES_URL
  PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"

cache:
  paths:
    - .cache/pip
    - venv/
    - venv/lib/python3.11/site-packages/

test:
  stage: test
  script:
    # Run test & lint
    - poetry install --with=test
    - poetry run ruff check .
    - poetry run ruff format --check .
    - poetry run pytest --verbose
  rules:
    # Run test jobs in non-default branches
    - if: $CI_COMMIT_REF_NAME != $CI_DEFAULT_BRANCH

build:
  stage: deploy
  script:
    - poetry build
  artifacts:
    paths:
      - build/*

build-python310:
  image: python:3.10
  stage: deploy
  script:
    - poetry build
  rules:
    # Run build jobs after test stage
    - if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH

preview:
  stage: deploy
  script:
    - poetry install --with=docs
    - cd docs; poetry run make dirhtml; cd ..;
    - mkdir -p public/preview/$CI_COMMIT_REF_NAME
    - mv docs/_build/dirhtml/* public/preview/$CI_COMMIT_REF_NAME/
  artifacts:
    paths:
      - public/preview/$CI_COMMIT_REF_NAME/
    expire_in: "10 days"
  rules:
    - if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH

pages:
  stage: deploy
  scripts:
    - cd docs; poetry run make dirhtml; cd ..;
    - cd mystmd; poetry run myst build --html; cd ..;
    - mv mystmd/_build/html/ public/
    - mv docs/_build/dirhtml/ public/docs/
  artifacts:
    paths:
      - public
    expire_in: "180 days"
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
  
deploy:
  stage: deploy
  script: echo "Define your deployment script!"
  environment: production
shotakahashotakaha

rules

rules:
  - if: 条件式1
    when: 実行タイミング
    allow_failure: false
  - if: 条件式2
    when: 実行タイミング
    allow_failure: false
  • 12.3で導入されたキーワード
    • only / except の置き換えとして導入された
  • ひとつのジョブに、複数のrulesを設定できる
  • 定義できるルール
    • if: 条件。条件にマッチしたときにパイプラインにジョブを追加する
    • changes: ファイルパス。特定のファイルに変更があったときに、パイプラインにジョブを追加する
    • exists: ファイルパスの配列。特定のファイルが存在するときに、パイプラインにジョブを追加する
    • allow_failure: ジョブが失敗しても、パイプラインを停止させないように設定できる
    • variables: 条件ごとにCI変数を設定できる
    • when: on_success(デフォルト値) / always / delayed / never / manual。パイプラインにジョブを追加するタイミング。デフォルトはon_successになっていて、前のステージのジョブがすべて完了したときになっている。

  • MRしたときと、特定のブランチにプッシュしたとき
rules:
  - if: $CI_MERGE_REQUEST_ID || $CI_COMMIT_REF_NAME == "main"
  • デフォルトブランチにMRしたとき
rules:
  - if: $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH
shotakahashotakaha

デフォルトブランチにプッシュしたとき

rules:
  - if: $CI_COMMIT_BRANCH == "main"
  • mainブランチを直接指定してもよいが、次のように$CI_DEFAULT_BRANCHのほうが汎用的
rules:
  - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
  • $CI_COMMIT_BRANCH: コミットしたブランチ名
  • $CI_DEFAULT_BRANCH: リポジトリの設定で設定したデフォルトブランチ名
shotakahashotakaha

デフォルトブランチ以外にプッシュしたとき

  • 機能ブランチにプッシュしたときを想定
  • コードのテストなどをしたいが、GitLab Pagesには公開しなくてよい場合などに該当
rules:
  - if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH
shotakahashotakaha

マージリクエストしたとき

  • 新規にMRしたとき or MRを更新したとき
rules:
  - if: $CI_MERGE_REQUEST_ID
  • MRを新規作成/更新したときはスキップしたいとき
    • ブランチへのプッシュすると、プッシュ用とMR更新用で、2つのパイプラインが実行されてしまう
    • パイプライン時間を節約するために、スキップ(when: never)してもよい
rules:
  - if: $CI_MERGE_REQUEST_ID
    when: never
shotakahashotakaha

グローバル・キーワード

  1. default: ジョブのデフォルト値
  2. include: CI設定のインポート
  3. stages: ["build", "test", "deploy"]): パイプラインの名前と順番を指定
  4. variables: パイプライン全体のCI/CD変数を設定
  5. workflow: パイプラインの実行タイプを設定
shotakahashotakaha

default

# .gitlab-ci.yaml
default:
  image: イメージ
  before_script:
    - ジョブの前に実行するスクリプト
    - コマンドを1つずつ記述する

build_job:
  stage: build
  script:
    - ビルド用スクリプト

test_job:
  stage: test
  script:
    - テスト用スクリプト
  • build_jobジョブとtest_jobジョブを定義する
  • それぞれのジョブにdefaultジョブの設定も適用される
shotakahashotakaha

include

  • 11.4から GitLab Free でも使えるようになったキーワード
  • .gitlab-ci.yamlを分割して作成できるようになる
  • インクルード対象
    • local: 同じリポジトリ内のCI設定ファイル
    • remote: 外部URLにあるCI設定ファイル
    • template: GitLabの組み込みテンプレート
    • project: 外部のGitLabプロジェクト
  • 読み込まれ方
    • インクルードされたファイルは、ひとつの.gitlab-ci.yml に統合される
    • なので、同じ名前のジョブは上書きされてします
    • .github/workflows/アクション.ymlとはちょっと違うかも

include:local

# .gitlab-ci.yaml
include:
  - local: "/.gitlab/workflows/build.yml"
  - local: "/.gitlab/workflows/test.yml"
  - local: "/.gitlab/workflows/deploy.yml"

include:template

# .gitlab-ci.yaml
include:
  - template: Python.gitlab-ci.yml
  - template: Workflows/Branch-Pipelines.gitlab-ci.yml
  - template: Workflows/MergeRequest-Pipelines.gitlab-ci.yml
  - template: Pages/Hugo.gitlab-ci.yml
  - template: Pages/HTML.gitlab-ci.yml
shotakahashotakaha

stages

  • パイプラインのステージ名と、実行する順番を設定
  • 同じステージ名のジョブは並行して実行
  • 前のステージ名のジョブが正常に終了したあとに、次のステージ名のジョブを実行
  • デフォルト値: [build, test, deploy]
    • ステージ名(stage)が設定されてないジョブはtestに割り当てられる
# .gitlab-ci.yml
stages:
  - build    # buildのすべてのジョブを並列実行
  - test      # buildのすべてのジョブが成功 -> testのすべてのジョブを並列実行
  - deploy    # testのすべてのジョブが成功 -> deployのすべてのジョブを並列実行
  # deployのすべてのジョブが成功 -> パイプラインを passed としてマーク
shotakahashotakaha

workflow

  • 12.5で利用可能になったキーワード
  • workflow:nameでワークフロー名を設定する
  • workflow:rulesで、ワークフローを実行する条件を設定する
    • workflow:rules:if
    • workflow:rules:changes
    • workflow:rules:exists
    • workflow:rules:when: ワークフローを実行するタイミング(always / never
    • workflow:rules:variables
workflow:
  name: ワークフロー名
  rules:
    - if: 実行する条件
      when: always
    - if: 実行しない条件
       when: never
shotakahashotakaha

ジョブ・キーワード

  1. after_script
  2. allow_failurefalse
  3. artifactsなし
  4. before_script
  5. cacheなし
  6. coverage
  7. dast_configuration
  8. dependencies
  9. environment
  10. except / onlyなし
  11. extends
  12. imageなし
  13. inherit
  14. interruptiblefalse
  15. needs
  16. pages
  17. parallel1
  18. release
  19. resource_group
  20. retry0
  21. rulesなし
  22. script
  23. secrets
  24. services
  25. stage
  26. tagsなし
  27. timeout1 hour
  28. trigger
  29. variables
  30. whenon_success
shotakahashotakaha

image

  • image: イメージ名:タグ名
    • ジョブで使用するDockerイメージを設定する
    • ジョブごとにイメージを変更できる
    • 指定しない場合はdefaultで指定したイメージに設定される

オプション

  • name: image: イメージ名:タグ名と同じ
  • entrypoint:
    • コンテナが起動するときに最初に実行されるコマンドを上書きできる
    • 特定のスクリプトを必ず実行したい場合に利用する
    • コマンドやオプションをリスト形式で記述する(例: `["/bin/sh", "-c"])
  • pull_policy: if-not-present(デフォルト) / always / never
    • イメージの取得方法を指定できる
  • services
    • servicesは、imageのオプションではなく、別のキーワード
    • 追加のイメージを設定できる
shotakahashotakaha

script / before_script / after_script

  • script: ジョブで実行するスクリプト
  • before_script: ジョブの前に実行するスクリプト。ツールのインストールなど
  • after_script: ジョブの後に実行するスクリプト
# .gitlab-ci.yaml
job:
  stage: test
  image: python:3.11
  before_script:
    - python --version
    - pip install virtualenv
    - virtualenv venv
    - source venv/bin/activate
    - pip install -U pip
    - pip install -U poetry
    - poetry install
   script:
     - テスト用スクリプト
shotakahashotakaha

cache

  • 15.0で導入されたキーワード
  • ジョブ間でキャッシュするファイルやディレクトリのリストを設定する
  • ローカルの作業コピーにあるパスのみ設定できる
  • cache:paths: CI設定ファイルからの相対パス
    • includeキーワードで読み込んだ場合は、パス設定を確認する

オプション

  • paths: []
    • キャッシュするファイルやディレクトリのパスを指定する
    • 複数のパスをリスト形式で指定する
    • リポジトリのルートを基準とした相対パスで指定する(要確認)
  • key: 文字列 / ファイル名 / CI変数
    • キャッシュのキー(ID)を指定できる
    • 同じキーのキャッシュは、ジョブ間で共有できる
    • キーを持たないジョブはすべて defaultキャッシュを共有する
    • ${CI_COMMIT_REF_SLUG}のようなCI変数を使って、コミットごとにキーを分けることもできる
    • key: filesで特定のファイル名を指定できる
  • untracked: false(デフォルト) / `true
    • Git管理されていないファイルをすべてキャッシュするかを指定できる
    • .gitignoreで除外されているファイルなどのキャッシュされるため、キャッシュサイズが大きくなる可能性がある
  • policy: pull-push(デフォルト) / pull / push
    • キャッシュの利用ポリシー(=取得または保存する条件)を設定できる。
    • pull-push: キャッシュを取得し、ジョブ終了後に新しいキャッシュを保存
    • pull: 既存のキャッシュを取得し、新しいキャッシュは作成しない
    • push: 既存のキャッシュを取得せず、新しいキャッシュを保存
  • when: on_success(デフォルト)
    • キャッシュの保存タイミンを設定できる
    • on_success: ジョブが成功した場合にキャッシュを保存
    • on_failure: ジョブが失敗した場合にキャッシュを保存
    • always: ジョブの結果に関係なく、常にキャッシュを保存
  • prefix: 文字列
    • キャッシュのキーに接頭辞を設定できる
    • ジョブごとにキャッシュを区別する場合に利用できる

基本的なキャッシュ設定

job_name:
    cache:
        paths:
            - .cache/pip/
            - venv/

ハッシュキーを使用したキャッシュ

job_name:
    cache:
        key:
            files:
                - poetry.lock
        paths:
            - .cache/pip/
            - venv/

キャッシュを常に保存する

job_name:
    cache:
        paths:
            - public/
    when: always

パイプラインごとにキーを設定

default:
    cache:
        key: "$CI_COMMIT_REF_NAME"
        paths:
            - build/
shotakahashotakaha

stages / stage

  • ジョブを実行するパイプライン名(=ステージ名)を設定する
  • デフォルトはbuild -> test -> deploy
  • 同じステージ名のジョブは並列処理される
  • 指定しない場合はtestが設定される
  • グローバル・キーワードのstagesで実行順をカスタマイズできる
# .gitlab-ci.yaml

stages:
    - lint
    - build
    - test
    - review
    - deploy

lint_job:
    stage: lint
    script:
        - echo "ソースコードの静的解析"

build_job:
    stabe: build
    script:
        - echo "ビルド開始"

unit_test:
    stage: test
    script:
        - echo "ユニットテスト開始"

review_job:
    stage: review
    script:
        - echo "レビュー環境にデプロイ"

deploy:
    stage: deploy
    script:
        - echo "プロダクション環境にデプロイ"
shotakahashotakaha

rulesworkflow

  • rulesはジョブをパイプラインに追加する条件を設定する
  • workflowはパイプラインの開始条件を設定する
shotakahashotakaha

マージリクエストのときだけ、パイプラインを実行したい

workflow:
    rules:
        - if: $CI_PIPELINE_SOURCE == "merge_request_event"
shotakahashotakaha

特定のブランチやタグのときのみ、パイプラインを実行したい

workflow:
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'
    - if: '$CI_COMMIT_TAG =~ /^v[0-9]+/'    # v* 形式のタブ
shotakahashotakaha

スケジュールされたパイプラインのみ実行したい

workflow:
  rules:
    - if: '$CI_PIPELINE_SOURCE == "schedule"'
shotakahashotakaha

workflowinclude

  • workflowはルートレベルで設定できるキーワード
  • stageごとの制御はできない(stageごとの条件はrulesで設定)
  • includeでCI設定を分割するときにworkflowキーワードを使える
.gitlab-ci.yml 分割ファイル.yml
workflow なし
なし workflow
workflow workflow
  • 上記の3パターンでworkflow設定ができる
  • 途中で変更するのは大変だと思うので、最初にストラテジーを決めたほうがよい
  • ファイルを分割したとき、ジョブ名にprefixをつけるなどして、一意にする
    • 分割ファイルが読み込まれるときに、名前空間的なものはなく、ひとつの.gitlab-ci.ymlに統合されるというイメージでよいはず
    • 同じ名前のジョブ名が存在した場合、あとから読み込まれたジョブ設定で上書きされる
    • 設定内容に不定性が生じるので、ジョブ名は重複しないように定義することが大事

設定ファイルの構造の例

.gitlab-ci.yml
.gitlab/pipelines/
  |--- main.yml
  |--- merge_request.yml
  |--- schedule.yml
.gitlab-ci.yml
workflow:
  rules:
    - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
      include:
        - local: '.gitlab/pipelines/main.yml'
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
      include:
        - local: '.gitlab/pipelines/merge_request.yaml'
    - if: '$CI_PIPELINE_SOURCE == "schedule"'
      include:
        - local: '.gitlab/pipelines/schedule.yml'
    - when: never    # 上記に該当しないときはパイプラインを開始しない
  • デフォルトブランチにプッシュしたとき
  • マージリクエストしたとき
  • スケジュール実行したとき
  • それ以外:パイプラインをスキップ