前回の記事で、nginxのトップページを差し替えた自作イメージ を作りました。 ただ、このイメージはビルドしたVMの中にしかありません。 別のマシンで動かしたり、この先Kubernetesから使ったりするには、レジストリ(イメージの置き場)に登録しておく必要があります。
OCI(Oracle Cloud Infrastructure。Oracleのクラウドサービス)には、OCIR(Oracle Cloud Infrastructure Registry。コンソール上の表記はコンテナ・レジストリ)というレジストリサービスがあります。 この記事では、前回のイメージをOCIRにpush(登録)し、いったん手元から消してpull(取得)し直して動かすところまでを、つまずいた点も含めて手順にまとめます。
前提条件
-
前回の記事の環境(OCI上のUbuntu VM、Docker、ビルド済みの
mysite:1.0) - OCIのアカウントで、テナンシ(OCIの契約単位。自分のクラウド環境全体を指す入れ物)の管理者グループに所属していること。管理者でない場合は、リポジトリを管理できるポリシー(OCIの権限設定)が別途必要です
- リージョンは大阪(Japan Central)。OCIRはリージョンごとに独立したサービスなので、VMと同じリージョンで進めます
pushに必要な情報
Docker Hubと違い、OCIRへのpushには自分のテナンシに固有の情報がいくつか要ります。 先に何が必要かを整理しておきます。
- テナンシのネームスペース — テナンシごとに自動生成された英数字の文字列。イメージ名の一部になる
-
レジストリのドメイン — リージョンごとに決まっているOCIRの宛先。大阪は
kix.ocir.io -
認証トークン —
docker loginのパスワードとして使う、API用の文字列。コンソールにログインするパスワードとは別物
この3つを順に用意して、push、確認、pullし直し、と進めます。
手順1:テナンシのネームスペースを確認する
OCIコンソール右上のプロファイルメニューから、テナンシ名を選びます。
テナンシの詳細画面に「オブジェクト・ストレージ・ネームスペース」という項目があり、この文字列がテナンシのネームスペースです。
(名前に「オブジェクト・ストレージ」と付いているのは、OCIRがイメージの保存先としてオブジェクト・ストレージ(ファイルをそのまま置くタイプのストレージサービス)を使っていて、その領域の名前を共有しているためです。)
手順2:認証トークンを生成する
同じプロファイルメニューから「ユーザー設定」(マイ・プロファイル)を開き、「トークンおよびキー」タブの「認証トークン」で「トークンの生成」を選びます。 説明を入力して生成すると、トークンの文字列が表示されます。
注意点: 認証トークンは生成したときの一度しか表示されません。閉じる前に必ずコピーして、パスワードと同じ扱いで保管してください。1ユーザーあたり2個まで作れるので、失くした場合は作り直せます。
手順3:リポジトリを作成する
コンソールのメニューから「開発者サービス」→「コンテナ・レジストリ」を開きます。
「リポジトリの作成」を選びます。
- コンパートメント — リポジトリを置く区画(OCIのリソースを整理するためのフォルダのようなもの)。今回はVMと同じコンパートメント
-
リポジトリ名 —
mysite
存在しないリポジトリ名にpushすると自動で作られる仕組みもありますが、これは「最初のプッシュ時にルート・コンパートメントにリポジトリを作成」というテナンシ全体の設定が有効なときだけで、しかも作られる先はルート・コンパートメントに固定です。 設定が無効な状態でpushすると、権限が無い旨のエラーで失敗します。 先にリポジトリを作っておく方が、置き場所も選べて確実です。
(リポジトリ名には project01/mysite のように / を含められますが、これはフォルダの階層ではなく、名前の一部として扱われます。複数のリポジトリをプロジェクトごとに見分けるための接頭辞として使うのが一般的です。)
手順4:OCIRにログインする
VMのターミナルで、レジストリのドメインを指定して docker login を実行します。
docker login kix.ocir.io
ユーザー名とパスワードを聞かれるので、次のように入力します。
-
Username —
<テナンシのネームスペース>/<OCIのユーザー名>。ユーザー名はコンソールのプロファイルメニューに表示されているもの(メールアドレス形式の場合はそのまま) - Password — 手順2の認証トークン。貼り付けても画面には表示されません
Login Succeeded と出ればログイン成功です。
(OCIのアカウントをフェデレーション(別のID管理サービスと連携したログイン)で使っている場合、ユーザー名は <ネームスペース>/<ドメイン名>/<ユーザー名> の形になります。例えば <ネームスペース>/oracleidentitycloudservice/<ユーザー名> です。プロファイルメニューに <ドメイン名>/<ユーザー名> の形で表示されているなら、その形をそのまま使います。)
手順5:イメージにOCIR用の名前を付ける
前回作ったイメージの名前は mysite:1.0 です。 これをOCIRにpushするには、「どのレジストリの、どのリポジトリか」まで含んだ完全な名前を付ける必要があります。
docker tag mysite:1.0 kix.ocir.io/<テナンシのネームスペース>/mysite:1.0
docker tag は、同じイメージにもう1つ名前を付けるコマンドです。 コピーが作られるわけではなく、docker images で見ると同じIMAGE IDの行が2つ並びます。
名前の構造は次のとおりです。
- kix.ocir.io — レジストリのドメイン。pushやpullの宛先
- <テナンシのネームスペース> — テナンシの識別子
- mysite — リポジトリ名(手順3で作ったもの)
- 1.0 — タグ(バージョンの識別子)
Docker Hubの nginx のような短い名前は、ドメインとネームスペースが省略されてDocker Hubの公式イメージを指すようになっているだけで、構造は同じです。
手順6:pushする
docker push kix.ocir.io/<テナンシのネームスペース>/mysite:1.0
出力には、レイヤー(イメージを構成する差分の1段)ごとに Pushed と表示され、最後に digest: sha256:... というイメージの識別子が出ます。 前回、イメージは土台の上に差分を重ねたものだと書きました。 自分で追加したのは index.html を置いた1段だけですが、土台にしたnginxのレイヤーもOCIRにはまだ無いので、まとめて送られます。
手順7:コンソールで確認する
「開発者サービス」→「コンテナ・レジストリ」の一覧に mysite リポジトリがあり、開くとタグ 1.0 のイメージが登録されています。 サイズや、pushの出力に出たdigestも確認できます。
手順8:手元から消して、pullし直して動かす
レジストリに置けたことを確かめるため、手元のイメージをいったん削除してから、OCIRから取り直して動かします。
まず、そのイメージから起動したコンテナが残っていると、イメージは削除できません。 docker ps は起動中のコンテナしか表示しないので、-a を付けて停止中のものも含めた一覧を確認します。 前回 mysite:1.0 から起動したコンテナが停止状態で残っているはずなので、先に削除します。
docker ps -a
docker rm <mysite:1.0 から起動したコンテナのID>
(停止中のコンテナを消し忘れたまま次に進むと、conflict: unable to delete ... (must be forced) - container ... is using its referenced image というエラーで削除が止まります。docker ps -a で該当のコンテナを消せば解決します。)
次に、イメージを手元から削除します。 docker rmi は、手元にあるイメージを削除するコマンドです。 今回のイメージには mysite:1.0 とOCIR用の名前の2つが付いているので、両方を指定します。
docker rmi mysite:1.0 kix.ocir.io/<テナンシのネームスペース>/mysite:1.0
docker images
(名前が2つ付いたイメージは、1つ目の名前を消した時点では Untagged と表示されるだけで、実体は残ります。すべての名前が外れたときに Deleted と表示され、イメージ本体が削除されます。)
docker images の一覧から mysite が消えました。 この状態でOCIRからpullして、起動します。
docker pull kix.ocir.io/<テナンシのネームスペース>/mysite:1.0
docker run -d -p 8084:80 --name web-from-ocir kix.ocir.io/<テナンシのネームスペース>/mysite:1.0
curl localhost:8084
<h1>Hello from my container</h1> が返ってきました。 レジストリに置いたイメージから、同じコンテナが再現できています。
(pullの出力に Already exists が並ぶのは、nginx公式イメージと共通のレイヤーがまだ手元に残っているためです。レジストリからは、手元に無い差分だけが取得されます。)
後片付け
今回作ったものは、次の順で消せます。
-
コンテナとイメージ
docker rm -f web-from-ocir、docker rmi kix.ocir.io/<テナンシのネームスペース>/mysite:1.0 -
リポジトリ — コンテナ・レジストリの画面から
mysiteを削除 - 認証トークン — 「トークンおよびキー」の画面から削除。使い終わったトークンは残しておかない方が安全です
(OCIRに置いたイメージはオブジェクト・ストレージの容量として課金対象になります。今回のイメージは数十MB程度なので影響はごく小さいですが、不要になったら消しておくと確実です。)
まとめ
- OCIRへのpushに必要なのは、テナンシのネームスペース、リージョンごとのドメイン(大阪は
kix.ocir.io)、認証トークン - リポジトリは先にコンソールで作っておく。自動作成はテナンシ設定が有効なときだけで、置き場所もルート・コンパートメントに固定される
- イメージの完全な名前は
ドメイン/ネームスペース/リポジトリ名:タグ。docker tagでこの名前を付けてからpushする - 手元から消してpullし直しても同じコンテナが動く。これがレジストリに置く意味
Kubernetesでは、Podを起動するときのイメージ指定にこの完全な名前(kix.ocir.io/<ネームスペース>/mysite:1.0)をそのまま使います。 OKE(Oracle Kubernetes Engine。OCI上でKubernetesを動かすサービス)からプライベートなOCIRのイメージを使うには、今回の認証トークンに相当する設定をKubernetes側にも持たせることになりますが、それは次回以降で扱います。











