Skip to content

Chapter 3 ボリューム

  • レベル:初級
  • 見込み時間:20分
  • コンテンツ

事前作業

一般ユーザー(ユーザー名 rhel)にスイッチする
# su - rhel

(コピペ用)

su - rhel

出力結果
# su - rhel
$

3.1 コンテナでのボリュームの使用

コンテナでのボリュームの使用

(このコンテンツは本書 3.1に該当します)

htmlディレクトリを作成し、その中にindex.htmlファイルを作成します

$ mkdir html
$ cat > html/index.html << _EOF
<html>
 <head>
 </head>
 <body>
  <h1>Goodbye World</h1>
 </body>
</html>
_EOF

(コピペ用)

mkdir html

cat > html/index.html << _EOF
<html>
 <head>
 </head>
 <body>
  <h1>Goodbye World</h1>
 </body>
</html>
_EOF

出力結果はありません

podman runコマンド実行時に-vオプションを使用することで、ホスト上のコンテンツをコンテナ内にマウントすることができます。

-v ./html:/var/www/html:ro,zオプションを使用してコンテナを起動します

:ro,zオプションについて

:roオプションはボリュームをコンテナ内で読み取り専用モードでマウントします。 :zオプションはSELinuxのラベルを、コンテナが読み書きできるように再ラベル付けします。詳細は本書3.1.2内のSELinux のボリュームオプションを参照ください。

$ podman run -d -v ./html:/var/www/html:ro,z -p 8080:8080 quay.io/rhatdan/myimage

(コピペ用)

podman run -d -v ./html:/var/www/html:ro,z -p 8080:8080 quay.io/rhatdan/myimage

出力結果
$ podman run -d -v ./html:/var/www/html:ro,z -p 8080:8080 quay.io/rhatdan/myimage
Trying to pull quay.io/rhatdan/myimage:latest...
Getting image source signatures
Copying blob e3460238f8a1 done  
Copying blob c7765172d3ce done  
Copying blob dfd8c625d022 done  
Copying blob 2b782a9ad894 done  
Copying blob a1eadb69adf1 done  
Copying config 2c7e43d880 done  
Writing manifest to image destination
Storing signatures
654cf2e2a6382f901b775296691cdf47231efd7da6c1bdb877f00ef9c4d6a654

curlコマンドでアクセスして確認します

$ curl localhost:8080

(コピペ用)

curl localhost:8080

出力結果
$ curl localhost:8080
<html>
 <head>
 </head>
 <body>
 <h1>Goodbye World</h1>
 </body>
</html>

podman rmコマンドを使用して実行中のコンテナを削除します。コンテナの削除後もコンテナ内にマウントしたコンテンツは削除されません。

--latest--forceオプションについて

podman rmコマンドに合わせて--latest--forceオプションを付けることで、少ないコマンドで実行中のコンテナを強制的に削除できます。

--latestまたは-lはコンテナ名やIDの代わりに最後に作成されたコンテナを使用します。 --forceまたは-fは実行中または一時停止中のコンテナを強制的に削除します。

$ podman rm --latest --force

(コピペ用)

podman rm --latest --force

出力結果
$ podman rm --latest --force
654cf2e2a6382f901b775296691cdf47231efd7da6c1bdb877f00ef9c4d6a654

(オプション問題)

htmlディレクトリの中を確認し、コンテンツが削除されていないことを確認します

$ ls -l html

(コピペ用)

ls -l html

出力結果
$ ls -l html

htmlディレクトリを削除します

$ rm -rf html

(コピペ用)

rm -rf html

出力結果はありません

名前付きボリューム

(このコンテンツは本書 3.1.1に該当します)

Podmanのコンテナでデータを永続化する別の仕組みとして「名前付きボリューム(または単にボリュームと呼ぶ)」があります。 名前付きボリュームはpodman volume createコマンドで作成できます。名前付きボリュームの実体はホスト上の特定のパス(ローカルコンテナストレージ)にあります。

podman volume createコマンドを使用してボリュームwebdataを作成します

$ podman volume create webdata

(コピペ用)

podman volume create webdata

出力結果
$ podman volume create webdata
webdata

ボリュームの情報を確認します

$ podman volume inspect webdata

(コピペ用)

podman volume inspect webdata

出力結果
$ podman volume inspect webdata
[
     {
          "Name": "webdata",
          "Driver": "local",
          "Mountpoint": "/home/rhel/.local/share/containers/storage/volumes/webdata/_data",
          "CreatedAt": "2023-09-11T15:55:56.024196806Z",
          "Labels": {},
          "Scope": "local",
          "Options": {},
          "MountCount": 0,
          "NeedsCopyUp": true,
          "NeedsChown": true
     }
]

ボリューム内にコンテンツを格納するために、ローカルコンテナストレージ上のディレクトリにコンテンツを作成します。

ホスト上で名前付きボリュームにコンテンツを作成する

この例では、/home/rhel/.local/share/containers/storage/volumes/webdata/_data/にコンテンツを作成することで、ボリューム内にコンテンツを作成したことと同等の結果を得られます。

$ cat > /home/rhel/.local/share/containers/storage/volumes/webdata/_data/index.html << _EOL
<html>
 <head>
 </head>
 <body>
 <h1>Goodbye World</h1>
 </body>
</html>
_EOL

(コピペ用)

cat > /home/rhel/.local/share/containers/storage/volumes/webdata/_data/index.html << _EOL
<html>
 <head>
 </head>
 <body>
 <h1>Goodbye World</h1>
 </body>
</html>
_EOL

出力結果はありません

-vオプションでホスト上のコンテンツをコンテナにマウントしたのと同様に、名前付きボリュームをコンテナにマウントすることができます。

-vオプションで名前付きボリュームwebdataを使用してコンテナを作成します

$ podman run -d -v webdata:/var/www/html:ro,z -p 8080:8080 quay.io/rhatdan/myimage
(コピペ用)
podman run -d -v webdata:/var/www/html:ro,z -p 8080:8080 quay.io/rhatdan/myimage

出力結果
$ podman run -d -v webdata:/var/www/html:ro,z -p 8080:8080 quay.io/rhatdan/myimage
8c1c69967f9cef8a0de312f65cb0e70c0be2e6af3965d299aec75e8f39d6e25a

(オプション問題)

curlコマンドやブラウザを使ってボリュームに作成したコンテンツ(Goodbye Worldが表示される)にアクセスできるか確認しましょう

podman stopコマンドを使用して実行中のコンテナを一時停止します。

-t 0オプションとコンテナIDを指定してコンテナを停止します。コンテナIDはご自身の環境のものを指定してください。

-t 0オプションについて

--timeまたは-tオプションは、強制的に停止するまでの待機時間を秒数で指定します。-t 0の場合は即座に停止が実行されます。

コンテナIDについて

コンテナIDはコンテナ作成時にランダムに割り当てられる64文字のハッシュ値です。このハッシュ値の先頭12文字をコンテナIDとして指定することができます。podman psコマンドを使用してコンテナIDを確認できます。

$ podman stop -t 0 8c1c69967f9c

(コピペ用)

podman stop -t 0 8c1c69967f9c

出力結果
$ podman stop -t 0 8c1c69967f9c
8c1c69967f9c

作成したボリュームはpodman volume rmコマンドを使って削除できます。

--forceオプションとボリューム名を指定して強制的にボリュームの削除とコンテナの削除を行います。

--forceオプションの使用について

podman volume rmのみを使用した場合、今回はコンテナがまだ停止状態で残っているためエラーが出て削除ができません。

Error: volume webdata is being used by the following container(s): e55377526ab98a9a875c244c9f110b70ed82656f8c3e6d6456181ed63594fbd1: volume is being used
そのため、ボリュームとコンテナを同時に強制的に削除するために--forceオプションを使用します。

$ podman volume rm --force webdata

(コピペ用)

podman volume rm --force webdata

出力結果
$ podman volume rm --force webdata
webdata

podman volume listを実行して、ボリュームが存在しないことを確認します

$ podman volume list

(コピペ用)

podman volume list

出力結果
$ podman volume list
$

(オプション問題)

podman ps -aコマンドを使ってコンテナが削除されているか確認しましょう

ボリュームが存在しない状態でpodman runを実行できます。その場合、ボリュームは自動的に作成されます。

webdata1ボリュームを指定してコンテナを起動します。そしてボリュームが作成されているか確認します。

$ podman run -d -v webdata1:/var/www/html:ro,z -p 8080:8080 quay.io/rhatdan/myimage
$ podman volume list

(コピペ用)

podman run -d -v webdata1:/var/www/html:ro,z -p 8080:8080 quay.io/rhatdan/myimage
podman volume list

出力結果
$ podman run -d -v webdata1:/var/www/html:ro,z -p 8080:8080 quay.io/rhatdan/myimage
b2613ca208811ac992a1215cffb9a20b5eb97e0d5cb543aacfe6616fc5bb6e49
$ podman volume list
DRIVER      VOLUME NAME
local       webdata1

(オプション問題)

curlコマンドやブラウザを使ってコンテンツにアクセスできるか確認しましょう。またその際に表示される内容についても確認しましょう。

空のボリュームをマウントした際の挙動

webdata1ボリュームは空なのでコンテナイメージ内の元のindex.htmlは保持された状態になります。 コンテナイメージは階層構造を持ち、PodmanはLinuxカーネルのoverlayfs機能を使いイメージが重ね合わされた結果のファイルシステムを実行します。 今回のようにボリュームが空で同名のファイルが存在しない場合は元のデータは上書きされません。

ボリュームを強制的に削除します。また同時にコンテナも削除します。

$ podman volume rm --force webdata1

(コピペ用)

podman volume rm --force webdata1

出力結果
$ podman volume rm --force webdata1
webdata1

(オプション問題)

podman volume listpodman psコマンドを使ってコンテナが削除されているか確認しましょう

ボリュームのマウントオプション

(このコンテンツは本書 3.1.2に該当します)

これまでにボリュームマウント時に使用した:ro:zオプション以外にもPodmanでは便利なオプションがあります。

U ボリュームオプション

:Uオプションはその一つです。ルートレスコンテナにおける所有権の問題を簡単に解決できるオプションです。ルートレスコンテナで、コンテナ内のプロセスがUID==60として実行する例を考えてみましょう。

ルートレスコンテナにおけるユーザー名前空間マッピングを確認します。

$ podman unshare cat /proc/self/uid_map

(コピペ用)

podman unshare cat /proc/self/uid_map

出力結果
$ podman unshare cat /proc/self/uid_map
         0       1002          1
         1     231072      65536

この結果は下記を表します

  • コンテナ内のUID 0はホスト上のUID 1002にマップされます。
  • UID 1UID 231072UID 2UID 231073 ... UID 65536UID 296607とマップされます。

コンテナ内でUID 60として実行するプロセスがボリュームに書き込む場合、ホスト上のユーザーの所有権と異なるため書き込みができません。 ユーザー名前空間内でボリュームの所有権をUID 60にするために、podman unshareを使用してchownを実行します。

podman unshareコマンドについて

podman unshareコマンドはコンテナを実行せずにユーザー名前空間内に入ることができます。このコマンドはPodmanの独自のコマンドでDockerにはありません。

$ podman unshare chown 60:60 ./html

(コピペ用)

podman unshare chown 60:60 ./html

出力結果はありません

(オプション問題)

ls -ldコマンドでhtmlディレクトリの所有権がどのようになったか確認してみましょう

$ ls -ld
drwxr-xr-x. 2 231131 231131 6 Oct 14 14:58 html

コンテナイメージによってはコンテナ内で実行するプロセスが特定のUIDを指定しているものがあります。mariadbコンテナイメージはその一つで、データベースのプロセスはmysqlユーザ(UID==999)によって実行されます。

mariadbコンテナイメージのmysqlユーザーのUIDを確認します。

$ podman run docker.io/mariadb grep mysql /etc/passwd

(コピペ用)

podman run docker.io/mariadb grep mysql /etc/passwd

出力結果
$ podman run docker.io/mariadb grep mysql /etc/passwd
Trying to pull docker.io/library/mariadb:latest...
Getting image source signatures
Copying blob 50ee0c078c93 done  
Copying blob 43f89b94cd7d done  
Copying blob dfb413a01c7e done  
Copying blob 1d3f76b535d3 done  
Copying blob f7efd05ec01e done  
Copying blob fe2ff83c75df done  
Copying blob 6975e72928bb done  
Copying blob 561d1b426cbd done  
Copying config f35870862d done  
Writing manifest to image destination
Storing signatures
mysql:x:999:999::/home/mysql:/bin/sh

:Uオプションについて

コンテナイメージによってはコンテナ内で実行するプロセスが特定のUIDを指定しているものがあります。

データベース用のディレクトリを作成します。ディレクトリの所有権がホスト上のユーザー(rhel)であることを確認します。

$ mkdir mariadb
$ ls -ld mariadb/

(コピペ用)

mkdir mariadb
ls -ld mariadb/

出力結果
$ mkdir mariadb
$ ls -ld mariadb/
drwxr-xr-x. 2 rhel rhel 6 Oct 14 15:25 mariadb/

mariadbコンテナイメージを実行します。

:Uオプションを使用しmariadbディレクトリをコンテナ内の/var/lib/mariadbディレクトリにマウントします。また--user mysqlオプションを使用し、コンテナの実行ユーザーをmysqlと指定します。

$ podman run --user mysql -v ./mariadb:/var/lib/mariadb:U docker.io/mariadb ls -ld /var/lib/mariadb

(コピペ用)

podman run --user mysql -v ./mariadb:/var/lib/mariadb:U docker.io/mariadb ls -ld /var/lib/mariadb

出力結果
$ podman run --user mysql -v ./mariadb:/var/lib/mariadb:U docker.io/mariadb ls -ld /var/lib/mariadb
drwxr-xr-x. 2 mysql mysql 6 Oct 14 15:25 /var/lib/mariadb

podman run --mountコマンドオプション

(このコンテンツは本書 3.1.3に該当します)

(オプション)podman run --mountコマンドでサポートされているマウントタイプやpodman volumeのサブコマンドの詳細はマニュアルページを参照してください

$ man podman-mount
$ podman-volume-create
$ podman-volume-exists
$ podman-volume-export
$ podman-volume-import
$ podman-volume-inspect
$ podman-volume-list
$ podman-volume-prune
$ podman-volume-rm

まとめ

バインドマウントや名前付きボリュームを使用することで永続化したデータをコンテナで使用することができます。 ボリュームはホスト上のファイルシステムをコンテナ内にマウントするために、SELinuxやユーザー名前空間のセキュリティ上の問題に対処する必要があります。 Podmanではそのための便利なボリュームマウントオプションがあります。