如何使用设置 `hostNetwork: true` 和 `NET_BIND_SERVICE` 调试 "didn't have free ports" 错误

How to debug the "didn't have free ports" error with settings `hostNetwork: true` and `NET_BIND_SERVICE`

我需要一些帮助来调试错误:0/1 nodes are available: 1 node(s) didn't have free ports for the requested pod ports.有人可以帮忙吗?

我正在尝试 运行 Mac 上的一个 pod(首先)使用 Docker 桌面风格的 Kubernetes,版本是 2.1.0.1 (37199)。我想尝试使用 hostNetwork 模式,因为它的效率和需要打开的端口数量(以千计)。仅设置 hostNetwork: true ,没有错误,但我也没有看到主机上打开的端口,也没有看到容器内的主机网络接口。由于我还需要打开端口 443,所以我添加了 NET_BIND_SERVICE 的功能,然后它开始抛出错误。

我在容器中 运行 lsof -i (ubuntu:18.04) 然后 sudo lsof -i 在我的 Mac 中,我没有发现冲突.然后,我也看了 /var/lib/log/containers/kube-apiserver-docker-desktop_kube-system_kube-apiserver-*.log ,但没有看到任何线索。谢谢!

附加信息: 我在容器中 运行 以下内容:

# ss -nltp
State  Recv-Q  Send-Q     Local Address:Port      Peer Address:Port
LISTEN 0       5                0.0.0.0:10024          0.0.0.0:*      users:(("pnnsvr",pid=1,fd=28))
LISTEN 0       5                0.0.0.0:2443           0.0.0.0:*      users:(("pnnsvr",pid=1,fd=24))
LISTEN 0       5                0.0.0.0:10000          0.0.0.0:*      users:(("pnnsvr",pid=1,fd=27))
LISTEN 0       50               0.0.0.0:6800           0.0.0.0:*      users:(("pnnsvr",pid=1,fd=14))
LISTEN 0       1                0.0.0.0:6802           0.0.0.0:*      users:(("pnnsvr",pid=1,fd=13))
LISTEN 0       50               0.0.0.0:443            0.0.0.0:*      users:(("pnnsvr",pid=1,fd=15))

然后,我 运行 netstat 在我的 Mac(主机)上搜索那些端口,但我找不到冲突。如果需要,我很乐意提供 netstat 的输出(767 行)。

这是 yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: pnnsvr
  labels:
    app: pnnsvr
    env: dev
spec:
  replicas: 1
  selector:
    matchLabels:
      app: pnnsvr
      env: dev
  template:
    metadata:
      labels:
        app: pnnsvr
        env: dev
    spec:
      hostNetwork: true
      containers:
      - name: pnnsvr
        image: dev-pnnsvr:0.92
        args: ["--root_ip=192.168.15.194"]
        # for using local images
        imagePullPolicy: Never
        ports:
        - name: https
          containerPort: 443
          hostPort: 443
        - name: cport6800tcp
          containerPort: 6800
          hostPort:  6800
          protocol: TCP
        - name: cport10000tcp
          containerPort: 10000
          hostPort: 10000
          protocol: TCP
        - name: cport10000udp
          containerPort: 10000
          hostPort: 10000
          protocol: UDP
        - name: cport10001udp
          containerPort: 10001
          hostPort: 10001
          protocol: UDP
        #test
        - name: cport23456udp
          containerPort: 23456
          hostPort: 23456
          protocol: UDP
        securityContext:
          capabilities:
            add:
              - SYS_NICE
              - NET_BIND_SERVICE
              - CAP_SYS_ADMIN

我无法在 docker 上为 mac 设置此功能,但您似乎应该在 Docker VM 中验证您的端口:

screen ~/Library/Containers/com.docker.docker/Data/vms/0/tty

请考虑是否可以更改默认节点端口范围(--service-node-port-range portRange-Default: 30000-32767) 在这里你可以找到很好的 post 如何在

中做到这一点

请记住,根据最佳实践,使用 hostNetwork: true 不是好的解决方案。

根据文档:

Don’t specify a hostPort for a Pod unless it is absolutely necessary. When you bind a Pod to a hostPort, it limits the number of places the Pod can be scheduled, because each combination must be unique. If you don’t specify the hostIP and protocol explicitly, Kubernetes will use 0.0.0.0 as the default hostIP and TCP as the default protocol. Avoid using hostNetwork, for the same reasons as hostPort.

If you explicitly need to expose a Pod’s port on the node, consider using a NodePort Service before resorting to hostPort.

为 Pod 或容器配置安全上下文 https://kubernetes.io/docs/tasks/configure-pod-container/security-context/

To specify security settings for a Container, include the securityContext field in the Container manifest. The securityContext field is a SecurityContext object. Security settings that you specify for a Container apply only to the individual Container, and they override settings made at the Pod level when there is overlap. Container settings do not affect the Pod’s Volumes.

另外请注意 POD 的 securityContext:

The runAsGroup field specifies the primary group ID of 3000 for all processes within any containers of the Pod. If this field is omitted, the primary group ID of the containers will be root(0)

如果有帮助,请告诉我。

我不小心解决了这个问题,我是通过弹跳广告连播而不是使用 kubectl apply -f ... 来解决的。在弹出 pod 后不久,新的 pod 将成为一个 go。我的理论是 Kubernetes 会启动一个新的 pod,并在杀死旧的 pod 之前先做好一切准备。由于旧 pod 仍然打开端口,新 pod 将看到这些端口已被占用,因此会触发错误:0/1 nodes are available: 1 node(s) didn't have free ports for the requested pod ports

我也收到了那个问题消息。在我的例子中是在容器定义中使用端口:

 hostPort: 80
 hostIP: 127.0.0.1

我删除了这些定义及其工作。在我的场景中,我正在测试 HPA 并且副本没有 运行 因为没有空闲端口,就像你的问题一样。只有一个 pod 是 运行,第一个 运行,其他(副本),它处于 Pending 状态。

我的解决方案是使用服务 NodePort 向主机公开端口并删除 hostPorthostIP.