CIでAmazon ECRにDockerイメージをpushするときのプラクティス

ECRにpushするとき、皆さんはどうやってECRの認証をしていますか? 大体の人が、aws cliをインストールして認証しているのではないかと思っています。

今回はAmazon ECRへPushする仕事があったので、一から見直してみた結果をここにまとめておきます。 いくつかのパターンを例に挙げながら、最終的に良さそうだな、と思った内容をここに書いておきます。

僕としては、「aws cli v2」でECRに認証するのが楽かな、という結論になりました。

前提

筆者はCircleCIを主に使っているので、CircleCIベースで話を進めます。 また、アプリケーションの開発時、Amazon ECRは認証が必要です。(認証なしでpush出来るように出来るかは筆者は分かりませんが、使うこともないでしょう。) 開発用の言語はpython以外の前提で書いていきます。 この辺りを踏まえた上で続きをお読みください。

今回の開発用の言語ではgoを想定した上で書いていきます。 また、特に言及がない限り、開発用の言語をビルドするためのイメージを使うことにします。 加えて、aws cliと表記した場合はaws cliのv1を指します。

はじめに

ECRに楽にログインする場合、aws cliを使うのがメジャーな方法だと思います。 しかし、aws cli v1ではpythonのランタイムが必須のため、aws cliのインストールのために 開発用の言語に加えてaws cliを入れたCI用のDockerイメージを作るか aws cliを使わず、他の手段で認証する必要がありました。

今回の記事ではそれらを踏まえた上で、ECRにDockerイメージをpushする方法を この記事で書いていきます。

今回この記事で書くのは以下の方法です。

  1. aws cliをインストールして認証を行う
  2. CircleCI orbを使ってaws cliをインストールして認証を行う
  3. persist_to_workspace/attach_workspaceを使って別のジョブでpushする
  4. 任意の言語で認証を行う
  5. amazon-ecr-credential-helperを使って認証を行う
  6. aws cli v2をインストールして認証を行う

pipからaws cliをインストールして認証を行う

これは単純です。しかし、aws cliをインストールするためだけに時間がかかります。 ちなみにCircleCIの公式のイメージのように、pythonの入ってないイメージの場合はpythonのインストールから必要になります。

  • メリット
    • 単純
  • デメリット
    • インストール時間がそれなりにかかる

CircleCI Orbを使ってaws cliをインストールする

CircleCI Orbを使ってaws cliをインストールすることで 公式がメンテナンスしてくれるという安心感があります。 しかし、awcliのインストールスクリプトpythonなので、やっぱりpythonのランタイムは必要です。

  • メリット
    • 公式がメンテナンスしてくれる安心感が得られる
  • デメリット

persist_to_workspace/attach_workspaceを使って別のジョブでpushする

CircleCIにはworkflowで生成された成果物を別のジョブに引きわたす機能があります。 それが、persist_to_workspace/attach_workspaceです。 この方法は、persist_to_workspace/attach_workspaceを使って 開発用の言語のジョブとは別のジョブでアプリケーションのDockerイメージを作成します。 そのため、開発用の言語のDockerイメージで生成した成果物を awscliを入れたイメージでのビルドに引き渡すことで awscliのインストールをすることがありません。 しかし、そもそもawscliの入ったdocker imageを公式が提供していません。。。

  • メリット
    • awscliのインストールがなくなる
  • デメリット
    • そもそもawscliの入ったdocker imageを公式が提供していないので自前で用意する必要がある
      • 野良のイメージを使ってもいいんですがライフサイクルのよく分からないイメージを使うのは怖い
    • ビルド間での成果物の引き渡しをするのでビルド自体の起動時間(docker imageのpullとコンテナが立ち上がるまでの時間)が増える

任意の言語で認証を行う

これは、前職でやっていた手法なのですが、gradleなどでビルドツールからECRとの認証を行ってpushします。 awscli周りは簡単になるのですが、ビルド周りの複雑さは避けられないでしょう。

  • メリット
    • awscliのインストールがなくなる
  • デメリット
    • ビルド周りの複雑さが少し増える
    • ジョブのコンテナの起動時間が増える

amazon-ecr-credential-helperを使って認証を行う

以下のようなjson~/.docker/config.json に配置しておきます。 そうすると、dockerは docker-credential-ecr-login というPATHに入っている実行ファイルを使って認証を行ってくれます。 ちなみに以下の方法の場合、全てのdockerの通信をecrの通信として扱います。ECR以外のリポジトリにもpushする場合は注意が必要です。 dockerの1.13以降ではリポジトリのURLで認証を分けられます。詳しくはDockerのドキュメントをみてください。

{
    "credsStore": "ecr-login"
} 

しかし、この方法もやはりデメリットがあり、amazon-ecr-credential-helperはディストリビューションからのインストール以外は 自分でビルドする必要があります。 ちなみに、goで開発されているため、ビルドにはgoのランタイムが必要です。

installする方法は https://github.com/awslabs/amazon-ecr-credential-helper をみてください。

aws cli v2をインストールして認証を行う

aws cli v2の場合、pythomのランタイム入りのzipが配布されています。 そのため、その他のツールのインストールが必要ありません。これは便利です。

aws cli v2のインストールは、以下のようなスクリプトを使ってインストールすることになるでしょう。

curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install

中のファイル構成に依存しても良いなら、キャッシュもうまく効かせられます。 ちなみに現状、上記のような形でunzipした場合は ./aws/dist/aws に実行バイナリが入っています。

  • メリット
    • 公式がランタイムも含めて配布してくれているので簡単にインストールできる
    • 中のファイルの構成に依存しても良いなら、キャッシュしやすい
  • デメリット
    • URLにバージョンが含まれていないので、動かないzipが配信された時にCIが壊れる

まとめ

今回、docker imageをECRにpushする要件があったので、調べていたところ aws cliをインストールをする必要があるなぁと思っていたんですが、それをTwitterで呟いていたところ、aws cli v2がリリースされていたのを思い出して リリース方法を確認したところ、ランタイムもまとめて配布されていることを確認しました。

aws cli v2を使ってビルドする前に、credential helperでPushも出来たのですが goのランタイムで自前ビルドをしてしまっていたので これもaws cli v2に移行しました。

Amazon ECRにpushするなら、aws cli v2で認証するので良いんじゃないでしょうか。

追記

書くの忘れてたんですが aws cli v2を使う場合、ECRへのログイン方法が変わっていることに注意してください。

# aws cli v1の場合
eval "$(aws ecr get-login --no-include-email)"

# aws cli v2の場合
aws ecr get-login-password | docker login --username AWS --password-stdin $REPO_URL