AWS
GitLab

Gitlab CI Runner のジョブに AWS ECR のイメージを使う

Gitlab Runner で実行するジョブのイメージを Amazon ECR から Pull する方法(ジョブの中で docker pull という話ではなく)。

要するに .gitlab-ci.yml で下記のように ECR のイメージを指定できるようにするということです。

test:

stage: test
image: 999999999999.dkr.ecr.ap-northeast-1.amazonaws.com/oreore:latest
script:
- make test

前提として Gitlab Runner が docker-credential-ecr-login (amazon-ecr-credential-helper) の Credentials store を使って ECR にログインできるようにする必要があるため、Gitlab Runner のイメージに docker-credential-ecr-login を追加したイメージを作成しました。


手順

# ディレクトリを準備

mkdir -p /opt/gitlab-runner/{ecr,runner}

# 環境変数で AWS 認証情報を指定
cat <<'EOS'> /opt/gitlab-runner/.env
AWS_ACCESS_KEY_ID=AKI...
AWS_SECRET_ACCESS_KEY=abc123...
EOS

# Gitlab Runner を開始
# --env-file で環境変数ファイルを指定
docker run --detach \
--name gitlab-runner \
--env-file /opt/gitlab-runner/.env \
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume /opt/gitlab-runner/runner/:/etc/gitlab-runner/ \
--volume /opt/gitlab-runner/ecr/:/root/.ecr/ \
ngyuki/gitlab-runner:alpine

# Gitlab に Runner を登録
# DOCKER_AUTH_CONFIG で Credentials store を指定
docker exec gitlab-runner gitlab-runner register \
--non-interactive \
--url 'http://gitlab.example.com/' \
--registration-token "${REGISTRATION_TOKEN:?}" \
--name 'docker-runner-with-ecr' \
--executor 'docker' \
--docker-image 'alpine:latest' \
--env 'DOCKER_AUTH_CONFIG={"credsStore":"ecr-login"}'

# docker-credential-ecr-login get で ECR 認証情報を `~/.ecr/cache.json` に保存
echo 999999999999.dkr.ecr.ap-northeast-1.amazonaws.com | docker exec -i gitlab-runner docker-credential-ecr-login get


詳細


Docker の Credentials store の指定

Docker の Credentials store は Gitlab のプロジェクトの CI のDOCKER_AUTH_CONFIG 変数に以下のような JSON の内容をそのまま指定できます。

{

"credsStore": "ecr-login"
}

もしくは gitlab-runner register--env 'DOCKER_AUTH_CONFIG={"credsStore":"ecr-login"}' のようにコマンドラインオプションを指定すれば、この Gitlab Runner が実行するすべてのジョブの変数に自動的に追加されるので、プロジェクトで個別に指定する必要はなくなります。

DOCKER_AUTH_CONFIG はもともとは次のようなプライベートレジストリの認証情報を指定するためのものですが、

{

"auths": {
"registry.example.com:5000": {
"auth": "b3JlX25vX2hpbWl0dQo="
}
}
}

ECR の場合 aws ecr get-login で取得したトークンは12時間で有効期限切れになるため、上のようにベタで指定することはできません。

Add support for credentials store (!501) · Merge Requests で Gitlab Runner で Credentials store がサポートされるようになったので、前述のように ecr-login が指定できます。ただし、Docker CLI と同等ではないので下記のような credHelpers とかは対応していません。

{

"credHelpers": {
"999999999999.dkr.ecr.ap-northeast-1.amazonaws.com": "ecr-login"
}
}

credsStore のみがベタで対応されているようです。

ただ、ひとつのプロジェクトで複数のレジストリで Credentials store を使い分けるとかでも無い限りは問題なさそうです。

なお、~/.docker/config.json に記述しても有効なので、DOCKER_AUTH_CONFIG の代わりに ~/.docker/config.json を作成しても OK です。


ECR 認証情報の取得

Gitlab Runner が Credentials store を使用するとき、list サブコマンドですべての認証情報を取得しようとします。

docker-credential-ecr-login list~/.ecr/cache.json に記録されている ECR の認証情報の一覧を返します。docker-credential-ecr-login get で認証情報を取得すると ~/.ecr/cache.json へキャッシュとして保存されるため、あらかじめ手動で認証情報を取得しておきます。

あるいは、~/.ecr/cache.json がなければ docker-credential-ecr-login listAWS_REGION 環境変数で指定されたリージョンの ECR の認証情報を返すので、docker-credential-ecr-login get を手で実行する代わりに AWS_REGION 環境変数を指定しておいても OK です。

# 環境変数でリージョンも指定

# (docker-credential-ecr-login get は不要)
cat <<'EOS'> /opt/gitlab-runner/.env
AWS_REGION=ap-northeast-1
AWS_ACCESS_KEY_ID=AKI...
AWS_SECRET_ACCESS_KEY=abc123...
EOS

もしくは、環境変数 AWS_SDK_LOAD_CONFIG=true があれば ~/.aws/config からでもリージョンを得られるので、AWS_REGION 環境変数の代わりに使用することもできます。


さいごに

Credentials store を使わなくても cron とかで定期的に $(aws ecr get-login --no-include-email) して ~/.docker/config.json の認証情報を更新すれば大丈夫だろうと思いますが、余分な処理が不要な分 docker-credential-ecr-login を使うほうがよいでしょう。


参考