Packerを使ってECRとGCRに同じDockerイメージをPushする

自分用の ML 環境として Docker イメージを作っていたのだが、 FROM: nvidia/cuda:9.2-cudnn7-devel-ubuntu18.04 なので DockerHub で public にするのも憚られ、ECR/GCR に置くことにした。
ECR/GCR に置くついでに packer build だけで ECR と GCR に同じイメージが置かれてほしいと思ってやってみた。

packer.json はこちら。
https://github.com/mazgi/docker.ml

ECR は Packer が対応しているのでpost-processors のなかで tag を打って push するだけで済む。便利。

"post-processors": [
  [
    {
      "type": "docker-tag",
      "repository": "{{ user `ecr_repository_uri` }}/ml",
      "tag": "latest"
    },
    {
      "type": "docker-push",
      "ecr_login": true,
      "aws_access_key": "{{ user `ecr_aws_access_key` }}",
      "aws_secret_key": "{{ user `ecr_aws_secret_key` }}",
      "login_server": "{{ user `ecr_repository_uri` }}"
    }
  ]
]

問題は GCR で、Packer が対応しているわけではないので tag は打てるが push ができなさそう。
結局 shell-local のなかで gcloud docker をたたくことにした。

"post-processors": [
  [
    {
      "type": "docker-tag",
      "repository": "gcr.io/{{ user `gcr_project_id` }}/ml",
      "tag": "latest"
    },
    {
      "type": "shell-local",
      "inline": [
        "gcloud --project {{ user `gcr_project_id` }} docker -- push gcr.io/{{ user `gcr_project_id` }}/ml"
      ]
    }
  ]
]

先に gcloud auth login が必要だがこんな感じで build && push できる。
すでに push 済みのイメージを build しているため already exists と言われている、また出力はところどころ省略している。
アカウント ID とかプロジェクト ID は公開して困る理由が思い当たらなかったので伏せていない。

$ ECR_REPOSITORY_URI='579744961348.dkr.ecr.us-east-1.amazonaws.com' \
ECR_AWS_ACCESS_KEY='********' \
ECR_AWS_SECRET_KEY='********' \
GCR_PROJECT_ID='mazgi-images-gcp' \
packer build packer.json
docker output will be in this color.

==> docker: Creating a temporary directory for sharing data...
==> docker: Pulling Docker image: nvidia/cuda:9.2-cudnn7-devel-ubuntu18.04
==> docker: Starting docker container...
==> docker: Provisioning with shell script: /var/folders/pg/_bczmpq12n35tfw327xw96dhsx9dly/T/packer-shell213792782
==> docker: Committing the container
    docker: Image ID: sha256:08098cb675df683a10c04cbd0931a9b927e7db0d854acebb67a3c1f0507284d5
==> docker: Killing the container: 131c687982f9600150fc1d254f82c4be18b841dce00aa0edf47bbd2e67be7368
==> docker: Running post-processor: docker-tag
    docker (docker-tag): Tagging image: sha256:08098cb675df683a10c04cbd0931a9b927e7db0d854acebb67a3c1f0507284d5
    docker (docker-tag): Repository: gcr.io/mazgi-images-gcp/ml:latest
==> docker: Running post-processor: shell-local
==> docker (shell-local): Running local shell script: /var/folders/pg/_bczmpq12n35tfw327xw96dhsx9dly/T/packer-shell861040660
    docker (shell-local): WARNING: `gcloud docker` will not be supported for Docker client versions above 18.03.
    docker (shell-local):
    docker (shell-local): As an alternative, use `gcloud auth configure-docker` to configure `docker` to
    docker (shell-local): use `gcloud` as a credential helper, then use `docker` as you would for non-GCR
    docker (shell-local): registries, e.g. `docker pull gcr.io/project-id/my-image`. Add
    docker (shell-local): `--verbosity=error` to silence this warning: `gcloud docker
    docker (shell-local): --verbosity=error -- pull gcr.io/project-id/my-image`.
    docker (shell-local):
    docker (shell-local): See: https://cloud.google.com/container-registry/docs/support/deprecation-notices#gcloud-docker
    docker (shell-local):
    docker (shell-local): The push refers to repository [gcr.io/mazgi-images-gcp/ml]
    docker (shell-local): 3990d099d2f3: Preparing
(omitted)
    docker (shell-local): a30b835850bf: Preparing
    docker (shell-local): 5b4434a5ca42: Waiting
(omitted)
    docker (shell-local): a30b835850bf: Waiting
    docker (shell-local): 25b849da05b2: Layer already exists
(omitted)
    docker (shell-local): f73b2816c52a: Layer already exists
    docker (shell-local): 3990d099d2f3: Pushed
    docker (shell-local): latest: digest: sha256:74d82f4a9454b8ead75136caccdbe1b78a2223fa18403e62aa640f10cacc9d2d size: 2837
==> docker: Running post-processor: docker-tag
    docker (docker-tag): Tagging image: sha256:08098cb675df683a10c04cbd0931a9b927e7db0d854acebb67a3c1f0507284d5
    docker (docker-tag): Repository: 579744961348.dkr.ecr.us-east-1.amazonaws.com/ml:latest
==> docker: Running post-processor: docker-push
    docker (docker-push): Fetching ECR credentials...
    docker (docker-push): Logging in...
    docker (docker-push): Login Succeeded
    docker (docker-push): Pushing: 579744961348.dkr.ecr.us-east-1.amazonaws.com/ml:latest
    docker (docker-push): The push refers to repository [579744961348.dkr.ecr.us-east-1.amazonaws.com/ml]
    docker (docker-push): 3990d099d2f3: Preparing
(omitted)
    docker (docker-push): a30b835850bf: Preparing
    docker (docker-push): 5b4434a5ca42: Waiting
(omitted)
    docker (docker-push): a30b835850bf: Waiting
    docker (docker-push): df42b75d1430: Layer already exists
(omitted)
    docker (docker-push): f73b2816c52a: Layer already exists
    docker (docker-push): 3990d099d2f3: Pushed
    docker (docker-push): latest: digest: sha256:74d82f4a9454b8ead75136caccdbe1b78a2223fa18403e62aa640f10cacc9d2d size: 2837
    docker (docker-push): Logging out...
    docker (docker-push): Removing login credentials for 579744961348.dkr.ecr.us-east-1.amazonaws.com
    docker (docker-push): WARNING: could not erase credentials: error erasing credentials - err: exit status 1, out: `The specified item could not be found in the keychain.`
Build 'docker' finished.

==> Builds finished. The artifacts of successful builds are:
--> docker: Imported Docker image: sha256:08098cb675df683a10c04cbd0931a9b927e7db0d854acebb67a3c1f0507284d5
--> docker: Imported Docker image: gcr.io/mazgi-images-gcp/ml:latest
--> docker: