What is a container
Linux container technology
A Linux container is a process with specific isolation provided by the Linux Kernel. Linux container technology allows you to package or isolate your application and its entire runtime environment (including all required files) together. This allows users to easily migrate applications between environments while retaining the full functionality of the application.
Docker’s problem
Docker is a famous open source container engine, which has become almost synonymous with containers now that container technology is gradually gaining popularity.
Docker itself is also a packaging of Linux container technology, through and provide users with a simple interface, so that users are very convenient to package and use containers.
As the mainstream container engine, Docker has a wealth of scenarios and solutions, but also has some problems.
- Docker needs to run a daemon, and all containers are children of the daemon
- Docker needs
root
identity to run the daemon
This may seem like a no-brainer, but if you try to use Docker at scale you will find that
- daemons are not as stable as you might think
- the OOM of one container is likely to drag down the parent process and affect neighboring containers
- The Docker process tree has some oddities, and you can’t be sure if it’s a Docker bug or something the Kernel has done
- The Docker container is the process started by
root
.
If we go in a different direction, is the daemon really necessary?
What is Podman
Podman was once part of the CRI-O project, but was later spun off as a separate project: libpod. Podman’s goal is to provide a Container CLI similar to Docker (even the official direct It is recommended to use: alias docker=podman
).
Installation
Installing Podman is very easy, the installation documentation: https://github.com/containers/libpod/blob/master/install.md
MacOS
Using Homebrew:
1
|
brew cask install podman
|
Fedora, CentOS
1
|
sudo yum -y install podman
|
Ubuntu(development versions)
1
2
3
4
5
|
sudo apt-get update -qq
sudo apt-get install -qq -y software-properties-common uidmap
sudo add-apt-repository -y ppa:projectatomic/ppa
sudo apt-get update -qq
sudo apt-get -qq -y install podman
|
Use
The following experiments are based on Podman V1.4.4.
1
2
3
4
5
|
# podman version
Version: 1.4.4
RemoteAPI Version: 1
Go Version: go1.10.3
OS/Arch: linux/amd64
|
Pulling images
Podman will pull the registry.access.redhat.com
image first by default. If the pull fails, Podman will try the docker.io
image again.
1
2
3
4
5
6
7
8
9
10
11
|
# podman pull nginx
Trying to pull registry.access.redhat.com/nginx...ERRO[0001] Error pulling image ref //registry.access.redhat.com/nginx:latest: Error initializing source docker://registry.access.redhat.com/nginx:latest: Error reading manifest latest in registry.access.redhat.com/nginx: name unknown: Repo not found
Failed
Trying to pull docker.io/library/nginx...Getting image source signatures
Copying blob 7acba7289aa3 done
Copying blob b8f262c62ec6 done
Copying blob e9218e8f93b1 done
Copying config f949e7d76d done
Writing manifest to image destination
Storing signatures
f949e7d76d63befffc8eec2cbf8a6f509780f96fb3bacbdc24068d594a77f043
|
Podman’s data path is under /var/lib/containers
, similar to Docker, which holds data such as layers.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
[root@podman-test-vm lib]# tree /var/lib/containers/ -L 2
/var/lib/containers/
├── cache
│ └── blob-info-cache-v1.boltdb
└── storage
├── libpod
├── mounts
├── overlay
├── overlay-containers
├── overlay-images
├── overlay-layers
├── storage.lock
└── tmp
|
You can see the information of the images you just pulled.
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
|
[root@podman-test-vm lib]# cat /var/lib/containers/storage/overlay-images/images.json | python -m json.tool
[
{
"big-data-digests": {
"manifest": "sha256:066edc156bcada86155fd80ae03667cf3811c499df73815a2b76e43755ebbc76",
"manifest-sha256:066edc156bcada86155fd80ae03667cf3811c499df73815a2b76e43755ebbc76": "sha256:066edc156bcada86155fd80ae03667cf3811c499df73815a2b76e43755ebbc76",
"sha256:f949e7d76d63befffc8eec2cbf8a6f509780f96fb3bacbdc24068d594a77f043": "sha256:f949e7d76d63befffc8eec2cbf8a6f509780f96fb3bacbdc24068d594a77f043"
},
"big-data-names": [
"sha256:f949e7d76d63befffc8eec2cbf8a6f509780f96fb3bacbdc24068d594a77f043",
"manifest-sha256:066edc156bcada86155fd80ae03667cf3811c499df73815a2b76e43755ebbc76",
"manifest"
],
"big-data-sizes": {
"manifest": 948,
"manifest-sha256:066edc156bcada86155fd80ae03667cf3811c499df73815a2b76e43755ebbc76": 948,
"sha256:f949e7d76d63befffc8eec2cbf8a6f509780f96fb3bacbdc24068d594a77f043": 6669
},
"created": "2019-09-24T23:33:17.034191345Z",
"digest": "sha256:066edc156bcada86155fd80ae03667cf3811c499df73815a2b76e43755ebbc76",
"id": "f949e7d76d63befffc8eec2cbf8a6f509780f96fb3bacbdc24068d594a77f043",
"layer": "ea345052c98934e4e4673b2d359b5000a9ff1cc7f0332df0d406980f172deea6",
"metadata": "{}",
"names": [
"docker.io/library/nginx:latest"
]
}
]
|
Starting containers
Most of Podman’s commands are compatible with Docker, so you can start containers in a similar way.
1
2
3
4
5
6
|
[root@podman-test-vm ~]# podman run -p 80:80 --name=web -d nginx
9d284597eeedbbdfb4df933e063fe1035cbd39f1e712173f7a8a3652773eac02
[root@podman-test-vm ~]# podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9d284597eeed docker.io/library/nginx:latest nginx -g daemon o... 48 seconds ago Up 48 seconds ago 0.0.0.0:80->80/tcp web
|
Try checking the processes of nginx.
1
2
3
4
|
[root@podman-test-vm ~]# ps -ef | grep nginx
root 2518 2508 0 12:01 ? 00:00:00 nginx: master process nginx -g daemon off;
101 2529 2518 0 12:01 ? 00:00:00 nginx: worker process
root 2637 1259 0 12:10 pts/0 00:00:00 grep --color=auto nginx
|
Then view the process tree based on the pid.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
[root@podman-test-vm ~]# pstree -H 2518
systemd─┬─NetworkManager─┬─2*[dhclient]
│ └─2*[{NetworkManager}]
├─anacron
├─auditd───{auditd}
├─conmon─┬─nginx───nginx
│ └─{conmon}
├─crond
├─dbus-daemon───{dbus-daemon}
├─firewalld───{firewalld}
├─login───bash
├─lvmetad
├─master─┬─pickup
│ └─qmgr
├─polkitd───5*[{polkitd}]
├─rsyslogd───2*[{rsyslogd}]
├─sshd───sshd───bash───pstree
├─systemd-journal
├─systemd-logind
├─systemd-udevd
└─tuned───4*[{tuned}]
|
View the parent process based on ppid.
1
2
3
4
|
[root@podman-test-vm ~]# ps -ef | grep 2508
root 2508 1 0 12:01 ? 00:00:00 /usr/libexec/podman/conmon -s -c 9d284597eeedbbdfb4df933e063fe1035cbd39f1e712173f7a8a3652773eac02 -u 9d284597eeedbbdfb4df933e063fe1035cbd39f1e712173f7a8a3652773eac02 -n web -r /usr/bin/runc -b /var/lib/containers/storage/overlay-containers/9d284597eeedbbdfb4df933e063fe1035cbd39f1e712173f7a8a3652773eac02/userdata -p /var/run/containers/storage/overlay-containers/9d284597eeedbbdfb4df933e063fe1035cbd39f1e712173f7a8a3652773eac02/userdata/pidfile --exit-dir /var/run/libpod/exits --exit-command /usr/bin/podman --exit-command-arg --root --exit-command-arg /var/lib/containers/storage --exit-command-arg --runroot --exit-command-arg /var/run/containers/storage --exit-command-arg --log-level --exit-command-arg error --exit-command-arg --cgroup-manager --exit-command-arg systemd --exit-command-arg --tmpdir --exit-command-arg /var/run/libpod --exit-command-arg --runtime --exit-command-arg runc --exit-command-arg --storage-driver --exit-command-arg overlay --exit-command-arg container --exit-command-arg cleanup --exit-command-arg 9d284597eeedbbdfb4df933e063fe1035cbd39f1e712173f7a8a3652773eac02 --socket-dir-path /var/run/libpod/socket -l k8s-file:/var/lib/containers/storage/overlay-containers/9d284597eeedbbdfb4df933e063fe1035cbd39f1e712173f7a8a3652773eac02/userdata/ctr.log --log-level error
root 2518 2508 0 12:01 ? 00:00:00 nginx: master process nginx -g daemon off;
root 2639 1259 0 12:10 pts/0 00:00:00 grep --color=auto 2508
|
As you can see, podman starts the container through podman/conmon, and this process is hooked under pid 1, which is systemd.
podman/conmon is Podman’s initiator and is responsible for two main functions: monitoring runc and managing containers with runc’s capabilities, and establishing communication with Podman and passing instructions for container operations.
Podman does not communicate with using the CRI protocol. Instead, Podman creates containers using runc, and manages storage using containers/storage. Technically, Podman launches conmon which launches and monitors the OCI Runtime (runc). Podman can exit and later reconnect to conmon to talk to the container. Runc stops running once the container starts.
《Crictl Vs Podman》:https://blog.openshift.com/crictl-vs-podman/
Build images
Podman can be built directly using Dockerfile.
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
|
[root@podman-test-vm ~]# git clone https://github.com/DaoCloud/dao-2048.git
正克隆到 'dao-2048'...
remote: Enumerating objects: 116, done.
remote: Total 116 (delta 0), reused 0 (delta 0), pack-reused 116
接收对象中: 100% (116/116), 304.76 KiB | 60.00 KiB/s, done.
处理 delta 中: 100% (40/40), done.
[root@podman-test-vm ~]# podman build dao-2048/
STEP 1: FROM daocloud.io/nginx:1.11-alpine
Getting image source signatures
Copying blob ed383a1b82df done
Copying blob c92260fe6357 done
Copying blob 4b21d71b440a done
Copying blob 709515475419 done
Copying config bedece1f06 done
Writing manifest to image destination
Storing signatures
STEP 2: MAINTAINER Golfen Guo <golfen.guo@daocloud.io>
711d32f788782528ad36a0c12ae895993474b168f7f2d65158e531a924b3dd55
STEP 3: COPY . /usr/share/nginx/html
b859763deeb7eaab39fd8c34a8c8af18e8de74c80e98f9fcb1e0c694881c5e9c
STEP 4: EXPOSE 80
eedb1a66c8316a309546b21a5c687f3e3611927b54a7fa0f4dbd3f175eeb253c
STEP 5: CMD sed -i "s/ContainerID: /ContainerID: "$(hostname)"/g" /usr/share/nginx/html/index.html && nginx -g "daemon off;"
STEP 6: COMMIT
fda5a2d14a918c3eb088c28dc0d8e89e66b061923a82e8722d9e2a62c994422d
[root@podman-test-vm ~]# podman images
REPOSITORY TAG IMAGE ID CREATED SIZE
<none> <none> fda5a2d14a91 22 seconds ago 56.9 MB
docker.io/library/nginx latest f949e7d76d63 4 days ago 130 MB
daocloud.io/nginx 1.11-alpine bedece1f06cc 2 years ago 55.9 MB
|
Dockerfile:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
[root@podman-test-vm ~]# cat dao-2048/Dockerfile
# Using a compact OS
FROM daocloud.io/nginx:1.11-alpine
MAINTAINER Golfen Guo <golfen.guo@daocloud.io>
# Add 2048 stuff into Nginx server
COPY . /usr/share/nginx/html
EXPOSE 80
# Start Nginx and keep it running background and start php
CMD sed -i "s/ContainerID: /ContainerID: "$(hostname)"/g" /usr/share/nginx/html/index.html
|
Problem
Podman is committed to removing the daemon, which means that Podman cannot do the tasks that need to be done by the daemon.
Restart issues
In Docker, you can specify a restart policy with the -restart
command, so that when a node restarts, the container with the restart policy will recover itself as long as dockerd is up.
Since Podman entrusts the management of containers to systemd, the official advice is to use systemd to solve this problem. describe the boot method and restart policy.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
$ vim /etc/systemd/system/nginx_container.service
[Unit]
Description=Podman Nginx Service
After=network.target
After=network-online.target
[Service]
Type=simple
ExecStart=/usr/bin/podman start -a nginx
ExecStop=/usr/bin/podman stop -t 10 nginx
Restart=always
[Install]
WantedBy=multi-user.target
|
Although some trouble (and feel a bit against the trend), but if you think about it, this is not the more recommended way to manage services on Linux. Secondly, although Docker supports container self-starting, it does not support sequential startup according to dependencies, but using systemd’s ability to make startup dependencies through After
, you can better manage the startup order instead.