Dockerプライベートリポジトリ(Docker Registry)構築レシピ

docker
240件のシェア(すこし話題の記事)

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

ども、大瀧です。
AWS Elastic BeanstalkのDocker対応、Amazon ECSの正式リリースからちょっと経ちますが、皆さん使っていますか?業務用途だとDockerイメージを共有するためのプライベートなDockerリポジトリが欲しくなるところですが、マネージドなDockerリポジトリサービスは現在AWSでは提供されていないため、自前で用意することもあると思います。今回は、自前でDockerリポジトリを構築するときのTipsをご紹介します。

Docker Registryを使う

Dockerリポジトリは、Docker RegistryというDocker公式のリポジトリ実装が公開されているため、特別な事情が無ければこちらを利用するのが良いでしょう。大規模なケースであれば、まだリリース前ですがDocker Hub Enterpriseという選択肢も頭の片隅に置いておいて良いかもしれません。

v1にするかv2にするか

Docker Registryには現在、v1系とv2系という2つのバージョンがあります。GitHubの異なるリポジトリで開発されており、v1系の方が古くREADMEではv2系が推奨とされています。v2系ではDocker 1.6とともにイメージ管理に関する機能強化が図られているため、特別な要件が無ければv2系がお奨めです。ただ、若いプロダクトで情報が少なかったり、ちまちまバグがあったりという状況なので一応、v1系の設定方法も併記します。v1とv2でバックエンドストレージの互換性は無いので、一つのバケットで両バージョンのデータを格納する場合は、階層が重複しないようプレフィックスを調節しましょう。

なお、v1/v2ともにDocker HubでDockerイメージが公開されており、以下のようにDockerで実行することが可能です。

Docker Registry v1

$ docker run -d -p 5000:5000 registry:latest

Docker Registry v2

$ docker run -d -p 5000:5000 registry:2.0

いずれもそのままでは既定のコンフィグで動作するため、別途Dockerfileを用意してカスタムイメージを作成するか、-eオプションで環境変数を用いて設定を変更し利用します。v1/v2で環境変数の互換性はないので、v1はこちら、v2はこちらを参考にしましょう。

バックエンドの選択

Docker RegistryはDockerイメージのデータ格納領域として様々なストレージサービスをサポートします。AWS環境であれば、信頼性や保存コストの点でAmazon S3一択で問題ないでしょう。EC2インスタンスで実行するのであれば、Docker Registryを実行するインスタンスにIAMロールをあらかじめ設定しておくとAWSのAPIキーを省略して利用でき、よりセキュアにできます *1

Docker Registry v2でS3バックエンドの実行例

$ docker run -d -p 5000:5000 \
  -e REGISTRY_STORAGE s3 \
  -e REGISTRY_STORAGE_S3_REGION <リージョン名> \
  -e REGISTRY_STORAGE_S3_BUCKET <バケット名> \
  -e REGISTRY_STORAGE_S3_ROOTDIRECTORY / \
registry:2.0

TLS(HTTPS)サポートを付けるか

DockerホストとRegistry間の通信は、ポート番号ではなくRegistryの設定でHTTPとHTTPSを選択 *2し、HTTPSの場合はSSL証明書が必要です。一方HTTPの場合はDockerホスト側でチェックが入り、特定ホスト以外は"非セキュア"として通信が許可されません。インターネットを介する場合はHTTPSが望ましいですが、VPC(AWS内のプライベートネットワーク)に閉じる通信であれば、HTTPで問題無いと判断する場合もあるでしょう。HTTPで通信するための方法を2つ紹介します。

ローカル接続

Dockerホスト側のチェックでは、既定でループバックアドレス(127.0.0.0/8)とのHTTPが許可されます。そこで、 Dockerホスト全台のローカルでDocker Registryを実行する構成が考えられます。Docker Registry自体はステートレスなWeb APIサーバーですので、共通のストレージバックエンドを参照するようにしておけばDockerイメージの共有に問題はありません *3

Beanstalk環境であれば、.ebextensionsという設定でDockerイメージのpullの前後でコマンドを実行する仕組みがあるため、そこでDocker Registryコンテナの実行/終了をキックする非常駐な構成が可能です。ちょっと古いですが、AWS SAブログの@thekentiestさんのブログ記事に手順と設定例があります。v1のみの紹介ですが、v2でも動作することを確認しました。

ECS環境の場合は、全台でRegistryを実行するためにServiceスケジューラを利用するのが良いでしょう。ECSインスタンスがAuto Scalingであれば、こちらのエントリーのように連動する設定にしておくと管理が楽だと思います。

いずれの場合でも、docker pushする開発機のローカルにもDocker Registryが必要なことに注意しましょう。

--insecure-registryオプション

Dockerホスト側のチェックで、Registryとの非セキュアな通信を許可するオプションとして--insecure-registryオプションがあります。Docker RegistryでHTTP通信を設定する場合と、後述の自己署名証明書の追加をせずにHTTPS通信を行う場合に指定します。DNS名/ドメイン名とIPアドレスのCIDR表記がサポートされます。

Docker Registryとの通信はDockerデーモンが行うため、--insecure-registryオプションはDockerデーモンの起動オプションに付与し、既にDockerデーモンが実行中の場合はデーモンの再起動が必要です。Amazon LinuxなどRedHat系ディストリビューションの場合は、/etc/sysconfig/docker(ファイル名(≒サービス名)はディストリビューションによって異なる)ファイルに以下のように記述します。

# Additional startup options for the Docker daemon, for example:
# OPTIONS="--ip-forward=true --iptables=true"
OPTIONS="--insecure-registry 10.0.0.0/16:5000"

Beanstalk環境では、.ebextensionsの設定ではDockerデーモンが先に起動してしまうため対応できません。カスタムAMIを作成する方法が考えられますが、インスタンスのメンテナンスが煩雑になる点に注意しましょう。

ECS環境では、ECSクラスタに参加するためインスタンスの起動時にamazon/amazon-ecs-agentコンテナが実行されるので、その後でdockerサービスのみを再起動することが難しい場合があります。インスタンスの再起動も検討しましょう。

自己署名証明書によるHTTPS構成

HTTPS通信にする場合は、ValidなSSL証明書を用意するのがベストですがRegistryのために購入するのも大げさですので、自己署名証明書で済ませたいところですよね。自己署名証明書を利用するためには、証明書をDockerホストに配置した上で、Docker RegistryのHTTPS通信を構成します。

自己署名証明書の作成

一般的な作成方法で構いません。今回はDockerドキュメントの手順に沿って作成してみます。

$ mkdir certs
$ openssl req \
>          -newkey rsa:2048 -nodes -keyout certs/domain.key \
>          -x509 -days 365 -out certs/domain.crt
Generating a 2048 bit RSA private key
........................+++
.............................+++
writing new private key to 'certs/domain.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:JP
State or Province Name (full name) []:Tokyo
Locality Name (eg, city) [Default City]:Chiyoda-ku
Organization Name (eg, company) [Default Company Ltd]:Classmethod
Organizational Unit Name (eg, section) []:AWS Consulting
Common Name (eg, your name or your server's hostname) []:ip-172-31-7-161
Email Address []:admin@ip-172-31-7-161
$ ls
certs
$ ls certs/
domain.crt  domain.key

DockerホストへのCA証明書の追加

作成した証明書を各Dockerホストの/etc/docker/certs.d/<Registryホスト名>:<ポート番号>/ca.crtファイルとしてコピーします。(今回は同じホストで検証しましたが、実際はリモートコピーなどを利用します)

$ sudo mkdir -p /etc/docker/certs.d/ip-172-31-7-161:5000/
$ sudo cp certs/domain.crt /etc/docker/certs.d/ip-172-31-7-161:5000/ca.crt

なお、この証明書を設定するとDockerデーモンが元々あるルート証明書を見に行かなくなるようで、以下の構成だとS3とのHTTPS通信時の証明書検証に失敗します。

  • 同一ホストでRegsitryを実行
  • RegistryのバックエンドがAmazon S3

ひとまず以下のようにルート証明書のシンボリックリンクを張ってエラーは回避できましたが、正しい対処なのか自信がないので、真っ当な対処方法があれば教えてください!

$ ln -s /etc/pki/tls/certs/ca-bundle.crt /etc/docker/certs.d/ip-172-31-7-161:5000/ca-bundle.crt

Docker Registry v2でHTTPS構成の実行例

Registry側でHTTPSを構成します。v1の場合はRegistry自体ではHTTPSをサポートしないようなので、NginxやAmazon ELBなどのリバースプロキシでHTTPSを構成しましょう。v2は組み込みでHTTPSをサポートするので、設定に追加してリバースプロキシなしで利用できます。HTTPS通信にはそれなりに負荷がかかるので、v2でも必要に応じてリバースプロキシによるSSLオフロードを検討しましょう。

$ docker run -d -p 5000:5000 \
  -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
  -e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
  -v $(pwd)/certs:/certs \
registry:2.0

Multi-AZ構成

Docker RegistryはシンプルなWeb APIサーバーですので、ELBをフロントにし複数のインスタンスで実行するDocker Registryにトラフィックを転送する構成が可能です。インスタンスを複数のAvailability Zoneに配置すればデータセンターレベルの障害を想定したMulti-AZ構成とすることもできます。ローカル接続での全台実行でない構成であれば検討をお奨めします。

まとめ

Docker Registryの構成パターンについて、いろいろご紹介しました。このほかにもBASIC認証Redisによるキャッシュ機能もあったりするのですが、また別のブログ記事でまとめたいと思います。Docker RegistryでプライベートなDockerイメージ管理を活用しましょう!

脚注

  1. v1/v2ともにIAMロール対応済みでした
  2. v1/v2ともに、既定のコンフィグではHTTPで動作します。
  3. /v1/searchなど一部APIについては未検証です