理系学生日記

おまえはいつまで学生気分なのか

GitLab CI/CD から ECR への PUSH

GitLab CI/CD から ECR へ PUSH するところを作りました。つらみがあって大変に時間を溶かしました。

原理的に何も難しいところはないのですが、つらかったところは以下になります。

  1. alpine ベースの Docker Image に AWS CLI v2 をインストールするのがつらい
  2. Docker のバグ(?)を引いてしまい、GitLab CI/CD 上での DinD がうまく動かなかったのでつらい

この辛みはあとで書くとして、.gitlab-ci.yml の該当箇所はこんな形で良かったです。 事前の Stage で GitLab Container Registroy 上に PUSH されているアプリケーション(backend[12])を、それぞれ ECR に PUSH するという例。 スクリプトは後段に貼ってます。

.deploy-ecr:
  image: docker:19.03.13
  stage: deploy-to-ecr
  variables:
    AWS_DEFAULT_REGION: $ECR_AWS_DEFAULT_REGION
  services:
    - name: docker:19.03.13-dind
  only:
    refs:
      - master
  before_script:
    - .ci/install-awscliv2-on-alpine.sh

deploy-backend1-to-ecr:
  extends: .deploy-ecr
  variables:
    IMAGE_PUSHED_TO_ECR: $CI_REGISTRY_IMAGE/backend1:$CI_COMMIT_REF_NAME
  script:
    - .ci/deploy-to-ecr.sh

deploy-backend2-to-ecr:
  extends: .deploy-ecr
  variables:
    IMAGE_PUSHED_TO_ECR: $CI_REGISTRY_IMAGE/backend2:$CI_COMMIT_REF_NAME
  script:
    - .ci/deploy-to-ecr.sh

alpine ベースの Docker Image に AWS CLI v2 をインストールするのがつらい

このツラミについては前に書きました。

だいたい以下のようなスクリプトを書いておけば alpine ベースの Container Image で AWS CLI v2 が使えるようになります。

#!/bin/sh
set -eux

# https://hub.docker.com/_/docker 等、alpine ベースの Container に対する AWS CLI v2 のインストールには glibc が必要
# see: https://stackoverflow.com/questions/60298619/awscli-version-2-on-alpine-linux/61268529#61268529

GLIBC_VER=2.31-r0

# install glibc
apk --no-cache add binutils curl
curl -sL https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub -o /etc/apk/keys/sgerrand.rsa.pub
curl -sLO https://github.com/sgerrand/alpine-pkg-glibc/releases/download/${GLIBC_VER}/glibc-${GLIBC_VER}.apk
curl -sLO https://github.com/sgerrand/alpine-pkg-glibc/releases/download/${GLIBC_VER}/glibc-bin-${GLIBC_VER}.apk
apk add --no-cache glibc-${GLIBC_VER}.apk glibc-bin-${GLIBC_VER}.apk

# install awscliv2
curl -sL https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip -o awscliv2.zip
unzip -q awscliv2.zip
aws/install

Docker のバグを引いてしまって GitLab CI/CD 上での DinD がうまく動かなかったのがつらい

GitLab CI/CD で Docker Executor を利用する前提で docker image push 等の docker コマンドを使おうとすると、DinD が選択肢になります。

しかしこの DinD を使うにあたって docker 19.03.12 を利用していたときにピンポイントでバグ挙動を引いてしまいました。 DinD 利用時に以下のエラーが発生してしまうというものです。

Cannot connect to the Docker daemon at <some address>. Is the docker daemon running?

おおよそ、この 1 年前の issue の状況と酷似しています。

私の場合、19.03.12 でこれを回避するためには、19.03.0 のバグへの以下の回避策が有効でした。

  • entrypoint を通るときは DOCKER_HOST 環境変数を無効化する
  • TLS 設定をしておく
deploy-backend-to-ecr:
  image: docker:19.03.12
  services:
    - name: docker:19.03.12-dind
      entrypoint: ["env", "-u", "DOCKER_HOST"]
      command: ["dockerd-entrypoint.sh"]
  variables:
    DOCKER_HOST: tcp://docker:2375
    DOCKER_TLS_CERTDIR: ""
    DOCKER_DRIVER: overlay2
(略)

19.0.13 を設定すると嘘のようにエラーと遭遇することがなくなり、冒頭で示した通り非常にシンプルになりました。

ECR への PUSH

これは何のひねりもないです。珍しく bash ではなく sh を使っているのは諸々の事情によるものです。

#!/bin/sh
# GitLab Container Repository 上の Image ($IMAGE_PUSHED_TO_ECR) にタグ付けした上で ECR に PUSH する

set -eux

# GitLab Container Registry から、branch に対応する Image を Pull する
docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
docker image pull $IMAGE_PUSHED_TO_ECR

# ECR 用のタグ付け
docker image tag $IMAGE_PUSHED_TO_ECR $ECR_REPOSITORY:$CI_COMMIT_REF_NAME
docker image tag $IMAGE_PUSHED_TO_ECR $ECR_REPOSITORY:$CI_COMMIT_SHORT_SHA

# master branch への merge の場合は latest タグを付与する
if [ "$CI_COMMIT_REF_NAME" == "master" ]; then
    docker image tag $IMAGE_PUSHED_TO_ECR $ECR_REPOSITORY:latest
fi
aws ecr get-login-password | docker login --username AWS --password-stdin $ECR_REPOSITORY
docker image push $ECR_REPOSITORY