実習で学ぶDocker入門 | 3. Dockerイメージ管理

前回はDockerfileからイメージをビルドする方法を紹介した。ローカルでビルドしたイメージはDocker Engineにキャッシュされているだけで、他の人は利用できない。イメージを他の人が利用できるようにするには、利用者がアクセスできる場所にイメージを公開する必要がある。Docker社やAWSをはじめとする各種クラウドベンダーは、Dockerイメージを管理・共有する仕組みとして「レジストリ」というサービスを提供している。今回はDockerイメージのレジストリとしてDocker HubおよびAWS ECR(EC2 Container Registry)の概要、簡単なイメージ登録・取得方法、そしてチーム内でイメージを管理するときに考慮すべき点について紹介する。

レジストリでイメージを共有する

まず、チームのイメージ管理方式の概要を理解するため、ベンダー中立的なレベルでレジストリの概要を紹介する。個別サービスに依存する部分については、サービスごとのセクションで説明する。

レジストリは、チームでイメージを管理・共有するために、主に次の2つの役割を提供する。

  • イメージ登録および共有
    • イメージ保存所にイメージを登録できる。
    • 他の利用者へイメージを公開できる。
  • イメージへのアクセス制限(認証・認可)
    • 特定の人にだけイメージの読み取りおよび書き込みを許可する。

次はレジストリサービスの概念図である。

保存所

  • 「レジストリ」は、イメージを登録するサービス全体を指す。
  • レジストリに公開するイメージ(NginxやNode.jsなど)の分類に対して、「リポジトリ」が実際のイメージ保存所として登録される。
  • リポジトリには複数のイメージを登録でき、各イメージはタグで区別される。バージョン番号ごとにイメージを区別したい場合などは、タグにバージョン番号を指定する。たとえばDocker公式Node.jsイメージの場合、14.17.114.17.1-alpineなどのように、Node.jsのバージョン番号やLinuxディストリビューションなどイメージの内容をタグで表現している。
    • 注意: タグが同じイメージは上書きされてしまうため、リポジトリへイメージをpushするときは注意が必要である。
  • レジストリへアクセスするときは認証が必要である。また、pushやpullなどリポジトリに対する操作について、ユーザーごとにアクセス権限を設定できる。したがって、イメージを管理する人にはリポジトリへのpush権限を付与し、イメージを利用する人にはpull権限を付与することができる。

Docker Hub - Docker社の公式レジストリ

次に個別レジストリについて説明する。まずDocker社がクラウドサービスとして提供するDocker Hubを紹介する。

Docker Hubとは

Docker HubはDocker社が提供するイメージ管理用クラウドサービスである。特徴は次のとおりである。

  • 完全マネージド
    • Docker社が管理するクラウドサービスであり、これを使用すると自分でサーバーを管理する必要がなくなる。
  • Web UI
    • イメージとDocker Hubアカウントの管理をブラウザから行える。
  • メタデータ保存所
    • ユーザー間のコミュニケーション支援のため、リポジトリにコメントを付けたり、スター(Facebookの「いいね」に相当)を付けたりできる。
  • 認証、認可
    • リポジトリへアクセスする他のユーザーに対して、イメージの読み取り、書き込み、管理などのアクセス制限を設定できる。
  • チームでのリポジトリ共有および管理
    • チームでリポジトリを共有し、共同で管理できる。
  • Webhook
    • CI/CD環境と連携するためのWebhookを提供する。

Docker Hubにイメージをpush/pullしてみる

ここでは実際に公開リポジトリを作成し、そのリポジトリへイメージをpushしてみよう。前にビルドしたイメージを利用するので、「Dockerイメージビルド」の実習を行っていない場合は、先に実習してから進めてほしい。

リポジトリを作成する

リポジトリを作成するにはDocker Hubアカウントが必要である。Docker Hubにアクセスし、事前にアカウントを作成しておく。
Docker Hubへ登録すると、メールアドレスで認証が行われる。認証が完了して初めてアカウント作成が最終完了となる。

Docker Hubへログインしたあと、画面で「Create Repository」をクリックし、リポジトリ作成画面を表示する。リポジトリ名はイメージと同じmyfirstappを指定する。Visibilityはpublicで問題ない。

リポジトリ作成

レジストリを認証する

リポジトリへイメージをpushする前に、レジストリを認証する必要がある。usernameとpasswordの入力を求められたら、Docker Hubに登録した内容を入力すればよい。Login Succeededと表示されればログイン成功である。

% docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: devkuma
Password:
Login Succeeded

リポジトリへイメージをpushする

リポジトリへpushするイメージ名は「リポジトリ名/イメージ名」とする必要がある。Docker Hubの場合、リポジトリ名はアカウント名(ここではdevkuma)である。

前にローカルでビルドしたイメージにはリポジトリ名が明示されていないため、次のようにdocker tagコマンドでDocker Hubへpushする別名を設定する必要がある。第1引数には別名を設定したいイメージID、第2引数には別名を指定する。それぞれ自分の環境に合わせて変更すればよい。

% docker images
REPOSITORY   TAG       IMAGE ID       CREATED        SIZE
myfirstapp   latest    ca9348c3dcd2   47 hours ago   67.7MB
% docker tag ca9348c3dcd2  devkuma/myfirstapp

docker imagesでイメージ一覧を表示すると、docker tagの結果としてdevkuma/myfirstappが追加されたことを確認できる。ここでmyfirstappdevkuma/myfirstappIMAGE IDが同じなので、どちらも同じイメージであることが分かる。

% docker images
REPOSITORY           TAG       IMAGE ID       CREATED        SIZE
devkuma/myfirstapp   latest    ca9348c3dcd2   47 hours ago   67.7MB
myfirstapp           latest    ca9348c3dcd2   47 hours ago   67.7MB

次にdocker pushコマンドでリポジトリへイメージをpushする。

% docker push devkuma/myfirstapp
Using default tag: latest
The push refers to repository [docker.io/devkuma/myfirstapp]
59714c8e53ee: Pushed
8b0d10b320d2: Pushed
8fd4f6c343b1: Pushed
29f7edf0d8fd: Pushed
38f96c395e73: Pushed
c311a1e10929: Pushed
f566c57e6f2d: Mounted from library/alpine
latest: digest: sha256:5a06d6baf0481446a51c590099608145935d6f3e903aa2472c081fde0a12d6fe size: 1783

もう一度ブラウザでDocker Hubダッシュボードを開き、pushしたmyfirstappリポジトリのTagsを見ると、タグlatestでイメージがpushされたことを確認できる。これは先ほどpush時にイメージのtagを省略したため、最新イメージを指すデフォルトtagであるlatestが指定されたためである。

リポジトリにpushされたイメージ

イメージのバージョン管理などを目的としてタグを明示的に指定するには、次のようにイメージ名をリポジトリ名/イメージ名:タグとしてタグを明示的に入れ、再度pushしてみよう。

% docker tag ca9348c3dcd2 devkuma/myfirstapp:0.0.1
% docker push devkuma/myfirstapp:0.0.1
The push refers to repository [docker.io/devkuma/myfirstapp]
59714c8e53ee: Layer already exists
8b0d10b320d2: Layer already exists
8fd4f6c343b1: Layer already exists
29f7edf0d8fd: Layer already exists
38f96c395e73: Layer already exists
c311a1e10929: Layer already exists
f566c57e6f2d: Layer already exists
0.0.1: digest: sha256:5a06d6baf0481446a51c590099608145935d6f3e903aa2472c081fde0a12d6fe size: 1783

再びDocker Hubダッシュボードを確認すると、TAGが0.0.1のイメージが追加されたことを確認できるはずである。

個人リポジトリをチームと共有するには

ここまでは個人の公開リポジトリにイメージをpushする方法を紹介した。公開リポジトリなので、次のコマンドを入力すれば誰でもイメージをpullできる。

% docker pull devkuma/myfirstapp

あまり重要ではない個人プロジェクトであれば個人アカウントの公開リポジトリでも構わないが、実際の開発ではチームの非公開リポジトリを用意し、チームメンバーだけがアクセスできるようにするべきである。

Docker Hubでは非公開リポジトリを作成でき、1つまでは無料、それ以上は有料である。料金はDocker HubダッシュボードのPricingページを参照してほしい。

Docker Hubには、チームのリポジトリを作成するためにOrganizationとTeamという機能がある。Organizationはチームメンバーが属する組織を意味し、Teamはその組織内で特定の役割を持つチームを意味する。

具体例として、問題を防ぐためにイメージ管理者だけがイメージをpushでき、他のメンバーはpullだけできるようにするには、次のようにOrganizationおよびTeamを用意する。

  • Organizationにチームメンバー全員を登録する。これにより、そのOrganization配下に用意した非公開リポジトリを全メンバーが閲覧できるようになる。
  • イメージ管理者のTeamにリポジトリへの書き込み権限を付与し、そのTeamにイメージ管理者を登録する。これにより、イメージ管理者はリポジトリへイメージをpushできるようになる。
  • イメージ利用者のTeamにリポジトリへの読み取り権限を付与し、そのTeamにイメージ利用者を登録する。これにより、イメージ利用者はリポジトリからイメージをpullできるようになる。

詳しくはDockerドキュメントを参照してほしい。

AWS ECRを利用したイメージ管理

次にAWSで提供されるイメージ保存所としてAWS ECR(EC2 Container Registry)を紹介する。

ECRとは

ECRはAWSが提供するイメージ管理用クラウドサービスである。他のAWSサービスと簡単に連携できるため、AWSを活用している人には非常に使いやすいサービスである。

具体的には次のような機能を持っている。

  • 完全マネージド
    • AWSのマネージドサービスとして管理されるクラウドサービスであり、自分でサーバーを管理する必要はない。
  • Web UI
    • ブラウザを使用してAWS管理コンソールからイメージ管理を行える。
  • 他のAWSサービスと簡単に統合できる。
  • 認証、認可
    • IAMを使用してイメージに対する認証・認可を設定する。
  • チームでのリポジトリ管理
    • チームで共有リポジトリを作成できる(IAM機能を使用してDocker HubのOrganizationおよびTeamに相当する機能を実現できる)。

なお、ECR自体の利用料金はないが、リポジトリに保存するデータおよびインターネットへ転送するデータ量に応じて課金される。詳しくは料金表を確認してほしい。

ECRにイメージをpush/pullしてみる

ECRを使用するには、次を事前に準備する必要がある。

  • AWSアカウントを準備する。
  • IAMユーザーを作成する。
    • リポジトリへのアクセスはIAMを使用して認証・認可するため、IAMユーザーが必要である。AWSドキュメントを参考にIAMユーザーを作成する。
  • AWS CLI(コマンドラインインターフェイス)をインストールする。
    • リポジトリ操作をCLIで行うため、AWSドキュメントを参考にCLIを事前にインストールする。
    • aws configureコマンドでキーおよびリージョンの設定も行う。

注意: 以降はAdministratorAccessポリシーが付与されたIAMユーザーで作業する必要がある。

レジストリを認証する

イメージをECRへpushするには、事前にCLIからレジストリへの認証を行う必要がある。認証はDocker Hubと同じくdocker loginコマンドを使用する。

注意: ECRへのログイン用docker loginコマンドにはAWS固有の認証情報を付加する必要があり、AWS CLIコマンドが自動生成する点に注意する。

次のコマンドを実行してdocker loginコマンドを取得する。--regionの後にはリポジトリを作成するリージョンを指定する。ログイン情報の生成に成功するとdocker loginコマンドが表示される。(参考: 下記では認証情報を省略している。実際には長い文字列が表示される。)

$ aws ecr get-login --region us-west-2
docker login -u AWS -p xxx -e none
 https://xxx.dkr.ecr.us-west-2.amazonaws.com

次に表示されたdocker loginコマンドを実行する。成功するとLogin Succeededが表示される。

$ docker login -u AWS -p xxx -e none
 https://xxx.dkr.ecr.us-west-2.amazonaws.com
Flag --email has been deprecated, will be removed in 1.14.
Login Succeeded

なお、AWS CLIで取得したdocker loginコマンドには有効期限がある。一定時間が経つとレジストリへアクセスできなくなるため、そのときはレジストリを再認証する必要がある。

リポジトリを作成する

イメージをpushする前に、対象となるリポジトリを用意する。

ブラウザでリポジトリを作成するには、次の手順を実行する。

  • https://console.aws.amazon.com/ecs/にアクセスし、AWS ECS(EC2 Container Service)の管理コンソールを開く。(注意: ECRはECSに統合されており、イメージ管理もECS管理コンソールで行う。)
  • 「リポジトリ設定画面」でリポジトリ名としてmyfirstappを入力し、「次のステップ」をクリックする。
  • リポジトリURIが表示されるので、以降の作業のため記録しておく。URIの形式はアカウント番号.dkr.ecr.リージョン名.amazonaws.com/リポジトリ名である。

CLIでも次のコマンドで作成できる。

# aws ecr create-repository --repository-name myfirstapp
{
    "repository": {
        "registryId": "xxx",
        "repositoryName": "myfirstapp",
        "repositoryArn": "arn:aws:ecr:us-west-2:xxx:repository/myfirstapp2",
        "createdAt": 1490510283.0,
        "repositoryUri": "xxx.dkr.ecr.us-west-2.amazonaws.com/myfirstapp2"
    }
}

リポジトリへイメージをpushする

リポジトリへイメージをpushするには、docker tagコマンドでリポジトリ名を明示するイメージ名の別名を準備する。別名には管理コンソールまたはCLIの応答に表示されたリポジトリURIを指定する。

% docker tag myfirstapp xxx.dkr.ecr.us-west-2.amazonaws.com/myfirstapp

docker pushするとイメージをpushできる。

% docker push xxx.dkr.ecr.us-west-2.amazonaws.com/myfirstapp
The push refers to a repository [xxx.dkr.ecr.us-west-2.amazonaws.com/myfirstapp]
17c42ed7fd27: Pushed
213ceaccd73e: Pushed
ac71ddba259e: Pushed
f8a68ba3c32d: Pushed
509e95f0d599: Pushed
3369321ad418: Pushed
23b9c7b43573: Pushed
latest: digest: sha256:7844dcb21756932f0cc93399519159f02f6c7b68f86af516d30c50b18b85d2ea size: 1783

イメージをpullするときも、リポジトリを明示してイメージ名を指定する。

% docker pull xxx.dkr.ecr.us-west-2.amazonaws.com/myfirstapp

個人リポジトリをチームと共有するには

Docker Hubと同じように、チームメンバーのIAMユーザーグループに対してIAMポリシーを設定し、イメージ管理者全員にpushを許可し、イメージ利用者全員にpullを許可できる。

また、ECRの場合、基本的にリポジトリは非公開なので、許可した相手に対して特定の操作を許可していく方法を取る必要がある。

具体的な権限設定方法は次の2つである。どちらも最終的にはIAMポリシーがIAMユーザーへ適用される点では同じだが、後者の管理コンソールを使用する方法は初心者にも分かりやすいため推奨する。

  • ECR以外のサービス共通: IAMポリシーを直接作成してユーザーへ接続する。
    • リポジトリに対する適切な使用権限を設定したIAMポリシーを作成し、許可するIAMユーザーまたはユーザーグループへ接続する。
    • 詳細はAWSドキュメントを参照する。
    • メリット
      • CLIで実行できるため、自動設定したい場合に有効である。
    • デメリット
      • IAM自体が複雑なため、IAMポリシーを書き間違えて適切な権限を設定できない危険がある。実施時には確認が必要である。
  • ECR限定: ECR管理コンソールで設定する。
    • 実施方法
      • ECR管理コンソールでリポジトリの「アクセス権限」ページを開き、リポジトリ管理ポリシーを作成できる。
      • 詳しくはAWSドキュメントを参照する。
    • メリット
      • 管理コンソールGUIで作業できる。CUIに慣れていない人には分かりやすい。
      • ユーザーを選択し、「pullのみ」・「pushとpull」・「すべて」の3つから許可する操作を選ぶだけなので、誰に何を許可しているか分かりやすい。
    • デメリット
      • GUIベースなので自動化が難しい。

結論

ここでは、ビルドしたイメージを共有する方法としてレジストリサービスを紹介した。また、具体的なレジストリサービスとしてDocker HubとAmazon ECRを題材に、リポジトリを管理してイメージをpushする方法を紹介した。今回はチーム内で共有するときのアクセス権限管理方法について概要だけを説明したが、実際のプロジェクトに適用するときに問題を防ぐには、適切なリポジトリ権限ポリシーを策定することが重要である。本文で紹介したDockerとAWSのドキュメントを参考にし、事前に検証したうえで導入することを推奨する。