GitLabCI(3/4) パイプライン変更

パイプライン作成


はじめに

前回からの続きです。前回はパイプラインを作成して実際にアプリのデプロイができるまでを確認しました。
今回は、前回作成したパイプラインを改善し、より効率的で管理しやすい形にしていきます。


システム構成

#項目内容
1GitLab のバージョン16.8.1

 

#項目内容
1GitLab Runner を構築した OSAmazon Linux 2023
2GitLab Runner のバージョン16.8.1
3GitLab Runner のタイプshell

システム概略図

※GitLab はすでに構築済みのものを使用

  1. Runner がパイプラインを確認(これは定期的に行われている)
  2. GitLabへpushするタイミングでRunnerがExecutorにパイプライン実行を指示
  3. Executorがジョブを実行


ディレクトリ構成

root
├── app
│   ├── backend
│   │   └── main
│   │       ├── Dockerfile
│   │       ├── app
│   │       │   └── bnbwebapi-0.0.1-SNAPSHOT.jar
│   │       └── db
│   │           ├── Dockerfile
│   │           ├── compose.yaml
│   │           └── data
│   │               └── data.sql
│   └── frontend
│       ├── compose.yaml
│       └── main
│           ├── Dockerfile
│           └── app
│               └── ...
└── bnbwebapi
    └── ...

パイプライン作成

今回は以下のjobを実行します。

#項目stage内容
1jar-build-jobbuildmavenを実行しjarファイルを作成
2image-build-jobbuilddocker imageをビルド
3deploy-jobdeployビルドしたdocker imageをコンテナレジストリにプッシュ
4cleanup-jobcleanup不要な Docker オブジェクトを削除

パイプライン編集

ここまででGitLab-Runnerを使ってアプリのデプロイを実施できました。ここからはオプションを使ってパイプラインを編集していきます。

①CIの実行条件を設定する

やりたいこと:

  • variablesで定義しているTAGをソースコードPUSH時のタグを取得するようにしたい。
  • タグが追加された時のみCIを実行するようにしたい。
  • jar-build-job → image-build-job → deploy-jobと順番に実行されるようにし、前のジョブが失敗した場合には次のジョブは実行されないようにしたい。
  • cleanup-job はタグが追加された場合に、他のジョブの成功にかかわらず実行するようにしたい。

ソースコードPUSH時のタグをCIで取得するには定義済み CI/CD 変数の中から CI_COMMIT_TAG を使います。この変数はPUSH時にタグがある場合はタグが入っており、ない場合は空になります。

⚠ 注意:
定義済み変数には CI_COMMIT_BRANCH というブランチ名を取得するタグも存在します。当初は、「指定のブランチでタグが追加されたらCIを実行する」という実行条件にしたかったのですが、 CI_COMMIT_TAG と CI_COMMIT_BRANCH は同時に使えない仕様でした。(タグが追加されると CI_COMMIT_BRANCH が空になる)testジョブを作成し、タグの有無でそれぞれ検証した結果がこちらです。

test-job:
  stage: test
  script:
    - echo $CI_COMMIT_BRANCH
    - echo $CI_COMMIT_TAG

タグ無し

タグ有り

この変数を使って、タグが追加された時のみにCIを実行するために、すべてのジョブで適用される共通ルールを設定します。 .gitlab-ci.yml に以下を追加します。

.default_rules:
  rules:
    # $CI_COMMIT_TAGがnullの時はジョブを実行しない
    - if: '$CI_COMMIT_TAG == null'
      when: never

共通ルールをジョブに適用させるため、各ジョブに以下を追記します。

rules:
    - !reference [.default_rules, rules]

これで、すべてのジョブがタグが追加された時のみ実行するようになりました。次にビルドジョブ、デプロイジョブに順序を付けていきます。

前のジョブが完了してから次のジョブを実行するにはrulesオプションで実行条件を設定します。

rules:
    - !reference [.default_rules, rules]
    - when: on_success

when: on_successを追記することで前のジョブが成功した時のみ実行されるようになります。
同じステージ内のジョブに順序をつけるには加えてneedsオプションをつかいます。

needs: ["jar-build-job"]

これをimage-build-jobに追記することで、jar-build-job成功時のみジョブが実行されるようになります。

cleanup-jobは他のジョブの成功にかかわらず実行したいのでwhen: alwaysを使います。

rules:
    - !reference [.default_rules, rules]
    - when: always

②共通処理

GitLab Runnerではextendsオプションを使って重複処理を共通化することができます。今回は重複処理はありませんがECRにログインする操作を共通化してみようと思います。

# 共通ジョブ
.login-ecr:
  script:
    - aws ecr get-login-password | docker login --username AWS --password-stdin https://$AWS_ACCOUNT.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com

・・・

image-build-job:
  stage: build
  needs: ["jar-build-job"]
  extends:
    - .login-ecr
  script:
    - cd ./app/frontend
    - docker compose build
    - docker image tag backend $AWS_ACCOUNT.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/app/backend-$AWS_IAM_USER_ID:$CI_COMMIT_TAG
    - docker image tag backend-db $AWS_ACCOUNT.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/app/backend-db-$AWS_IAM_USER_ID:$CI_COMMIT_TAG
    - docker image tag frontend $AWS_ACCOUNT.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/app/frontend-$AWS_IAM_USER_ID:$CI_COMMIT_TAG
  rules:
    - !reference [.default_rules, rules]
    - when: on_success

先頭がドット(.)から始まるジョブは、無効化されそのジョブ自体は処理されなくなりますが、他のジョブのベースとすることができます。extendsで.login-ecrジョブを呼び出すことで他のジョブでECRにログインすることが可能になります。

③ジョブの共通ファイル化

cleanup-jobのように他のCIでも使えるような汎用ジョブはincludeを使って共通ファイルにして呼ぶことができます。

.gitlab-ci.yml

include:
 - local: .gitlab-ci/test.yml
 - local: .gitlab-ci/cleanup.yml

cleanup.yml

cleanup-job:
  stage: cleanup
  script:
    - docker system prune -f
    - docker volume prune -f
  rules:
    - !reference [.default_rules, rules]
    - when: always

test.yml

test-job:
  stage: test
  script:
    - echo $CI_COMMIT_BRANCH
    - echo $CI_COMMIT_TAG
  rules:
    - !reference [.default_rules, rules]
    - when: always

これで一通りの修正ができました。修正後の.gitlab-ci.ymlはこちらです。

image: maven:3.9.9-jdk-21

.default_rules:
  rules:
    - if: '$CI_COMMIT_TAG == null'
      when: never

.login-ecr:
  script:
    - aws ecr get-login-password | docker login --username AWS --password-stdin https://$AWS_ACCOUNT.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com

stages:
  - build
  - deploy
  - cleanup
  - test

include:
 - local: .gitlab-ci/test.yml
 - local: .gitlab-ci/cleanup.yml

jar-build-job:
  stage: build
  script:
    - cd ./bnbwebapi
    - mvn clean package -DskipTests=true
    - cp ./target/bnbwebapi-0.0.1-SNAPSHOT.jar ../app/backend/main/app/
  artifacts:
    paths:
      - ./bnbwebapi/target/bnbwebapi-0.0.1-SNAPSHOT.jar
    expire_in: "1 day"
  rules:
    - !reference [.default_rules, rules]
    - when: always

image-build-job:
  stage: build
  needs: ["jar-build-job"]
  extends:
    - .login-ecr
  script:
    - cd ./app/frontend
    - docker compose build
    - docker image tag backend $AWS_ACCOUNT.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/app/backend-$AWS_IAM_USER_ID:$CI_COMMIT_TAG
    - docker image tag backend-db $AWS_ACCOUNT.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/app/backend-db-$AWS_IAM_USER_ID:$CI_COMMIT_TAG
    - docker image tag frontend $AWS_ACCOUNT.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/app/frontend-$AWS_IAM_USER_ID:$CI_COMMIT_TAG
  rules:
    - !reference [.default_rules, rules]
    - when: on_success

deploy-job:
  stage: deploy
  script:
    - docker image push $AWS_ACCOUNT.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/app/backend-$AWS_IAM_USER_ID:$CI_COMMIT_TAG
    - docker image push $AWS_ACCOUNT.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/app/backend-db-$AWS_IAM_USER_ID:$CI_COMMIT_TAG
    - docker image push $AWS_ACCOUNT.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/app/frontend-$AWS_IAM_USER_ID:$CI_COMMIT_TAG
  rules:
    - !reference [.default_rules, rules]
    - when: on_success

終わりに

今回の改善によって、パイプラインの柔軟性とメンテナンス性が向上しました。実行条件を適切に設定することで不要なジョブの実行を防ぎ、共通処理や共通ファイルを活用することで、設定の重複を減らし管理しやすくなりました。
次回は、GitLab Runner の Executor を Docker に変更し、Docker-in-Docker(dind)環境を構築していきます。

--------------------------
開発支援・技術研修のご要望・ご相談はこちらから
--------------------------
【この技術ブログを読んだエンジニアの皆様へ】
カサレアルブログをお読みいただき、ありがとうございます!

私たちは、常に新しい技術に挑戦し、ユーザーのニーズに応えるサービスを提供しています。
もし、当社の技術への情熱や、会社・チーム・社員の雰囲気に共感いただけたなら、
ぜひ私たちと一緒に働きませんか?
現在、株式会社カサレアルでは事業拡大に伴い、新たな仲間となるエンジニアを積極的に募集しています。

少しでも興味をお持ちいただけましたら、まずは弊社のことを知っていただけると嬉しいです。
▼採用サイト
https://www.casareal.co.jp/recruit/career
▼社員インタビュー
https://hrmos.co/pages/casareal/jobs/0000016
▼エンジニアの仲間になる! エントリーはこちらから
https://hrmos.co/pages/casareal/jobs

皆様のエントリーを心よりお待ちしています!

Laravelのジョブがタイムアウトした際に再実行しない方法

コメントを残す

メールアドレスが公開されることはありません。 ※ が付いている欄は必須項目です

コメント ※

名前 ※

メール ※

サイト