GitLab CIのTips的なものを記載していきます。

環境(stg / prd)毎に異なるレジストリにpushする

実際の運用では、stagingとproductionのDockerイメージを、異なるレジストリで管理することもあると思います。そのようなケースではEnvironment scopeを使うと良いと思います。
まず、以下のイメージのように同名のカスタム変数を異なるEnvironment scope(stg / prd)で登録します。

その上で、.gitlab-ci.ymlを以下のようにします。

  • 元々のbuildの内容は.buildとしてテンプレート化する
  • build_stgbuild_prdを新たに作って.buildをextendする
  • タグ名$CI_COMMIT_TAGのパターンマッチで、x.y.zの形式なら環境名をprdとし、それ以外なら環境名をstgとする(それにより読み込まれるカスタム変数が切り替わる)

    stages:
      - build_stage
    
    .build:
      stage: build_stage
      image:
        name: gcr.io/kaniko-project/executor:debug
      # 省略(上の実例と全く同じ)
    
    build_stg:
      extends: .build
      environment:
        name: stg
      except:
        variables:
          - $CI_COMMIT_TAG =~ /^([\d]+\.){2,3}[\d]+$/
    
    build_prd:
      extends: .build
      environment:
        name: prd
      only:
        variables:
          - $CI_COMMIT_TAG =~ /^([\d]+\.){2,3}[\d]+$/

これで、タグ名によってpush先のレジストリを変更することができました。

初めてのパイプラインが登録されない

こちらのissueにあるように、masterブランチ(デフォルトブランチ)に.gitlab-ci.ymlが存在しない場合、たとえ別ブランチに.gitlab-ci.ymlが存在しても、GitLab CIが有効にならないようです。

自分の場合は、masterブランチに存在しない状況で、topicブランチを切って.gitlab-ci.ymlを作成したため、まさにこの問題に当たってしまいました。

結局、masterブランチに.gitlab-ci.ymlを配置してあげるとうまくパイプラインが登録されるようになりました。

GitLab CIでGCR上のDockerイメージをpullして使う

以下の様な感じで、GCR上のDockerイメージを利用してGitLab CIの処理を行う方法です。

test:
  stage: test
  image:
    name: asia.gcr.io/myproject/myimage:1.2.3
  script:
    - poetry run python -m unittest

何も設定なしに実行すると以下の様なエラーが発生します。

ERROR: Preparation failed: Error response from daemon: unauthorized: You don’t have the needed permissions to perform this operation, and you may have invalid credentials. To authenticate your request, follow the steps in: https://cloud.google.com/container-registry/docs/advanced-authentication (executor_docker.go:192:0s)

GCRはプライベートリポジトリなので docker pullする際に、認証を行ってあげる必要があります。設定方法はこちらのドキュメントに書いてあります。

方法はいくつかあるようです。

  • 案1) DOCKER_AUTH_CONFIG変数にクレデンシャル情報を設定する
    • UIからカスタム変数として登録する【採用】
      • ○ 開発担当者が好きに設定できる
      • ○ クレデンシャル情報もcommit対象にならない
    • .gitlab-ci.ymlでvariableとして登録する【不採用】
      • ○ 開発担当者が好きに設定できる
      • × クレデンシャル情報がcommit対象になる
    • config.tomlに記載する【不採用】
      • × インフラ担当者(GitLabが動いているサーバに入って設定できる人)しか設定できない
      • × runnerに対してクレデンシャル設定が固定になってしまう(プロジェクトによって使い分けたりできない)
  • 案2) config.jsonにcredential helperやcredential storeの情報を記載する【不採用】
    • × インフラ担当者(GitLabが動いているサーバに入って設定できる人)しか設定できない
    • × サーバに対してクレデンシャル設定が固定になってしまう
    • × shared runnerだと使えない
    • × Credentials Store and Credential Helpers require binaries to be added to the GitLab Runner’s $PATH

結局、UIからカスタム変数としてDOCKER_AUTH_CONFIGを設定する方法を採用しました。

GitLab管理画面の対象プロジェクトで Settings > CI/CD > Variables > Add variable で、DOCKER_AUTH_CONFIGという名前のカスタム変数を登録します。値は以下の形式になります。

{
    "auths": {
        "asia.gcr.io": {
            "auth": "Base64の文字列"
        }
    }
}

このBase64の文字列ですが、以下の形式の文字列をBase64に変換する必要があります。

$ echo -n "username:password" | base64
bXlfdXNlcm5hbWU6bXlfcGFzc3dvcmQ= # サンプルです

GCRの場合は、usernameが_json_key固定で、passwordがjsonキーファイルの中身のJSONそのものになります(この情報がなかなか分からず探すのに時間がかかったw)。実際には以下の様なコマンドを実行してあげて出てきた文字列を、DOCKER_AUTH_CONFIGのauthのところに貼り付けてあげればOKです。

$ echo -n "_json_key:$(cat ./key.json)" | base64
ZW5fdXJpIda90jmad@spkfvfadm,dGgyLmdvb2dsZWFwaXMuYerqwrw29tL3Rva2VuIiwKICAiYXV0aF9wcm92aWRlcl94NTA5X2Nadsabag:sdpakmfpadsmfajfe8bfnpuqwehfjhsdnv7qewjkbvdsag1MDkvc2NyYXBlciU0MHByZC1hc3RhbXVzZS1hc3RhbXVzZS5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIKfQ==    # サンプルです

これで設定は完了で、ジョブを実行すればちゃんとGCRからdocker pullできると思います。
ちなみにうまくいくと、以下の様なログが出力され、$DOCKER_AUTH_CONFIGを使って認証が行われていることを確認できます。

Running with gitlab-runner 12.2.0 (88hrewe6q)
  on my-runner 9jqf932qe
Using Docker executor with image asia.gcr.io/myproject/myimage:1.2.3 ...
03:06
Authenticating with credentials from $DOCKER_AUTH_CONFIG
Pulling docker image asia.gcr.io/myproject/myimage:1.2.3 ...
Using docker image sha256:sa9nfbpiahfp98qwendpjoahv09ufheqwofndnoafnsfa for asia.gcr.io/myproject/myimage:1.2.3