使用无根 podman 公开端口

Expose ports with rootless podman

我正在尝试在 RHEL 8.3 上使用无根 podman 公开端口 8080。

我使用的podman版本是:

$ podman --version
podman version 2.2.1

我正在使用一个简单的 Flask API 来测试它:

from flask import Flask

app = Flask(__name__)


@app.route("/")
def hello():
    return "Hello from the container!\n"


if __name__ == "__main__":
    app.run(host="0.0.0.0")

容器文件如下所示:

FROM python:3.6-alpine

RUN pip3 install flask

COPY app.py app.py

EXPOSE 5000

ENTRYPOINT python3 app.py

我正在使用以下方法构建图像:

$ podman build -t testapi .

我正在创建一个 pod 并在该 pod 中启动一个容器

$ podman pod create --name testpod -p 8080:5000
$
$ podman run -d --rm --name testapi --pod testpod testapi 

所有容器都运行符合预期:

$ podman ps
CONTAINER ID  IMAGE                     COMMAND  CREATED             STATUS            PORTS                   NAMES
85289290cc7a  localhost/testapi:latest           3 seconds ago       Up 2 seconds ago  0.0.0.0:8080->5000/tcp  testapi
4b1ac2354a1a  k8s.gcr.io/pause:3.2               About a minute ago  Up 3 seconds ago  0.0.0.0:8080->5000/tcp  81aa31a38084-infra

但是,我无法连接到端口:

$ telnet <IP> 8080
Trying <IP>...
telnet: Unable to connect to remote host: No route to host

当我使用 netstat 查看正在使用哪个端口时,我得到以下信息:

$ netstat -tulpn | grep LISTEN
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      -                   
tcp6       0      0 :::8080                 :::*                    LISTEN      638593/containers-r 
tcp6       0      0 :::22                   :::*                    LISTEN      -                   

然后使用 lsof 我得到:

$ lsof -i -P -n | grep LISTEN
exe     638593   ds   13u  IPv6 593362      0t0  TCP *:8080 (LISTEN)

当我使用 rootfull podman 做同样的事情时,它起作用了,即:

$ sudo podman pod create --name testpod -p 8080:5000 
$ sudo podman run -d --rm --name testapi --pod testpod testapi

现在的响应是:

$ telnet 10.100.2.220 8080
Trying 10.100.2.220...
Connected to 10.100.2.220.

网络统计returns:

$ netstat -tulpn | grep LISTEN
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      -                   
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      -                   
tcp6       0      0 :::22                   :::*                    LISTEN      -      

和 lsof:

$ sudo lsof -i -P -n | grep LISTEN
conmon  639312   root    5u  IPv4 590239      0t0  TCP *:8080 (LISTEN)

有没有办法使用无根 podman 公开端口,以便我可以从 podman 主机访问它?

使用无根 pod 时仔细检查此步骤:

$ 远程登录 8080 试 ... telnet:无法连接到远程主机:没有到主机的路由

我已经复制了你的环境和图片,没有发现任何问题。

PS: 可能和firewalld有关,尝试打开8080端口

# firewall-cmd --add-port=8080/tcp --permanent 
# firewall-cmd --reload

我在 Podman 3.1.2 (Ubuntu 20.04.2) 上进行了同样的测试。 它似乎工作。也许您的 Podman 版本太旧并且包含一些错误?

esjolund@laptop:~/test$ cat Dockerfile 
FROM python:3.6-alpine

RUN pip3 install flask

COPY app.py app.py

EXPOSE 5000

ENTRYPOINT python3 app.py
esjolund@laptop:~/test$ cat app.py 
from flask import Flask

app = Flask(__name__)


@app.route("/")
def hello():
    return "Hello from the container!\n"


if __name__ == "__main__":
    app.run(host="0.0.0.0")
esjolund@laptop:~/test$ podman build -t testapi .
STEP 1: FROM python:3.6-alpine
✔ docker.io/library/python:3.6-alpine
Getting image source signatures
Copying blob 8b0340cff2c8 done  
Copying blob c89910f38943 done  
Copying blob a7ad1a75a999 done  
Copying blob 5545670c3922 done  
Copying blob 540db60ca938 done  
Copying config 118f82a946 done  
Writing manifest to image destination
Storing signatures
STEP 2: RUN pip3 install flask
Collecting flask
  Downloading Flask-2.0.0-py3-none-any.whl (93 kB)
Collecting itsdangerous>=2.0
  Downloading itsdangerous-2.0.1-py3-none-any.whl (18 kB)
Collecting Jinja2>=3.0
  Downloading Jinja2-3.0.1-py3-none-any.whl (133 kB)
Collecting Werkzeug>=2.0
  Downloading Werkzeug-2.0.1-py3-none-any.whl (288 kB)
Collecting click>=7.1.2
  Downloading click-8.0.0-py3-none-any.whl (96 kB)
Collecting MarkupSafe>=2.0
  Downloading MarkupSafe-2.0.1.tar.gz (18 kB)
Collecting dataclasses
  Downloading dataclasses-0.8-py3-none-any.whl (19 kB)
Building wheels for collected packages: MarkupSafe
  Building wheel for MarkupSafe (setup.py): started
  Building wheel for MarkupSafe (setup.py): finished with status 'done'
  Created wheel for MarkupSafe: filename=MarkupSafe-2.0.1-py3-none-any.whl size=9743 sha256=93d0dc7d9d4546b1b9b0a9b4c14c7313c101969f3442c00d180f37a3f253bc6c
  Stored in directory: /root/.cache/pip/wheels/05/46/9b/189d9acb1f643857fb8ad990ca04c02509c35d3ad6fac81794
Successfully built MarkupSafe
Installing collected packages: MarkupSafe, dataclasses, Werkzeug, Jinja2, itsdangerous, click, flask
Successfully installed Jinja2-3.0.1 MarkupSafe-2.0.1 Werkzeug-2.0.1 click-8.0.0 dataclasses-0.8 flask-2.0.0 itsdangerous-2.0.1
WARNING: Running pip as root will break packages and permissions. You should install packages reliably by using venv: https://pip.pypa.io/warnings/venv
--> cddad03925e
STEP 3: COPY app.py app.py
--> 56afbc68fea
STEP 4: EXPOSE 5000
--> 0d76f34a2c3
STEP 5: ENTRYPOINT python3 app.py
STEP 6: COMMIT testapi
--> e40c443149a
e40c443149a7cc16cbecfd2e8dab059ed4c148982b84b536ac62a16dc9869a75
esjolund@laptop:~/test$ podman pod create --name testpod -p 8080:5000
25c16eb23ccf256677ad643a361d8f3b1197495a33c0378b6938f8884e20787e
esjolund@laptop:~/test$ podman run -d --rm --name testapi --pod testpod testapi 
d6e112e00e29603e489863802f6cf7f2854c5aa4a24da479a1df48fb154627d4
esjolund@laptop:~/test$ curl localhost:8080
Hello from the container!
esjolund@laptop:~/test$ podman --version
podman version 3.1.2
esjolund@laptop:~/test$ nc  -4 -z -v localhost 8080
Connection to localhost 8080 port [tcp/http-alt] succeeded!
esjolund@laptop:~/test$ 

RHEL 8.4 现已发布。我认为它包含您可能想尝试的更新的 Podman 版本。