青梅梦呓

和世界交手的这许多年,你是否光彩依旧,兴致盎然

0%

Podman 初体验

最近把自己的虚拟机升级到了CetnOS 8,内核版本4.18.0-147.8.1.el8_1.x86_64,感觉带来的变化还是很大,网络管理彻底替换了 network.service,防火墙管理等等。居然还去Docker,引进了新一代的容器管理工具(😢 国内很多开发都还没用docker,就已经去docker了),使用 Podman、Buildah(提供构建image的能力)、Skopeo(提供远程仓库的镜像管理能力) ,对docker进行了替换。 我体验了下 Podman,谨做小文以记。

为啥不用Docker

我觉得主要是因为docker需要运行一个守护进程,docker的稳定性问题(感觉在向好的趋势不断发展,其实远比podman稳定多了),还有的话就是root运行。随着K8S抛弃CRI标准,CRI-O进入CNCF孵化阶段,国外越来越多的在使用CRI-O 来替代Docker,Docker正在被大家抛弃 (:–

podman特色

优点

podman创建容器不需要守护进程,可以用普通用户创建容器。podman的命令方式与docker没有什么太大的区别,可以认为 alias docker=podman,会用docker就会用podman。

缺点

  • 有一个podman-compose(但是还没有release1.0),不是很好用。与docker-compose还有很大的差距。
  • 更新频繁(你永远不知道这个锅是你的问题还是podman的问题,心累)

安装

CenOS8默认就是podman,docker安装反倒是需要去安装仓库源。 直接运行sudo yum install podman -y就行

yum info podman 能看到以下信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
名称         : podman
版本 : 1.6.4
发布 : 4.module_el8.1.0+298+41f9343a
架构 : x86_64
大小 : 55 M
源 : podman-1.6.4-4.module_el8.1.0+298+41f9343a.src.rpm
仓库 : @System
来自仓库 : AppStream
概况 : Manage Pods, Containers and Container Images
URL : https://podman.io/
协议 : ASL 2.0
描述 : podman (Pod Manager) is a fully featured container engine that is a simple daemonless tool. podman provides a Docker-CLI
: comparable command line that eases the transition from other container engines and allows the management of pods, containers and
: images. Simply put: alias docker=podman. Most podman commands can be run as a regular user, without requiring additional
: privileges.
:
: podman uses Buildah(1) internally to create container images. Both tools share image (not container) storage, hence each can use
: or manipulate images (but not containers) created by the other.
:
: Manage Pods, Containers and Container Images
: libpod Simple management tool for pods, containers and images

配置说明

podman rpm中附带的文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ rpm -ql podman | grep -v "/usr/share/doc/"
/etc/cni/net.d/87-podman-bridge.conflist
/usr/bin/podman
/usr/lib/.build-id
/usr/lib/.build-id/82
/usr/lib/.build-id/82/21ca637b743ef63235a38b3195f6563a96967a
/usr/lib/systemd/system/io.podman.service
/usr/lib/systemd/system/io.podman.socket
/usr/lib/systemd/user/io.podman.service
/usr/lib/systemd/user/io.podman.socket
/usr/lib/tmpfiles.d/podman.conf
/usr/share/bash-completion/completions/podman
/usr/share/containers/libpod.conf
/usr/share/licenses/podman
/usr/share/licenses/podman/LICENSE
/usr/share/man/man5/oci-hooks.5.gz
/usr/share/zsh/site-functions
/usr/share/zsh/site-functions/_podman

能看到的只有一个配置文件,就在/etc/cni/net.d/下面,与Bridge的配置有关,打开看看:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
$ cat /etc/cni/net.d/87-podman-bridge.conflist
{
"cniVersion": "0.4.0",
"name": "podman",
"plugins": [
{
"type": "bridge",
"bridge": "cni-podman0",
"isGateway": true,
"ipMasq": true,
"ipam": {
"type": "host-local",
"routes": [{ "dst": "0.0.0.0/0" }],
"ranges": [
[
{
"subnet": "10.88.0.0/16",
"gateway": "10.88.0.1"
}
]
]
}
},
{
"type": "portmap",
"capabilities": {
"portMappings": true
}
},
{
"type": "tuning"
}
]
}

然而安装的时候,能看到需要的一个重要依赖就是containers-common,这个里面有很多配置文件。
rpm -ql containers-common | grep -v "/usr/share/man/" 可以查看具体的文件信息。

registries.conf

/etc/containers/registries.conf 用于保存 registries 相关配置:

mounts.conf

这个配置指定在执行 podman run 或者 podman build 命令时自动挂载的路径,该路径只会在容器运行时挂载,不会提交到容器镜像中。

1
2
$ cat /usr/share/containers/mounts.conf
/usr/share/rhel/secrets:/run/secrets

policy.json

证书相关的配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ cat /etc/containers/policy.json
{
"default": [
{
"type": "insecureAcceptAnything"
}
],
"transports":
{
"docker-daemon":
{
"": [{"type":"insecureAcceptAnything"}]
}
}
}

images使用

Ps:以下操作已经使得虚拟机可以科学上网,终端已经export https_proxy
PPs: 我修改了下仓库,如下

1
2
3
4
5
6
7
8
9
$ cat  /etc/containers/registries.conf
......

# 仅仅改了下面部分
[registries.search]
#registries = ['registry.access.redhat.com', 'registry.fedoraproject.org', 'registry.centos.org', 'docker.io']
registries = ['registry.redhat.io','quay.io','docker.io','registry.access.redhat.com']

......

搜索镜像

1
2
3
4
5
6
7
$ podman search nginx | head -6
INDEX NAME DESCRIPTION STARS OFFICIAL AUTOMATED
redhat.io registry.redhat.io/rhscl/nginx-112-rhel7 Nginx is a web server and a reverse proxy se... 0
redhat.io registry.redhat.io/rhel8/nginx-116 Platform for running nginx 1.16 or building ... 0
redhat.io registry.redhat.io/rhel8/nginx-114 Nginx is a web server and a reverse proxy se... 0
redhat.io registry.redhat.io/rhscl/nginx-18-rhel7 Nginx 1.8 server and a reverse proxy server 0
redhat.io registry.redhat.io/rhscl/nginx-110-rhel7 Nginx container image that delivers an nginx... 0

构建镜像

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
$ mkdir -p $HOME/padmon/hello
$ cd $HOME/podman/hello
$ cat Dockerfile
FROM docker.io/library/ubuntu:latest

RUN echo 'hello'
# 第一次构建出错
podman build -t hello:1.0 .
STEP 1: FROM docker.io/library/ubuntu:latest
Getting image source signatures
Copying blob fee5db0ff82f done
Copying blob fc878cd0a91c done
Copying blob d51af753c3d3 done
Copying blob 6154df8ff988 done
Error: error creating build container: Error writing blob: error storing blob to file "/var/tmp/storage169362295/3": unexpected EOF
# 我啥都没干,重新试了一下
$ podman build -t hello:1.0 .
STEP 1: FROM docker.io/library/ubuntu:latest
Getting image source signatures
Copying blob 6154df8ff988 done
Copying blob d51af753c3d3 done
Copying blob fee5db0ff82f done
Copying blob fc878cd0a91c done
Copying config 1d622ef86b done
Writing manifest to image destination
Storing signatures
STEP 2: RUN echo 'hello'
hello
STEP 3: COMMIT hello:1.0
58013a9566306982c614d34f74ba6c658182a640e4fd31bd9a69698791b2f782
$ podman images
REPOSITORY TAG IMAGE ID CREATED SIZE
localhost/hello 1.0 58013a956630 About a minute ago 76.3 MB
docker.io/library/ubuntu latest 1d622ef86b13 10 days ago 76.3 MB

拉取

1
2
3
4
5
6
7
8
podman image pull nginx
#前两次失败,啥也没干,第三次成功 失败的原因是unexpected EOF
# 从github的issue上来看显然不是我一个人人品不行,多尝试几次,有时候会成功。
$ podman images
REPOSITORY TAG IMAGE ID CREATED SIZE
localhost/hello 1.0 58013a956630 9 minutes ago 76.3 MB
docker.io/library/ubuntu latest 1d622ef86b13 10 days ago 76.3 MB
docker.io/library/nginx latest 602e111c06b6 11 days ago 131 MB

除了像 Docker 一样从网络拉取镜像,Podman 为了方便用户从 Docker 迁移过来,Podman 支持从本地的 docker daemon 中直接拉取镜像,如果没有 domain 的话,目前会自动补全 docker.io/library/ 前缀。

检查和删除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$ podman image inspect docker.io/library/nginx |head -n 15
[
{
"Id": "602e111c06b6934013578ad80554a074049c59441d9bcd963cb4a7feccede7a5",
"Digest": "sha256:86ae264c3f4acb99b2dee4d0098c40cb8c46dcf9e1148f05d3a51c4df6758c12",
"RepoTags": [
"docker.io/library/nginx:latest"
],
"RepoDigests": [
"docker.io/library/nginx@sha256:86ae264c3f4acb99b2dee4d0098c40cb8c46dcf9e1148f05d3a51c4df6758c12",
"docker.io/library/nginx@sha256:cccef6d6bdea671c394956e24b0d0c44cd82dbe83f543a47fdc790fadea48422"
],
"Parent": "",
"Comment": "",
"Created": "2020-04-23T13:03:01.355887897Z",
"Config": {

$ podman image rm docker.io/library/nginx
Untagged: docker.io/library/nginx:latest
Deleted: 602e111c06b6934013578ad80554a074049c59441d9bcd963cb4a7feccede7a5

$ podman images
REPOSITORY TAG IMAGE ID CREATED SIZE
localhost/hello 1.0 58013a956630 11 minutes ago 76.3 MB
docker.io/library/ubuntu latest 1d622ef86b13 10 days ago 76.3 MB

容器

运行,停止和删除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$ podman images
REPOSITORY TAG IMAGE ID CREATED SIZE
localhost/hello 1.0 58013a956630 13 minutes ago 76.3 MB
docker.io/library/ubuntu latest 1d622ef86b13 10 days ago 76.3 MB
docker.io/library/nginx latest 602e111c06b6 11 days ago 131 MB
$ podman run -it docker.io/library/ubuntu sh
# cat /etc/issue
Ubuntu 20.04 LTS \n \l

# exit
$ podman ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6e20cab0d0dc docker.io/library/ubuntu:latest sh 2 minutes ago Exited (0) About a minute ago gallant_wright
$ podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4dffd4d2a97d docker.io/library/ubuntu:latest sh 3 seconds ago Up 3 seconds ago modest_dewdney

$ podman stop 4dffd4d2a97d
4dffd4d2a97d079de9b777813b379fee66ed3b38b889545f764500032aefb1ec

$ podman rm 4dffd4d2a97d 6e20cab0d0dc
4dffd4d2a97d079de9b777813b379fee66ed3b38b889545f764500032aefb1ec
6e20cab0d0dc2007c51dc84fd2b3bd00caea2aa514b0e4f417646ba525ad5b16

$ podman ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

checkpoint/restore

Podman 提供了类似于 git 的功能,能够对 container 进行 checkpoint(commit),并且可以 restore(checkout),看着很美好的样子,我到这里已经不是很想验证了,毕竟构建或者拉取这样基础的操作都要靠人品,还是等子弹先飞一会儿再说。

健康检查

podman提供了healthcheck功能,在运行容器时,可以通过参数--healthcheck-command来指定健康检查的方式,然后通过podman healthcheck命令来检测

1
2
3
4
$ podman run -dt --name healthtest --healthcheck-command 'CMD-SHELL curl https://www.baidu.com || exit 1' --healthcheck-interval=0 nginx:latest
b3fa86705f2acfb59bcaa8bbed0a531e6fa17092593768a66bec56ba98623550
$ podman healthcheck run healthtest
unhealthy

我到现在没明白我运行容器不健康的原因,我看了一堆issue,貌似各种说法不一,没有再深究下去。

systemd

Podman没有daemon,没办法像docker一样通过指定参数--restart=always在docker进程启动时自动拉起镜像。 而采用systemd来支持该功能。

到这里我已经无力吐槽,完全没有再实验的动力了,暂时先空着吧,或许以后有机会我又会变心喜欢也有可能呢,到时候再研究这个怎么玩。

Pod

总得对得起名字啊,主要不就是为了吹k8s pod概念嘛(: 根据podman自己的目标和说法,对于最终要运行在k8s环境的来说,Podman非常适合,能很大的减少环境不通导致的工作量,Podman的YAML和k8s pod yaml文件格式是兼容的。

podman pod架构

先创建一个pod

瞅瞅帮助命令, 基本上想要的都还有。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
$ podman pod --help
Manage pods

Description:
Pods are a group of one or more containers sharing the same network, pid and ipc namespaces.

Usage:
podman pod [command]

Available Commands:
create Create a new empty pod
exists Check if a pod exists in local storage
inspect Displays a pod configuration
kill Send the specified signal or SIGKILL to containers in pod
pause Pause one or more pods
prune Remove all stopped pods
ps List pods
restart Restart one or more pods
rm Remove one or more pods
start Start one or more pods
stats Display a live stream of resource usage statistics for the containers in one or more pods
stop Stop one or more pods
top Display the running processes of containers in a pod
unpause Unpause one or more pods


$ podman pod create --help
Create a new empty pod

Description:
After creating the pod, the pod ID is printed to stdout.

You can then start it at any time with the podman pod start <pod_id> command. The pod will be created with the initial state 'created'.

Usage:
podman pod create [flags]

Flags:
--cgroup-parent string Set parent cgroup for the pod
--hostname string Set a hostname to the pod
--infra Create an infra container associated with the pod to share namespaces with (default true)
--infra-command string The command to run on the infra container when the pod is started (default "/pause")
--infra-image string The image of the infra container to associate with the pod (default "k8s.gcr.io/pause:3.1")
-l, --label strings Set metadata on pod (default [])
--label-file strings Read in a line delimited file of labels
-n, --name string Assign a name to the pod
--pod-id-file string Write the pod ID to the file
-p, --publish strings Publish a container's port, or a range of ports, to the host (default [])
--share string A comma delimited list of kernel namespaces the pod will share (default "cgroup,ipc,net,uts")

创建一个pod, 由于重新打开了终端窗口失去了科学上网的proxy,第一次timeout了,一顿操作后创建成功了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
$ podman pod create --name test_stack
217143af2d6a44fe4fee99263d01bf26ca6cf287e62b4d3807fa968daea8ef7f

$ podman run -dt --pod new:web_server -p 8080:80 nginx
e6336a56d0f217adb9938142fd0e1d98dd4b733140b7c88f4825359c096c4d3a

$ podman pod list
POD ID NAME STATUS CREATED # OF CONTAINERS INFRA ID
01e985f62511 web_server Running 7 seconds ago 2 ae0341aac4c7
9474f961f6e9 test_stack Created 50 seconds ago 1 ce0c41bf1c79

$ podman pod ps
POD ID NAME STATUS CREATED # OF CONTAINERS INFRA ID
01e985f62511 web_server Running 2 minutes ago 2 ae0341aac4c7
9474f961f6e9 test_stack Created 2 minutes ago 1 ce0c41bf1c79

$ curl localhost -I
HTTP/1.1 200 OK
Content-Length: 612
Accept-Ranges: bytes
Connection: keep-alive
Content-Type: text/html
Date: Mon, 04 May 2020 13:43:33 GMT
Etag: "5e95c66e-264"
Keep-Alive: timeout=4
Last-Modified: Tue, 14 Apr 2020 14:19:26 GMT
Proxy-Connection: keep-alive
Server: nginx/1.17.10

创建了两个pod节点,web_server这个pod中有一个容器nginx,并且暴露端口给外面,通过curl可以很轻易的验证是否正常工作。也可以检查根据端口查看哪个进程在使用

1
2
$ ss -tplun | grep 80
tcp LISTEN 0 1 0.0.0.0:80 0.0.0.0:* users:(("slirp4netns",pid=28816,fd=8))

但是坑爹是的我stop这个pod,想要再次起来却始终无法起来。

1
2
3
4
$ podman pod start web_server
ERRO[0000] "error starting some containers: container already exists"
ERRO[0000] "error from slirp4netns while setting up port redirection: map[desc:bad request: add_hostfwd: slirp_add_hostfwd failed]"
Error: a dependency of container e6336a56d0f217adb9938142fd0e1d98dd4b733140b7c88f4825359c096c4d3a failed to start: container state improper

emmmm,我理解新东西坑多点,但这个真的不是很好用啊。一开始还有给提issue的想法,现在完全没有一点意愿做这件事,而且在解决问题的过程中,能看到不少issue和我遇到的是相同的问题,都被粗暴的关闭了。

k8s联动

通过podman generate命令可以生成k8s可用的YAML文件,使用podman play命令可以直接创建完整的 Pod 及其所拥有的容器。 但是这个还是遇到了一个no matching entries in passwd file。 我没有继续尝试下去的勇气😔

总结

如果从Docker迁移过来,估计大半还是要抓狂:

  1. 缺少国内镜像源,没有科学上网,什么都做不了,即使有,也要看运气。
  2. 说好了rootless, 但是你要是想对端口映射,还是得老老实实的sudo,否则就是各种各样的问题。
  3. 各种不稳定,编译失败,拉取失败,启动pod失败,关闭pod失败,关键是很多错误根本就不知道自己错在了哪里,过一会儿又会成功。
  4. 还需要更多地用户去采坑,去修复更多地问题。
  5. 文档资源稀缺,几乎全是英文的,而且都是很简单的示例,不知道能不能经受的生产环境的各种考验。

总体来说,现在没有docker香,以后返回来看就不好说了。