こんにちは。サイオステクノロジー OSS サポート担当 山本 です。
前回に引き続き、今回も Podman を使ってコンテナの可搬性…「コンテナ単位で別環境に簡単に移せるぞ!」というところを見ていきます。
前回はコンテナイメージをファイルに書き出して、そのファイルを使って別環境にコンテナを移す、という方法をやってみました。
この方法は特に事前準備が必要なく、ファイル形式でコンテナイメージを残しておけるなどのメリットも考えられますが、頻繁にコンテナの更新を別環境へ移したい場合や複数の環境にコンテナを移したい場合にはちょっと面倒になりそうです。
(それでもコンテナを使わないで同じようなことをするよりはラクだとは思いますが…)
今回はわざわざファイルをやりとりしなくても、各環境の Podman コマンドだけでコンテナイメージをやりとりできる方法、レジストリを試してみます。
■レジストリを用意する
そもそも “レジストリ” って何者?というところを最初に大雑把に言ってしまうと、コンテナイメージ置き場だと思っておけばいい…はずです。
このレジストリには Podman コマンドを使ってコンテナイメージを保存したり、逆に Podman コマンドでレジストリに保存されているコンテナイメージを入手することができるため、予めレジストリを用意しておくことでコンテナイメージのやり取りがより簡単にできるようになります。
今回は自前のレジストリを用意して試してみようと思います。
■必要パッケージのインストール
まずは必要となるパッケージをインストールします。
[ ~]$ sudo dnf install -y podman httpd-tools : Complete! [ ~]$
■認証情報の作成
今回の手順で使用するディレクトリを纏めて作成します。
[ ~]$ sudo mkdir -p /opt/registry/{auth,certs,data} [ ~]$
続いて、htpasswd コマンドでレジストリにアクセスするためのユーザ名/パスワードを作成します。
[ ~]$ sudo htpasswd -bBc /opt/registry/auth/htpasswd (ユーザ名) (パスワード) Adding password for user (ユーザ名) [ ~]$
■証明書の準備
今回は自己署名証明書を使用します。
検証用や内部用であれば、各項目は特に設定しなくても問題はないでしょう。
(自前のレジストリを公開することはまずないと思いますが、レジストリを公開するのであれば自己署名証明書ではなく正規の証明書を用意したほうがよいでしょう。)
[ ~]$ sudo openssl req -newkey rsa:4096 -nodes -sha256 \ -keyout /opt/registry/certs/domain.key -x509 -days 365 \ -out /opt/registry/certs/domain.crt \ -addext "subjectAltName = DNS:(ホスト名)" Generating a RSA private key : Country Name (2 letter code) [XX]: State or Province Name (full name) []: Locality Name (eg, city) [Default City]: Organization Name (eg, company) [Default Company Ltd]: Organizational Unit Name (eg, section) []: Common Name (eg, your name or your server's hostname) []: Email Address []: [ ~]$
自己署名証明書を作成したら、この証明書を信頼する証明書として扱うようにします。
[ ~]$ sudo cp /opt/registry/certs/domain.crt /etc/pki/ca-trust/source/anchors/ [ ~]$ sudo update-ca-trust [ ~]$
■レジストリの起動
先に用意した認証情報と証明書を使ったレジストリを起動します。
と言っても、公開されているレジストリのコンテナイメージを使えばコマンド一つで OK です。
[ ~]$ sudo podman run --name test_registry \ -p 5000:5000 \ -v /opt/registry/data:/var/lib/registry:z \ -v /opt/registry/auth:/auth:z \ -e "REGISTRY_AUTH=htpasswd" \ -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \ -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \ -v /opt/registry/certs:/certs:z \ -e "REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt" \ -e "REGISTRY_HTTP_TLS_KEY=/certs/domain.key" \ -e REGISTRY_COMPATIBILITY_SCHEMA1_ENABLED=true \ -d \ docker.io/library/registry
これでレジストリが起動できました。
うまくいっていれば、先の手順で htpasswd で設定したユーザ名/パスワードを使って以下のような curl コマンドを実行すると、{“repositories”:[]} と返ってくるはずです。
[ ~]$ curl --basic -u (ユーザ名):(パスワード) https://(ホスト名):5000/v2/_catalog {"repositories":[]} [ ~]$
■レジストリにコンテナイメージを置いてみる
レジストリが用意できたら、このレジストリを使ってコンテナイメージをやり取りしてみましょう。
まずは配置の方法からです。
■実験用のコンテナイメージを作る
今回もテスト用に、quay.io の httpd コンテナイメージをベースに適当なコンテンツを追加したコンテナを作り、それを基にコンテナイメージを作ります。
以前も案内している手順なので細かい説明は省きます。
コンテナを「test-container-base」という名前を付けて起動して
[ ~]$ podman run -dt -p 8080:8443/tcp --name test-container-base quay.io/centos7/httpd-24-centos7
コンテナの内部でコマンドを実行して適当にコンテンツを作って
[ ~]$ podman exec -it test-container-base /bin/bash bash-4.2$ bash-4.2$ echo -e "This content was created manually.\n Made with bash in Container." > /opt/rh/httpd24/root/var/www/html/test_content.html bash-4.2$ bash-4.2$ exit [ ~]$
作成した「test_content.html」が curl で見れるかを確認します。
この先ではこの「test_content.html」の内容を確認基準として使います。
[ ~]$ curl -k https://localhost:8080/test_content.html This content was created manually. Made with bash in Container. [ ~]$
続いて、”podman commit” コマンドで作成したコンテナ「test-container-base」をコンテナイメージに保存します。
この時、コンテナイメージ名の最初の “/” の前には必ずレジストリのホスト名 (とポート番号) を入れてください。
今回は先の手順で 5000 番ポートを使ってレジストリを起動したので、「(ホスト名):5000/test/test_image」という名前のコンテナイメージにしています。
[ ~]$ podman commit test-container-base (ホスト名):5000/test/test_image Getting image source signatures : Writing manifest to image destination Storing signatures e299946baa784216bd35befe75acbf49afb406dc259a41bf1ee1b071241f65c3 [ ~]$
最後に “podman images” コマンドでコンテナイメージが作れていることを確認しましょう。
[ ~]$ podman images REPOSITORY TAG IMAGE ID CREATED SIZE (ホスト名):5000/test/test_image latest e299946baa78 About a minute ago 356 MB : [ ~]$
■コンテナイメージをアップロードする
では、作成したコンテナイメージをアップロードしてみましょう。
まずは、“podman login” コマンドでレジストリにアクセスできる状態にします。
ユーザ名とパスワードは先の手順で htpasswd で設定したユーザ名/パスワードです。
[ ~]$ podman login (ホスト名):5000 Username: (ユーザ名) Password: (パスワード) Login Succeeded! [ ~]$
ログインに成功したら、あとは先に作成したレジストリのホスト名で始まる名前を持つコンテナイメージを指定して、“podman push” コマンドを実行するだけです。
[ ~]$ podman push (ホスト名):5000/test/test_image Getting image source signatures : Writing manifest to image destination Storing signatures [ ~]$
これでレジストリにコンテナイメージをアップロードできました。
先の手順で使った curl コマンドを改めて実行してみると、コンテナイメージ名から先頭のレジストリのホスト名 (とポート番号) を抜いた「test/test_image」が追加されていることが確認できるはずです。
[ ~]$ curl --basic -u (ユーザ名):(パスワード) https://(ホスト名):5000/v2/_catalog {"repositories":["test/test_image"]} [ ~]$
■レジストリからコンテナイメージを入手する
続いて、別の環境を用意してレジストリからコンテナイメージを入手してみましょう。
firewall 等を使用している場合は、レジストリの環境と通信できるよう予めうまいこと設定しておいてください。
■別環境での前準備
まず、podman が未インストールであればインストールします。
[ ~]$ sudo dnf install -y podman : Complete! [ ~]$
続いて、レジストリで使用している証明書を信頼する証明書として扱うようにします。
今回の手順では自己署名証明書を使っているため、openssl コマンドを使って以下のような手順で実施できます。
[ ~]$ sudo openssl s_client -connect (ホスト名):5000 <<<'' | \ > sudo openssl x509 -out /etc/pki/ca-trust/source/anchors/test.crt : verify return:1 DONE [ ~]$ [ ~]$ sudo update-ca-trust [ ~]$
■コンテナイメージをダウンロードしてみる
レジストリからコンテナイメージをダウンロードしてみましょう。
その前に念のため、保存されているイメージ一覧を確認しておきます。
[ ~]$ podman images REPOSITORY TAG IMAGE ID CREATED SIZE [ ~]$
ダウンロードも “podman pull” コマンドでダウンロードしたいコンテナイメージ名を指定するだけです。
コンテナイメージ名はレジストリのホスト名 (とポート番号) を含めて入力します。
また、こちらも予め “podman login” でレジストリにアクセスできる状態にしておく必要があります。
一気にやってみましょう。
[ ~]$ podman login (ホスト名):5000 Username: (ユーザ名) Password: (パスワード) Login Succeeded! [ ~]$ [ ~]$ podman pull (ホスト名):5000/test/test_image Trying to pull (ホスト名):5000/test/test_image:latest... Getting image source signatures : Writing manifest to image destination Storing signatures e299946baa784216bd35befe75acbf49afb406dc259a41bf1ee1b071241f65c3 [ ~]$
これだけで OK です。改めて保存されたコンテナイメージを確認すると、レジストリからダウンロードしたコンテナイメージが追加されているはずです。
[ ~]$ podman images REPOSITORY TAG IMAGE ID CREATED SIZE (ホスト名):5000/test/test_image latest e299946baa78 23 hours ago 356 MB [ ~]$
また、このコンテナイメージを使ってコンテナを起動してみると、基となったコンテナで作成したコンテンツがちゃんとあることも確認できるはずです。
[ ~]$ podman run -dt -p 8080:8443/tcp --name test-container (ホスト名):5000/test/test_image 20f62c78ab09f8881ed6927801b32549a9322cd9eca5e28c1df140bf61107a9c [ ~]$ curl -k https://localhost:8080/test_content.html This content was created manually. Made with bash in Container. [ ~]$
■別環境側からもアップロードしてみる
念のため、別環境側からもアップロードしてみましょう。
まず変更をアップロードできたことを確認する目印として、起動したコンテナのコンテンツに適当な内容を追加してみます。
[ ~]$ podman exec -it test-container /bin/bash bash-4.2$ echo -e "-------------------\n\nThis is New Content." >> /opt/rh/httpd24/root/var/www/html/test_content.html bash-4.2$ exit exit [ ~]$ curl -k https://localhost:8080/test_content.html This content was created manually. Made with bash in Container. ------------------- This is New Content. [ ~]$
続いて、”podman commit” で先頭部分がレジストリのホスト名 (とポート番号) を持つコンテナイメージを作成します。
今回はダウンロードしたコンテナイメージと同じ名前を設定しています。
コンテナイメージを作成できたら、あとは “podman push” するだけです。(もしレジストリからログアウトしている場合、再度 “podman login” する必要があります。)
最初に podman push した手順と全く同じ手順ですね。
[ ~]$ podman commit test-container (ホスト名):5000/test/test_image Getting image source signatures : Writing manifest to image destination Storing signatures d404c0abfaac2d48a6047156192fdd1d3d18d4bdfcc78c56fbea1ea860488e0b [ ~]$ [ ~]$ podman push (ホスト名):5000/test/test_image Getting image source signatures : Writing manifest to image destination Storing signatures [ ~]$
最後に、元の環境のほうでレジストリに保存されたイメージが更新されているか確認しましょう。
“podman pull” でコンテナイメージをダウンロードしてコンテナを実行し、別環境で書き換えたコンテンツの内容が反映されていることを確認してみましょう。
[ ~]$ podman pull (ホスト名):5000/test/test_image Trying to pull (ホスト名):5000/test/test_image:latest... Getting image source signatures : Writing manifest to image destination Storing signatures d404c0abfaac2d48a6047156192fdd1d3d18d4bdfcc78c56fbea1ea860488e0b [ ~]$ podman run -dt -p 8082:8443/tcp --name test-container-after (ホスト名):5000/test/test_image 0e72404ca7cf2471ed823f8a11f407487618808a1c177acab458a9964c0d3473 [ ~]$ curl -k https://localhost:8082/test_content.html This content was created manually. Made with bash in Container. ------------------- This is New Content. [ ~]$
■最後に
今回はレジストリについて見てきました。
「コンテナイメージ置き場」っぽいかなぁ、というところをなんとなく感じてもらえたかと思います。
最初の準備こそ必要になりますが、一度準備をしてしまえば
“podman push” (と “podman commit”) でコンテナイメージをアップロードし、
“podman pull” でダウンロードする、
という非常に手間の少ない方法でコンテナイメージが共有できるようになります。
ここまで見ると、コンテナの “可搬性” という強みをなんとなく理解できた気になります…よね。
以前にも少しお話ししましたが、一連の記事で使わせてもらっている quay.io や docker.io もレジストリです。
これらのように特にログイン操作をせずともコンテナイメージのダウンロードなら自由にできるレジストリや、今回のやり方のようにログイン操作が必要でコンテナイメージのアップロードなども可能なレジストリなどのような、レジストリ自体をサービスとして提供する団体・サービスなども存在しています。
レジストリを使いたい場合、今回のような自前でレジストリを用意するも含めて用途に合わせて使い分けるとよいと思います。
各レジストリサービスの使い方や規約などについては、そのレジストリサービス側の情報を参照してください。
ちょっとした余談ですが、これまでの記事で見てきたように “podman run” だけでもローカルに指定したコンテナイメージがない場合にはコンテナイメージのダウンロードを試みてくれます。
一方で、今回のように別環境から更新されたコンテナイメージへの変更を確実に反映するためには “podman pull” が必要となるため、状況や目的によって使い分けましょう。
次回はもう少し、レジストリ関連のお話にする予定です。
(他の回)
わからないなりに理解したい Podman ① ~ 何をするもの?
わからないなりに理解したい Podman ② ~ コンテナを書き換える
わからないなりに理解したい Podman ③ ~ 可搬性とは?
(今回)わからないなりに理解したい Podman ④ ~ 可搬性とは?その2
わからないなりに理解したい Podman ⑤ ~ レジストリと TAG
わからないなりに理解したい Podman ⑥ ~ Pod って何だ?
わからないなりに理解したい Podman ⑦ ~ Pod の可搬性