`aws ecr get-login` のトラブルシュート

ECR サーバにログインするとき、 aws ecr get-login コマンドでログインに必要なコマンドを取得できる。単にこのコマンドの結果を eval すればログインが完了するので、通常は eval $(aws ecr get-login) とすればよい。

しかし、次のようなエラーに遭遇してしまった。

$ eval $(aws ecr get-login)
Flag --email has been deprecated, will be removed in 1.13.
error getting credentials - err: exit status 1, out: `2017-04-13T08:27:26Z [ERROR] docker-credential-ecr-login can only be used with Amazon EC2 Container Registry.
credentials not found in native keychain`

credentials not found in native keychain の意味がわからず、「キーチェーンなんて動いてないけど…」と時間を無駄に費やしてしまった。

今回のケースでは、~/.docker/config.json に次のような情報が詰まっていたことが問題であった (どのタイミングでこの情報が入ったのか不明だけど…)。

$ cat ~/.docker/config.json
{"credsStore":"ecr-login"}

これを削除して再度 eval $(aws ecr get-login) を実行することで、ECR にログインできた。

Kubernetes Meetup #2 の補足 – その2

前回に続いて Kubernetes Meetup #2 での LT について振り返ろう。

Docker Registry v2 の認証スキーム

公式ドキュメントによると Docker Registry v2 の認証スキームは次の通り。

Docker Registry v2 Auth

各々の矢印は次の操作を意味する。

  1. Registry に対して push/pull を試みる
  2. Registry が認証を求める場合は 401 ステータスコードと一緒に認証方法に関する情報を返す
  3. Registry クライアントが authorization service に Bearer トークンをリクエストする
  4. authorization service が Registry クライアントの認証情報を示す Bearer トークンを返す
  5. Registry クライアントが Authorization ヘッダに Bearer トークンを含めて再度リクエストを試みる
  6. Registry が Bearer トークンを検証することで認証を行い push/pull のセッションを開始する

ここで難しいのは、図中の RegistryDocker Inc. がコンテナを公開しているのに Authorization Service にはオフィシャルな実装が存在しないことだ (仕様は公開されている)。

この隙間を埋めるのが Cesanta Software が公開している cesanta/docker_auth だ。このコンテナは上図の Authorization Service として機能する。

cesanta/docker_auth の設定

cesanta/docker_auth は設定ファイルが読みやすい。

次のような設定ファイルを作ることになる。

個別に説明する必要がないくらい簡単だ。このファイルを /opt/registry/config/auth_config.yml というパスに配置したと仮定する。この設定を利用して Authorization Service を起動するにはどうすればいいだろう? このサービスは Docker Registry と一緒に使うものだから、Docker Compose で Registry もまとめて起動するのが素直な方法だろう。

/opt/registry/registry.yml に次のような Docker Compose の設定ファイルがあるとしよう。

これで docker-compose -f /opt/registry/registry.yml とすることで RegistryAuthorization Service が起動し、docker login http://www.example.com での認証が可能となる。

Kubernetes Meetup #2 の補足

昔のことだが Kubernetes Meetup #2 で LT をする機会をもらった。

このときはマイクロサービスを実現するために Docker Registry をどう運用するか、というテーマで話した。5分の枠で話したことなので、詳細は省略せざるを得なかった。話しきれなかったことをブログにて補記しようと思う。

プライベートな Docker Registry

LT では Docker Registry へのアクセスを制限する方法について、二つ紹介した。簡単に実現できる方から解説していこう。

例えば AWS (Amazon Web Services)VPC (Virtual Private Cloud) を使うと仮定し、パブリックサブネットとプライベートサブネットが中にあるとする。Docker Registry は VPC の中でのみアクセス可能であればいいから、これはプライベートサブネットに配置する。

プライベートサブネットにある Docker Registry にどうコンテナをプッシュすればいいのだろうか? また、開発環境で Docker Registry にあるコンテナが必要になったとき、どうプルすればいいのだろう?

パブリックサブネットに踏み台サーバを用意して、そこを経由してアクセスするようにすればいい。

具体的には次のようになるだろう。

SSH Tunnel for Docker Registry

(注意: 本文中で Docker Registry と書いているものと図中の Private Registry は同じ)

踏み台を通した Docker Registry へのアクセス

次の三つの条件は満たしているものとする。

  1. インターネットから踏み台サーバへ 22番ポートで SSH 接続が可能
  2. 踏み台サーバから Docker Registry へ 22番ポートで SSH 接続が可能
  3. 踏み台サーバから Docker Registry へ 5000番ポートで Docker Registry への接続が可能

このとき、次のコマンドを実行して踏み台サーバ越しにDockerコンテナを取得できる。

(SSHトンネルの作成)
$ ssh -N -L 5000:docker-registry.example.jp:5000 user-name@fumidai.example.jp

(ローカルホストの5000番ポートを通して、Docker Registry から ubuntu コンテナを取得)
$ docker pull localhost:5000/ubuntu:latest

ここで ssh コマンドに渡したオプションの意味は次の通り。

  • -N 接続先でコマンドを実行しない。 (ポートフォワードをしたいときに指定する)
  • -L “ポート:ホスト:ホスト側ポート” のように指定する。localhost の “ポート” が “ホスト” の “ホスト側ポート” に転送されるようにする。

こうして、簡単にセキュアな Docker Registry を設定できる。

残る課題

ここまでで、踏み台へアクセス可能なユーザしかアクセスできない Docker Registry を作ることができた。ただ、もっと粒度の高いコントロールをしたいこともあるだろう。例えば「コンテナAにはユーザBからだけアクセスさせたい」というような場合だ。これについては、後のポストで書く。