あとがきのようなもの

インフラ関連,コンテナ,仮想化技術、過去に書いた記事の解説など

【Podman v3.3.x】podman machineの自動ポートフォワード機能を使う

Podman v3.3.0からpodman machine内のコンテナに自動的にポートフォワードが行われる機能が追加された。 この機能についてはv3.3.0のリリースノートの一番初めに記載されている。

v3.3.0のリリースノートより抜粋

Containers inside VMs created by podman machine will now automatically handle port forwarding - containers in podman machine VMs that publish ports via --publish or --publish-all will have these ports not just forwarded on the VM, but also on the host system.

(翻訳)podman machine で作成された VM 内のコンテナは、ポートフォワーディングを自動的に処理するようになりました。--publish または --publish-all でポートを公開した podman machine VM 内のコンテナは、これらのポートが VM 上だけでなく、ホストシステム上にも転送されます。

podman machineとgvproxyによる自動ポートフォワードの使い方について解説。

gvproxyについて

自動ポートフォワードの機能の追加によりpodman machineを使うためにはgvproxyが必要になった。 このことはv3.3.0リリースノートのChangesに記載がある

The new port forwarding offered by podman machine requires gvproxy in order to function.

gvproxyはGitHubリポジトリ上ではgvisor-tap-vsockという名前になっている。libslirp と VPNKitを置き換えるものでGoで書かれており、gVisorのネットワークスタックをベースにしている。

gvproxy自体の使い方や詳細はGitHubリポジトリを参照。

github.com

rootモード on Linuxで実行する場合

rootモード on Linuxの実行環境

$ cat /proc/version
Linux version 5.13.12-200.fc34.x86_64 (mockbuild@bkernel01.iad2.fedoraproject.org) (gcc (GCC) 11.2.1 20210728 (Red Hat 11.2.1-1), GNU ld version 2.35.2-4.fc34) #1 SMP Wed Aug 18 13:27:18 UTC 2021
$ podman -r version
Client:
Version:      3.3.1
API Version:  3.3.1
Go Version:   go1.16.6
Built:        Tue Aug 31 05:46:36 2021
OS/Arch:      linux/amd64

Server:
Version:      3.3.0
API Version:  3.3.0
Go Version:   go1.16.6
Built:        Sat Aug 21 04:36:14 2021
OS/Arch:      linux/amd64

[実行手順]

  • podman machineの初期化と起動
  • nginxイメージのpull
  • TCP:8888を公開ポートとしてnginxコンテナを起動
  • 公開ポートの確認とcurlによる接続
# podman machine init; podman machine start
# podman -r pull docker.io/library/nginx
# podman -r run --rm -d --name nginx -p 8888:80 nginx
# podman -r ps
CONTAINER ID  IMAGE                           COMMAND               CREATED         STATUS             PORTS                 NAMES
b75a5a32c09a  docker.io/library/nginx:latest  nginx -g daemon o...  30 seconds ago  Up 30 seconds ago  0.0.0.0:8888->80/tcp  nginx
# ss -ltnup | grep 8888
tcp   LISTEN 0      4096               *:8888             *:*    users:(("gvproxy",pid=8857,fd=31))
# curl http://localhost:8888
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
</html>

gvproxyを使って自動的にポートフォワーディングが行われ、ホスト上からpodman machine VM上のコンテナへ接続ができる

ルートレスモード on LinuxまたはmacOSで実行する場合

ルートレスモード on LinuxまたはmacOSで実行する場合は注意が必要。rootモードと同じ手順では自動的にポートフォワーディングが行われない。 この問題についてはGitHubにIssueを上げている。

github.com

Issueを上げてすぐにコメントが付いて、その内容のワークアラウンドを適用することでルートレスモードおよびmacOSで自動ポートフォワードが実行が可能となった。

ワークアラウンド

コンテナ実行時に--network bridgeを付与する

ルートレスモード on Linuxの場合

実行環境はrootモード on Linuxと同じ

[実行手順]

  • podman machineの初期化と起動
  • nginxイメージのpull
  • TCP:8888を公開ポートとしてnginxコンテナを起動
  • 公開ポートの確認とcurlによる接続
$ podman machine init; podman machine start
$ podman -r pull docker.io/library/nginx
$ podman -r run --rm -d --name nginx -p 8888:80 --network bridge nginx
$ ss -ltnup |grep 8888
tcp   LISTEN 0      4096               *:8888             *:*    users:(("gvproxy",pid=9725,fd=17))
$ curl http://localhost:8888
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
</html>

macOSの場合

実行環境

$ podman version
Client:
Version:      3.3.1
API Version:  3.3.1
Go Version:   go1.17
Built:        Tue Aug 31 04:15:26 2021
OS/Arch:      darwin/amd64

Server:
Version:      3.3.0
API Version:  3.3.0
Go Version:   go1.16.6
Built:        Sat Aug 21 04:36:14 2021
OS/Arch:      linux/amd64

[実行手順]

  • podman machineの初期化と起動
  • nginxイメージのpull
  • TCP:8888を公開ポートとしてnginxコンテナを起動
  • 公開ポートの確認とcurlによる接続
$ podman machine init; podman machine start
$ podman pull docker.io/library/nginx
$ podman run --rm -d --name nginx -p 8888:80 --network bridge nginx
$ ss -ltnup |grep 8888
tcp   LISTEN 0      4096               *:8888             *:*    users:(("gvproxy",pid=9725,fd=17))
$curl http://localhost:8888
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
</html>

別のワークアラウンド

GitHubのIssueでは議論が進んでおり、別のワークアラウンドとしてcontainers.confに設定を書き込む方法が紹介されている。

github.com

Just confirming that adding rootless_networking = "cni" under the [containers] section of ~/.config/containers/containers.conf does also fix this on MacOS :)

containers.conf[containers]セクションにrootless_networking = "cni"を追記する。

ルートレスモード on LinuxmacOS共通の手順

$ vi ~/.config/containers/containers.conf

[containers]
rootless_networking = "cni"

この設定を行うことでコンテナ実行時に--network bridgeを付与しなくても自動的にポートフォワードが行われるようになる。

ルートレスモード on Linuxの場合

$ podman -r run --rm -d --name nginx -p 8888:80 nginx
$ ss -ltnup |grep 8888
tcp   LISTEN 0      4096               *:8888             *:*    users:(("gvproxy",pid=9725,fd=14))
$ curl http://localhost:8888
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
</html>

macOSの場合

$ podman run --rm -d --name nginx -p 8888:80 nginx
$ netstat -an|grep 8888
tcp46      0      0  *.8888                 *.*                    LISTEN
$ curl http://localhost:8888
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
</html>