docker desktop の有料化に対する猶予期間が終了する、1月31日が近づいてきました。皆様いかがお過ごしでしょうか。
さて、今日は windows10 の wsl2 環境で docker desktop の代替として podman が使えそうか検証していきたいと思います!
用意するもの
wsl2
> wsl -l -v
NAME STATE VERSION
* Ubuntu Running 2
docker-desktop Stopped 2
docker-desktop-data Stopped 2
ubuntu
❯ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 20.04.3 LTS
Release: 20.04
Codename: focal
まだ 18.04 使ってるよーという方がこのあたりを参考に、20.04 にされることをお勧めします。
なお、sudo do-release-upgrade
コマンドが Reading state information... Done
の後でfailしてしまう場合は、こちらに書かれているように、 sudo apt-get purge snapd
してあげると進みます(ました)。
Install
install と書きましたが、まずは docker desktop を uninstall します。
いつでも戻せるという甘えを断ち切ります。
>wsl -l -v
NAME STATE VERSION
* Ubuntu Running 2
docker いなくなりました
では、install していきます。
公式Docを見ると下記blogポストがリンクされています。
これによると、install コマンドはこう。
. /etc/os-release
sudo sh -c "echo 'deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/x${NAME}_${VERSION_ID}/ /' > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list"
wget -nv https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable/x${NAME}_${VERSION_ID}/Release.key -O Release.key
sudo apt-key add - < Release.key
sudo apt-get update -qq
sudo apt-get -qq -y install podman
sudo mkdir -p /etc/containers
echo -e "[registries.search]\nregistries = ['docker.io', 'quay.io']" | sudo tee /etc/containers/registries.conf
ubuntu 20.10 以降だと
# Ubuntu 20.10 and newer
sudo apt-get -y update
sudo apt-get -y install podman
sudo mkdir -p /etc/containers
echo -e "[registries.search]\nregistries = ['docker.io', 'quay.io']" | sudo tee /etc/containers/registries.conf
でいけんのかな?未確認。
上記の blog によると、構成オプションの変更が必要そうなのですが、
--cgroup-manager cgroupfs --event-logger file
podman info
してみると、すでに該当の構成で設定されており、必要なさそうです。
❯ podman info
...
cgroupManager: cgroupfs
...
eventLogger: file
...
version
❯ podman version
Version: 3.4.2
API Version: 3.4.2
Go Version: go1.16.6
Built: Thu Jan 1 09:00:00 1970
OS/Arch: linux/amd64
podman run
とりあえず run してみます。
❯ podman run -dt -p 8080:80/tcp httpd
✔ docker.io/library/httpd:latest
Trying to pull docker.io/library/httpd:latest...
Getting image source signatures
Copying blob 0d58b11d2867 done
Copying blob e88da7cb925c done
Copying blob ba1caf8ba86c done
Copying blob eff15d958d66 done
Copying blob ab86dc02235d done
Copying config ad17c88403 done
Writing manifest to image destination
Storing signatures
7ae5b62981563f779be7af3c2210841d70ac513a0941f76ead7fffe7e7f2a350
❯ podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7ae5b6298156 docker.io/library/httpd:latest httpd-foreground 17 seconds ago Up 18 seconds ago 0.0.0.0:8080->80/tcp jolly_mayer
イケてる!
止めます。
❯ podman stop jolly_mayer
jolly_mayer
❯ podman ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS
PORTS NAMES
7ae5b6298156 docker.io/library/httpd:latest httpd-foreground 6 minutes ago Exited (0) 5 seconds ago 0.0.0.0:8080->80/tcp jolly_mayer
restart してみたり、 rm してみたり。このあたりの使用感は docker と全然変わらないですね。
volume mount
マウントしてみます。
echo "test page" > index.html
podman run -d --rm -p 8080:80 -v $PWD:/usr/share/nginx/html --name web nginx
うむ、普通にできました。
external network
default 状態の確認。
❯ podman network ls
NETWORK ID NAME VERSION PLUGINS
2f259bab93aa podman 0.4.0 bridge,portmap,firewall,tuning
ここにネットワークを作ります。
❯ podman network create ex-network
/etc/cni/net.d/ex-network.conflist
できた。
❯ podman network ls
NETWORK ID NAME VERSION PLUGINS
2f259bab93aa podman 0.4.0 bridge,portmap,firewall,tuning
34f160cc6cae ex-network 0.4.0 bridge,portmap,firewall,tuning,dnsname
nginx をたててみます。
❯ podman run -d --rm -p 8080:80 -v $PWD:/usr/share/nginx/html --name web --net ex-network nginx
7759d6c9199f29891b1fed4fc7543e9bf01054698710c41392bedb927e619411
busybox の debug コンテナから web コンテナにアクセスしてみます。
podman run -it --rm --net ex-network busybox sh
Resolved "busybox" as an alias (/etc/containers/registries.conf.d/000-shortnames.conf)
Trying to pull docker.io/library/busybox:latest...
Getting image source signatures
Copying blob e685c5c858e3 done
Copying config 7138284460 done
Writing manifest to image destination
Storing signatures
/ # wget -q -O - web:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
問題なくイケてますね!
docker と podman の network 実装の違いの話
ちなみに、こちらの記事で述べられている、
docker network create コマンドと同様に podman network create コマンドでカスタムネットワークを作成できますが、Podman (3.0.0-rc1) では複数のネットワーク間での通信が禁止されていません。
について検証してみました。
こちらの issue ですね。
もう1つ network を作成して、
❯ podman network create ex-network-alt
/etc/cni/net.d/ex-network-alt.conflist
コンテナ名でのアクセスはできませんが、
❯ podman run -it --rm --net ex-network-alt busybox sh
/ # wget -q -O - web:80
wget: bad address 'web:80'
/ # exit
IP だとアクセスできてしまいました。
podman run -it --rm --net ex-network-alt busybox sh
/ # wget -q -O - 10.89.0.2:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
なるほど。
k8s yaml
podman は(公式には)docker-compose をサポートしていません。
その代わり、k8s yaml をサポートしています。
そんな podman の醍醐味(?)である k8s yaml での動作を見てみます。
container から pod yaml をつくる
まず手始めに、起動している container から k8s pod yaml を生成してみます。
単一の container から pod yaml をつくる方法です。
❯ podman generate kube web > web-kube.yaml
おぉ。見慣れたやつ。
# Save the output of this file and use kubectl create -f to import
# it into Kubernetes.
#
# Created with podman-3.4.2
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: "2021-11-24T13:49:13Z"
labels:
app: web
name: web
spec:
containers:
- args:
- nginx
- -g
- daemon off;
image: docker.io/library/nginx:latest
name: web
ports:
- containerPort: 80
hostPort: 8080
securityContext:
capabilities:
drop:
- CAP_MKNOD
- CAP_NET_RAW
- CAP_AUDIT_WRITE
volumeMounts:
- mountPath: /usr/share/nginx/html
name: root-workspace-host-0
volumes:
- hostPath:
path: /root/workspace
type: Directory
name: root-workspace-host-0
では次に複数の container から pod yaml を作ってみたいと思います。
が、そのためにまず pod そのものをコマンドで作ります。
空のpodを作るコマンド
podman pod create --name my-pod
お、pod ができている!
❯ podman pod list
POD ID NAME STATUS CREATED INFRA ID # OF CONTAINERS
70976cb582e2 my-pod Created 4 minutes ago 8bdec75f2026 1
❯ podman ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8bdec75f2026 k8s.gcr.io/pause:3.5 8 minutes ago Created 70976cb582e2-infra
この pod に対して、次のように、podman run コマンドを --pod
で実行すると container が pod に割り当てられると言うわけです。
(この時、--pod new:my-pod2
のように new を付けるとpodの作成もやってくれるらしいです。)
podman run -d --rm -p 8080:80 -v $PWD:/usr/share/nginx/html --name web --net ex-network --pod my-pod nginx
おー container 増えた。
❯ podman pod ls
POD ID NAME STATUS CREATED INFRA ID # OF CONTAINERS
70976cb582e2 my-pod Running 10 minutes ago 8bdec75f2026 2
❯ podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8bdec75f2026 k8s.gcr.io/pause:3.5 10 minutes ago Up 33 seconds ago 70976cb582e2-infra
aef5792650c1 docker.io/library/nginx:latest nginx -g daemon o... 32 seconds ago Up 32 seconds ago 0.0.0.0:8080->80/tcp web
例があまりよくないけど、さっきの busybox コンテナも pod に入れて、30s 毎に web container にアクセスするようにしてみます。
❯ podman run -d --rm --name debug --net ex-network --pod my-pod busybox sh -c "while true; do wget -q -O - web:80; sleep 30; done;"
87cd836c39135dc59bb4bbd3414bd03dc0ec5aa5cf6ef8b475ae2011dcf56562
❯ podman logs debug
test page
test page
うむうむ。
さてさて、これらをいよいよ k8s pod yaml に変換します。
コマンドは単一 container の時と同じですが、今度は pod 名で。
❯ podman generate kube my-pod > my-pod-kube.yaml
できてるできてる。
# Save the output of this file and use kubectl create -f to import
# it into Kubernetes.
#
# Created with podman-3.4.2
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: "2021-11-24T16:12:52Z"
labels:
app: my-pod
name: my-pod
spec:
containers:
- args:
- nginx
- -g
- daemon off;
image: docker.io/library/nginx:latest
name: web
resources: {}
securityContext:
capabilities:
drop:
- CAP_MKNOD
- CAP_NET_RAW
- CAP_AUDIT_WRITE
volumeMounts:
- mountPath: /usr/share/nginx/html
name: root-workspace-host-0
- command:
- sh
- -c
- while true; do wget -q -O - web:80; sleep 30; done;
image: docker.io/library/busybox:latest
name: debug
resources: {}
securityContext:
capabilities:
drop:
- CAP_MKNOD
- CAP_NET_RAW
- CAP_AUDIT_WRITE
restartPolicy: Never
volumes:
- hostPath:
path: /root/workspace
type: Directory
name: root-workspace-host-0
status: {}
ex-networkを指定している要素は yaml には表れてこないですね
必要ないからかな。
というわけで、podman だと、ローカル環境などで(試行錯誤しながら)複数 container によるオーケストレーション環境を作り、それを k8s yaml に吐きだして管理できることが分かりました。
docker-compose には compose yaml を ganerate する仕組みはなかった(気がする)から新鮮
pod yaml を作ってしまえば、一度 pod も container も消して、
❯ podman pod stop my-pod
70976cb582e2758ecf8f3f9900cfc96919fc31b5f40c66edbfb0905a74f4c998
❯ podman pod rm my-pod
70976cb582e2758ecf8f3f9900cfc96919fc31b5f40c66edbfb0905a74f4c998
❯ podman ps -a --pod
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES POD ID PODNAME
何もない状態から、podman play
コマンドで、docker-compose up
のように先ほどの環境が作れます。
❯ podman play kube my-pod-kube.yaml
Pod:
b9ccabbc6312534340feef2ee4f37b86f306bc0a0e509801ab1f52aec68eefd1
Containers:
89579f9b1b615a6ddab8b86eb7d0c8950fb5e8a4341e0e8976d1956140b34feb
fc1ec0acc05c246c7eff078dd9fe0e90bba100d553c25e129962bbb31aad3a08
❯ podman pod ls
POD ID NAME STATUS CREATED INFRA ID # OF CONTAINERS
b9ccabbc6312 my-pod Degraded 18 seconds ago 732642163dc8 3
❯ podman ps -a --pod
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES POD ID PODNAME
732642163dc8 k8s.gcr.io/pause:3.5 22 seconds ago Up 15 seconds ago b9ccabbc6312-infra b9ccabbc6312 my-pod
89579f9b1b61 docker.io/library/nginx:latest nginx -g daemon o... 19 seconds ago Up 15 seconds ago my-pod-web b9ccabbc6312 my-pod
fc1ec0acc05c docker.io/library/busybox:latest 15 seconds ago Exited (0) 12 seconds ago my-pod-debug b9ccabbc6312 my-pod
と思ったらあれ?
❯ podman logs my-pod-debug
wget: bad address 'web:80'
yamlを少し修正する必要がありそうです。
...
spec:
containers:
- args:
- nginx
- -g
- daemon off;
image: docker.io/library/nginx:latest
ports: # ここ追記
- containerPort: 80 # ここ追記
name: web
...
- command:
- sh
- -c
- while true; do wget -q -O - localhost:80; sleep 30; done; # ここ web -> localhost
image: docker.io/library/busybox:latest
name: debug
...
❯ podman logs my-pod-debug
test page
test page
test page
でたでた。
ちなみに、podman generate command の
❯ podman generate systemd --files --name my-pod
/root/workspace/pod-my-pod.service
/root/workspace/container-my-pod-web.service
/root/workspace/container-my-pod-debug.service
を実行すると、systemd 用の unit file が作られて、これを /usr/lib/systemd/system
などに配置すると daemon のいない podman でもサービスを永続化できるっぽい。
けど今回は docker desktop の代替を目指すので、ここでは触れません。
resource limit
k8s yaml で行けるとなると、contaier 毎の resource request/limit も yaml 通りに設定されるんでしょうか
少し見てみたいと思います。
何も制限を設けず、負荷をかけてみます。
debug コンテナのコマンドを少し修正して、
sleep 5; while true; do wget -q -O - localhost:80 > /dev/null; done;
❯ podman top my-pod-debug
USER PID PPID %CPU ELAPSED TTY TIME COMMAND
root 1 0 22.060 36.2640195s ? 8s sh -c while true; do wget -q -O - localhost:80 > /dev/null; done;
では、cpu に limit を追加します。
...
- command:
- sh
- -c
- sleep 5; while true; do wget -q -O - localhost:80 > /dev/null; done;
image: docker.io/library/busybox:latest
name: debug
resources:
limits: # ここだよー
cpu: "200m" # ここだよー
securityContext:
capabilities:
drop:
- CAP_MKNOD
- CAP_NET_RAW
- CAP_AUDIT_WRITE
...
おーだいぶ控えめになりました。
❯ podman top my-pod-debug
USER PID PPID %CPU ELAPSED TTY TIME COMMAND
root 1 0 4.034 1m39.1670656s ? 4s sh -c sleep 5; while true; do wget -q -O - localhost:80 > /dev/null; done;
root 21940 1 0.000 1.1671397s ? 0s wget -q -O - localhost:80
registry login
docker login
command と同じでした。
❯ podman login registry.gitlab.com -u yo_C_ta
Password:
Login Succeeded!
小ネタ
調べてて見つけた小ネタです。
所感
なんとなく個人の感想ですが、k8s 化を見据えて何らかのサービスを作っている場合には、初期の段階から k8s yaml の構成を考えていけるので、docker で始めるよりも開発者体験はいいのかなーと思いました。
あと、docker desktop の代替検討として考えると、podman は daemonless らしいので何もしていない時に手元の PC リソースを圧迫しないのもいいのかも(程度は未確認)。
podman 自体のリリースサイクルも早いらしいので、今後さらに期待できそうです
乗り換え候補としては十分ありだと思いますが、もう少し他も見てみよう