【问题标题】:Kubernetes pods cannot communicate internallyKubernetes Pod 内部无法通信
【发布时间】:2021-06-03 20:29:33
【问题描述】:

在我的 K8 集群中,我在同一个命名空间中有两个部署。一个部署用于 Database-Postgres,另一个部署用于 Tomcat。 Tomcat 应该可以从外部访问,因此我已经配置了“NodePort”服务,并且对于内部通信,我通过公开 Postgres 的端口(即 5432)创建了一个“ClusterIP”服务。部署完所有内容后,我希望 Tomcat pod 与 Postgres pod 进行通信。但是当我从 Tomcat pod 中“curl postgres-service:5432”时,我收到“Connection denied”消息。有没有配置错误?

apiVersion: v1
kind: Service
metadata:
  name: tomcat-service
  namespace: application
  labels:
    app: application-tomcat
spec:
  type: NodePort
  ports:
  - name: tomcat-port
    targetPort: 80
    port: 80
  selector:
    app: application-tomcat

---

apiVersion: v1
kind: Service
metadata:
  name: postgres-service
  namespace: application
  labels:
    app: application-postgres
spec:
  ports:
  - port: 5432
    name: postgres-port
  selector:
    app: application-postgres

---

apiVersion: apps/v1
kind: Deployment
metadata:
  name: application-tomcat-deployment
  namespace: application
  labels:
    app: application-tomcat
spec:
  replicas: 1
  selector:
    matchLabels:
      app: application-tomcat
  template:
    metadata:
      labels:
        app: application-tomcat
    spec:
      containers:
      - name: application-container
        image: tomcat
        command:
          - sleep
          - "infinity"
        ports:
        - containerPort: 80
     
---

apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: application
  name: application-postgres-deployment
  labels:
    app: application-postgres
spec:
  replicas: 1
  selector:
    matchLabels:
      app: application-postgres
  template:
    metadata:
      labels:
        app: application-postgres
    spec:
      containers:
      - name: postgres
        image: postgres
        command:
          - sleep
          - "infinity"
        ports:
        - containerPort: 5432
          name: postgredb

Postgres pod 正在侦听端口“5432”并且数据库正在运行。

Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:5432            0.0.0.0:*               LISTEN      -
tcp6       0      0 :::5432                 :::*                    LISTEN      -

命名空间中的资源

$ kubectl get all -n application
NAME                                                   READY   STATUS    RESTARTS   AGE
pod/application-postgres-deployment-694869cd5d-wrhzr   1/1     Running   0          9m9s
pod/application-tomcat-deployment-6db75ffb6d-ds8fr     1/1     Running   0          9m9s

NAME                       TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
service/postgres-service   ClusterIP   10.32.0.207   <none>        5432/TCP       9m9s
service/tomcat-service     NodePort    10.32.0.59    <none>        80:31216/TCP   9m9s

NAME                                              READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/application-postgres-deployment   1/1     1            1           9m9s
deployment.apps/application-tomcat-deployment     1/1     1            1           9m9s

NAME                                                         DESIRED   CURRENT   READY   AGE
replicaset.apps/application-postgres-deployment-694869cd5d   1         1         1       9m9s
replicaset.apps/application-tomcat-deployment-6db75ffb6d     1         1         1       9m9s

【问题讨论】:

  • 您不需要手动/显式创建ClusterIP 类型的ServiceNodePort 服务在内部创建了一个ClusterIP 服务,可用于内部通信。
  • 我省略了 ClusterIP 类型的服务,但它只会创建一个 NodePort 服务。那么如何在 Tomcat 中指定主机名以便与 Postgres pod 通信呢?那么我应该使用什么名称从 Tomcat pod 中“卷曲”?
  • 您可以使用curl http:servicename/这样的服务名称访问pod
  • 请编辑问题以在此处添加详细信息。
  • 为什么你的容器运行command: [sleep, infinity]?这肯定会导致“连接被拒绝”错误,因为数据库和 Web 服务器进程实际上并未运行。

标签: postgresql tomcat kubernetes kubernetes-service


【解决方案1】:

您已通过指定 deployment.spec.template.containers[0].command 覆盖了 postgresql 映像中的默认 ENTRYPOINT。因此,现在在部署 nginx-statefulset 的 pod 内运行的唯一进程是 sleep infinity 并且 postgres 没有运行。删除命令字段并添加 POSTGRES_PASSWORDPOSTGRES_HOST_AUTH_METHOD=trust 环境变量应该可以解决问题。为nginx-statefulset 使用以下清单

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-statefulset
  namespace: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      BIZID: nginx
  template:
    metadata:
      labels:
        BIZID: nginx
    spec:
      containers:
      - name: postgres
        image: postgres
        env:
        - name: POSTGRES_PASSWORD
          value: admin
        ports:
        - containerPort: 5432
          name: postgredb

您必须设置环境变量POSTGRES_PASSWORDPOSTGRES_HOST_AUTH_METHOD=trust。如果没有这个,pod 将崩溃循环并显示以下错误消息:

Error: Database is uninitialized and superuser password is not specified.
       You must specify POSTGRES_PASSWORD to a non-empty value for the
       superuser. For example, "-e POSTGRES_PASSWORD=password" on "docker run".

       You may also use "POSTGRES_HOST_AUTH_METHOD=trust" to allow all
       connections without a password. This is *not* recommended.

       See PostgreSQL documentation about "trust":
       https://www.postgresql.org/docs/current/auth-trust.html

【讨论】:

  • 我更新了问题。你能再检查一下吗?
  • 有趣。我尝试在我的同类集群中本地使用您的清单,并注意到 postgres 没有运行。你的 k8s 集群在哪里运行?你能分享你为打开连接输出执行的命令吗?
  • 我正在使用 GCP 计算引擎并在那里安装了 K8。我使用了“netstat -tulpn”命令并检查运行的进程我使用了“ps aux”
  • 一个服务由 2 个组件组成:将查询 postgres-service 映射到集群 ip(在您的情况下为 10.32.0.207)的 dns 条目,k8s 节点上拦截到集群的流量的 iptables 规则ip 并对实际的 pod ips 执行 dnat。不要执行“curl postgres-service:5432”,而是尝试对实际的 postgres pod ip 执行 curl。
  • 我能够完成这项工作。安装“ebtables”包并加载内核模块 - modprobe br_netfilter"
【解决方案2】:

查看您的 yaml,您的 tomcat 部署似乎位于名为“test”的命名空间中,而您的 postgres 部署位于“默认”命名空间中。

因此,为了进行跨命名空间通信,您必须将命名空间附加到服务域。这个 - 如果从 tomcat Pod 执行 - 应该可以工作:

curl http://postgres-service.default:5432

或者,只需将您的 tomcat 部署到“默认”命名空间。

【讨论】:

  • 但它们在同一个命名空间中
  • 如果您仍在使用您发布的相同 yaml,则将 tomcat 部署到“test”命名空间,将 postgres 部署到默认命名空间。如果没有,请相应地更新问题。
  • 是的,我错过了命名空间。但是当我应用 Yaml 文件时,我明确地使用了 --namespace 命令。 “kubectl create -f data.yml -n test”
  • 所以都在同一个命名空间中。我将编辑问题
  • 仅供参考:如果我尝试使用 kubectl 覆盖在 yaml 中定义的命名空间,我会收到“命名空间不匹配”错误消息。这是 kubectl 1.20 的版本。
猜你喜欢
  • 2019-02-26
  • 2020-03-13
  • 2020-04-20
  • 2021-06-19
  • 2017-05-04
  • 1970-01-01
  • 2019-04-02
  • 2020-01-16
  • 1970-01-01
相关资源
最近更新 更多