Kubernetesやクラウドネイティブをより便利に利用する技術やツールの概要、使い方を凝縮して紹介する連載。今回は、GitLabによるCI(継続的インテグレーション)について解説します。
この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。
Kubernetesやクラウドネイティブをより便利に利用する技術やツールの概要、使い方を凝縮して紹介する本連載「Cloud Nativeチートシート」。前回は、Kubernetesの利用を前提とした「Kubernetes Native」なCI/CD(継続的インテグレーション/継続的デリバリー)について、歴史と背景を踏まえ、CI/CDに具備すべき機能がどういったものかをツールの比較と動向も交えて解説しました。
今回は、CIによるKubernetesにデプロイするコンテナイメージの作成方法を紹介します。CIを行う際にポイントとなるマージリクエストによるCIの実行、コンテナの脆弱(ぜいじゃく)性スキャン、テスト結果やカバレッジのCIの結果、開発者環境とCI環境でテスト結果を同じようするコツなどを併せて紹介します。Kubernetesを用いたCI/CDを、これから行うとしている方の参考になればと思います。
なおCDについては、次回記事で紹介します。
前回の記事の再掲となりますが、KubernetesでCI/CDを行う場合、CIはアプリケーションをソースコードから最終的にコンテナイメージを作成し、コンテナレジストリに登録するところまでを担当します。つまり、コンテナレジストリにイメージを登録できればゴールです。
なお今回は、CIツールとして「GitLab」を、サンプルアプリケーションとして「Go言語」で作成したWebアプリケーションを、コンテナイメージの脆弱性スキャンツールとして「Trivy」を利用します。Trivyは、Kubernetesのセキュリティで定評のあるAqua Securityが開発しています。
以降、ソースコードからコンテナイメージをビルドし、イメージをレジストリに登録していく手順を紹介します。
下準備として、機能追加、バグフィクス用にGitブランチを作成しておきます。Gitのブランチに関する詳細は「いまさら聞けない、成功するブランチモデルとgit-flowの基礎知識」などの記事をご覧ください。このブランチ作成は、ソースコードの変更を承認してもらうための、下記手順3.マージリクエストの下準備です。
ソースコードを作成、編集し、Gitリポジトリにコミット、プッシュします。
手順1.で作成したブランチからマージリクエストを作成します。CIはマージリクエスト作成、更新時に実行します。マージリクエストの更新は、手順1.で作成したブランチに変更をプッシュすると自動的に反映されます。また、マージリクエストをmain(master)ブランチにマージした際にも、手順1.でブランチを作成した後の変更に影響がないかどうかを確認するためにCIを実行します。
最近、Master(主人)やSlave(奴隷)といった、差別を想起させる用語を使わないようにしようという動きがIT業界にあります。
Gitのデフォルトブランチ名で利用される「master」についても同様で、廃止して「main」にしようという動きがあります。
GitLabにおいても、2021年5月22日にリリースされたGitLab 14でデフォルトブランチ名をmasterからmainに変更しました。GitHubでは、既に2020年10月からデフォルトブランチをmainブランチに変更しています(GitHubのアナウンス)。
デフォルトブランチは今後、できるだけ「main」を利用した方がよいでしょう。
コンテナイメージをビルドします。ビルドは、マージ/プルリクエストの作成、修正や、mainブランチへのマージをトリガーとして行います。
コンテナイメージに脆弱性がないかどうかをスキャンします。
コンテナレジストリにコンテナイメージを登録します。
最近は、ソースコードをGitのリポジトリで管理する現場が増えていると思いますが、CIはマージリクエスト(GitLab)、プルリクエスト(GitHub)上で行うと便利です。マージリクエスト上でCIを行うことにより、次のようなメリットがあります。
本稿で紹介するGitLabを利用したCIの特徴を簡単に紹介します。
GitLabは、Gitリポジトリの機能、Gitブランチのマージの承認を依頼するマージリクエスト(プルリクエスト)の機能を持っています。また、このマージリクエストが作成されたときとマージリクエストで指定されたブランチが更新されたときに、自動的にCIを実行する機能も持っています。
GitLabには、コンテナイメージのレジストリ機能もあるので、ユーザーはビルドしたコンテナイメージをGitLabで管理できます。GitLabのレジストリにプッシュしたコンテナは、他のユーザーに公開することもできますし、プロジェクトや個人に閉じて非公開にすることもできます。
広く使われているツールなので、CIを実行するスクリプトのサンプルが簡単に見つかります。
無料のSaaSバージョンを利用すれば、インストールせずにイメージのビルドからコンテナレジストリへのアップロードまで可能です。何もインストールしなくても、手軽に始めることができます。
ここからは、「GitLabでコンテナイメージを作成するにはどうすればよいか」についてサンプルアプリケーションを用いて解説します。本稿では、サンプルアプリケーションとしてGo言語で記述された簡易なREST APIを利用します。
サンプルアプリケーションは「https://gitlab.com/cloudnativetips/ci-sample」にあります。本稿の手順に沿ってサンプルを試す場合、GitLabアカウントを作成し、上記リポジトリをフォークしてご利用ください。
この章で一通り動きを確認した後で、サンプルのコードとCIの実装を確認します。
GitLabでは、CIが実行されるタイミングを設定することができます。CIは設定されたタイミングで実行されることになります。基本的に、ソースコードの変更リクエストがマージリクエストとして投げられたときと、マージリクエストが修正されたときに、CIを実行します。マージリクエスト上でのCIによって、変更の承認者がソースコードの変更内容と、CIの実行結果(主にテスト結果)を確認して、変更を承認できるようになります。
また、マージリクエストを修正している間に、mainブランチに対する変更が現在のマージリクエストに影響を与える場合があるので、mainブランチにマージした後も念のためCIを実行します。
それでは、今回のサンプルを使って、CIを実行してみましょう。
本記事では、GitLabの言語を日本語に設定した状態で解説しています。言語設定を日本語にする方法は、「GitLab.comのアカウントを作成し、安全に利用する方法」の「UIを日本語に変更する」をご覧ください。
下準備として、GitLabのサンプルプロジェクトをクローンします。GitLabのSaaS版のアカウントをお持ちでなければ、GitLabのサインアップのページから作成してログインします。ログインしたら、サンプルのサイト「https://gitlab.com/cloudnativetips/ci-sample」に移動して、右上の「フォーク」ボタンを押してください。
フォークするネームスペース(ユーザー名もしくはグループ名)の「選択」を押してください。
次にソースコード変更用のブランチを作成します。Gitコマンドをあらかじめインストールしておいてください。先ほどフォークしたリポジトリのクローンと、変更するためのフィーチャーブランチ(ここではfeature-test)を作成します。
$ git clone https://gitlab.com/フォーク先の「アカウント名」もしくは「プロジェクト名」/ci-sample $ cd ci-sample $ git checkout -b feature-test
ソースコードを変更します。今回はWebサーバの待受ポートを80から8080に変更してみます。「cmd/main.go」ファイルを下記のように変更します。
func main() { router := sample.NewRouter() router.Logger.Fatal(router.Start(":80")) // 修正箇所 }
func main() { router := sample.NewRouter() router.Logger.Fatal(router.Start(":8080")) // 修正箇所 }
変更したら、コミットし、プッシュします。
$ git add cmd/main.go $ git commit -m "ブランチの編集のテスト" $ git push --set-upstream origin feature-test (※初回のみ--set-upstream originが必要)
これで、GitLabのリポジトリ上にブランチが新たに作成されます。
2021年6月22日の公開当初の「ci-sample」プロジェクトはfeature-testブランチが既に存在していたため、プッシュ時にエラーが発生していました。プッシュに失敗した場合は、一度GitLabにフォークしたプロジェクト(リポジトリ)を削除し、もう一度フォークし直してください。読者ならびに関係者の方々にお詫び申し上げます(編集部)。
作成したブランチからマージリクエストを作成します。マージリクエストとは、ブランチを別のブランチ(ここではmainブランチ)にマージするための要求です。
GitLab上でフォークした「ci-sample」プロジェクトの画面で「リポジトリ」→「ブランチ」から作成したブランチ(ここではfeature-test)の「マージリクエスト」ボタンを押してください。
「New merge request」画面が表示されるので、タイトルや内容を入力し、「Create マージリクエスト」ボタンを押してください。
先ほど作成したマージリクエスト上に時間がたつと、マージリクエスト上にCIの実行結果が表示されます。成功すれば、緑のチェックマークが表示されます。
失敗すると、赤で×マークが表示されます。
マージリクエスト上のCIの実行結果にパイプラインIDが表示されています。
このパイプラインIDをクリックすると、パイプラインの実行状況の詳細が確認できます。
この実行結果では、buildとscanのジョブが成功したことを示しています。失敗した場合は、赤の×ボタンが表示されます。
また、各ジョブをクリックすると、ジョブの実行結果を確認できます。
CIが失敗した場合は、失敗したジョブの実行結果をこの画面で確認し、エラーの原因を探ります。
一度マージリクエストの作成が完了すると、次からは、マージリクエストに対応するブランチ(ここではfeature-testブランチ)を修正、コミット、プッシュするだけで、マージリクエストに自動的に新たな変更が通知され、CIがブランチの修正を都度実行します。
以下、今回利用したCIのサンプルについて解説します。
GitLabのビルド定義ファイルは、「.gitlab-ci.yml」という名前で、リポジトリのルートディレクトリに配置します。また、Dockerfileも今回は、ルートディレクトリに配置しました。Dockerfileは他の場所に配置することも可能です。
GitLabでは、CIおよびCDを行う一連のフローを「パイプライン」として定義します。パイプラインは幾つかのステージに分かれ、各ステージを順番に実行します。例えば、「ビルド」「テスト」「イメージスキャン」などのステージを用意し、これらのステージを順番に実行します。各ステージで実行する具体的な内容はジョブとして記述します。本稿のサンプルでは、1ステージ1ジョブの構成ですが、1ステージに複数のジョブを定義することもできます。その場合、ステージ内の複数のジョブを並列で実行します。順序性を持たせたいときは「ステージを分ける」と考えるとよいでしょう。今回作成したビルドファイルは、下記のステージとジョブがあります。
ステージ | ステージに含まれるジョブ | ジョブの説明 |
---|---|---|
stage-build | build | コンテナイメージ作成処理(アプリケーションのコードスキャン、ビルド、単体テスト、カバレッジ取得、中間イメージのプッシュ) |
stage-scan | scan | コンテナイメージのスキャン |
stage-update-latest-image | update-latest-image | コンテナイメージのlatestイメージをアップデート |
以下、サンプルファイルのビルド定義ファイルを見ていきます。
# 使用するイメージの指定 image: docker:stable # 使用するサービスの指定 services: - docker:dind # 環境変数 variables: CONTAINER_IMAGE: registry.gitlab.com/$CI_PROJECT_PATH REPO_NAME: gitlab.com/cloudnativetips/ci-sample TRIVY_VERSION: 0.29.1 before_script: - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN registry.gitlab.com # ステージ stages: - stage-build - stage-scan - stage-update-latest-image # tage-buildステージ build: # ステージ stage: stage-build # 処理内容 script: - docker build --target codescan -t $CONTAINER_IMAGE:work . - docker build --target unittest -t $CONTAINER_IMAGE:work . - docker run $CONTAINER_IMAGE:work cat ./report.xml > report.xml - docker run $CONTAINER_IMAGE:work cat ./cover.txt - docker build --target build_image -t $CONTAINER_IMAGE:$CI_COMMIT_SHA . - docker push $CONTAINER_IMAGE:$CI_COMMIT_SHA # カバレッジ coverage: '/coverage: \d+\.\d+% of statements/' # アーティファクト artifacts: reports: junit: report.xml # CI実行契機 only: - merge_requests - main # stage-scanステージ scan: stage: stage-scan script: - docker pull $CONTAINER_IMAGE:$CI_COMMIT_SHA - wget --no-verbose https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VERSION}/trivy_${TRIVY_VERSION}_Linux-64bit.tar.gz -O - | tar -zxvf - - ./trivy --cache-dir .trivycache/ image --exit-code 0 --no-progress --format template --template "@contrib/gitlab.tpl" -o gl-container-scanning-report.json $CONTAINER_IMAGE:$CI_COMMIT_SHA - ./trivy --cache-dir .trivycache/ image --exit-code 1 --severity CRITICAL --no-progress $CONTAINER_IMAGE:$CI_COMMIT_SHA artifacts: reports: container_scanning: gl-container-scanning-report.json only: - merge_requests - main # stage-update-latest-imageステージ update-latest-image: stage: stage-update-latest-image script: - docker pull $CONTAINER_IMAGE:$CI_COMMIT_SHA - docker tag $CONTAINER_IMAGE:$CI_COMMIT_SHA $CONTAINER_IMAGE:latest - docker push $CONTAINER_IMAGE:latest only: - main
それでは、設定パラメーターを見ていきましょう。
image: docker:stable
使用するイメージを指定します。今回は、コンテナイメージを作成するので、「docker:stable」を指定します。このイメージから起動したコンテナ上で、CIのスクリプトを実行します。
services: - docker:dind
使用するサービスのイメージを指定します。サービスでは、スクリプトを実行するコンテナ以外のコンテナを起動できます。
例えば、データベースなどのミドルウェアの試験などに利用します。ここでは、コンテナ上でさらにDockerを利用する「Docker IN Docker」を利用する「dind」コンテナを起動します。
dindコンテナをサービスとして起動することにより、パイプライン内のスクリプトでDockerコマンドを利用できます。
詳細は、「Use Docker to build Docker images」をご覧ください。
上記で、imageとservicesでコンテナを起動していますが、この2つのコンテナの関係は、図12のようになります。
dockerコンテナ上でジョブのスクリプトを実行します。dockerコンテナ上で実行したdockerコマンドの処理は、dindコンテナの「dockerd」(コンテナ管理の常駐プロセス)に移譲され、dindコンテナ上でコンテナを操作します。
「docker cp」コマンドが「docekr run」コマンドのリダイレクトを利用して、dindで起動されたコンテナ内のファイルをコピーしたり(result.xml)、標準出力に出力したり(cover.txt)しています。
あまり意識しないかもしれませんが、トラブルシューティングなどでこの構成を覚えておくと役に立つでしょう。
variables: CONTAINER_IMAGE: registry.gitlab.com/$CI_PROJECT_PATH REPO_NAME: gitlab.com/cloudnativetips/ci-sample TRIVY_VERSION: 0.29.1
各ジョブで使用する共通変数を設定します。「CONTAINER_IMAGE」変数で使用している「$CI_PROJECT_PATH」変数は、GitLabのプロジェクトのパスを表すGitLabで定義済みの環境変数です。
その他のGitLabで定義済の環境変数については「Predefined environment variables reference | GitLab」をご参照ください。参考までに今回のサンプルでは、下記の定義済み環境変数を利用しています。
変数 | 説明 |
---|---|
CI_PROJECT_PATH | CIが実行されるGitLabのプロジェクトのパス |
CI_JOB_TOKEN | GitLabコンテナレジストリで利用する認証トークン |
CI_COMMIT_SHA | CIを実行する対象のGitリポジトリへのコミットのハッシュ値 |
キャプション |
before_script: - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN registry.gitlab.com
before_scriptでは、各ジョブ実行前の処理を記述します。今回は事前にGitLabコンテナレジストリに「docker login」でログインし、コンテナレジストリにプッシュできるようにしています。
「-p $CI_JOB_TOKEN」オプションを利用すると、GitLabのコンテナレジストリにログインできます。
stages: - stage-build - stage-scan - stage-update-latest-image
パイプラインの各ステージを設定します。今回は下記3ステージの構成としました。
ステージを細かく分割すると各ステージの処理内容が分かりやすくなりますが、各ステージの処理時間やステージ間の待ち時間が長くなります。ステージの分割方針はプロジェクトに応じて変更してください。
各ステージには、パイプライン内の具体的な処理、つまりジョブを含めることができます。1つのステージに1つのジョブを記述したり、1つのステージに複数のジョブを記述したり、ジョブを並列実行させたりすることもできます。
Docker社の「CI/CD Best practices」には、下記のような記述があります。
ここで、Dockerfileに単体テストのステージを設け、「docker build」コマンドで単体テストを実行することにより、ローカルマシンとCIで同じコンテナを利用した同じテストが行え、同じテスト結果を簡単に得ることができます。そこで、テストはDockerfileの中でテストステージを設けてテストすることが推奨されます。
この考え方に従った実践例として、Docker社の記事が紹介されています。本実践例では、単体テストだけではなく、ビルド(コンパイル)やコードの静的解析をDockerfileのステージ(GitLabのステージとは異なります)で設け、各ステージをdocker buildで呼び出す仕組みです。
ここまでの内容を踏まえ、今回の実践例においてもdocker buildでDockerfileの各ステージをコマンドで呼び出せるように構成しました。
次に、各ステージのジョブ定義を見ていきます。
# stage-buildステージ build: # ステージ stage: stage-build # 処理内容 script: - docker build --target codescan -t $CONTAINER_IMAGE:work . - docker build --target unittest -t $CONTAINER_IMAGE:work . - docker run $CONTAINER_IMAGE:work cat ./report.xml > report.xml - docker run $CONTAINER_IMAGE:work cat ./cover.txt - docker build --target build_image -t $CONTAINER_IMAGE:$CI_COMMIT_SHA . - docker push $CONTAINER_IMAGE:$CI_COMMIT_SHA # カバレッジ coverage: '/coverage: \d+\.\d+% of statements/' # アーティファクト artifacts: reports: junit: report.xml # CI実行契機 only: - merge_requests - main
stage-buildステージでは、下記処理を実行します。なお、下記のDockerfileのステージはDockerfileのマルチステージ機能で利用するステージで、GitLabのパイプラインのステージではないので、注意してください。Dockerfileのステージについては、後ほどDockerfileの説明の箇所で詳説します。
上記処理の6.でコンテナイメージをプッシュしているのは、stage-scan、stage-update-latest-imageステージでこのイメージを使用するからです。docker buildで作成したローカルのコンテナイメージを、GitLab CIのジョブ/ステージに跨がって利用することはできません。そのため、ここでは、GitLabのコンテナレジストリをキャッシュとして利用しています。
コンテナイメージのキャッシュについては「Use Docker to build Docker images」のマニュアルにも記載があるので、ご参照ください。
coverage: '/coverage: \d+\.\d+% of statements/'
coverageキーワードでジョブのコードカバレッジを設定します。カバレッジは正規表現で記載する必要あり、Goでは「go test -cover」コマンドを実行すると、下記のように出力されます。
ok golang-ci/pkg/sample 0.546s coverage: 100.0% of statements
出力結果のうち、カバレッジ値「100.0」を抽出するので、上記正規表現となります。他の言語を使用する場合は、使用する言語の表示形式に合わせて正規表現を修正する必要があります。
GitLab上には図13のように表示されます。
artifacts: reports: junit: report.xml
artifacts:reports:junitキーワードを設定することで、「JUnit」形式で出力された「report.xml」をartifactとして保存しています。これにより、ジョブの実行結果にテストレポートを表示できます。
GitLab上には図14のように表示されます。
# CI実行契機 only: - merge_requests - main
onlyキーワードを指定することで、ジョブの実行タイミングを、マージリクエスト時とmainブランチコミット時に指定します。
次に、今回利用したDockerfileの内容を見ていきます。Dockerfileはステージで分かれているので、ステージごとに処理内容を解説します。
FROM golang:latest as codescan WORKDIR /go/src/gitlab.com/cloudnativetips/ci-sample COPY . . RUN go vet $(go list ./... | grep -v /vendor/) FROM golang:latest as unittest WORKDIR /go/src/gitlab.com/cloudnativetips/ci-sample COPY . . RUN go install github.com/jstemmer/go-junit-report@v1.0.0 && \ go test -race -v $(go list ./... | grep -v /vendor/) 2>&1 | \ go-junit-report -set-exit-code > report.xml && \ go test -race $(go list ./... | grep -v /vendor/) -cover > cover.txt FROM golang:latest as build_app WORKDIR /go/src/gitlab.com/cloudnativetips/ci-sample COPY . . RUN go build -o app cmd/main.go FROM scratch as build_image COPY --from=build_app /go/src/gitlab.com/cloudnativetips/ci-sample/app /app ENTRYPOINT ["/app"]
・ソースコード静的解析
FROM golang:latest as codescan WORKDIR /go/src/gitlab.com/cloudnativetips/ci-sample COPY . . RUN go vet $(go list ./... | grep -v /vendor/)
codescanステージでは「golang:latest」を「Docker Hub」から取得し、「go vet」(ソースコードの静的解析)を行います。このステージのみ、イメージを外部から取得するので、処理時間が長くなります。
・単体テスト
FROM golang:latest as unittest WORKDIR /go/src/gitlab.com/cloudnativetips/ci-sample COPY . . RUN go install github.com/jstemmer/go-junit-report@v1.0.0 && \ go test -race -v $(go list ./... | grep -v /vendor/) 2>&1 | \ go-junit-report -set-exit-code > report.xml && \ go test -race $(go list ./... | grep -v /vendor/) -cover > cover.txt
unittestステージでは「go test」(単体テスト)を行い、テスト結果をJUnit形式に変換します。また、「go test -cover」によりカバレッジも取得しています。golang:latestイメージはcodescanステージで取得したイメージを使うので、処理時間は短くなります(以降のステージも同様)。
・アプリケーションコンパイル
FROM golang:latest as build_app WORKDIR /go/src/gitlab.com/cloudnativetips/ci-sample COPY . . RUN go build -o app cmd/main.go
build_appステージでは「go build」(コンパイル)を行います。
・コンテナイメージビルド
FROM scratch as build_image COPY --from=build_app /go/src/gitlab.com/cloudnativetips/ci-sample/golang-ci/app /app ENTRYPOINT ["/app"]
build_imageステージではbuild_appステージで生成したバイナリを配置します。このステージは作成されたコンテナイメージをできるだけ小さくするために、イメージが極力小さい「scratch」を使用します。
# stage-scanステージ scan: stage: stage-scan script: - docker pull $CONTAINER_IMAGE:$CI_COMMIT_SHA - wget --no-verbose https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VERSION}/trivy_${TRIVY_VERSION}_Linux-64bit.tar.gz -O - | tar -zxvf - - ./trivy --cache-dir .trivycache/ image --exit-code 0 --no-progress --format template --template "@contrib/gitlab.tpl" -o gl-container-scanning-report.json $CONTAINER_IMAGE:$CI_COMMIT_SHA - ./trivy --cache-dir .trivycache/ image --exit-code 1 --severity CRITICAL --no-progress $CONTAINER_IMAGE:$CI_COMMIT_SHA artifacts: reports: container_scanning: gl-container-scanning-report.json only: - merge_requests - main
stage-scanステージでは、Trivyでコンテナの脆弱性をスキャンします。scriptセクションで下記処理を実行します。
artifacts: reports: container_scanning: gl-container-scanning-report.json
artifacts:reports:container_scanningキーワードを指定し、スキャンした結果を保存しています。GitLab上には図15のように表示されます。
なお、Trivyによるスキャンで脆弱性が検出された場合、下記のような情報が出力されます。
LIBRARY | VULNERABILITY ID | SEVERITY | INSTALLED VERSION | FIXED VERSION | TITLE |
---|---|---|---|---|---|
apk-tools | CVE-2021-30139 | UNKNOWN | 2.10.4-r3 | 2.10.6-r0 | -->avd.aquasec.com/nvd/cve-2021-30139 |
busybox | CVE-2021-28831 | HIGH | 1.31.1-r9 | 1.31.1-r10 | busybox: invalid free or segmentation fault via malformed gzip data -->avd.aquasec.com/nvd/cve-2021-28831 |
ssl_client | CVE-2021-28831 | HIGH | 1.31.1-r9 | 1.31.1-r10 | busybox: invalid free or segmentation fault via malformed gzip data -->avd.aquasec.com/nvd/cve-2021-28831 |
脆弱性の詳細は、脆弱性データベースサイトの「CVE(Common Vulnerabilities and Exposures)」で確認できます。CVEのサイトを参考にしながら、脆弱性に対応するとよいでしょう。
# stage-update-latest-imageステージ update-latest-image: stage: stage-update-latest-image script: - docker pull $CONTAINER_IMAGE:$CI_COMMIT_SHA - docker tag $CONTAINER_IMAGE:$CI_COMMIT_SHA $CONTAINER_IMAGE:latest - docker push $CONTAINER_IMAGE:latest only: - main
stage-update-latest-imageステージでは、scriptセクションで下記処理を実行しています。
stage-build、stage-scanステージと異なり、本ステージはmainブランチマージ時のみ動作するようにしています。これは、マージリクエストの承認前の途中のCIの状態では、最新のイメージとして登録せずに、マージリクエストが承認されて、mainブランチにマージされたときに最新イメージとしてlatestタグを付けて登録するためです。
今回は、アプリケーションのコードからコンテナイメージまでを作成するCIについて、GitLab CIを例に解説しました。CIには、「アプリケーションのビルドテストをどのように行うか」(ここでは、Dockerfileから呼び出させるステージ上で実行)、CIの実行をどこで行うか」(マージリクエストが操作されたタイミング)、「テスト結果をどう格納するか」などを記述するのがポイントです。
次回は、KubernetesにデプロイするCDについて「Argo CD」を例に紹介していきます。
Copyright © ITmedia, Inc. All Rights Reserved.