CrescPia

Podman でサービス運用

サービス運用に利用していた VPS が障害により起動しなくなり、初期化することになりました。
いい機会なので、運用方針を見直しています。
サービスは Podman というコンテナツールを利用するようにします。


同じコンテナツールである Docker と比較して、以下のような特徴があります。

  • 一般ユーザーで利用するように作られている。
  • dockerd デーモンのようなデーモンで起動の管理するのではなく、Linux の systemd の仕組みを利用するなどして管理する。

僕は Web サービスは主に Go 言語を使っています。
Go の場合は基本的には実行ファイルが一つできて、これをデプロイする形になります。
Python などのように実行環境が不要なのでコンテナ化せずに、実行ファイルを直接 systemd で管理してもいいのですが、以下のようなメリットがあります。

  • デプロイが簡単。podman pullコマンドでデプロイできます。ほとんどこれが採用の決め手です。
  • Go でもまれに環境に依存することがある。Ubuntu のバージョン違いによる共有ライブラリのバージョン違いなど。
  • Go 以外のものをデプロイするときにも同じやり方でデプロイできる。

Podmanについて

Podman の特徴です。

1. Rootlessモード

Podman コンテナを起動するのに一般ユーザーで起動できる。
一般ユーザーで起動すればいいだけ。
デフォルトで Rootless モードなので。
一般ユーザーのプロセスなので万が一何かあっても、一般ユーザーの権限内の事故で収まる。

2. IDマッピング

ボリュームを使ってコンテナ内のファイルを永続化している場合を考える。
Docker ではコンテナ内で作成したファイルはホスト側ではアクセス権限の都合で編集できない。アクセスできるようにしようとすると権限の設定が面倒。

Podman ではコンテナを起動すると、特にユーザーを指定しないとコンテナ内では root が実行ユーザーになっている。
この root はホスト側の起動したユーザーにマッピングされている。
コンテナ内で root でファイルを作成した場合、ホスト側ではそのファイルの owner はコンテナを起動した一般ユーザーになっている。
sudo せずに普通に編集できる。

3. Quadlet

Podman コンテナを systemd で管理するようにする。
systemd で管理すると、

  • OS 起動時に自動起動できる。
  • ログを journalctl で見られる。特に何もしなくてもコンテナ内のログが見られるので便利。

などのメリットがある。


systemd で起動するにはコンテナ用の設定を書いた .container ファイルを用意してリロードコマンドを実行する。
以下のようなファイルを次の場所に用意します。~/.config/containers/systemd/mysleep.container
mysleep.container ファイルは RedHat のドキュメントより引用。


第14章 Podman を使用した systemd へのコンテナーの移植 | コンテナーの構築、実行、および管理 | Red Hat Enterprise Linux | 8 | Red Hat Documentation

[Unit]
Description=The sleep container
After=local-fs.target

[Container]
Image=registry.access.redhat.com/ubi8-minimal:latest
Exec=sleep 1000

[Install]
# Start by default on boot
WantedBy=multi-user.target default.target

.container ファイルにはボリュームの設定や、ポートの設定なども書けます。

そして、次のコマンドを実行する。

systemctl --user daemon-reload

Quadlet というツールが裏で systemd と連動して動いてくれています。
Quadlet がリロードコマンド実行時に上記のコンテナ設定用のファイルから systemd 用の設定ファイルである .service ファイルを作成しています。
.service ファイルは /run/user/1000/systemd/generator/mysleep.service に作成される。

# Automatically generated by /usr/lib/systemd/user-generators/podman-user-generator
#
[Unit]
Description=The sleep container
After=local-fs.target
SourcePath=/home/myuser/.config/containers/systemd/mysleep.container
RequiresMountsFor=%t/containers

[X-Container]
Image=registry.access.redhat.com/ubi8-minimal:latest
Exec=sleep 1000

[Install]
# Start by default on boot
WantedBy=multi-user.target default.target

[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
KillMode=mixed
ExecStop=/usr/bin/podman rm -v -f -i --cidfile=%t/%N.cid
ExecStopPost=-/usr/bin/podman rm -v -f -i --cidfile=%t/%N.cid
Delegate=yes
Type=notify
NotifyAccess=all
SyslogIdentifier=%N
ExecStart=/usr/bin/podman run --name=systemd-%N --cidfile=%t/%N.cid --replace --rm --cgroups=split --sdnotify=conmon -d registry.access.redhat.com/ubi8-minimal:latest sleep 1000

そして、以下のコマンドでサービスとして起動します。

systemctl --user start mysleep.service