最近技术群里有朋友问我,不是说K8S要弃用Docker了吗?还要不要继续学习这块内容?是不是得改行卖白菜了?
毫无疑问,传统虚拟机的造反,容器化的革命是从Docker开始的。发展至今,并成为最受欢迎和广泛使用的容器管理系统之一。它改变了我们构建云原生应用程序的方式。Docker为构建、部署和管理容器提供了非常好的端到端架构。
作为一种开源的应用容器引擎,基于 Linux 容器的一种封装,Docker 提供简单易用的容器使用接口,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上。容器是完全使用沙箱机制,相互之间不会有任何接口。Docker体系结构基于守护程序,该守护程序在后台作为服务运行。Docker守护程序负责运行命令,将镜像推入/拉出仓库或从中拉出镜像,管理计算机上的容器和镜像。
下面我们看下Docker的体系架构,具体如下所示:
基于上述架构图,我们可以看出,Docker体系主要围绕“Docker Daemon 和 Docker CLI”2大核心组件运行:
Docker Daemon:一个常驻的系统后台进程,帮助管理和创建 Docker 镜像、容器、网络和存储卷等。
Docker CLI:一个用来与 Docker 守护进程进行交互的 Docker 命令行客户端。
除此之外,Docker Engine REST API,应用程序用来与 Docker 守护进程进行交互的 API,可以通过 HTTP 客户端来访问它。
Podman 是一个开源的容器运行时项目,可在大多数 Linux 平台上使用。Podman 提供与 Docker 非常相似的功能。正如前面提到的那样,它不需要在你的系统上运行任何守护进程,并且它也可以在没有 root 权限的情况下运行。
Podman 可以管理和运行任何符合 OCI(Open Container Initiative)规范的容器和容器镜像。Podman 提供了一个与 Docker 兼容的命令行前端来管理 Docker 镜像。
下面我们看下Podman的体系架构,具体如下所示:
相比Docker,Podman没有Daemon的概念,直接通过 OCI runtime(默认也是 runc)来启动容器,所以容器的进程是 Podman 的子进程。这比较像 Linux 的 fork/exec 模型,而 Docker 采用的是 C/S(客户端/服务器)模型。与 C/S 模型相比,fork/exec 模型有很多优势。
那么,针对Podman 和Docker,它们到底有哪些本质不同之处呢?
具体,Docker 需要在我们的系统上运行一个守护进程(Docker Daemon),而Podman 则不需要。
两者启动容器方式不同:
1、Docker Cli 命令通过API跟 Docker Engine(引擎)交互告诉它我想创建一个Container,然后Docker Engine才会调用OCI Container Runtime(runc)来启动一个Container。这代表Container的Process(进程)不会是Docker CLI的Child Process(子进程),而是Docker Engine的Child Process。
2、Podman是直接给OCI Containner Runtime(runc)进行交互来创建Container的,所以Container Process直接是Podman的Child Process。
3、因为Docke有Docker Daemon,所以Docker启动的容器支持--restart策略,但Podman不支持,如果在K8S中就不存在这个问题,我们可以设置Pod的重启策略,在系统中我们可以采用编写Systemd服务来完成自启动。
4、Docker需要使用root用户来创建容器,而Podman则不需要。
下面我们就针对Podman相关具体实践操作进行简要解析,以方便大家能够熟悉2者之间的差异,具体如下:
[administrator@JavaLangOutOfMemory ~ ]%podman version Version: 1.6.4 RemoteAPI Version: 1 Go Version: go1.12.12 OS/Arch: linux/amd64
[administrator@JavaLangOutOfMemory ~ ]%podman info host: BuildahVersion: 1.11.5 CgroupVersion: v1 Conmon: package: conmon-2.0.8-1.el7.x86_64 path: /usr/bin/conmon version: 'conmon version 2.0.8, commit: f85c8b1ce77b73bcd48b2d802396321217008762' Distribution: distribution: '"centos"' version: "7" MemFree: 339603456 MemTotal: 3973734400 OCIRuntime: name: runc package: containerd.io-1.2.13-3.2.el7.x86_64 path: /usr/bin/runc version: |- runc version 1.0.0-rc10 commit: dc9208a3303feef5b3839f4323d9beb36df0a9dd spec: 1.0.1-dev SwapFree: 0 SwapTotal: 0 arch: amd64 cpus: 2 eventlogger: journald hostname: k8s-node01 kernel: 3.10.0-1127.18.2.el7.x86_64 os: linux rootless: false uptime: 3h 44m 8.68s (Approximately 0.12 days) registries: blocked: null insecure: null search: - registry.access.redhat.com - registry.redhat.io - docker.io store: ConfigFile: /etc/containers/storage.conf ContainerStore: number: 3 GraphDriverName: overlay GraphOptions: {} GraphRoot: /var/lib/containers/storage GraphStatus: Backing Filesystem: xfs Native Overlay Diff: "true" Supports d_type: "true" Using metacopy: "false" ImageStore: number: 4 RunRoot: /var/run/containers/storage VolumePath: /var/lib/containers/storage/volumes
现在,我们运行一个简单的示例容器,以Tomcat Web容器为例,具体如下所示:
[administrator@JavaLangOutOfMemory ~ ]% podman run -d -t -p 9988:9988 tomcat Trying to pull registry.access.redhat.com/tomcat... name unknown: Repo not found Trying to pull registry.redhat.io/tomcat... unable to retrieve auth token: invalid username/password: unauthorized: Please login to the Red Hat Registry using your Customer Portal credentials. Further instructions can be found here: https://access.redhat.com/RegistryAuthentication Trying to pull docker.io/library/tomcat... Getting image source signatures Copying blob d557ee20540b skipped: already exists Copying blob b9a857cbf04d skipped: already exists Copying blob 667fd949ed93 skipped: already exists Copying blob 3b9ca4f00c2e skipped: already exists Copying blob 661d3b55f657 skipped: already exists Copying blob 0115df4a56b1 done Copying blob 292eeca13ab1 done Copying blob 6f89638f9b1f done Copying blob a2353fa2a135 done Copying blob 511ef4338a0b done Copying config 345867df08 done Writing manifest to image destination Storing signatures 3887123f2a92beda0a949e5f462ce7fde8c4b7fb7a3ebf6f0738064bae17c917
此时,列出所有创建的容器,具体如下:
[administrator@JavaLangOutOfMemory ~ ]% podman ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 3887123f2a92 docker.io/library/tomcat:latest catalina.sh run 2 minutes ago Up 2 minutes ago 0.0.0.0:9988->9988/tcp luga-tomcat-2 66c05be56143 docker.io/unidata/tomcat-docker:latest start-tomcat.sh 8 minutes ago Up 8 minutes ago 0.0.0.0:8088->8088/tcp luga-tomcat-1 6accf83c23c9 docker.io/library/nginx:alpine nginx -g daemon o... 30 minutes ago Up 30 minutes ago luga-nginx
我们再看下容器是否运行成功,可借助Log参考,具体如下所示:
[administrator@JavaLangOutOfMemory ~ ]% podman logs 3887123f2a92 Using CATALINA_BASE: /usr/local/tomcat Using CATALINA_HOME: /usr/local/tomcat Using CATALINA_TMPDIR: /usr/local/tomcat/temp Using JRE_HOME: /usr/local/openjdk-11 Using CLASSPATH: /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar Using CATALINA_OPTS: NOTE: Picked up JDK_JAVA_OPTIONS: --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED --add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED 01-Feb-2021 17:35:57.858 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version name: Apache Tomcat/9.0.41 01-Feb-2021 17:35:57.957 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server built: Dec 3 2020 11:43:00 UTC 01-Feb-2021 17:35:57.959 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version number: 9.0.41.0 01-Feb-2021 17:35:57.959 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Name: Linux 01-Feb-2021 17:35:57.969 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Version: 3.10.0-1127.18.2.el7.x86_64 01-Feb-2021 17:35:57.969 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Architecture: amd64 01-Feb-2021 17:35:57.980 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Java Home: /usr/local/openjdk-11 01-Feb-2021 17:35:57.980 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Version: 11.0.10+9 01-Feb-2021 17:35:57.980 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Vendor: Oracle Corporation 01-Feb-2021 17:35:57.981 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_BASE: /usr/local/tomcat 01-Feb-2021 17:35:57.981 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_HOME: /usr/local/tomcat 01-Feb-2021 17:35:58.141 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.lang=ALL-UNNAMED 01-Feb-2021 17:35:58.141 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.io=ALL-UNNAMED 01-Feb-2021 17:35:58.144 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED 01-Feb-2021 17:35:58.144 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.config.file=/usr/local/tomcat/conf/logging.properties 01-Feb-2021 17:35:58.145 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager 01-Feb-2021 17:35:58.148 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djdk.tls.ephemeralDHKeySize=2048 01-Feb-2021 17:35:58.149 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.protocol.handler.pkgs=org.apache.catalina.webresources 01-Feb-2021 17:35:58.149 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dorg.apache.catalina.security.SecurityListener.UMASK=0027 01-Feb-2021 17:35:58.149 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dignore.endorsed.dirs= 01-Feb-2021 17:35:58.150 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.base=/usr/local/tomcat 01-Feb-2021 17:35:58.150 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.home=/usr/local/tomcat 01-Feb-2021 17:35:58.150 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.io.tmpdir=/usr/local/tomcat/temp 01-Feb-2021 17:35:58.229 INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent Loaded Apache Tomcat Native library [1.2.25] using APR version [1.6.5]. 01-Feb-2021 17:35:58.233 INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent APR capabilities: IPv6 [true], sendfile [true], accept filters [false], random [true]. 01-Feb-2021 17:35:58.237 INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent APR/OpenSSL configuration: useAprConnector [false], useOpenSSL [true] 01-Feb-2021 17:35:58.261 INFO [main] org.apache.catalina.core.AprLifecycleListener.initializeSSL OpenSSL successfully initialized [OpenSSL 1.1.1d 10 Sep 2019] 01-Feb-2021 17:36:03.709 INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["http-nio-8080"] 01-Feb-2021 17:36:04.128 INFO [main] org.apache.catalina.startup.Catalina.load Server initialization in [9607] milliseconds 01-Feb-2021 17:36:05.784 INFO [main] org.apache.catalina.core.StandardService.startInternal Starting service [Catalina] 01-Feb-2021 17:36:05.785 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet engine: [Apache Tomcat/9.0.41] 01-Feb-2021 17:36:06.135 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"] 01-Feb-2021 17:36:06.778 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in [2648] milliseconds
同时,我们查看其进程资源,具体如下所示:
[administrator@JavaLangOutOfMemory ~ ]% podman top 3887123f2a92 USER PID PPID %CPU ELAPSED TTY TIME COMMAND root 1 0 5.313 21m57.402336601s pts/0 1m10s /usr/local/openjdk-11/bin/java -Djava.util.logging.config.file=/usr/local/tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Dorg.apache.catalina.security.SecurityListener.UMASK=0027 -Dignore.endorsed.dirs= -classpath /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar -Dcatalina.base=/usr/local/tomcat -Dcatalina.home=/usr/local/tomcat -Djava.io.tmpdir=/usr/local/tomcat/temp org.apache.catalina.startup.Bootstrap start
[administrator@JavaLangOutOfMemory ~ ]% podman stats 3887123f2a92 ID NAME CPU % MEM USAGE / LIMIT MEM % NET IO BLOCK IO PIDS 3887123f2a92 festive_chandrasekhar 3.10% 83.09MB / 3.974GB 2.09% 1.028kB / 836B -- / -- 36 ID NAME CPU % MEM USAGE / LIMIT MEM % NET IO BLOCK IO PIDS 3887123f2a92 festive_chandrasekhar 3.02% 83.09MB / 3.974GB 2.09% 1.028kB / 836B -- / -- 36 ID NAME CPU % MEM USAGE / LIMIT MEM % NET IO BLOCK IO PIDS 3887123f2a92 festive_chandrasekhar 6.11% 83.09MB / 3.974GB 2.09% 1.028kB / 836B -- / -- 36 ID NAME CPU % MEM USAGE / LIMIT MEM % NET IO BLOCK IO PIDS 3887123f2a92 festive_chandrasekhar 1.08% 83.09MB / 3.974GB 2.09% 1.028kB / 836B -- / -- 36
然后,我们通过CURL命令查看,具体如下所示:
[administrator@JavaLangOutOfMemory ~ ]% curl http://192.168.56.109:8888/ <!doctype html><html lang="en"><head><title>HTTP Status 404 – Not Found</title><style type="text/css">body {font-family:Tahoma,Arial,sans-serif;} h1, h2, h3, b {color:white;background-color:#525D76;} h1 {font-size:22px;} h2 {font-size:16px;} h3 {font-size:14px;} p {font-size:12px;} a {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style></head><body><h1>HTTP Status 404 – Not Found</h1><hr class="line" /><p><b>Type</b> Status Report</p><p><b>Description</b> The origin server did not find a current representation for the target resource or is not willing to disclose that one exists.</p><hr class="line" /><h3>Apache Tomcat/9.0.41</h3></body></html
由于 Podman 不再使用守护进程管理服务,所以不能通过守护进程去实现自动重启容器的功能。那如果要实现开机自动重启容器,又该如何实现呢?很简单,现在大多数系统都已经采用 Systemd 作为守护进程管理工具。有兴趣的可以自行尝试。
由上面的返回结果可知,服务已经正常启动,至此,Podman解析到此为止。
回到前面的问题:K8S为什么要弃用Docker?因为,Docker 至始至终并不支持 CRI(容器运行时接口)这一Kubernetes运行时API,而 Kubernetes 用户一直以来所使用的其实是名为“dockershim”的桥接服务。Dockershim 能够转换 Docker API 与 CRI,但在后续版本当中,Kubernetes 将不再提供这项桥接服务。针对CRI运行时,后续文章将对其进行剖析。