業務ではGITリポジトリとしてGitLabを使ってるのですが、ローカルPCでDockerイメージを作成する運用だと
- ローカルの変更が混じってしまう可能性がある
- イメージを作成するタイミングがあいまいだし、作成忘れがあったりする
などの問題があり微妙だったので、GitLabにタグ(1.5.2など)をプッシュしたタイミングで、自動的にDockerイメージを作成してGCRにビルドさせることにしました。
少し前に 会社のブログ で kaniko を使うケースを紹介してくれていたので、やってみることにしました。
GitLabでDockerイメージをビルドする方法の候補
改めてGitLabの ドキュメント を見てみると、以下のように書いてあります。
There are three methods to enable the use of docker build and docker run during jobs, each with their own tradeoffs.
An alternative to using docker build is to use kaniko. This avoids having to execute a runner in privileged mode.
どうやら3つの方法があるけどどれもセキュリティの問題があるので、それを避けるなら kanikoを使う のがおすすめってことのようです。
セキュリティの問題というのは、Dockerコンテナの中でDockerイメージを作成するためには、コンテナ内からホストマシンのDockerデーモンにアクセスできるようにする必要があり、それをできるようにする(privileged containerにする)とコンテナ内からホストマシンの全てのデバイスにアクセスできるようになってしまう、ということみたいです。
kanikoであれば、ホストマシンのDockerデーモンにアクセスする必要がないので安全ということなので、kanikoを利用することにしました。
kanikoとは
- コンテナまたはKubernetesクラスタ内のDockerfileからDockerイメージを構築するためのツール
- kanikoはDockerデーモンに依存せず、Dockerfile内の各コマンドを完全にユーザースペースで実行する。これにより、Dockerデーモンを簡単または安全に実行できない環境でコンテナイメージを構築できる
- kanikoのexecutorはGCRで公開されている
公式ドキュメントのサンプルを確認
サンプルの.gitlab-ci.ymlの内容を確認してみます。
build:
stage: build
image:
name: gcr.io/kaniko-project/executor:debug
entrypoint: [""]
script:
- mkdir -p /kaniko/.docker
- echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > /kaniko/.docker/config.json
- /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG
only:
- tags
思った以上にシンプルで、以下の流れで処理されるようです。
- Gitのタグがpushされた時に
- kanikoのexecutorのイメージ(gcr.io/kaniko-project/executor:debug)をGCRから取得して
-
/kaniko/.docker
フォルダを作って - GitLab ContainerRegistry用の認証情報を
config.json
に出力して -
/kaniko/executor
コマンドで、Dockerイメージを作成してレジストリにpushする-
--context
: ビルド内容を指定。ここでは対象のタグにおけるプロジェクトディレクトリが指定されている -
--dockerfile
: 使用するDockerfileのパスを指定 -
--destination
: Dockerイメージ名を指定
-
$CI_REGISTRY
などの環境変数はどうやら全て 事前定義された環境変数 のようです。
GCRやECRなどのプライベートコンテナレジストリに出力する場合は、認証情報を UIからカスタム変数として設定 して、スクリプトで参照することになりそうです。
実際にやってみる
サンプルでだいたいやり方が分かったので、次は実際にGitLab CIでkanikoを使ってDockerイメージを作成して、GCRにpushしてみようと思います。
GitLab Runnerの設定
実は自分でやったことがないのですが、この辺のドキュメントを見ながらGitLab Runnerを設定する必要があります。ぱらぱらと読んでいくと以下の作業が必要なようでした。
- GitLabが動いているサーバとは別のサーバに GitLab Runner アプリケーションをインストール
- さらに Dockerをインストール
-
GitLab Runnerを登録する
- その際、executorに
docker
を選択する
- その際、executorに
カスタム変数を登録
今回は.gitlab-ci.ymlで利用するため、以下の二つのカスタム変数を登録します。
GitLab管理画面の対象プロジェクトで Settings > CI/CD > Variables > Add variable で登録できます。
-
GCR_CREDENTIAL
: GCPサービスアカウントのJSONキーの中身のJSON -
GCR_REGISTRY_IMAGE
: GCR上のDockerイメージ名
.gitlab-ci.ymlを作成
プロジェクト直下に.gitlab-ci.ymlを以下の内容で作成します。サンプルとほぼ同じですが、以下の点を修正しています。
- カスタム変数
GCR_CREDENTIAL
をjsonファイルに出力する - 環境変数
GOOGLE_APPLICATION_CREDENTIALS
に出力したjsonファイルのパスを設定する -
GCR上のイメージ名にカスタム変数
GCR_REGISTRY_IMAGE
を指定するstages: - build_stage build: stage: build_stage image: name: gcr.io/kaniko-project/executor:debug entrypoint: [""] script: - echo "$GCR_CREDENTIAL" > $CI_PROJECT_DIR/service_account_key.json - export GOOGLE_APPLICATION_CREDENTIALS=$CI_PROJECT_DIR/service_account_key.json - /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination $GCR_REGISTRY_IMAGE:$CI_COMMIT_TAG only: - tags
Dockerfileの作成
プロジェクト内容を元にDerwentイメージを作成するためのDockerfileをプロジェクト直下に作成します。雑ですが、ubuntuのイメージに、src
ディレクトリをコピーするだけの超シンプルな内容にしておきます。
FROM ubuntu:20.04
COPY src ./src/
パイプラインを実行
あとは、Gitの適当なcommitにタグを打って、pushすると自動的にパイプラインが登録・実行されます。実際、思ったよりあっさりと動いてくれました。
さいごに
久々にGitLab CIを触りましたが、kanikoを使ってDockerイメージをビルドする部分はほとんど何も引っかからず、サクッとできました。
実装や設定も非常にシンプルですし、セキュリティの問題もないのでDockerイメージをGitLab CIで作成するならkaniko一択で問題ないかなと思います。