hana_shinのLinux技術ブログ

Linuxの技術情報を掲載しています。特にネットワークをメインに掲載していきます。

コンテナを自動更新する方法

1 はじめに

イメージは時間が経つとバグや脆弱性の修正が必要になることがあります。修正が必要な場合、リポジトリから最新のイメージをプルし、コンテナを再作成する必要があります。io.containers.autoupdate は、コンテナの自動更新に関する設定を行うためのラベルです。このラベルには、コンテナの更新方法を指定する値を設定できます。具体的な設定値は以下の2つです。

io.containers.autoupdateの値 意味
registry リモートレジストリのイメージが更新されると、コンテナが自動的に更新されます
local ローカルに保存されているイメージが更新されると、コンテナが自動的に更新されます

io.containers.autoupdate を使うことで、コンテナの自動更新を効率的に管理し、常に最新の状態を維持することができます。本記事では、io.containers.autoupdate に local を指定した際の動作について確認します。

参考記事:podman-auto-update — Podman documentation

2 検証環境

サーバのAlmaLinux版数は以下のとおりです。

[user1@server ~]$ cat /etc/redhat-release
AlmaLinux release 9.2 (Turquoise Kodkod)

カーネル版数は以下のとおりです。

[user1@server ~]$ uname -r
5.14.0-284.11.1.el9_2.x86_64

3 動作確認( io.containers.autoupdate=local )

タグは何を使ってもかまいませんが、ここでは、タグが2.4の httpd イメージをダウンロードします。

[user1@server ~]$ podman pull docker.io/library/httpd:2.4

ダウンロードしたイメージを確認します。httpd イメージのタグが2.4であることが確認できます。

[user1@server ~]$ podman images
REPOSITORY               TAG         IMAGE ID      CREATED      SIZE
docker.io/library/httpd  2.4         a49fd2c04c02  5 weeks ago  152 MB

podman create コマンドを使用して、my-httpd という名前のコンテナを作成し、自動更新の設定を行います。ラベルに "io.containers.autoupdate=local" を指定することで、このコンテナはローカルのイメージが更新された際に自動的に再作成されるようになります。

[user1@server ~]$ podman create --name my-httpd --label "io.containers.autoupdate=local" docker.io/library/httpd:2.4
8649fb16b03903842fb4ba2486c35375f6f5d8db1ec4733428d8161244f04a78

コンテナの状態を確認すると 「Created」 になっています。この状態は、コンテナが作成されたがまだ実行されていないことを示しています。コンテナは停止しており、実際に動作していません。

[user1@server ~]$ podman ps -a
CONTAINER ID  IMAGE                        COMMAND           CREATED        STATUS      PORTS       NAMES
8649fb16b039  docker.io/library/httpd:2.4  httpd-foreground  9 seconds ago  Created                 my-httpd

ユニットファイルを格納するディレクトリを作成します。

[user1@server ~]$ mkdir -p /home/user1/config/systemd/user

ユニットファイルを生成します。

[user1@server ~]$ podman generate systemd my-httpd --new  > /home/user1/.config/systemd/user/my-httpd.service

新しく作成したユニットファイルを systemd が認識できるようにします。

[user1@server ~]$ systemctl --user daemon-reload

サービスを有効化し、サービスを起動(--now)します。

[user1@server ~]$ systemctl --user enable --now my-httpd.service
Created symlink /home/user1/.config/systemd/user/default.target.wants/my-httpd.service → /home/user1/.config/systemd/user/my-httpd.service.

サービスの状態を確認すると、Active であることが確認できます。

[user1@server ~]$ systemctl --user status my-httpd.service
● my-httpd.service - Podman container-8649fb16b03903842fb4ba2486c35375f6f5d8db1ec4733428d8161244f04a78.service
     Loaded: loaded (/home/user1/.config/systemd/user/my-httpd.service; enabled; preset: disabled)
     Active: active (running) since Tue 2024-08-27 22:23:40 JST; 3s ago
       Docs: man:podman-generate-systemd(1)
   Main PID: 9891 (conmon)
      Tasks: 2 (limit: 22895)
     Memory: 1.6M
        CPU: 201ms
     CGroup: /user.slice/user-1001.slice/[email protected]/app.slice/my-httpd.service
             tq9886 /usr/bin/slirp4netns --disable-host-loopback --mtu=65520 --enable-sandbox --enable-seccomp --enable-ipv6 -c -e 3 -r 4 --netns-type>
             mq9891 /usr/bin/conmon --api-version 1 -c b885329c56abf5f6ebc297b09df2eabb327023b81d6989dc9431a29da8a29ed2 -u b885329c56abf5f6ebc297b09df>
[user1@server ~]$

コンテナのラベルを確認します。

[user1@server ~]$ podman inspect my-httpd --format '{{json .Config.Labels}}' | jq
{
  "PODMAN_SYSTEMD_UNIT": "my-httpd.service",
  "io.containers.autoupdate": "local"
}

podman auto-update コマンドを実行してコンテナの更新をしてみます。この時点ではイメージが更新されていないため、UPDATED の値が 「false」 となっています。これにより、コンテナがまだ更新されていないことが確認できます。

[user1@server ~]$ podman auto-update
            UNIT              CONTAINER                IMAGE                        POLICY      UPDATED
            my-httpd.service  b885329c56ab (my-httpd)  docker.io/library/httpd:2.4  local       false

LABELディレクティブを使って、イメージにラベルをつける Containerfile を作成します。ラベルをつけることで、ローカルに保存されているイメージを更新することができます。Containerfile の作成方法は、コンテナイメージの作り方(Containerfile 編) - hana_shinのLinux技術ブログを参照してください。

[user1@server ~]$ vi Containerfile
[user1@server ~]$ cat Containerfile
FROM docker.io/library/httpd:2.4
LABEL maintainer="[email protected]"

イメージをビルドします。

[user1@server ~]$ podman build -t docker.io/library/httpd:2.4 .

ビルドしたイメージを確認します。

[user1@server ~]$ podman images
REPOSITORY               TAG         IMAGE ID      CREATED        SIZE
docker.io/library/httpd  2.4         dd47d65b4c2f  4 seconds ago  152 MB

podman auto-update コマンドを実行すると、今度は UPDATED の値が true となりました。これは、更新されたイメージを検知した結果、コンテナが自動的に更新されたことを示しています。つまり、自動更新が正常に動作していることが確認できました。

[user1@server ~]$ podman auto-update
            UNIT              CONTAINER                IMAGE                        POLICY      UPDATED
            my-httpd.service  b885329c56ab (my-httpd)  docker.io/library/httpd:2.4  local       true

コンテナのラベルを確認すると、Containerfile で指定したラベル("maintainer": "hana_shin@example.com")が付加されていることが確認できます。つまり更新したイメージでコンテナが動作していることがわかります。

[user1@server ~]$ podman inspect my-httpd --format '{{json .Config.Labels}}' | jq
{
  "PODMAN_SYSTEMD_UNIT": "my-httpd.service",
  "io.buildah.version": "1.29.0",
  "io.containers.autoupdate": "local",
  "maintainer": "[email protected]"
}

4 あと始末

サービスを停止します。

[user1@server ~]$ systemctl --user stop my-httpd.service

サービスを無効化します。

[user1@server ~]$ systemctl --user disable my-httpd.service
Removed "/home/user1/.config/systemd/user/default.target.wants/my-httpd.service".

ユニットファイルを削除します。

[user1@server ~]$ rm /home/user1/.config/systemd/user/my-httpd.service

ユニットファイルが削除されたことを systemd が認識できるようにします。

[user1@server ~]$ systemctl --user daemon-reload

イメージを削除します。

[user1@server ~]$ podman rmi a49fd2c04c02

5 メモ

Docker Hub の httpd イメージのタグを確認するには、次のコマンドを使用します。

[user1@server ~]$ curl -s https://registry.hub.docker.com/v2/repositories/library/httpd/tags/ | jq '.results[].name'
"latest"
"bookworm"
"2.4.62-bookworm"
"2.4.62"
"2.4-bookworm"
"2.4"
"2-bookworm"
"2"
"alpine3.20"
"alpine"

Y 参考図書

今回の記事執筆にあたり参考にした図書は以下のものです。

単行本


Docker実践ガイド 第3版 (impress top gear)

電子書籍

c.scripts[c.scripts.length-2];(b[a].q=b[a].q []).push(arguments)};

c.getElementById(a)||(d=c.createElement(f),d.src=g,
d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})
(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");
msmaflink({"n":"Software Design (ソフトウェアデザイン) 2023年11月号 [雑誌]","b":"","t":"","d":"https:\/\/m.media-amazon.com","c_p":"","p":["\/images\/I\/51gnbOVIwuL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/B0CKF3J1M9","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/B0CKF3J1M9","a_id":3177459,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":5,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/Software%20Design%20(%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3)%202023%E5%B9%B411%E6%9C%88%E5%8F%B7%20%5B%E9%9B%91%E8%AA%8C%5D\/","a_id":3177083,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2}],"eid":"ax2oE","s":"s"});


Software Design (ソフトウェアデザイン) 2023年11月号 [雑誌]


Docker実践ガイド 第3版 impress top gearシリーズ


Z 参考情報

私が業務や記事執筆で参考にした書籍を以下のページに記載します。
Linux技術のスキルアップをしよう! - hana_shinのLinux技術ブログ
Rootless コンテナはいいぞ - Speaker Deck
CentOS 8 : Podman : Dockerfile を利用する : Server World

https://pocketstudio.net/2020/01/31/cmd-and-entrypoint/#google_vignette
https://www.grandream.jp/blog/docker-cmd-entrypoint

httpd コンテナを自動起動する方法

1 はじめに

Podmanはデーモンとして動作しないため、サーバのブート時にコンテナを自動起動するには、Podman をデーモンとして使用できません。サーバブート時のコンテナの自動起動は、systemd を通じて起動する必要があります。このことを確認するため、まず、httpd コンテナの起動方法を確認し、その後にsystemdを使用したコンテナの自動起動を確認します。
・httpd コンテナの起動方法の確認
・サーバ起動時のhttpd コンテナの自動起動

2 検証環境

構成は以下のとおりです。

                                  httpdコンテナ (80)
                                        |
                                        |
                                        |
PC ------------ (192.168.1.200:8080) サーバ(AlmaLinux 9.2)

サーバのAlmaLinux版数は以下のとおりです。

[user1@server ~]$ cat /etc/redhat-release
AlmaLinux release 9.2 (Turquoise Kodkod)

カーネル版数は以下のとおりです。

[user1@server ~]$ uname -r
5.14.0-284.11.1.el9_2.x86_64

3 コンテナの起動方法

サーバでhttpdのイメージをダウンロードします。レジストリの検索方法は、コンテナイメージのレジストリ検索方法(Podman編) - hana_shinのLinux技術ブログを参照してください。

[user1@server ~]$ podman pull docker.io/library/httpd

ダウンロードしたイメージを確認します。httpd イメージの最新版がダウンロードされたことが確認できます。

[user1@server ~]$ podman images
REPOSITORY               TAG         IMAGE ID      CREATED      SIZE
docker.io/library/httpd  latest      19c71fbb7140  2 weeks ago  152 MB

test1 という名前の httpd コンテナを起動します。このとき、-p オプションを指定して、サーバの 8080 番ポートへのパケットをコンテナの 80 番ポートに転送するように設定します。

[user1@server ~]$ podman run -d -p 8080:80 --rm --name test1 httpd
73482f0731f7002a416e20aae490836e82f1d25136f796981b83ac7e6532e057

ポート番号のマッピングを確認します。サーバの任意(0.0.0.0.)の IP アドレス宛の 8080 番ポートへのパケットを、コンテナ内の 80 番ポートに転送する設定になっていることが確認できます。

[user1@server ~]$ podman port test1
80/tcp -> 0.0.0.0:8080

curlコマンドを実行すると、HTTPサーバからの応答が確認できます。

[user1@server ~]$ curl http://192.168.1.200:8080
<html><body><h1>It works!</h1></body></html>

podman top コマンドを実行して、test1 という名前のコンテナ内で実行中のプロセスを確認します。

[user1@server ~]$ podman top test1
USER        PID         PPID        %CPU        ELAPSED          TTY         TIME        COMMAND
root        1           0           0.000       1m37.434702295s  ?           0s          httpd -DFOREGROUND
www-data    3           1           0.000       1m37.435169864s  ?           0s          httpd -DFOREGROUND
www-data    4           1           0.000       1m37.43535964s   ?           0s          httpd -DFOREGROUND
www-data    5           1           0.000       1m37.435440962s  ?           0s          httpd -DFOREGROUND

TCPの8080番ポートへのアクセスを許可します。

[user1@server ~]$ sudo firewall-cmd --add-port=8080/tcp
success

許可しているポート番号のリストを確認します。TCPの8080番ポートへのアクセスが許可されていることが確認できます。

[user1@server ~]$ sudo firewall-cmd --list-ports
8080/tcp

PCのブラウザで以下のURLにアクセスすると、HTTPサーバから応答が返ってくることが確認できます。
http://192.168.1.200:8080/

あと始末をします。コンテナを削除します。

[root@server ~]# podman rm test1 --force
test1

あと始末をします。イメージを削除します。

[root@server ~]# podman rmi httpd
Untagged: docker.io/library/httpd:latest
Deleted: 19c71fbb71404e06730aa9bc4ec079eefc63d84d46fa0fa1c768263669adb0d3

4 コンテナを自動起動する方法

次は、サーバを再起動した際にコンテナを自動で起動する方法を説明します。コンテナを自動起動するには、コンテナ用のユニットファイルを作成する必要があります。

コンテナを作成します。

[user1@server ~]$ podman create -p 8080:80 --name test1 docker.io/library/httpd
a327394e0a68d0495ed72e8099bcfd99274e99a238df6916928c89282c76d6ca

作成したコンテナを確認します。test1 の状態が「Created」であることから、このコンテナは作成されたものの、まだ起動していないことがわかります。

[user1@server ~]$ podman ps -a
CONTAINER ID  IMAGE                           COMMAND           CREATED         STATUS      PORTS                 NAMES
a327394e0a68  docker.io/library/httpd:latest  httpd-foreground  10 seconds ago  Created     0.0.0.0:8080->80/tcp  test1

podman generate コマンドを実行して、httpd コンテナーの systemd ユニットファイルを生成します。

[user1@server ~]$ podman generate systemd --new --files --name test1
/home/user1/container-test1.service

作成したユニットファイルのSELinuxコンテキストを確認します。

[user1@server ~]$ ls -lZ container-test1.service
-rw-r--r--. 1 user1 user1 unconfined_u:object_r:user_home_t:s0 757  8月  4 21:02 container-test1.service

作成したユニットファイルを確認します。

[user1@server ~]$ cat /home/user1/container-test1.service
# container-test1.service
# autogenerated by Podman 4.4.1
# Sun Aug  4 21:02:56 JST 2024

[Unit]
Description=Podman container-test1.service
Documentation=man:podman-generate-systemd(1)
Wants=network-online.target
After=network-online.target
RequiresMountsFor=%t/containers

[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=on-failure
TimeoutStopSec=70
ExecStart=/usr/bin/podman run \
        --cidfile=%t/%n.ctr-id \
        --cgroups=no-conmon \
        --rm \
        --sdnotify=conmon \
        -d \
        --replace \
        -p 8080:80 \
        --name test1 docker.io/library/httpd
ExecStop=/usr/bin/podman stop \
        --ignore -t 10 \
        --cidfile=%t/%n.ctr-id
ExecStopPost=/usr/bin/podman rm \
        -f \
        --ignore -t 10 \
        --cidfile=%t/%n.ctr-id
Type=notify
NotifyAccess=all

[Install]
WantedBy=default.target

作成したユニットファイルを /etc/systemd/system にコピーします。

[user1@server ~]$ sudo cp -Z container-test1.service /etc/systemd/system

コピーしたユニットファイルの SELinuxコンテキストを確認します。/etc/systemd/systemのデフォルトのSELinuxコンテキストであることが確認できます。

[user1@server ~]$ ls -lZ /etc/systemd/system/container-test1.service
-rw-r--r--. 1 root root unconfined_u:object_r:systemd_unit_file_t:s0 757  8月  4 21:07 /etc/systemd/system/container-test1.service

systemctl daemon-reload コマンドを実行して、systemdにユニットファイルの作成を通知し、ユニットファイルの再読み込みを指示します。

[user1@server ~]$ systemctl daemon-reload

システム起動時に自動的に起動(enable)するように設定して、サービスを即時起動(--now)します。これにより、サービスがすぐに開始されます。

[user1@server ~]$ sudo systemctl enable --now container-test1.service

サービスの状態を確認します。サービスが動作していることが確認できます。

[user1@server ~]$ systemctl status container-test1.service
● container-test1.service - Podman container-test1.service
     Loaded: loaded (/etc/systemd/system/container-test1.service; enabled; preset: disabled)
     Active: active (running) since Sun 2024-08-04 21:12:21 JST; 31s ago
       Docs: man:podman-generate-systemd(1)
   Main PID: 4791 (conmon)
      Tasks: 1 (limit: 22895)
     Memory: 168.1M
        CPU: 13.844s
     CGroup: /system.slice/container-test1.service
             mq4791 /usr/bin/conmon --api-version 1 -c 3803b2b1bf5c4a7e8a6a740f9fcc9ba10267e166248d470329758e88289e6bc5 >
[user1@server ~]$

サーバを再起動します。

[user1@server ~]$ shutdown -r now

サーバが再起動したあと、サービスの状態を確認します。サービスが自動的に起動していることが確認できます。

[user1@server ~]$ systemctl status container-test1.service
● container-test1.service - Podman container-test1.service
     Loaded: loaded (/etc/systemd/system/container-test1.service; enabled; preset: disabled)
     Active: active (running) since Sun 2024-08-04 21:14:25 JST; 6min ago
       Docs: man:podman-generate-systemd(1)
   Main PID: 1831 (conmon)
      Tasks: 1 (limit: 22895)
     Memory: 51.3M
        CPU: 878ms
     CGroup: /system.slice/container-test1.service
             mq1831 /usr/bin/conmon --api-version 1 -c ef1e2a77f99e88fd0f2a97279bad86ce2678d5ca57b995c417106f439485cb85 >
[user1@server ~]$

curlコマンドを実行すると、HTTPサーバからの応答が確認できます。

[user1@server ~]$ curl http://192.168.1.200:8080
<html><body><h1>It works!</h1></body></html>

後始末します。サービス(httpdコンテナ)を停止します。

[user1@server ~]$ sudo systemctl stop container-test1.service
[user1@server ~]$

サービスを停止したので、curl コマンドを実行すると、HTTPサーバに接続拒否されていることがわかります。

[user1@server ~]$ curl http://192.168.1.200:8080
curl: (7) Failed to connect to 192.168.1.200 port 8080: 接続を拒否されました

Y 参考図書

今回の記事執筆にあたり参考にした図書は以下のものです。

単行本


Docker実践ガイド 第3版 (impress top gear)

電子書籍

c.scripts[c.scripts.length-2];(b[a].q=b[a].q []).push(arguments)};

c.getElementById(a)||(d=c.createElement(f),d.src=g,
d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})
(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");
msmaflink({"n":"Software Design (ソフトウェアデザイン) 2023年11月号 [雑誌]","b":"","t":"","d":"https:\/\/m.media-amazon.com","c_p":"","p":["\/images\/I\/51gnbOVIwuL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/B0CKF3J1M9","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/B0CKF3J1M9","a_id":3177459,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":5,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/Software%20Design%20(%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3)%202023%E5%B9%B411%E6%9C%88%E5%8F%B7%20%5B%E9%9B%91%E8%AA%8C%5D\/","a_id":3177083,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2}],"eid":"ax2oE","s":"s"});


Software Design (ソフトウェアデザイン) 2023年11月号 [雑誌]


Docker実践ガイド 第3版 impress top gearシリーズ


Z 参考情報

私が業務や記事執筆で参考にした書籍を以下のページに記載します。
Linux技術のスキルアップをしよう! - hana_shinのLinux技術ブログ
Rootless コンテナはいいぞ - Speaker Deck
CentOS 8 : Podman : Dockerfile を利用する : Server World

https://pocketstudio.net/2020/01/31/cmd-and-entrypoint/#google_vignette
https://www.grandream.jp/blog/docker-cmd-entrypoint

仮想ファイルシステムのマスク/アンマスク方法

1 はじめに

コンテナがホストの仮想ファイルシステムへの参照を禁止または許可する方法について説明します。仮想ファイルシステムとは、/proc、/sys、/dev などを指します。コンテナが動作するのに必要のない仮想ファイルシステムは、コンテナから見えないようにマスクすることで、セキュリティを向上させることができます。例えば、以下に抜粋したマニュアルを参照すると、/proc/acpi や /proc/kcore などはデフォルトでマスクされています。つまり、コンテナからこれらのファイルシステムをデフォルトで参照することはできません。

[root@kvm-host ~]# man podman-run
              ~ unmask=ALL  or  /path/1:/path/2,  or  shell  expanded paths (/proc/*): Paths to unmask separated by a
                colon. If set to ALL, it unmasks all the paths that are masked or made read-only by default.  The de‐
                fault  masked  paths are /proc/acpi, /proc/kcore, /proc/keys, /proc/latency_stats, /proc/sched_debug,
                /proc/scsi, /proc/timer_list, /proc/timer_stats, /sys/firmware,  and  /sys/fs/selinux.   The  default
                paths  that  are  read-only are /proc/asound, /proc/bus, /proc/fs, /proc/irq, /proc/sys, /proc/sysrq-
                trigger, /sys/fs/cgroup.
-snip-

2 検証環境

サーバのAlmaLinux版数は以下のとおりです。

[root@server ~]# cat /etc/redhat-release
AlmaLinux release 9.2 (Turquoise Kodkod)

カーネル版数は以下のとおりです。

[root@server ~]# uname -r
5.14.0-284.11.1.el9_2.x86_64

3 podmanのインストール方法

podmanパッケージをインストールします。

[root@server ~]# dnf -y install podman

podmanコマンドの版数を確認します。

[root@server ~]# podman -v
podman version 4.9.4-rhel

4 アンマスクする方法(--security-opt unmask=dir)

コンテナを起動するイメージを確認します。ここでは、almalinux イメージを使用します。

[user1@server ~]$ podman images
REPOSITORY                   TAG         IMAGE ID      CREATED     SIZE
docker.io/library/almalinux  latest      fe9652e6c62e  5 days ago  191 MB

デフォルトの状態を確認するため、--security-opt オプションを指定せずコンテナを起動します。

[user1@server ~]$ podman run -it --rm --name test1 almalinux
[root@1b1a123822ef /]#

ls コマンドで /proc/scsi を確認します。マニュアルに記載されている通り、/proc/scsi はデフォルトでマスクされているため、/proc/scsi 配下には何も表示されないことが確認できます。

[root@1b1a123822ef /]# ls /proc/scsi/
[root@1b1a123822ef /]#

コンテナ内でマウントしているファイルシステムを確認します。/proc/scsi には tmpfs がマウントされていることがわかります。つまり、/proc/scsi にアクセスすると、ホストのメモリを参照することになります。これにより、ホストの /proc/scsi へのアクセスが制限されていることが確認できます。

[root@c8db3cd3c364 /]# findmnt -a | grep /proc/scsi
| |-/proc/scsi          tmpfs                                                                                                                         tmpfs    ro,relatime,context="system_u:object_r:container_file_t:s0:c63,c112",size=0k,uid=1000,gid=1000,inode64

コンテナから抜けます。

[root@c8db3cd3c364 /]# exit
exit

次に、--security-opt オプションを使用して /proc/scsi をアンマスクしてみます。アンマスクを指定すると、コンテナからホストの /proc/scsi を参照できるようになります。

[user1@server ~]$ podman run -it --rm --security-opt unmask=/proc/scsi  --name test1 almalinux
[root@99e528143a44 /]#

lsコマンドで/proc/scsi 配下を確認すると、各種ファイルを確認することができます。

[root@326649924a35 /]# ls -l /proc/scsi/
total 0
-r--r--r--. 1 nobody nobody 0 Jul 28 12:35 device_info
-r--r--r--. 1 nobody nobody 0 Jul 28 12:35 scsi
dr-xr-xr-x. 9 nobody nobody 0 Jul 28 12:35 sg

コンテナ内でマウントしているファイルシステムを確認します。/proc/scsi には tmpfsはマウントされていません。つまり、ホストの/proc/scsi を参照できることがわかります。

[root@326649924a35 /]# findmnt -a | grep /proc/scsi
[root@326649924a35 /]#

コンテナから抜けます。

[root@326649924a35 /]# exit
exit

5 マスクする方法(--security-opt mask=dir)

コンテナに特定の仮想ファイルシステムを参照できないようにするには、マスクするパスを --security-opt オプションで指定します。例えば、コンテナから /proc/sys/net を参照できないようにする場合は、次のように実行します。

まず初期状態を確認するため、--security-opt オプションを指定せずコンテナを起動してみます。

[user1@server ~]$ podman run -it --rm --name test1 almalinux
[root@96ac14e1d2a3 /]#

lsコマンドで /proc/sys/net 配下を確認してみます。

[root@96ac14e1d2a3 /]# ls -l /proc/sys/net
total 0
dr-xr-xr-x. 1 root root 0 Jul 28 12:36 core
dr-xr-xr-x. 1 root root 0 Jul 28 12:36 ipv4
dr-xr-xr-x. 1 root root 0 Jul 28 12:36 ipv6
dr-xr-xr-x. 1 root root 0 Jul 28 12:36 mptcp
dr-xr-xr-x. 1 root root 0 Jul 28 12:36 netfilter
dr-xr-xr-x. 1 root root 0 Jul 28 12:36 unix

コンテナから抜けます。

[root@d42f33ba2d95 /]# exit
exit

次に、--security-opt オプションを使用して /proc/sys/net をマスクしてみます。マスクを指定すると、コンテナからホストの /proc/sys/net を参照できなくなります。

[user1@server ~]$ podman run -it --rm --security-opt mask=/proc/sys/net --name test1 almalinux
[root@0c40734feca6 /]#

lsコマンドで /proc/sys/net 配下を確認すると、何も表示されないことが確認できます。

[root@0c40734feca6 /]# ls -l /proc/sys/net
total 0

コンテナから抜けます。

[root@0c40734feca6 /]# exit
exit

6 マスク/アンマスクのパスを同時に指定する方法

マスク、アンマスクするパスを複数同時に指定する場合は、パスを「:」で区切ります。ここでは、コンテナからホストの以下の仮想ファイルシステムをマスクしてみます。
・/proc/sys/net/ipv4
・/proc/sys/net/ipv6

[user1@server ~]$ podman run -it --rm --security-opt mask=/proc/sys/net/ipv4:/proc/sys/net/ipv6  --name test1 almalinux

コンテナ内で /proc/sys/net/ipv4 配下を確認してみます。/proc/sys/net/ipv4 がマスクされているため、ls コマンドで /proc/sys/net/ipv4 配下を確認すると、何も表示されないことが確認できます。

[root@598c9f73964c /]# ls -l /proc/sys/net/ipv4/
total 0

コンテナ内で /proc/sys/net/ipv6 配下を確認してみます。/proc/sys/net/ipv6 がマスクされているため、ls コマンドで /proc/sys/net/ipv6/ 配下を確認すると、何も表示されないことが確認できます。

[root@598c9f73964c /]# ls -l /proc/sys/net/ipv6/
total 0

Y 参考図書

今回の記事執筆にあたり参考にした図書は以下のものです。

単行本


Docker実践ガイド 第3版 (impress top gear)

電子書籍

c.scripts[c.scripts.length-2];(b[a].q=b[a].q []).push(arguments)};

c.getElementById(a)||(d=c.createElement(f),d.src=g,
d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})
(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");
msmaflink({"n":"Software Design (ソフトウェアデザイン) 2023年11月号 [雑誌]","b":"","t":"","d":"https:\/\/m.media-amazon.com","c_p":"","p":["\/images\/I\/51gnbOVIwuL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/B0CKF3J1M9","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/B0CKF3J1M9","a_id":3177459,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":5,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/Software%20Design%20(%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3)%202023%E5%B9%B411%E6%9C%88%E5%8F%B7%20%5B%E9%9B%91%E8%AA%8C%5D\/","a_id":3177083,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2}],"eid":"ax2oE","s":"s"});


Software Design (ソフトウェアデザイン) 2023年11月号 [雑誌]


Docker実践ガイド 第3版 impress top gearシリーズ


Z 参考情報

私が業務や記事執筆で参考にした書籍を以下のページに記載します。
Linux技術のスキルアップをしよう! - hana_shinのLinux技術ブログ
Rootless コンテナはいいぞ - Speaker Deck
CentOS 8 : Podman : Dockerfile を利用する : Server World

https://pocketstudio.net/2020/01/31/cmd-and-entrypoint/#google_vignette
https://www.grandream.jp/blog/docker-cmd-entrypoint

Podman secretコマンドの使い方

1 はじめに

コンテナを実行する際、コンテナ内で稼働するサービスに機密情報を渡す場合があります。例えば、データベースを操作するサービスの場合、管理者ユーザー名とパスワードが必要です。これらを環境変数としてコンテナに渡すこともできますが、その場合、稼働中のコンテナのイメージをcommitすると、機密情報がイメージに書き込まれてしまいます。これを防ぐために、secretコマンドがあります。secretコマンドを使うと、機密情報をコンテナに渡しても、これらはコンテナをcommitしてもイメージに書き込まれません。そのため、イメージから機密情報を盗まれる心配がありません。

2 検証環境

サーバのAlmaLinux版数は以下のとおりです。

[root@server ~]# cat /etc/redhat-release
AlmaLinux release 9.2 (Turquoise Kodkod)

カーネル版数は以下のとおりです。

[root@server ~]# uname -r
5.14.0-284.11.1.el9_2.x86_64

3 podmanのインストール方法

podmanパッケージをインストールします。

[root@server ~]# dnf -y install podman

podmanコマンドの版数を確認します。

[root@server ~]# podman -v
podman version 4.9.4-rhel

4 secretコマンドのオプション一覧

secret コマンドのオプション一覧は以下のとおりです。

[user1@server ~]$ podman secret --help
Manage secrets

Description:
  Manage secrets

Usage:
  podman secret [command]

Available Commands:
  create      Create a new secret
  exists      Check if a secret exists in local storage
  inspect     Inspect a secret
  ls          List secrets
  rm          Remove one or more secrets

5 シークレットの作成、削除方法

秘密情報をファイルに書き込みます。

[user1@server ~]$ echo "This is my secret" > /tmp/secret

秘密情報からシークレットを作成します。

[user1@server ~]$ podman secret create my_secret /tmp/secret
316775a474faa7e8fd7d02ae9

作成したシークレットを確認します。my_secret という名前のシークレットが作成できたことが確認できます。

[user1@server ~]$ podman secret ls
ID                         NAME        DRIVER      CREATED         UPDATED
316775a474faa7e8fd7d02ae9  my_secret   file        30 seconds ago  30 seconds ago

シークレットを削除します。

[user1@server ~]$ podman secret rm my_secret
316775a474faa7e8fd7d02ae9

シークレットを確認します。シークレットが削除されたことが確認できます。

[user1@server ~]$ podman secret ls
ID          NAME        DRIVER      CREATED     UPDATED

6 シークレットを使った実施例

コンテナに秘密情報(IDやパスワード等)をシークレットとして渡す方法について説明します。

6.1 シークレットをパラメータでコンテナに渡す方法

秘密情報(ID/パスワード)をファイルに書き込みます。

[user1@server ~]$ echo "My_ID" > /tmp/ID
[user1@server ~]$ echo "My_PASS" > /tmp/PASS

秘密情報のシークレットを作成します。

[user1@server ~]$ podman secret create my_id /tmp/ID
[user1@server ~]$ podman secret create my_pass /tmp/PASS

作成したシークレットを確認します。

[user1@server ~]$ podman secret ls
ID                         NAME        DRIVER      CREATED        UPDATED
7e2ee29c41b71ad99f1ae6ff8  my_pass     file        3 seconds ago  3 seconds ago
40e84374a2b5845bf8409aa92  my_id       file        7 seconds ago  7 seconds ago

イメージ(almalinux)からコンテナ(test1 )を起動します。このとき、--secretオプションを使用して、シークレットをコンテナ内で使用できるようにします。

[user1@server ~]$ podman run -dit --secret my_id --secret my_pass --name test1 almalinux

コンテナでbashを実行します。

[user1@server ~]$ podman exec -it test1 bash
[root@e369a7f4a5ab /]#

/run/secrets 配下を確認すると、ホストからコンテナにシークレットが渡されていることがわかります。

[root@e369a7f4a5ab /]# cat /run/secrets/my_id
My_ID
[root@e369a7f4a5ab /]# cat /run/secrets/my_pass
My_PASS

コンテナからぬけます。

[root@e369a7f4a5ab /]# exit
exit

コンテナを確認します。test1という名前のコンテナが動作していることが確認できます。

[user1@server ~]$ podman ps
CONTAINER ID  IMAGE                               COMMAND     CREATED         STATUS         PORTS       NAMES
e369a7f4a5ab  docker.io/library/almalinux:latest  /bin/bash   47 seconds ago  Up 47 seconds              test1

commit コマンドを実行して、コンテナをイメージ(secret_img)に保存します。

[user1@server ~]$ podman commit test1 secret_img

イメージを確認します。

[user1@server ~]$ podman images
REPOSITORY                   TAG         IMAGE ID      CREATED        SIZE
localhost/secret_img         latest      a6524b1eb359  9 seconds ago  191 MB
docker.io/library/almalinux  latest      8109fa501eaf  6 weeks ago    191 MB

シークレットイメージ(secret_img)でコンテナを起動します。

[user1@server ~]$ podman run -dit --name test2 secret_img

コンテナでbashを実行します。

[user1@server ~]$ podman exec -it test2 bash
[root@0b2d003707e0 /]#

コンテナを起動したイメージにシークレットが含まれないので、/run/secrets 配下にシークレットが存在しないことが確認できます。

[root@0b2d003707e0 /]# ls /run/secrets/*
ls: cannot access '/run/secrets/*': No such file or directory

コンテナからぬけます。

[root@0b2d003707e0 /]# exit
exit

次の検証のため、コンテナとイメージを削除します。

[user1@server ~]$ podman rm -f $(podman ps -aq)
[user1@server ~]$ podman rmi -f $(podman images -q)

6.2 シークレットを環境変数でコンテナに渡す方法

前回の検証でalmalinuxのイメージを削除したので、あたらめてalmalinuxイメージをダウンロードします。

[user1@server ~]$ podman pull docker.io/library/almalinux

シークレットは前回作成したものを使います。

[user1@server ~]$ podman secret ls
ID                         NAME        DRIVER      CREATED         UPDATED
40e84374a2b5845bf8409aa92  my_id       file        57 minutes ago  57 minutes ago
7e2ee29c41b71ad99f1ae6ff8  my_pass     file        57 minutes ago  57 minutes ago

イメージからコンテナを起動します。このとき、コンテナにシークレットを環境変数(type=env)として渡します。

[user1@server ~]$ podman run -dit --secret my_id,type=env --secret my_pass,type=env --name test1 almalinux

コンテナでbashを実行します。

[user1@server ~]$ podman exec -it test1 bash

コンテナで環境変数my_id、my_passの値を確認すると、環境変数に値が設定されていることが確認できます。

[root@53262a122865 /]# echo $my_id
My_ID
[root@53262a122865 /]# echo $my_pass
My_PASS
[root@53262a122865 /]#

コンテナからぬけます。

[root@53262a122865 /]# exit
exit

commit コマンドを実行して、コンテナをイメージ(secret_img)に保存します。

[user1@server ~]$ podman commit test1 secret_img

イメージを確認します。

[user1@server ~]$ podman images
REPOSITORY                   TAG         IMAGE ID      CREATED         SIZE
localhost/secret_img         latest      9a6defa8a539  42 seconds ago  191 MB
docker.io/library/almalinux  latest      8109fa501eaf  6 weeks ago     191 MB

シークレットイメージ(secret_img)でコンテナを起動します。

[user1@server ~]$ podman run -dit --name test2 secret_img

コンテナでbashを実行します。

[user1@server ~]$ podman exec -it test2 bash

コンテナを起動したイメージにシークレットが含まれないので、環境変数には値が何も設定されていないことが確認できます。

[root@eb48fee287cc /]# echo $my_id

[root@eb48fee287cc /]# echo $my_pass

[root@eb48fee287cc /]#

コンテナからぬけます。

[root@eb48fee287cc /]# exit
exit

Y 参考図書

今回の記事執筆にあたり参考にした図書は以下のものです。

単行本


Docker実践ガイド 第3版 (impress top gear)

電子書籍

c.scripts[c.scripts.length-2];(b[a].q=b[a].q []).push(arguments)};

c.getElementById(a)||(d=c.createElement(f),d.src=g,
d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})
(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");
msmaflink({"n":"Software Design (ソフトウェアデザイン) 2023年11月号 [雑誌]","b":"","t":"","d":"https:\/\/m.media-amazon.com","c_p":"","p":["\/images\/I\/51gnbOVIwuL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/B0CKF3J1M9","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/B0CKF3J1M9","a_id":3177459,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":5,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/Software%20Design%20(%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3)%202023%E5%B9%B411%E6%9C%88%E5%8F%B7%20%5B%E9%9B%91%E8%AA%8C%5D\/","a_id":3177083,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2}],"eid":"ax2oE","s":"s"});


Software Design (ソフトウェアデザイン) 2023年11月号 [雑誌]


Docker実践ガイド 第3版 impress top gearシリーズ


Z 参考情報

私が業務や記事執筆で参考にした書籍を以下のページに記載します。
Linux技術のスキルアップをしよう! - hana_shinのLinux技術ブログ
Rootless コンテナはいいぞ - Speaker Deck
CentOS 8 : Podman : Dockerfile を利用する : Server World

https://pocketstudio.net/2020/01/31/cmd-and-entrypoint/#google_vignette
https://www.grandream.jp/blog/docker-cmd-entrypoint

コンテナイメージの作り方(Containerfile 編)

1 はじめに

イメージの作成は、以下の方法があります。

  • Containerfileを使う方法
  • Podmanのcommitコマンドを使う方法

ここでは、Containerfileを使用したイメージの作り方について説明します。Containerfileでイメージを作成する際には、buildコマンドを使用します。書式は以下の通りです。

$ podman build -t Podmanイメージ名 Containerfile格納ディレクトリ

参考情報:Dockerfile リファレンス — Docker-docs-ja 24.0 ドキュメント

2 検証環境

サーバのAlmaLinux版数は以下のとおりです。

[root@server ~]# cat /etc/redhat-release
AlmaLinux release 9.2 (Turquoise Kodkod)

カーネル版数は以下のとおりです。

[root@server ~]# uname -r
5.14.0-284.11.1.el9_2.x86_64

3 podmanのインストール方法

podmanパッケージをインストールします。

[root@server ~]# dnf -y install podman

podmanコマンドの版数を確認します。

[root@server ~]# podman -v
podman version 4.9.4-rhel

4 ディレクティブ

ディレクティブとは、Containerfile内に記述するコマンドのことです。ディレクティブを使用すると、コンテナにソフトウェアをインストールしたり、ホストのファイルをコンテナ内にコピーしたりすることができます。

ディレクティブ 概要
FROM ベースとなるコンテナイメージを指定します
COPY ホストのファイル、ディレクトリ、URLをコンテナにコピーします。ADD と異なる点は、リモートURL の指定不可、アーカイブファイルを自動で展開しません
ADD ホストのファイル、ディレクトリ、URLをコンテナにコピーします。ADDはCOPYに比べ多機能ですが、シンプルなコピーにはCOPYを使うことが推奨されているようです
RUN イメージのビルド中に実行するコマンドを指定します。具体的には、イメージの構築に必要なソフトウェアのインストール、設定変更、ファイルのダウンロードなどを行うことができます
ENTRYPOINT コンテナが起動したときに実行されるメインプロセスを指定するために使用します
CMD コンテナが起動するときに実行するコマンドのデフォルトのパラメータを指定します
EXPOSE コンテナがパケットを待ち受けるポート番号を指定するために使用します。パケットはlistenシステムコールを実行して待ち受けます
ENV コンテナ内で環境変数を設定するために使用します。これにより、コンテナ内のプロセスが利用する環境変数を定義できます。ENV ディレクティブで設定した環境変数は、結果として作成されたイメージから実行したコンテナでも維持されます
LABEL イメージに任意のラベル(キー・バリュー形式で指定)を付けるために使用します。ラベルは、プロジェクトでイメージを管理するために使用しま。例えば、誰が作成したイメージなのかといった情報をイメージに付けることができます
WORKDIR コンテナ内の作業ディレクトリを変更するために使用します
USER USERディレクティブで指定したユーザー権限でコンテナ内のプロセスやコマンドを実行します

5 FROMディレクティブの使い方

イメージの初期状態を確認します。

[user1@server ~]$ podman images
REPOSITORY  TAG         IMAGE ID    CREATED     SIZE

Containerfileを使って、次の内容のイメージを作成します。
・ベースイメージにAlmaLinuxを使用する(FROM )

[user1@server ~]$ vi Containerfile
[user1@server ~]$ cat Containerfile
FROM docker.io/library/almalinux

イメージをビルドします。-t(タグ)オプションは、ビルドするイメージの名前(test_image)を指定します。最後に指定するパラメータは、Containerfile を格納したディレクトリを示します。ここではピリオド(.)を指定しているため、podman コマンドを実行する場所と同じディレクトリに Containerfile があることを意味しています。

[user1@server ~]$ podman build -t test_image .
STEP 1/1: FROM docker.io/library/almalinux
Trying to pull docker.io/library/almalinux:latest...
Getting image source signatures
Copying blob 587e68e1d836 done   |
Copying config 8109fa501e done   |
Writing manifest to image destination
COMMIT test_image
--> 8109fa501eaf
Successfully tagged localhost/test_image:latest
Successfully tagged docker.io/library/almalinux:latest
8109fa501eaf5af622946e7c5c033cb7aef816c3267b1c17c7b62b34fea099a5

イメージを確認すると、イメージ(test_image)が作成されたことがわかります。

[user1@server ~]$ podman images
REPOSITORY                   TAG         IMAGE ID      CREATED      SIZE
localhost/test_image         latest      8109fa501eaf  5 weeks ago  191 MB
docker.io/library/almalinux  latest      8109fa501eaf  5 weeks ago  191 MB

次の検証のため、イメージを削除します。

[user1@server ~]$ podman rmi -f $(podman images -q)

6 COPY/ADDディレクティブの使い方

6.1 COPY ディレクティブの使い方

ホストからコンテナにコピーするファイルを作成します。

[user1@server ~]$ vi test.sh
[user1@server ~]$ cat test.txt
12345

作成したファイルの所有者と所有グループを確認します。ホスト環境では、user1 でファイルを作成しているため、所有者および所有グループが user1 になっていることが確認できます。

[user1@server ~]$ ls -l test.txt
-rw-r--r--. 1 user1 user1 6  7月  8 20:20 test.txt

Containerfileを使って、次の内容のイメージを作成します。
・ベースイメージにAlmaLinuxを使用する(FROM )
・ホストで作成したファイル(test.txt)をコンテナの /tmpにコピーする(COPY )

[user1@server ~]$ vi Containerfile
[user1@server ~]$ cat Containerfile
FROM docker.io/library/almalinux
COPY test.txt /tmp

イメージをビルドします。

[user1@server ~]$ podman build -t test_image .

ビルドしたイメージを確認します。

[user1@server ~]$ podman images
REPOSITORY                   TAG         IMAGE ID      CREATED        SIZE
localhost/test_image         latest      4d4957e1ef46  2 seconds ago  191 MB
docker.io/library/almalinux  latest      8109fa501eaf  6 weeks ago    191 MB

ビルドしたイメージ(test_image)からコンテナを起動します。

[user1@server ~]$ podman run -dit --name test1 test_image
ce501fb90adaa9828d45f3ad02fb2e24b242048228f42dbc095cfb4fa1265fcc

コンテナでbashを実行します。

[user1@server ~]$  podman exec -it test1 bash
[root@ce501fb90ada /]#

ホストからコンテナにコピーしたファイルを確認します。ファイルの所有者、所有グループはrootになっています。ファイルの所有者、所有グループの変更方法は後述します。

[root@ce501fb90ada /]# ls -l /tmp/test.txt
-rw-r--r--. 1 root root 6 Jul  8 11:20 /tmp/test.txt

コンテナからぬけます。

[root@ce501fb90ada /]# exit
exit

次の検証のため、コンテナ、イメージを削除します。

[user1@server ~]$ podman rm test1 --force
[user1@server ~]$ podman rmi -f $(podman images -q)

次は、コンテナ内にコピーしたファイルの所有者、所有グループをuser1に変更してみます。

[user1@server ~]$ cat Containerfile
FROM docker.io/library/almalinux
RUN adduser user1
COPY test.txt /tmp
RUN chown user1:user1 /tmp/test.txt

コンテナを起動してファイル(/tmp/test.txt)の所有者および所有グループを確認すると user1 に変更されていることが確認できます。

[root@45abd84d6676 /]# ls -l /tmp/test.txt
-rw-r--r--. 1 user1 user1 6 Jul  8 11:20 /tmp/test.txt

次の検証のため、コンテナ、イメージを削除します。

[user1@server ~]$ podman rm test1 --force
[user1@server ~]$ podman rmi -f $(podman images -q)

6.2 ADDディレクティブの使い方

6.2.1 圧縮ファイルのコピー

(1) 事前準備(圧縮ファイルの作成)
テスト用のファイルを作成します。

[user1@server ~]$ vi test.txt
[user1@server ~]$ cat test.txt
12345

テスト用の圧縮ファイルを作成します。

[user1@server ~]$ tar -zcvf test.tar.gz test.txt
test.txt

(2) ADDディレクティブの動作確認
Containerfileを使って、次の内容のイメージを作成します。
・ベースイメージにAlmaLinuxを使用する(FROM )
・ホストで作成した圧縮ファイル(test.tar.gz )を解凍してコンテナの/tmpにコピーする(ADD)

[user1@server ~]$ cat Containerfile
FROM docker.io/library/almalinux
ADD test.tar.gz /tmp/

イメージをビルドします。

[user1@server ~]$ podman build -t test_image .

ビルドしたイメージ(test_image)からコンテナを起動します。

[user1@server ~]$ podman run -dit --name test1 test_image
23fb9dc21856fd4dec4d02f1310a74d02468213c456dc66dd270bd39ed3b43ca

コンテナでbashを実行します。

[user1@server ~]$ podman exec -it test1 bash
[root@23fb9dc21856 /]#

ADD ディレクティブは圧縮ファイルを解凍してコンテナにコピーするため、ホストで作成した圧縮ファイルがコンテナ内で解凍されることが確認できます。

[root@23fb9dc21856 /]# cat /tmp/test.txt
12345

コンテナからぬけます。

[root@23fb9dc21856 /]# exit
exit

次の検証のため、コンテナ、イメージを削除します。

[user1@server ~]$ podman rm test1 --force
[user1@server ~]$ podman rmi -f $(podman images -q)
6.2.2 ディレクトリのコピー

ホストでテスト用のディレクトリ、ファイルを作成します。

[user1@server ~]$ mkdir host_dir
[user1@server ~]$ echo "12345" > host_dir/test1.txt
[user1@server ~]$ echo "67890" > host_dir/test2.txt

Containerfileを使って、次の内容のイメージを作成します。
・(FROM )
・ホストで作成したディレクトリ(host_dir )をコンテナの/tmpにコピーする(ADD)

[user1@server ~]$ cat Containerfile
FROM docker.io/library/almalinux
ADD host_dir /tmp

イメージをビルドします。

[user1@server ~]$ podman build -t test_image .

ビルドしたイメージ(test_image)からコンテナを起動します。

[user1@server ~]$ podman run -dit --name test1 test_image
ba931b22c906117c514d604b1a556cbc933665b4e39e3500d8e081a0b0c37183

コンテナでbashを実行します。

[user1@server ~]$ podman exec -it test1 bash
[root@ba931b22c906 /]#

コンテナで/tmp配下のファイルを確認します。ホストのhost_dir 配下に作成したファイルがコンテナの/tmp配下にコピーされていることが確認できます。

[root@ba931b22c906 /]# ls -l /tmp/*
-rw-r--r--. 1 root root 6 Jul 14 00:24 /tmp/test1.txt
-rw-r--r--. 1 root root 6 Jul 14 00:24 /tmp/test2.txt

コンテナからぬけます。

[root@ba931b22c906 /]# exit
exit

次の検証のため、コンテナ、イメージを削除します。

[user1@server ~]$ podman rm test1 --force
[user1@server ~]$ podman rmi -f $(podman images -q)

7 RUNディレクティブの使い方

Containerfileを使って、次の内容のイメージを作成します。
・ベースイメージにAlmaLinuxを使用する(FROM )
・iprouteパッケージをイメージにインストールする(RUN )

[user1@server ~]$ cat Containerfile
FROM docker.io/library/almalinux
RUN dnf -y install iproute

イメージをビルドします。

[user1@server ~]$ podman build -t test_image .

ビルドしたイメージを確認します。

[user1@server ~]$ podman images
REPOSITORY                   TAG         IMAGE ID      CREATED         SIZE
localhost/test_image         latest      f28aa2f7799c  54 seconds ago  238 MB
docker.io/library/almalinux  latest      8109fa501eaf  5 weeks ago     191 MB

ビルドしたイメージ(test_image)からコンテナを起動します。

[user1@server ~]$ podman run -dit --name test1 test_image
db3023492a4caf5ce9b0b653bc5b2ecb6cba5065ccf68de12e6ed268bc44631c

コンテナでbashを実行します。

[user1@server ~]$ podman exec -it test1 bash
[root@db3023492a4c /]#

コンテナでパッケージを確認すると、iprouteパッケージがインストールされていることが確認できます。

[root@db3023492a4c /]# rpm -qa|grep iproute
iproute-6.2.0-6.el9_4.x86_64

コンテナからぬけます。

[root@db3023492a4c /]# exit
exit

次の検証のため、コンテナ、イメージを削除します。

[user1@server ~]$ podman rm test1 --force
[user1@server ~]$ podman rmi -f $(podman images -q)

8 ENTRYPOINT/CMDディレクティブの使い方

Dockerfile リファレンス — Docker-docs-ja 24.0 ドキュメントによると、ENTRYPOINTディレクティブは以下の書式があります。 exec 形式が推奨されているようです。ここでも、ディレクティブはexec 形式を使用します。

  • exec 形式(推奨されている形式)
ENTRYPOINT ["実行ファイル", "パラメータ1", "パラメータ2"]
  • shell 形式
ENTRYPOINT コマンド パラメータ1 パラメータ2

Containerfileを使って、次の内容のイメージを作成します。
・ベースイメージにAlmaLinuxを使用する(FROM )
・コンテナ起動時に実行するプログラムを指定する(ENTRYPOINT )
・ENTRYPOINT で指定するコマンドのパラメータを指定する(CMD )

[user1@server ~]$ vi Containerfile
[user1@server ~]$ cat Containerfile
FROM docker.io/library/almalinux
ENTRYPOINT ["ping","-c","1"]
CMD ["example.com"]

イメージをビルドします。

[user1@server ~]$ podman build -t test_image .

もう1つターミナルを開いてtcpdumpを実行します。-iはインタフェース名を指定します。お使いの環境に合わせて適宜変更してください。なお。、tcpdumpの詳細な使い方は、tcpdumpの使い方(基本編) - hana_shinのLinux技術ブログを参照してください。

[root@server ~]# tcpdump -i enp1s0 icmp -n

ビルドしたイメージ(test_image)からコンテナを起動します。

[user1@server ~]$ podman run --name test1 test_image

tcpdumpの実行結果を確認すると、example.com(93.184.215.14)宛てのping実行結果が確認できます。

[root@server ~]# tcpdump -i enp1s0 icmp -n
22:21:10.429828 IP 192.168.122.87 > 93.184.215.14: ICMP echo request, id 20, seq 1, length 64
22:21:10.524670 IP 93.184.215.14 > 192.168.122.87: ICMP echo reply, id 20, seq 1, length 64

digコマンドで確認すると、example.comのIPアドレスは93.184.215.14であることが確認できます。なお、digコマンドの使い方は、digコマンドの使い方 - hana_shinのLinux技術ブログを参照してください。

[root@server ~]# dig example.com +short
93.184.215.14

次の検証のため、コンテナを削除します。

[user1@server ~]$ podman rm test1 --force

次に、コンテナ起動時にパラメータを明示的に指定します。指定するパラメータは、デフォルトゲートウェイのIPアドレス(192.168.122.1)です。

[user1@server ~]$ podman run --name test1 test_image 192.168.122.1

tcpdumpの実行結果を確認すると、example.comに対するpingの結果ではなく、デフォルトゲートウェイのIPアドレス(192.168.122.1)に対するpingの結果であることが確認できます。つまり、CMDで指定したパラメータがコンテナ起動時に指定したパラメータで上書きされたことがわかります。

[root@server ~]# tcpdump -i enp1s0 icmp -n
22:27:21.353640 IP 192.168.122.87 > 192.168.122.1: ICMP echo request, id 24, seq 1, length 64
22:27:21.353973 IP 192.168.122.1 > 192.168.122.87: ICMP echo reply, id 24, seq 1, length 64

次の検証のため、コンテナ、イメージを削除します。

[user1@server ~]$ podman rm test1 --force
[user1@server ~]$ podman rmi -f $(podman images -q)

9 EXPOSEディレクティブの使い方

Containerfileを使って、次の内容のイメージを作成します。
・ベースイメージにAlmaLinuxを使用する(FROM )
・コンテナのhttpdが80番ポートでリッスンする(EXPOSE )

[user1@server ~]$ vi Containerfile
[user1@server ~]$ cat Containerfile
FROM httpd:latest
EXPOSE 80

イメージをビルドします。

[user1@server ~]$ podman build -t test_image .

作成したイメージを確認します。

[user1@server ~]$ podman images
REPOSITORY               TAG         IMAGE ID      CREATED         SIZE
localhost/test_image     latest      72416f67c6ae  36 seconds ago  152 MB
docker.io/library/httpd  latest      c0c20df5e7be  5 days ago      152 MB

ビルドしたイメージ(test_image)からコンテナを起動します。このとき、-pオプションを使って、ホストの8080番ポートへのアクセスをコンテナの80番ポートにマッピングします。

[user1@server ~]$ podman run -d -p 8080:80 --name test1 test_image
1f8a374faf80f2bd28b48710de04b74f8d2cdc2ef98489f4e6d027136fc271d4

ポートのマッピングを確認します。ホストの任意(0.0.0.0)のIPアドレスに対する8080番ポートへのアクセスが、コンテナの80番ポートへのアクセスに変換されることが確認できます。

[user1@server ~]$ podman port test1
80/tcp -> 0.0.0.0:8080

curlコマンドを実行してホストの8080番ポートにアクセスしてみます。コンテナのhttpdからの応答を確認することができます。

[user1@server ~]$ curl http://localhost:8080
<html><body><h1>It works!</h1></body></html>

コンテナからぬけます。

[root@db3023492a4c /]# exit
exit

次の検証のため、コンテナ、イメージを削除します。

[user1@server ~]$ podman rm test1 --force
[user1@server ~]$ podman rmi -f $(podman images -q)

10 ENVディレクティブの使い方

Containerfileを使って、次の内容のイメージを作成します。
・ベースイメージにAlmaLinuxを使用する(FROM )
・環境変数(TEST)に文字列("Hello, World!")を設定する(ENV )
・環境変数に設定した文字列をechoコマンドで出力する(CMD )

[user1@server ~]$ cat Containerfile
FROM docker.io/library/almalinux
ENV TEST="Hello, World!"
CMD echo $TEST

イメージをビルドします。

[user1@server ~]$ podman build -t test_image .

ビルドしたイメージ(test_image)からコンテナを起動します。コンテナを起動する際に、環境変数TESTに設定した文字列が出力されることを確認できます。

[user1@server ~]$ podman run --name test1 test_image
Hello, World!

あと始末をします。

[user1@server ~]$ podman rm test1
test1

コンテナを実行する際に、設定された環境変数を上書きすることもできます。例えば、環境変数TESTに"bye"を設定してコンテナを起動してみます。この場合、コンテナが起動する際に、”Hello, World!”ではなく"bye"が出力されることを確認できます。

[user1@server ~]$ podman run -e TEST=bye --name test1 test_image
bye

次の検証のため、コンテナ、イメージを削除します。

[user1@server ~]$ podman rm test1 --force
[user1@server ~]$ podman rmi -f $(podman images -q)

11 LABELディレクティブの使い方

Containerfileを使って、次の内容のイメージを作成します。
・ベースイメージにAlmaLinuxを使用する(FROM )
・イメージにラベルをつける(LABEL )。ラベルの内容は、作成者(maintainer)、イメージのバージョン(version)、イメージの作成日(2024/7/10)

[user1@server ~]$ cat Containerfile
FROM docker.io/library/almalinux
LABEL maintainer="[email protected]"
LABEL version="1.0"
LABEL created="2024-07-10"

イメージをビルドします。

[user1@server ~]$ podman build -t test_image .

Podmanのinspectコマンドとjqコマンドを併用して、イメージに付けたラベルを確認してみます。なお、io.buildah.versionはBuildahのバージョン情報を示しており、ビルドツールが自動的に追加するものです。

[user1@server ~]$ podman inspect test_image --format '{{json .Config.Labels}}' | jq
{
  "created": "2024-07-10",
  "io.buildah.version": "1.33.7",
  "maintainer": "[email protected]",
  "version": "1.0"
}

次の検証のため、イメージを削除します。

[user1@server ~]$ podman rmi -f $(podman images -q)

12 WORKDIRディレクティブの使い方

Containerfileを使って、次の内容のイメージを作成します。
・ベースイメージにAlmaLinuxを使用する(FROM )
・作業ディレクトリを /etc に変更する(WORKDIR )
・ファイル(test.conf)に文字列を書き込む(RUN )

[user1@server ~]$ cat Containerfile
FROM docker.io/library/almalinux
WORKDIR /etc
RUN echo "Hello" > test.conf

イメージをビルドします。

[user1@server ~]$ podman build -t test_image .

ビルドしたイメージ(test_image)からコンテナを起動します。

[user1@server ~]$ podman run -dit --name test1 test_image
734466e173c07719688d9deb0304eacc4ece68bdb3cbc58685b47954142c8eae

コンテナでbashを実行します。

[user1@server ~]$ podman exec -it test1 bash
[root@734466e173c0 etc]#

作業ディレクトリを確認すると /etc であることが確認できます。

[root@734466e173c0 etc]# pwd
/etc

ファイル(test.conf)に書き込んだ内容を確認すると、"Hello"であることが確認できます。

[root@734466e173c0 etc]# cat test.conf
Hello

コンテナからぬけます。

[root@734466e173c0 etc]# exit
exit

次の検証のため、コンテナ、イメージを削除します。

[user1@server ~]$ podman rm test1 --force
[user1@server ~]$ podman rmi -f $(podman images -q)

13 USERディレクティブの使い方

Containerfileを使って、次の内容のイメージを作成します。
・ベースイメージにAlmaLinuxを使用する(FROM )
・ユーザー(user2)を作成する(RUN )
・実行ユーザーをuser2に変更する(USER )
・作業ディレクトリを/home/user2に変更する(USER )

[user1@server ~]$ cat Containerfile
FROM docker.io/library/almalinux
RUN adduser user2
USER user2
WORKDIR /home/user2

イメージをビルドします。

[user1@server ~]$ podman build -t test_image .

ビルドしたイメージ(test_image)からコンテナを起動します。

[user1@server ~]$ podman run -dit --name test1 test_image
ae3345f70a53062894ff5b050ff48fe7225553d0799d97f2e38baddee92a1692

コンテナでbashを実行します。

[user1@server ~]$ podman exec -it test1 bash
[user2@ae3345f70a53 ~]$

idコマンドを使用してユーザー名を確認してみます。ユーザ名がuser2であることが確認できます。

[user2@ae3345f70a53 ~]$ id
uid=1000(user2) gid=1000(user2) groups=1000(user2)

次に、pwdコマンドを使用して現在の作業ディレクトリを確認すると、作業ディレクトリが/home/user2であることが確認できます。

[user2@ae3345f70a53 ~]$ pwd
/home/user2

コンテナからぬけます。

[user2@ae3345f70a53 ~]$ exit
exit

次の検証のため、コンテナ、イメージを削除します。

[user1@server ~]$ podman rm test1 --force
[user1@server ~]$ podman rmi -f $(podman images -q)

Y 参考図書

今回の記事執筆にあたり参考にした図書は以下のものです。

単行本


Docker実践ガイド 第3版 (impress top gear)

電子書籍

c.scripts[c.scripts.length-2];(b[a].q=b[a].q []).push(arguments)};

c.getElementById(a)||(d=c.createElement(f),d.src=g,
d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})
(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");
msmaflink({"n":"Software Design (ソフトウェアデザイン) 2023年11月号 [雑誌]","b":"","t":"","d":"https:\/\/m.media-amazon.com","c_p":"","p":["\/images\/I\/51gnbOVIwuL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/B0CKF3J1M9","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/B0CKF3J1M9","a_id":3177459,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":5,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/Software%20Design%20(%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3)%202023%E5%B9%B411%E6%9C%88%E5%8F%B7%20%5B%E9%9B%91%E8%AA%8C%5D\/","a_id":3177083,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2}],"eid":"ax2oE","s":"s"});


Software Design (ソフトウェアデザイン) 2023年11月号 [雑誌]


Docker実践ガイド 第3版 impress top gearシリーズ


Z 参考情報

私が業務や記事執筆で参考にした書籍を以下のページに記載します。
Linux技術のスキルアップをしよう! - hana_shinのLinux技術ブログ
Rootless コンテナはいいぞ - Speaker Deck
CentOS 8 : Podman : Dockerfile を利用する : Server World

https://pocketstudio.net/2020/01/31/cmd-and-entrypoint/#google_vignette
https://www.grandream.jp/blog/docker-cmd-entrypoint

Podmanでコンテナ/ホスト間でファイルをコピーする方法

1 はじめに

  • コンテナ/ホスト間でファイルをコピーする方法
  • ボリュームをマウントする方法
  • コンテナをイメージ化する方法

2 検証環境

サーバのAlmaLinux版数は以下のとおりです。

[root@server ~]# cat /etc/redhat-release
AlmaLinux release 9.2 (Turquoise Kodkod)

カーネル版数は以下のとおりです。

[root@server ~]# uname -r
5.14.0-284.11.1.el9_2.x86_64

SELinuxは有効にしておきます。

[root@server ~]# getenforce
Enforcing

3 インストール方法

podmanパッケージをインストールします。

[root@server ~]# dnf -y install podman

podmanコマンドの版数を確認します。

[root@server ~]# podman -v
podman version 4.9.4-rhel

4 事前準備

テスト用のユーザを作成します。

[root@server ~]# useradd user1

user1のパスワードを設定します。

[root@server ~]# passwd user1

以降の作業は、一般ユーザで実行します。

[user1@server ~]$ id
uid=1000(user1) gid=1000(user1) groups=1000(user1) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

almalinuxイメージをダウンロードします。

[user1@server ~]$ podman pull almalinux

ダウンロードしたイメージを確認します。

[user1@server ~]$ podman images
REPOSITORY                   TAG         IMAGE ID      CREATED      SIZE
docker.io/library/almalinux  latest      8109fa501eaf  4 weeks ago  191 MB

5 コンテナ/ホスト間でファイルをコピーする方法

コンテナとホストの間でファイルをコピーする方法について説明します。
書式は以下のとおりです。

  • ホストからコンテナにファイルをコピーする時
$ podman cp ホスト側パス コンテナ名:コンテナ側パス
  • コンテナからホストにファイルをコピーする時
$ podman cp コンテナ名:コンテナ側パス ホスト側パス

5.1 ホストからコンテナにファイルをコピーする方法

test1という名前のコンテナを起動します。

[user1@server ~]$ podman run -dit --name test1 almalinux
06ed782d14df2a869b2a3b10eaee8a59c1e55a28f834ad7c4836eebed4bd222c

起動したコンテナを確認します。

[user1@server ~]$ podman ps
CONTAINER ID  IMAGE                               COMMAND     CREATED         STATUS         PORTS       NAMES
06ed782d14df  docker.io/library/almalinux:latest  /bin/bash   11 seconds ago  Up 11 seconds              test1

コンテナにコピーするファイルを作成します。

[user1@server ~]$ echo "test" > test.txt
[user1@server ~]$ cat /home/user1/test.txt
test

ファイルをコンテナの/tmpにコピーします。

[user1@server ~]$ podman cp /home/user1/test.txt test1:/tmp

コンテナでbashコマンドを実行します。

[user1@server ~]$ podman exec -it test1 bash
[root@06ed782d14df /]#

コピーしたファイルを確認します。ホストで作成したファイルがコンテナにコピーできていることが確認できます。

[root@06ed782d14df /]# cat /tmp/test.txt
test

5.2 コンテナからホストにファイルをコピーする方法

ホストにコピーするファイルを作成します。

[root@06ed782d14df /]# echo "12345" > /tmp/test.txt

作成したファイルの中身を確認します。

[root@06ed782d14df /]# cat /tmp/test.txt
12345

コンテナから抜けます。

[root@06ed782d14df /]# exit
exit

コンテナの /tmp/test.txt をホストの /home/user1/test2.txt にコピーします。

[user1@server ~]$ podman cp test1:/tmp/test.txt /home/user1/test2.txt

コピーしたファイルを確認します。コンテナで作成したファイルがホストにコピーできていることが確認できます。

[user1@server ~]$ cat /home/user1/test2.txt
12345

6 マウントする方法

6.1 概要

ボリュームやファイル/ディレクトリのマウントについて説明します。

マウント方法 概要
ボリュームマウント ボリュームとは、ハードディスクの1つの領域です。作成したボリュームをコンテナ内にマウントする方法です。これにより、データを永続的に保存することができます。例えば、コンテナが削除されたり再起動されたりしても、ボリュームに保存されたデータは失われません。ボリュームは、コンテナ間でデータを共有するためにも使用されます。
バインドマウント ホストの特定のファイルやディレクトリをコンテナ内にマウントする方法です。これにより、ホスト上のデータをコンテナ内から直接アクセスすることができます

6.2 ボリュームマウント

ボリューム(vol1)を作成します。

[user1@server ~]$ podman volume create vol1
vol1

作成したボリュームを確認します。vol1という名前のボリュームが作成されたことがわかります。

[user1@server ~]$ podman volume ls
DRIVER      VOLUME NAME
local       vol1

コンテナ(test1)を起動します。このとき、作成したボリューム(vol1)をコンテナの/mntにマウントします。

[user1@server ~]$ podman run -dit --name test1 -v vol1:/mnt docker.io/library/almalinux
efe1bcf540fc2e947b1f22028b7a297798eccd3934951a0c76de55c2995ba5d1

起動したコンテナでbashコマンドを実行します。

[user1@server ~]$ podman exec -it test1 bash
[root@efe1bcf540fc /]#

マウントしたボリュームにファイルを作成します。

[root@efe1bcf540fc /]# echo "12345" > /mnt/file1.txt
[root@efe1bcf540fc /]# cat /mnt/file1.txt
12345

コンテナからぬけます。

[root@efe1bcf540fc /]# exit
exit

コンテナ(test2)を起動します。このとき、作成したボリューム(vol1)をコンテナの/mntにマウントします。

[user1@server ~]$ podman run -dit --name test2 -v vol1:/mnt docker.io/library/almalinux
2f54ed031bcae970db373f2a5e479db34e6f588c4a5b1ae179f60bfdfbffef5f

起動したコンテナでbashコマンドを実行します。

[user1@server ~]$ podman exec -it test2 bash
[root@2f54ed031bca /]#

マウントしたボリューム内のファイルの内容を確認します。このファイルはtest1コンテナで作成されたものですが、test2コンテナでもその内容を参照できることが確認できます。

[root@2f54ed031bca /]# cat /mnt/file1.txt
12345

コンテナからぬけます。

[root@2f54ed031bca /]# exit
exit

コンテナを削除します。

[user1@server ~]$ podman rm test1 test2 --force

作成したボリュームを削除します。

[user1@server ~]$ podman volume rm vol1
vol1

6.3 バインドマウント

SELinuxが有効な場合、マウントしたボリュームやファイルにアクセスできません。マウントする際、状況に応じて z(小文字)または Z(大文字)を指定する必要があります。これらのオプションを指定すると、PodmanがボリュームやファイルのSELinuxコンテキストを再ラベルします。これにより、コンテナがマウントしたボリュームやファイルにアクセスできるようになります。

オプション 概要
z(小文字) 複数のコンテナでボリュームやファイルを共有する場合
Z(大文字) 他のコンテナとボリュームやファイルを共有しない場合

podman-run — Podman documentationよりオプションの説明を以下に引用します。

To change a label in the container context, add either of two suffixes :z or :Z to the volume mount. 
These suffixes tell Podman to relabel file objects on the shared volumes. 
The z option tells Podman that two or more containers share the volume content. 
As a result, Podman labels the content with a shared content label. 
Shared volume labels allow all containers to read/write content. 
The Z option tells Podman to label the content with a private unshared label Only the current container can use a private volume. 
Relabeling walks the file system under the volume and changes the label on each file, 
if the volume has thousands of inodes, this process takes a long time, delaying the start of the container. 
If the volume was previously relabeled with the z option, Podman is optimized to not relabel a second time. 
If files are moved into the volume, then the labels can be manually change with the chcon -Rt container_file_t PATH command.

コンテナがマウントするディレクトリを作成します。

[root@server ~]# mkdir /host_dir

作成したディレクトリの所有者(ユーザ、グループ)をrootからuser1に変更します。

[root@server ~]# chown user1:user1 /host_dir/

ディレクトリの所有者(ユーザ、グループ)を確認します。所有者がuser1に変更されたことがわかります。また、/host_dirのコンテキストは以下のようになっています。

  • ユーザ:unconfined_u
  • ロール:object_r
  • タイプ:default_t
[root@server ~]# ls -ldZ /host_dir
drwxr-xr-x. 2 user1 user1 unconfined_u:object_r:default_t:s0 6  7月  7 22:50 /host_dir

マウントするディレクトリにファイルを作成します。

[user1@server ~]$ echo "12345" > /host_dir/test.txt
[user1@server ~]$ cat /host_dir/test.txt
12345

コンテナを起動します。このとき、大文字のZを指定して、マウントするディレクトリを他のコンテナと共有しないようにしてみます。

[user1@server ~]$ podman run --name test1 -dit -v /host_dir:/var:Z docker.io/library/almalinux:latest
265a303d3dcf22b80d21f90b34d5f283fcf40db273fb71a209588c7c37278c2e

起動したコンテナでbashコマンドを実行します。

[user1@server ~]$ podman exec -it test1 bash
[root@265a303d3dcf /]#

マウントしたディレクトリのファイルの中身を確認します。

[root@265a303d3dcf /]# cat /var/test.txt
12345

コンテナからぬけます。

[root@265a303d3dcf /]# exit
exit

あと始末をします。

[user1@server ~]$ podman rm test1 --force

マウントしたディレクトリのSELinuxコンテキストを確認します。コンテキストのタイプがdefault_tからcontainer_file_tに変更されていることがわかります。これは、Zオプションを付けることで、コンテナが/host_dirにアクセスできるように、ディレクトリのコンテキストタイプがdefault_tからcontainer_file_tに変更されたためです。

[user1@server ~]$ ls -ldZ /host_dir
drwxr-xr-x. 2 user1 user1 system_u:object_r:container_file_t:s0:c168,c334 22  7月  7 22:53 /host_dir

タイプを元のdefault_t に戻す場合は、以下のようにchconコマンドを実行します。

[user1@server ~]$ chcon -t default_t /host_dir

ディレクトリのSELinuxコンテキストを確認します。コンテキストのタイプがdefault_tに戻ったことがわかります。

[user1@server ~]$ ls -ldZ /host_dir/
drwxr-xr-x. 2 user1 user1 system_u:object_r:default_t:s0:c168,c334 22  7月  7 22:53 /host_dir/

7 イメージを作成する方法(commit)

イメージを作成する方法は2つあります。
1. podman commitコマンドでコンテナをイメージに書き出す方法
2. Containerfileからイメージを作成する方法
ここでは、1について説明します。2については別の記事で説明します。

イメージを確認します。

[user1@server ~]$ podman images
REPOSITORY                   TAG         IMAGE ID      CREATED      SIZE
docker.io/library/almalinux  latest      8109fa501eaf  4 weeks ago  191 MB

イメージ(almalinux)からコンテナ(test1)を起動します。

[user1@server ~]$ podman run -dit --name test1 almalinux
9bfd0427bbdd1482f17ea78a9b717b9b3e6f86298c924ae4d99508ad0b2d118c

コンテナ(test1)に入り、bashシェルを起動します。

[user1@server ~]$ podman exec -it test1 bash
[root@9bfd0427bbdd /]#

ipコマンドの版数を確認してみます。しかし、イメージ(almalinux)にはipコマンドが入っていないので、エラーになります。

[root@9bfd0427bbdd /]# ip -V
bash: ip: command not found

dnfコマンドを実行して、iprouteパッケージをインストールします。

[root@9bfd0427bbdd /]# dnf -y install iproute

ipコマンドの版数を確認します。

[root@9bfd0427bbdd /]# ip -V
ip utility, iproute2-6.2.0, libbpf 1.3.0

コンテナから抜けます。

[root@9bfd0427bbdd /]# exit
exit

もう1つターミナルを開いて、コンテナをイメージ(test-ip)に書き出します。

[user1@server ~]$ podman commit test1 test1-ip
Getting image source signatures
Copying blob 926bdaa81747 skipped: already exists
Copying blob 878b4f5d7422 done   |
Copying config f88cafa116 done   |
Writing manifest to image destination
f88cafa116a62a69141aed482e81a49280712084662cb5a4176202c5940231b1

イメージを確認すると、test1-ipという名前のイメージが作成できたことがわかります。

[user1@server ~]$ podman images
REPOSITORY                   TAG         IMAGE ID      CREATED             SIZE
localhost/test1-ip           latest      f88cafa116a6  About a minute ago  238 MB
docker.io/library/almalinux  latest      8109fa501eaf  4 weeks ago         191 MB

イメージ(test1-ip)からコンテナ(test2)を起動します。

[user1@server ~]$ podman run -dit --name test2 test1-ip
fe5e178feca69b92b753d7f7b3963080fdfb55792f5003e5de3a48c0fb3c1cd9

コンテナ(test2)に入り、bashシェルを起動します。

[user1@server ~]$ podman exec -it test2 bash
[root@fe5e178feca6 /]#

ipコマンドのバージョンを確認します。イメージ(test1-ip)には最初からipコマンドが含まれているため、ipコマンドのバージョン確認をしてもエラーにならないことが確認できます。

[root@fe5e178feca6 /]# ip -V
ip utility, iproute2-6.2.0, libbpf 1.3.0

Y 参考図書

今回の記事執筆にあたり参考にした図書は以下のものです。

単行本


Docker実践ガイド 第3版 (impress top gear)

電子書籍

c.scripts[c.scripts.length-2];(b[a].q=b[a].q []).push(arguments)};

c.getElementById(a)||(d=c.createElement(f),d.src=g,
d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})
(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");
msmaflink({"n":"Software Design (ソフトウェアデザイン) 2023年11月号 [雑誌]","b":"","t":"","d":"https:\/\/m.media-amazon.com","c_p":"","p":["\/images\/I\/51gnbOVIwuL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/B0CKF3J1M9","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/B0CKF3J1M9","a_id":3177459,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":5,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/Software%20Design%20(%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3)%202023%E5%B9%B411%E6%9C%88%E5%8F%B7%20%5B%E9%9B%91%E8%AA%8C%5D\/","a_id":3177083,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2}],"eid":"ax2oE","s":"s"});


Software Design (ソフトウェアデザイン) 2023年11月号 [雑誌]


Docker実践ガイド 第3版 impress top gearシリーズ

Z 参考情報

私が業務や記事執筆で参考にした書籍を以下のページに記載します。
Linux技術のスキルアップをしよう! - hana_shinのLinux技術ブログ

Rootless コンテナはいいぞ - Speaker Deck

コンテナイメージのレジストリ検索方法(Podman編)

1 はじめに

以下の項目について、コンテナに関する記事を作成しました。

2 検証環境

ホストのAlmaLinux版数は以下のとおりです。

[root@server ~]# cat /etc/redhat-release
AlmaLinux release 9.2 (Turquoise Kodkod)

カーネル版数は以下のとおりです。

[root@server ~]# uname -r
5.14.0-284.11.1.el9_2.x86_64

3 レジストリとリポジトリについて

レジストリは、コンテナイメージを保存し配布する場所です。レジストリの中には複数のリポジトリがあり、それぞれのリポジトリでコンテナイメージを管理します。

レジストリ 概要
registry.access.redhat.com Red Hat社が提供するレジストリです。レジストリを利用するさい、認証は不要です
registry.redhat.io Red Hat社が提供するレジストリです。レジストリを利用するさい、認証が必要です。あらかじめRedHatのアカウントを持っている必要があります。Red Hat社 の配布するコンテナーイメージは registry.redhat.io に移行しつつあるようです
registry.connect.redhat.com Red Hat社が提供するサードパーティ製品のレジストリです。レジストリを利用するさい、認証が必要です。あらかじめRedHatのアカウントを持っている必要があります
docker.io Docker社が提供するレジストリです
quay.io CoreOSによって開発されました。CoreOSは後にRed Hatによって買収され、現在はRed Hatが運営されています

Red Hat コンテナーレジストリーの認証 - Red Hat Customer Portal

4 イメージの名前(短縮名およびFQIN)について

コンテナのイメージ名は以下の呼び方があります。

名前 概要
FQIN(Fully Qualified Image Name) レジストリ名/リポジトリ名/イメージ名で指定する名前です
短縮名 イメージ名で指定する名前です

短縮名は以下のファイルに定義されています。例えば、短縮名 "almalinux" は、FQINでは "docker.io/library/almalinux" となります。

[root@server ~]# cat /etc/containers/registries.conf.d/000-shortnames.conf
[aliases]
  # almalinux
  "almalinux" = "docker.io/library/almalinux"
  "almalinux-minimal" = "docker.io/library/almalinux-minimal"
-snip-

短縮名(almalinux)を使ってイメージをダウンロードしてみます。ダウンロード中の様子を確認すると、1行目で短縮名をFQINに変換している旨が表示されているのがわかります。そして、2行目でFQINを指定してイメージをダウンロードしていることがわかります。

[root@server ~]# podman pull almalinux
Resolved "almalinux" as an alias (/etc/containers/registries.conf.d/000-shortnames.conf)
Trying to pull docker.io/library/almalinux:latest...
Getting image source signatures
Copying blob 5f50a3278457 skipped: already exists
Copying config ac7ec62599 done   |
Writing manifest to image destination
ac7ec6259981906060844582e873ea43f41c6045fdbd8969d22bb6f0ec044219

ダウンロードしたイメージを確認すると、イメージの名前が FQIN であることがわかります。

[root@server ~]# podman images
REPOSITORY                   TAG         IMAGE ID      CREATED      SIZE
docker.io/library/almalinux  latest      ac7ec6259981  3 weeks ago  191 MB

registries.conf の注意事項には、短縮名を使用すると偽装されたイメージをダウンロードする可能性があることが述べられています。そのため、短縮名ではなくFQINの使用が推奨されています。さらに、イメージをハッシュ値でダウンロードすることで、偽装されたイメージではなく、意図したイメージを確実にダウンロードすることができます。

[root@server ~]# cat /etc/containers/registries.conf
# NOTE: RISK OF USING UNQUALIFIED IMAGE NAMES
# We recommend always using fully qualified image names including the registry
# server (full dns name), namespace, image name, and tag
# (e.g., registry.redhat.io/ubi8/ubi:latest). Pulling by digest (i.e.,
# quay.io/repository/name@digest) further eliminates the ambiguity of tags.
# When using short names, there is always an inherent risk that the image being
# pulled could be spoofed. For example, a user wants to pull an image named
-snip

5 レジストリの検索について

Podmanには、イメージの格納場所を検索する際のデフォルトのレジストリが定義されています。ただし、この定義はPodmanをパッケージ化したディストリビューションによって異なります。Podman infoコマンドを使用すると、以下の3つのレジストリがイメージの検索対象であることがわかります。

[root@server ~]# podman info
-snip-
registries:
  search:
  - registry.access.redhat.com
  - registry.redhat.io
  - docker.io

jqコマンドを使用して、Podmanに設定されているレジストリのリストを表示してみます。

[root@server ~]# podman info --format json | jq '.registries'
{
  "search": [
    "registry.access.redhat.com",
    "registry.redhat.io",
    "docker.io"
  ]
}

なお、デフォルトで検索するレジストリは、registries.confに定義されていることが確認できます。

[root@server ~]# cat /etc/containers/registries.conf
-snip-
unqualified-search-registries = ["registry.access.redhat.com", "registry.redhat.io", "docker.io"]

6 認証が必要なレジストリからイメージをダウンロードする方法

registry.redhat.ioからイメージをダウンロードする場合、ID/パスワードによるユーザ認証が必要になります。

6.1 アカウントの作成

以下のページにアクセスしてアカウントを作成します。ここで作成したアカウントは、registry.redhat.ioとregistry.connect.redhat.comの両方に使用できます。
https://sso.redhat.com/auth/realms/redhat-external/login-actions/registration?client_id=customer-portal&tab_id=c1freLsJpuA

6.2 イメージのダウンロード

レジストリ(registry.redhat.io)に存在するrsyslogイメージを検索してみます。この中から、rhel9リポジトリのrsyslogイメージをダウンロードしてみます(下記1行目のイメージ)。

[root@server ~]# podman search registry.redhat.io/rsyslog
NAME                                                          DESCRIPTION
registry.redhat.io/rhel9/rsyslog                              rhcc_registry.access.redhat.com_rhel9/rsyslo...
registry.redhat.io/rhel7/rsyslog                              A containerized version of the rsyslog utili...
registry.redhat.io/rhel8/rsyslog                              Rocket Fast System For Log Processing (rsysl...
registry.redhat.io/rhosp-rhel8/openstack-rsyslog              openstack-rsyslog
registry.redhat.io/rhosp-beta/openstack-rsyslog               openstack-rsyslog
registry.redhat.io/rhosp-rhel8/openstack-rsyslog-base         openstack-rsyslog-base
registry.redhat.io/rhosp-dev-preview/openstack-rsyslog-rhel9  Red Hat Red Hat OpenStack image for openstac...
registry.redhat.io/rhosp-rhel9/openstack-rsyslog              rhcc_registry.access.redhat.com_rhosp-rhel9/...
registry.redhat.io/rhoso-beta/openstack-rsyslog-rhel9         Red Hat Red Hat OpenStack Services on OpenSh...

rhel9のリポジトリからrsyslogイメージをダウンロードしようとしましたが、レジストリ(registry.redhat.io)にログインしていないため、認証に失敗し、イメージをダウンロードできませんでした。

[root@server ~]# podman pull registry.redhat.io/rhel9/rsyslog
Trying to pull registry.redhat.io/rhel9/rsyslog:latest...
Error: initializing source docker://registry.redhat.io/rhel9/rsyslog:latest: unable to retrieve auth token: invalid username/password: unauthorized: Please login to the Red Hat Registry using your Customer Portal credentials. Further instructions can be found here: https://access.redhat.com/RegistryAuthentication

レジストリ(registry.redhat.io)にログインします。

[root@server ~]# podman login registry.redhat.io
Username: test_user
Password:
Login Succeeded!

rhel9リポジトリからrsyslogイメージをダウンロードします。今回は、イメージをダウンロードすることができました。

[root@server ~]# podman pull registry.redhat.io/rhel9/rsyslog
Trying to pull registry.redhat.io/rhel9/rsyslog:latest...
Getting image source signatures
Checking if image destination supports signatures
Copying blob 7de73bed2a9f done   |
Copying blob edab65b863ae done   |
Copying config e3197b3b88 done   |
Writing manifest to image destination
Storing signatures
e3197b3b884c5cd6b32a39801f1c21965cbbee63adc46df86ec8a56553a20f14

ダウンロードしたイメージを確認します。rhel9リポジトリからrsyslogイメージの最新版がダウンロードされたことが確認できます。

[root@server ~]# podman images rsyslog
REPOSITORY                        TAG         IMAGE ID      CREATED      SIZE
registry.redhat.io/rhel9/rsyslog  latest      e3197b3b884c  2 weeks ago  243 MB

レジストリ(registry.redhat.io)からログアウトします。

[root@server ~]# podman logout registry.redhat.io
Removed login credentials for registry.redhat.io

Y 参考図書

今回の記事執筆にあたり参考にした図書は以下のものです。

単行本


Docker実践ガイド 第3版 (impress top gear)

電子書籍

c.scripts[c.scripts.length-2];(b[a].q=b[a].q []).push(arguments)};

c.getElementById(a)||(d=c.createElement(f),d.src=g,
d.id=a,e=c.getElementsByTagName("body")[0],e.appendChild(d))})
(window,document,"script","//dn.msmstatic.com/site/cardlink/bundle.js?20220329","msmaflink");
msmaflink({"n":"Software Design (ソフトウェアデザイン) 2023年11月号 [雑誌]","b":"","t":"","d":"https:\/\/m.media-amazon.com","c_p":"","p":["\/images\/I\/51gnbOVIwuL._SL500_.jpg"],"u":{"u":"https:\/\/www.amazon.co.jp\/dp\/B0CKF3J1M9","t":"amazon","r_v":""},"v":"2.1","b_l":[{"id":1,"u_tx":"Amazonで見る","u_bc":"#f79256","u_url":"https:\/\/www.amazon.co.jp\/dp\/B0CKF3J1M9","a_id":3177459,"p_id":170,"pl_id":27060,"pc_id":185,"s_n":"amazon","u_so":1},{"id":5,"u_tx":"楽天市場で見る","u_bc":"#f76956","u_url":"https:\/\/search.rakuten.co.jp\/search\/mall\/Software%20Design%20(%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3)%202023%E5%B9%B411%E6%9C%88%E5%8F%B7%20%5B%E9%9B%91%E8%AA%8C%5D\/","a_id":3177083,"p_id":54,"pl_id":27059,"pc_id":54,"s_n":"rakuten","u_so":2}],"eid":"ax2oE","s":"s"});


Software Design (ソフトウェアデザイン) 2023年11月号 [雑誌]


Docker実践ガイド 第3版 impress top gearシリーズ

Z 参考情報

私が業務や記事執筆で参考にした書籍を以下のページに記載します。
Linux技術のスキルアップをしよう! - hana_shinのLinux技術ブログ

コンテナーの構築、実行、および管理 | Red Hat Product Documentation

Podman Networkをやってみる | Reafnex
The tale of a single register value