Podman 是 Docker 的直接替代品吗?

news2024/12/23 19:18:33

在许多地方,你可以读到Podman是Docker的替代品。但是,真的像听起来那么简单吗?在这篇文章中,你将从一个可以立即投入生产使用的Dockerfile开始,并执行Podman命令,就像你使用Docker时会做的那样。让我们看看这是否可以无任何问题地工作!

引言

Podman是一个容器引擎,就像Docker一样。然而,Podman是一个无守护进程的容器引擎,它默认运行的是无根容器(rootless containers)。这比作为根用户运行容器更安全。现在,Docker守护进程也可以作为非根用户运行。

Podman在其网站上宣传,Podman是Docker的替代品。只需添加alias docker=podman ,你就会没问题。让我们看看是否就那么简单。

在本文的余下部分,你将尝试构建一个用于运行Spring Boot应用程序的生产就绪的Dockerfile。你将把它作为一个单独的容器来运行,并且你将尝试运行两个容器并进行一些容器间的通信。最后,你将验证如何挂载卷。本文的一个先决条件是使用Linux操作系统。Podman不适用于Windows。本文使用的源代码可以在GitHub上找到。

你将使用的Dockerfile运行一个Spring Boot应用程序。这是一个基础的Spring Boot应用程序,包含一个返回欢迎消息的控制器。

构建jar文件:

$ mvn clean verify

运行jar文件:

$ java -jar target/mypodmanplanet-0.0.1-SNAPSHOT.jar

检查端点:

$ curl http://localhost:8080/hello
Hello Podman!

文件1-Dockerfile-starter可以在Dockerfiles目录中找到。

FROM eclipse-temurin:17.0.6_10-jre-alpine@sha256:c26a727c4883eb73d32351be8bacb3e70f390c2c94f078dc493495ed93c60c2f AS builder
WORKDIR application
ARG JAR_FILE
COPY target/${JAR_FILE} app.jar
RUN java -Djarmode=layertools -jar app.jar extract

FROM eclipse-temurin:17.0.6_10-jre-alpine@sha256:c26a727c4883eb73d32351be8bacb3e70f390c2c94f078dc493495ed93c60c2f
WORKDIR /opt/app
RUN addgroup --system javauser && adduser -S -s /usr/sbin/nologin -G javauser javauser
COPY --from=builder application/dependencies/ ./
COPY --from=builder application/spring-boot-loader/ ./
COPY --from=builder application/snapshot-dependencies/ ./
COPY --from=builder application/application/ ./
RUN chown -R javauser:javauser .
USER javauser

ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"]

先决条件

本文的先决条件是:

  • 基本的Linux知识,本篇文章中使用的是Ubuntu 22.04;
  • 基本的Java和Spring Boot知识;
  • 基本的Docker知识。

安装

安装Podman非常简单。只需运行以下命令。

$ sudo apt-get install podman

验证正确的安装。

$ podman --version
podman version 3.4.4

你还可以安装podman-docker,当你在命令中使用docker时,它会创建一个别名。建议等到本篇文章的结论部分再安装这个。

构建Dockerfile

首先要做的是构建容器镜像。从仓库的根目录执行以下命令。

$ podman build . --tag mydeveloperplanet/mypodmanplanet:0.0.1-SNAPSHOT -f Dockerfiles/1-Dockerfile-starter --build-arg JAR_FILE=mypodmanplanet-0.0.1-SNAPSHOT.jar
[1/2] STEP 1/5: FROM eclipse-temurin:17.0.6_10-jre-alpine@sha256:c26a727c4883eb73d32351be8bacb3e70f390c2c94f078dc493495ed93c60c2f AS builder
[2/2] STEP 1/10: FROM eclipse-temurin:17.0.6_10-jre-alpine@sha256:c26a727c4883eb73d32351be8bacb3e70f390c2c94f078dc493495ed93c60c2f
Error: error creating build container: short-name "eclipse-temurin@sha256:c26a727c4883eb73d32351be8bacb3e70f390c2c94f078dc493495ed93c60c2f" did not resolve to an alias and no unqualified-search registries are defined in "/etc/containers/registries.conf"

这会在检索基础镜像时返回一个错误。错误信息引用了/etc/containers/registries.conf。这个文件中写明了以下内容。

# For more information on this configuration file, see containers-registries.conf(5).
#
# NOTE: RISK OF USING UNQUALIFIED IMAGE NAMES
# We recommend always using fully qualified image names including the registry
# server (full dns name), namespace, image name, and tag
# (e.g., registry.redhat.io/ubi8/ubi:latest). Pulling by digest (i.e.,
# quay.io/repository/name@digest) further eliminates the ambiguity of tags.
# When using short names, there is always an inherent risk that the image being
# pulled could be spoofed. For example, a user wants to pull an image named
# `foobar` from a registry and expects it to come from myregistry.com. If
# myregistry.com is not first in the search list, an attacker could place a
# different `foobar` image at a registry earlier in the search list. The user
# would accidentally pull and run the attacker's image and code rather than the
# intended content. We recommend only adding registries which are completely
# trusted (i.e., registries which don't allow unknown or anonymous users to
# create accounts with arbitrary names). This will prevent an image from being
# spoofed, squatted or otherwise made insecure.  If it is necessary to use one
# of these registries, it should be added at the end of the list.

总的来说,建议使用全限定的镜像名称。这意味着你需要将含有以下内容的行:

eclipse-temurin:17.0.6_10-jre-alpine@sha256:c26a727c4883eb73d32351be8bacb3e70f390c2c94f078dc493495ed93c60c2f

更改为:

docker.io/eclipse-temurin:17.0.6_10-jre-alpine@sha256:c26a727c4883eb73d32351be8bacb3e70f390c2c94f078dc493495ed93c60c2f

你只需要在镜像名称前添加docker.io/。这是一个微小的改变,但已经是与Docker的一处不同了。

镜像名称在文件2-Dockerfile-fix-shortname中已经被修正,所以我们再试一次构建镜像。

$ podman build . --tag mydeveloperplanet/mypodmanplanet:0.0.1-SNAPSHOT -f Dockerfiles/2-Dockerfile-fix-shortname --build-arg JAR_FILE=mypodmanplanet-0.0.1-SNAPSHOT.jar
[1/2] STEP 1/5: FROM docker.io/eclipse-temurin:17.0.6_10-jre-alpine@sha256:c26a727c4883eb73d32351be8bacb3e70f390c2c94f078dc493495ed93c60c2f AS builder
Trying to pull docker.io/library/eclipse-temurin@sha256:c26a727c4883eb73d32351be8bacb3e70f390c2c94f078dc493495ed93c60c2f...
Getting image source signatures
Copying blob 72ac8a0a29d6 done 
Copying blob f56be85fc22e done 
Copying blob f8ed194273be done 
Copying blob e5daea9ee890 done 
[2/2] STEP 1/10: FROM docker.io/eclipse-temurin:17.0.6_10-jre-alpine@sha256:c26a727c4883eb73d32351be8bacb3e70f390c2c94f078dc493495ed93c60c2f
Error: error creating build container: writing blob: adding layer with blob "sha256:f56be85fc22e46face30e2c3de3f7fe7c15f8fd7c4e5add29d7f64b87abdaa09": Error processing tar file(exit status 1): potentially insufficient UIDs or GIDs available in user namespace (requested 0:42 for /etc/shadow): Check /etc/subuid and /etc/subgid: lchown /etc/shadow: invalid argument

现在有一个关于用户命名空间中可能的UID或GID不足的错误。你可以在这里找到更多关于此错误的信息。这篇文章非常详细地解释了这个问题,重复所有内容太过繁琐。总的来说,试图拉取的镜像,其文件所属的UID超过了65,536。由于这个问题,镜像无法适应无根Podman的默认UID映射,后者限制了可用的UID和GID数量。

那么,如何解决这个问题呢?

首先,检查/etc/subuid 和 /etc/subgid 的内容。在我的情况下,输出如下。对于你来说,可能会有所不同。

$ cat /etc/subuid
admin:100000:65536
$ cat /etc/subgid
admin:100000:65536

输出中列出的admin用户有100,000作为第一个可用的UID或GID,并且大小为65,536。格式为user:start:size。这意味着admin用户可以访问从100,000到包括165,535在内的UID或GID。

我的当前用户在这里没有列出,这意味着我的用户只能为容器分配1个UID和1个GID。这1个UID/GID已经被容器中的root用户使用了。如果一个容器镜像需要一个额外的用户,就会出现问题,如你在上面所看到的。

这个问题可以通过为你的用户添加UID和GID来解决。让我们给你的用户添加从200,000到包括265,535的值。

$ sudo usermod --add-subuids 200000-265535 --add-subgids 200000-265535 <replace with your user>

再次验证两个文件的内容。用户已添加到两个文件中。

$ cat /etc/subgid
admin:100000:65536
<your user>:200000:65536
$ cat /etc/subuid
admin:100000:65536
<your user>:200000:65536

其次,你需要运行以下命令。

$ podman system migrate

再次尝试构建镜像,现在它可以工作了。

$ podman build . --tag mydeveloperplanet/mypodmanplanet:0.0.1-SNAPSHOT -f Dockerfiles/2-Dockerfile-fix-shortname --build-arg JAR_FILE=mypodmanplanet-0.0.1-SNAPSHOT.jar
[1/2] STEP 1/5: FROM docker.io/eclipse-temurin:17.0.6_10-jre-alpine@sha256:c26a727c4883eb73d32351be8bacb3e70f390c2c94f078dc493495ed93c60c2f AS builder
Trying to pull docker.io/library/eclipse-temurin@sha256:c26a727c4883eb73d32351be8bacb3e70f390c2c94f078dc493495ed93c60c2f...
Getting image source signatures
Copying blob f56be85fc22e done 
Copying blob f8ed194273be done 
Copying blob 72ac8a0a29d6 done 
Copying blob e5daea9ee890 done 
Copying config c74d412c3d done 
Writing manifest to image destination
Storing signatures
[1/2] STEP 2/5: WORKDIR application
--> d4f0e970dc1
[1/2] STEP 3/5: ARG JAR_FILE
--> ca97dcd6f2a
[1/2] STEP 4/5: COPY target/${JAR_FILE} app.jar
--> 58d88cfa511
[1/2] STEP 5/5: RUN java -Djarmode=layertools -jar app.jar extract
--> 348cae813a4
[2/2] STEP 1/10: FROM docker.io/eclipse-temurin:17.0.6_10-jre-alpine@sha256:c26a727c4883eb73d32351be8bacb3e70f390c2c94f078dc493495ed93c60c2f
[2/2] STEP 2/10: WORKDIR /opt/app
--> 4118cdf90b5
[2/2] STEP 3/10: RUN addgroup --system javauser && adduser -S -s /usr/sbin/nologin -G javauser javauser
--> cd11f346381
[2/2] STEP 4/10: COPY --from=builder application/dependencies/ ./
--> 829bffcb6c7
[2/2] STEP 5/10: COPY --from=builder application/spring-boot-loader/ ./
--> 2a93f97d424
[2/2] STEP 6/10: COPY --from=builder application/snapshot-dependencies/ ./
--> 3e292cb0456
[2/2] STEP 7/10: COPY --from=builder application/application/ ./
--> 5dd231c5b51
[2/2] STEP 8/10: RUN chown -R javauser:javauser .
--> 4d736e8c3bb
[2/2] STEP 9/10: USER javauser
--> d7a96ca6f36
[2/2] STEP 10/10: ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"]
[2/2] COMMIT mydeveloperplanet/mypodmanplanet:0.0.1-SNAPSHOT
--> 567fd123071
Successfully tagged localhost/mydeveloperplanet/mypodmanplanet:0.0.1-SNAPSHOT
567fd1230713f151950de7151da82a19d34f80af0384916b13bf49ed72fd2fa1

像你使用Docker一样,用Podman验证镜像列表:

$ podman images
REPOSITORY                                  TAG             IMAGE ID      CREATED        SIZE
localhost/mydeveloperplanet/mypodmanplanet  0.0.1-SNAPSHOT  567fd1230713  2 minutes ago  209 MB

Podman是否可以直接替换Docker来构建Dockerfile?

不,它不是一个直接的替代品,因为你需要在Dockerfile中为基础镜像使用全限定的镜像名称,并且你需要更改用户名称空间以便能够拉取镜像。除了这两个更改之外,构建容器镜像就正常工作了。

启动容器

现在你已经构建了镜像,是时候启动一个容器了。

$ podman run --name mypodmanplanet -d localhost/mydeveloperplanet/mypodmanplanet:0.0.1-SNAPSHOT

容器已成功启动。

$ podman ps
CONTAINER ID  IMAGE                                                      COMMAND     CREATED         STATUS             PORTS       NAMES
27639dabb573  localhost/mydeveloperplanet/mypodmanplanet:0.0.1-SNAPSHOT              18 seconds ago  Up 18 seconds ago              mypodmanplanet

你也可以查看容器日志。

$ podman logs mypodmanplanet

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v3.0.5)

2023-04-22T14:38:05.896Z  INFO 1 --- [           main] c.m.m.MyPodmanPlanetApplication          : Starting MyPodmanPlanetApplication v0.0.1-SNAPSHOT using Java 17.0.6 with PID 1 (/opt/app/BOOT-INF/classes started by javauser in /opt/app)
2023-04-22T14:38:05.898Z  INFO 1 --- [           main] c.m.m.MyPodmanPlanetApplication          : No active profile set, falling back to 1 default profile: "default"
2023-04-22T14:38:06.803Z  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2023-04-22T14:38:06.815Z  INFO 1 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2023-04-22T14:38:06.816Z  INFO 1 --- [           main] o.apache.catalina.core.StandardEngine    : Starting Servlet engine: [Apache Tomcat/10.1.7]
2023-04-22T14:38:06.907Z  INFO 1 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2023-04-22T14:38:06.910Z  INFO 1 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 968 ms
2023-04-22T14:38:07.279Z  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2023-04-22T14:38:07.293Z  INFO 1 --- [           main] c.m.m.MyPodmanPlanetApplication          : Started MyPodmanPlanetApplication in 1.689 seconds (process running for 1.911)

验证端点是否可以访问。

$ curl http://localhost:8080/hello
curl: (7) Failed to connect to localhost port 8080 after 0 ms: Connection refused

这是不行的。在Docker中,你可以查看容器以看到为容器分配了哪个IP地址。

$ podman inspect mypodmanplanet | grep IPAddress
            "IPAddress": "",

看来容器没有特定的IP地址。端点在localhost上也无法访问。

解决方案是在创建容器时添加端口映射。

停止容器并删除它。

$ podman stop mypodmanplanet 
mypodmanplanet
$ podman rm mypodmanplanet 
27639dabb5730d3244d205200a409dbc3a1f350196ba238e762438a4b318ef73

再次启动容器,但这次将内部端口8080映射到外部端口8080。

$ podman run -p 8080:8080 --name mypodmanplanet -d localhost/mydeveloperplanet/mypodmanplanet:0.0.1-SNAPSHOT

再次验证是否可以访问端点。这次可以了。

$ curl http://localhost:8080/hello
Hello Podman!

在继续阅读这个文章之前,请停止并删除容器。

Podman是否可以替代Docker运行容器镜像?

不,它不是可以直接替代的。尽管可以使用与Docker完全相同的命令,但你需要明确添加端口映射。如果没有端口映射,就无法访问端点。

卷挂载

卷挂载以及访问容器外部和容器内部的目录和文件常常导致Permission Denied错误。在之前的文章中,已经详细描述了Docker引擎的这种行为。使用Podman时,看看这是如何工作的会很有趣。

接下来,你将在容器中映射一个application.properties文件,这个文件位于jar文件旁边。Spring Boot应用程序将使用这个application.properties文件。该文件将服务器端口配置为8082端口,并且文件位于存储库根目录下的properties目录中。

server.port=8082

使用端口映射从内部端口8082到外部端口8083来运行容器,并将application.properties文件挂载到容器目录/opt/app中,jar文件也位于这个目录中。卷挂载具有属性ro,以表明它是一个只读文件。

$ podman run -p 8083:8082 --volume ./properties/application.properties:/opt/app/application.properties:ro --name mypodmanplanet localhost/mydeveloperplanet/mypodmanplanet:0.0.1-SNAPSHOT

验证是否可以访问端点以及它是否工作。

$ curl http://localhost:8083/hello
Hello Podman!

在容器中打开一个shell并列出目录内容以查看文件的所有权。

$ podman exec -it mypodmanplanet sh
/opt/app $ ls -la
total 24
drwxr-xr-x    1 javauser javauser      4096 Apr 15 10:33 .
drwxr-xr-x    1 root     root          4096 Apr  9 12:57 ..
drwxr-xr-x    1 javauser javauser      4096 Apr  9 12:57 BOOT-INF
drwxr-xr-x    1 javauser javauser      4096 Apr  9 12:57 META-INF
-rw-r--r--    1 root     root            16 Apr 15 10:24 application.properties
drwxr-xr-x    1 javauser javauser      4096 Apr  9 12:57 org

在Docker中,文件将由您的本地系统用户拥有,但在Podman中,文件由root拥有。我们来检查本地系统上的文件权限。

$ ls -la
total 12
drwxr-xr-x 2 <myuser> domain users 4096 apr 15 12:24 .
drwxr-xr-x 8 <myuser> domain users 4096 apr 15 12:24 ..
-rw-r--r-- 1 <myuser> domain users   16 apr 15 12:24 application.properties

正如你所看到的,本地系统上的文件由拥有。这意味着,运行容器的主机用户,在容器内部被视为root用户。

在容器内打开一个shell,并尝试更改application.properties文件的内容。你会注意到,作为javauser用户,你并不被允许这样做。

$ podman exec -it mypodmanplanet sh
/opt/app $ vi application.properties 
/opt/app $ whoami
javauser

停止并删除容器。

运行容器,但这次使用属性U而不是ro。U后缀告诉Podman,根据容器内的UID和GID,使用正确的主机UID和GID来递归地改变源卷的所有者和组。

$ podman run -p 8083:8082 --volume ./properties/application.properties:/opt/app/application.properties:U --name mypodmanplanet localhost/mydeveloperplanet/mypodmanplanet:0.0.1-SNAPSHOT

在容器中打开一个shell,现在javauser用户是文件的所有者。

$ podman exec -it mypodmanplanet sh
/opt/app $ ls -la
total 24
drwxr-xr-x    1 javauser javauser      4096 Apr 15 10:41 .
drwxr-xr-x    1 root     root          4096 Apr  9 12:57 ..
drwxr-xr-x    1 javauser javauser      4096 Apr  9 12:57 BOOT-INF
drwxr-xr-x    1 javauser javauser      4096 Apr  9 12:57 META-INF
-rw-r--r--    1 javauser javauser        16 Apr 15 10:24 application.properties
drwxr-xr-x    1 javauser javauser      4096 Apr  9 12:57 org

在本地系统中,与我的本地用户不同的UID和GID已经取得了所有权。

$ ls -la properties/
total 12
drwxr-xr-x 2  <myuser> domain  users 4096 apr 15 12:24 .
drwxr-xr-x 8  <myuser> domain  users 4096 apr 15 12:24 ..
-rw-r--r-- 1    200099        200100   16 apr 15 12:24 application.properties

这次,在本地系统上更改文件是不被允许的,但在容器内的 javauser 用户却可以更改。

Podman 是否可以作为在容器内挂载卷的 Docker 的替代品?

不,它不能替代。文件权限功能与 Docker 引擎有些不同。你需要知道这些区别,以便能够在容器内挂载文件和目录。

Pod

Podman 知道 Pod 的概念,就像 Kubernetes 中的 Pod 一样。Pod 允许你将容器分组。Pod 也有一个共享的网络命名空间,这意味着 Pod 内的容器可以相互连接。有关容器网络的更多信息可以在此找到。这意味着 Pods 是分组容器的首选。当使用 Docker 时,你会使用 Docker Compose 来实现。有像 Podman Compose 这样的东西,但这值得写一篇文章。

图片

让我们看看这是如何工作的。你将设置一个运行两个带有 Spring Boot 应用程序的容器的 Pod。

首先,你需要创建一个 Pod。你还需要暴露你希望在 Pod 之外可以访问的端口。这可以用 -p 参数来实现。并给 Pod 一个名字,在这种情况下是 hello-pod。

$ podman pod create -p 8080-8081:8080-8081 --name hello-pod

当你列出 Pod 时,你会注意到它已经包含一个容器。这就是 infra 容器。这个 infra 容器持有命名空间,以便容器可以相互连接,并且它使 Pod 中的容器启动和停止成为可能。infra 容器基于 k8s.gcr.io/pause 镜像。

$ podman pod ps
POD ID        NAME        STATUS      CREATED        INFRA ID      # OF CONTAINERS
dab9029ad0c5  hello-pod   Created     3 seconds ago  aac3420b3672  1
$ podman ps --all
CONTAINER ID  IMAGE                 COMMAND     CREATED        STATUS      PORTS                             NAMES
aac3420b3672  k8s.gcr.io/pause:3.5              4 minutes ago  Created     0.0.0.0:8080-8081->8080-8081/tcp  dab9029ad0c5-infra

创建一个名为 mypodmanplanet-1 的容器,并将其添加到 Pod 中。通过 --env 参数,你将 Spring Boot 应用的端口改为 8081。

$ podman create --pod hello-pod --name mypodmanplanet-1 --env 'SERVER_PORT=8081' localhost/mydeveloperplanet/mypodmanplanet:0.0.1-SNAPSHOT env

启动 Pod。

$ podman pod start hello-pod

验证是否可以在端口 8081 处访问端点,并验证在端口 8080 处的端点是否无法访问。

$ curl http://localhost:8081/hello
Hello Podman!
$ curl http://localhost:8080/hello
curl: (56) Recv failure: Connection reset by peer

将第二个容器 mypodmanplanet-2 添加到 Pod 中,这次在默认端口 8080 运行。

$ podman create --pod hello-pod --name mypodmanplanet-2 localhost/mydeveloperplanet/mypodmanplanet:0.0.1-SNAPSHOT

验证 Pod 状态。它显示状态为 Degraded。

$ podman pod ps
POD ID        NAME        STATUS      CREATED        INFRA ID      # OF CONTAINERS
dab9029ad0c5  hello-pod   Degraded    9 minutes ago  aac3420b3672  3

查看容器。有两个容器正在运行,而一个新容器刚被创建。这就是 Pod 状态为 Degraded 的原因。

$ podman ps --all
CONTAINER ID  IMAGE                                                      COMMAND     CREATED             STATUS            PORTS                             NAMES
aac3420b3672  k8s.gcr.io/pause:3.5                                                   11 minutes ago      Up 2 minutes ago  0.0.0.0:8080-8081->8080-8081/tcp  dab9029ad0c5-infra
321a62fbb4fc  localhost/mydeveloperplanet/mypodmanplanet:0.0.1-SNAPSHOT  env         3 minutes ago       Up 2 minutes ago  0.0.0.0:8080-8081->8080-8081/tcp  mypodmanplanet-1
7b95fb521544  localhost/mydeveloperplanet/mypodmanplanet:0.0.1-SNAPSHOT              About a minute ago  Created           0.0.0.0:8080-8081->8080-8081/tcp  mypodmanplanet-2

启动第二个容器并验证 Pod 的状态。现在的状态是运行中。

$ podman start mypodmanplanet-2
$ podman pod ps
POD ID        NAME        STATUS      CREATED         INFRA ID      # OF CONTAINERS
dab9029ad0c5  hello-pod   Running     12 minutes ago  aac3420b3672  3

现在可以访问两个端点了。

$ curl http://localhost:8080/hello
Hello Podman!
$ curl http://localhost:8081/hello
Hello Podman!

验证一下,是否可以从mypodmanplanet-2内部访问mypodmanplanet-1的端点。这同样可以实现。

$ podman exec -it mypodmanplanet-2 sh
/opt/app $ wget http://localhost:8081/hello
Connecting to localhost:8081 (127.0.0.1:8081)
saving to 'hello'
hello                100% |***********************************************************************************************************************************|    13  0:00:00 ETA
'hello' saved

清理工作

最后,你可以进行一些清理工作。

停止正在运行的Pod。

 $ podman pod stop hello-pod

现在,Pod的状态为Exited。

$ podman pod ps
POD ID NAME STATUS CREATED INFRA ID # OF CONTAINERS 
dab9029ad0c5 hello-pod Exited 55 minutes ago aac3420b3672 3

Pod中的所有容器也都处于Exited状态。

$ podman ps --all
CONTAINER ID  IMAGE                                                      COMMAND     CREATED         STATUS                           PORTS                             NAMES
aac3420b3672  k8s.gcr.io/pause:3.5                                                   56 minutes ago  Exited (0) About a minute ago    0.0.0.0:8080-8081->8080-8081/tcp  dab9029ad0c5-infra
321a62fbb4fc  localhost/mydeveloperplanet/mypodmanplanet:0.0.1-SNAPSHOT  env         48 minutes ago  Exited (143) About a minute ago  0.0.0.0:8080-8081->8080-8081/tcp  mypodmanplanet-1
7b95fb521544  localhost/mydeveloperplanet/mypodmanplanet:0.0.1-SNAPSHOT              46 minutes ago  Exited (143) About a minute ago  0.0.0.0:8080-8081->8080-8081/tcp  mypodmanplane

删除Pod。

$ podman pod rm hello-pod

Pod和容器都被删除。

$ podman pod ps
POD ID      NAME        STATUS      CREATED     INFRA ID    # OF CONTAINERS
$ podman ps --all
CONTAINER ID  IMAGE       COMMAND     CREATED     STATUS      PORTS       NAMES

结论

关于Podman是Docker的兼容替代品的说法并不准确。Podman在构建容器镜像、启动容器、网络、卷挂载、容器间通信等方面与Docker存在一些差异。然而,Podman确实支持许多Docker命令。正确的说法应该是Podman是Docker的一种替代选择。 这是完全正确的。在切换到Podman之前,你需要了解并理解这些差异。在了解清楚之后,Podman绝对是一个很好的替代方案。

作者:Gunter Rotsaert

更多技术干货请关注公号“云原生数据库

squids.cn,基于公有云基础资源,提供云上 RDS,云备份,云迁移,SQL 窗口门户企业功能,

帮助企业快速构建云上数据库融合生态。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/618371.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Vite环境变量】import.meta.env 和 loadEnv使用和区别

前言 我们在做项目时需要各种配置信息&#xff08;如应用标题、API 地址等&#xff09;&#xff0c;这些配置信息可能在不同环境下有所不同&#xff08;如开发环境和生产环境&#xff09;。 如果每次更改开发或者更改生产环境需要修改源代码中的相关配置&#xff0c;这会导致…

老生常谈:接口幂等性,防止并发插入重复数据

分布式系统中&#xff0c;接口幂等性问题&#xff0c;对于开发人员来说&#xff0c;是一个跟语言无关的公共问题。不知道你有没有遇到过这些场景&#xff1a; 有时我们在填写某些form表单时&#xff0c;保存按钮不小心快速点了两次&#xff0c;表中竟然产生了两条重复的数据&a…

AI时代的三类人:探索掌握AIGC,引领未来的人才之路

&#xff08;本文阅读时间&#xff1a;6 分钟&#xff09; 1 AI时代&#xff1a;ChatGPT引领AIGC技术革命 对于那些热衷于探索新技术的小伙伴而言&#xff0c;ChatGPT早已超越了抽象的概念&#xff0c;我们对其能力已有所了解。那么&#xff0c;ChatGPT究竟能够做些什么呢&…

Java 集合全教程

一、集合简介 集合&#xff08;有时称为容器&#xff09;只是将多个元素分组到单个单元中的对象。集合用于存储、检索、操作和传达聚合数据。通常&#xff0c;它们表示形成自然组的数据项&#xff0c;例如扑克手&#xff08;纸牌集合&#xff09;、邮件文件夹&#xff08;字母…

【Java多线程进阶】synchronized工作原理

前言 本期讲解 synchronized 工作的原理以及常见的锁优化机制&#xff0c;相信大家在看完这篇博文后对 synchronized 工作流程有一定的理解。话不多说&#xff0c;让我们快速进入学习吧~ 目录 1. 锁的工作流程 2. 偏向锁 3. 轻量级锁和重量级锁 3.1 轻量级锁 3.2 重量级锁…

Kubernetes基本存储

Kubernetes基本存储 容器的生命周期可能很短&#xff0c;会被频繁地创建和销毁&#xff0c;容器销毁时&#xff0c;保存在容器中的数据也会被清除。为了持久化保存容器中数据&#xff0c;引入Volume概念。 Volume时Pod中多个容器共同访问的共享目录&#xff0c;它被定义在Pod中…

“碳”寻青蓝锦色,锦江酒店(中国区)用行动点亮酒店可持续发展

第52个世界环境日之际&#xff0c;为响应“减塑捡塑”号召&#xff0c;锦江酒店&#xff08;中国区&#xff09;以“‘碳’寻青蓝锦色”为主题&#xff0c;在6月5日至6月11日期间&#xff0c;开启第二届“绿色生活创益周”&#xff0c;通过线上线下联动&#xff0c;倡导时尚低碳…

2023智源大会议程公开丨类脑计算论坛

6月9日&#xff0c;2023北京智源大会&#xff0c;将邀请这一领域的探索者、实践者、以及关心智能科学的每个人&#xff0c;共同拉开未来舞台的帷幕&#xff0c;你准备好了吗&#xff1f;与会知名嘉宾包括&#xff0c;图灵奖得主Yann LeCun、图灵奖得主Geoffrey Hinton、OpenAI创…

Mocha AE:Clip 模块

Clip&#xff08;剪辑&#xff09;模块主要用于对素材或遮罩文件的格式进行查看或设置&#xff0c;包括视频格式、时间码格式、色彩空间等&#xff0c;还可以进行裁剪。 General 常规 Input 输入 当前图层素材。 Matte for Layer n 图层 n 的遮罩 Name 名称 显示素材的名称。 …

通信大史记:互联网的起源故事

点击文末“阅读原文”即可参与节目互动 剪辑、音频 / 卷圈 运营 / SandLiu 卷圈 监制 / 姝琦 文案 / 朱峰 产品统筹 / bobo 这是一期“两年更”的节目&#xff0c;通信大史记录完第一期后&#xff0c;因为资料准备和主播时间的关系一直没有后续更新。今天&#xff0c;我们…

nodejs的path模块

path路径模块 path模块是Node.js官方提供的&#xff0c;用来处理路径的模块。提供一系列的方法和属性&#xff0c;用来满足用户对路径的处理需求。 例如&#xff1a; 如果在js代码中&#xff0c;使用path模块来处理路径&#xff0c;需要先导入 const pathrequire(path)常用的…

chatgpt赋能python:Python如何调成白色的SEO文章

Python 如何调成白色的 SEO 文章 介绍 Python 是一种流行的编程语言&#xff0c;在数据分析、人工智能、Web 开发以及其他许多领域都有广泛的应用。然而&#xff0c;很少有人会把 Python 与 SEO 联系起来。 事实上&#xff0c;Python 是一个强大的工具&#xff0c;可以帮助 …

软件工程师,学会封装不香么

什么是封装 从面向对象编程的角度来说&#xff0c;封装是指利用抽象数据类型将数据和基于数据的操作封装在一起&#xff0c;使其构成一个不可分割的独立实体&#xff0c;数据被保护在抽象数据类型的内部&#xff0c;尽可能地隐藏内部的细节&#xff0c;只保留一些对外接口使之与…

rk3568 TF卡启动

rk3568 SD卡启动 SD卡启动系统&#xff0c;它可以让rk3568在没有硬盘或其他存储设备的情况下启动和运行操作系统。这使得rk3568变得与树梅派一样灵活切换系统&#xff0c;与此同时进行故障排查和修复&#xff0c;而不需要拆卸设备或者使用专业的烧录工具。SD卡启动还可以方便地…

音视频同步的方法:深入探索基于FFmpeg的音视频同步策略

音视频同步艺术&#xff1a;深入探索基于FFmpeg的同步策略 &#xff08;一&#xff09;音视频同步的基本概念与重要性&#xff08;Basic Concepts and Importance of Audio-Video Synchronization&#xff09;1.1 音视频同步的定义与影响&#xff08;Definition and Impact of …

【SQL】Oracle数据库实现远程访问

文章目录 前言1. 数据库搭建2. 内网穿透2.1 安装cpolar内网穿透2.2 创建隧道映射 3. 公网远程访问4. 配置固定TCP端口地址4.1 保留一个固定的公网TCP端口地址4.2 配置固定公网TCP端口地址4.3 测试使用固定TCP端口地址远程Oracle 前言 Oracle&#xff0c;是甲骨文公司的一款关系…

【Python入门】Python循环语句(for循环的基础语法)

前言 Python循环语句 1. for循环的基础语法1.1 for循环1.2 程序中的for循环1.3 for循环语句1.4 for循环注意点1.5 总结1.6 练习案例&#xff1a;数一数有几个a 2. range语句2.1 range语句讲解2.2 for循环遍历range序列2.3 总结2.4 练习案例&#xff1a;有几个偶数 3. 变量作用域…

RFID软件:简介、功能和应用范围

在当今快节奏的商业环境中&#xff0c;RFID&#xff08;射频识别&#xff09;技术已经成为物流、供应链和库存管理等领域中不可或缺的工具。本文将向您介绍RFID软件的基本知识&#xff0c;探讨其功能和广泛应用的范围。 第一部分&#xff1a;RFID软件简介 RFID软件是一种应用…

【开源项目】SofaBoot实现Spring Bean 异步初始化的源码拆解

使用场景 在实际使用 Spring/Spring Boot 开发中&#xff0c;一些 Bean 在初始化过程中执行准备操作&#xff0c;如拉取远程配置、初始化数据源等等。在应用启动期间&#xff0c;这些 Bean 会增加 Spring 上下文刷新时间&#xff0c;导致应用启动耗时变长。 Demo展示 Spring…

苹果 Apple 发布的 AR 头显 Vision Pro 介绍

苹果今天凌晨的发布会&#xff0c;隆重推出了用了8 年时间研发的AR&#xff08;增强现实&#xff09;头戴显示器 Vision Pro。作为苹果 AR系列的最新成员&#xff0c;为用户带来了前所未有的沉浸式增强现实体验。 硬件 12个摄像头 &#xff0c;包括苹果首个 3D 相机&#xff0c…