无法通过 postgres 容器本身的服务访问 postgres

Can't access postgres via service from the postgres container itself

我正在尝试验证我的 postgres pod 是否可以通过我刚刚设置的服务访问。截至目前,我无法验证这一点。我能做的是登录容器 运行 postgres 本身,并尝试通过服务的 IP 与 postgres 服务器通信。这不会成功。但是,我不确定这是否是集群中其他 pods 是否可以通过服务与 postgres 通信的有效测试,或者我的测试方式是否存在问题,或者是否存在我的服务或 pod 配置中的基本问题。

我在一个 minikube 集群上做这一切。

设置 pod 和服务:

$> kubectl create -f postgres-pod.yml
$> kubectl create -f postgres-service.yml

postgres-pod.yml

apiVersion: v1
kind: Pod
metadata:
    name: postgres
    labels:
        env: prod
        creation_method: manual
        domain: infrastructure
spec:
    containers:
        - image: postgres:13-alpine
          name: kubia-postgres
          ports:
              - containerPort: 5432
                protocol: TCP
          env:
              - name: POSTGRES_PASSWORD
                value: dave
              - name: POSTGRES_USER
                value: dave
              - name: POSTGRES_DB
                value: tmp
# TODO:
#    volumes:
#        - name: postgres-db-volume


postgres-service.yml

apiVersion: v1
kind: Service
metadata:
    name: postgres-service
spec:
    ports:
        - port: 5432
          targetPort: 5432
    selector:
        name: postgres

检查服务是否启动kubectl get services:

kubernetes         ClusterIP   10.96.0.1       <none>        443/TCP    35d
postgres-service   ClusterIP   10.110.159.21   <none>        5432/TCP   71m

然后,登录postgres容器:

$> kubectl exec --stdin --tty postgres -- /bin/bash

从那里,尝试访问 服务 的 IP:

bash-5.1# psql -U dave -h 10.110.159.21 -p 5432 tmp
psql: error: could not connect to server: Connection refused
    Is the server running on host "10.110.159.21" and accepting
    TCP/IP connections on port 5432?

所以使用这种方法我无法使用服务的 IP 连接到 postgres 服务器。

我不确定此过程中的几个步骤:

  1. 服务配置yaml中的selecting by name块是否正确?
  2. 您能否从服务“背后”的 pods 访问服务的 IP?
  3. 事实上,这是验证数据库服务器是否可通过服务访问的有效方法,还是有其他方法?

您好,希望您开启 Kubernetes 之旅!

我想在本地集群(docker 中的 Kubernetes)集群上尝试这个。这就是我所做的:

首先,我使用此配置在本地设置了一个类集群(此处信息:https://kind.sigs.k8s.io/docs/user/quick-start/):

kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
name: so-cluster-1
nodes:
- role: control-plane
  image: kindest/node:v1.23.5
- role: control-plane
  image: kindest/node:v1.23.5
- role: control-plane
  image: kindest/node:v1.23.5
- role: worker
  image: kindest/node:v1.23.5
- role: worker
  image: kindest/node:v1.23.5
- role: worker
  image: kindest/node:v1.23.5

在此之后,我使用以下命令创建了我的集群:

kind create cluster --config=config.yaml

接下来,我创建了一个测试命名空间(通过以下方式获得的清单:kubectl create ns so-tests -o yaml --dry-run):

apiVersion: v1
kind: Namespace
metadata:
  name: so-tests

从那里开始,我设置了我的环境,所以我不得不在上面部署一个 postgres,但这里是我所做的更改:

1- 我没有创建单例 pod,而是创建了一个有状态集(目的是部署数据库)

2- 我决定继续使用您的 docker 图像“postgres:13-alpine”,并以本机 postgres 用户(不是 dave,也不是 root)向 运行 添加了一个安全上下文——要知道 postgres 用户的 ID 是什么,我首先部署了没有安全上下文的 statefulset 并执行了这个命令:

❯ k exec -it postgres-0 -- bash
bash-5.1# whoami
root
bash-5.1# id
uid=0(root) gid=0(root) groups=1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)
bash-5.1# id postgres
uid=70(postgres) gid=70(postgres) groups=70(postgres),70(postgres)
bash-5.1# exit

所以,一旦我知道 postgres 用户的 ID 是 70,我就在 statefulset 清单中添加了这个:

securityContext:
runAsUser: 70
fsGroup: 70

3- 我决定创建一个 secret 和一个 configmap,而不是将配置和 secrets 作为环境变量直接添加到 statefulset 的 pod 配置中:

首先让我们用你的密码创建一个 kubernetes 秘密,这是清单(从这个命令获得:“k create secret generic --from-literal password=dave postgres-secret -o yaml --dry-run=客户端"):

apiVersion: v1
data:
  password: ZGF2ZQ==
kind: Secret
metadata:
  name: postgres-secret

在此之后我创建了一个 configmap 来存储我们的 postgres 配置,这是清单(通过 运行ning 获得:kubectl create configmap postgres-config --from-literal user=dave - -from-literal db=tmp --dry-run=client -o yaml )

apiVersion: v1
data:
  db: tmp
  user: dave
kind: ConfigMap
metadata:
  name: postgres-config

因为这只是为了测试目的,我没有为 statefulset 设置动态卷配置,pre-provisionned 卷也没有。相反,我配置了一个简单的 emptyDir 来存储 postgres 数据 (/var/lib/postgresql/data)。

N.B.: 默认情况下,emptyDir 卷存储在支持节点的任何介质上 - 可能是磁盘、SSD 或网络存储,具体取决于您的环境。但是,您可以将 emptyDir.medium 字段设置为“Memory”,以告诉 Kubernetes 为您挂载一个 tmpfs(RAM-backed 文件系统)。 (这来自这里Create a new volume when pod restart in a statefulset

由于它是有状态集,因此必须由无头 kubernetes 服务公开 (https://kubernetes.io/fr/docs/concepts/services-networking/service/#headless-services)

清单如下:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgres
spec:
  serviceName: "postgres"
  replicas: 2
  selector:
    matchLabels:
      env: prod
      domain: infrastructure
  template:
    metadata:
      labels:
        env: prod
        domain: infrastructure
    spec:
      terminationGracePeriodSeconds: 20
      securityContext:
        runAsUser: 70
        fsGroup: 70
      containers:
      - name: kubia-postgres
        image: postgres:13-alpine
        env:
        - name: POSTGRES_PASSWORD
          valueFrom:
            secretKeyRef:
              name: postgres-secret
              key: password
        - name: POSTGRES_USER
          valueFrom:
            configMapKeyRef:
              name: postgres-config
              key: user
        - name: POSTGRES_DB
          valueFrom:
            configMapKeyRef:
              name: postgres-config
              key: db
        ports:
        - containerPort: 5432
          protocol: TCP
        volumeMounts:
        - name: postgres-test-volume
          mountPath: /var/lib/postgresql
        resources:
          requests:
            memory: "64Mi"
            cpu: "250m"
          limits:
            memory: "128Mi"
            cpu: "500m"
      volumes:
      - name: postgres-test-volume
        emptyDir: {}

---

apiVersion: v1
kind: Service
metadata:
  name: postgres-service
  labels:
    env: prod
    domain: infrastructure
spec:
  ports:
  - port: 5432
    protocol: TCP
    targetPort: 5432
    name: pgsql
  clusterIP: None
  selector:
    env: prod
    domain: infrastructure

---

apiVersion: v1
data:
  password: ZGF2ZQ==
kind: Secret
metadata:
  name: postgres-secret

---

apiVersion: v1
data:
  db: tmp
  user: dave
kind: ConfigMap
metadata:
  name: postgres-config
---

我使用以下方式部署:

kubectl apply -f postgres.yaml

我测试连接到 postgres-0 pod 以使用 $POSTGRES_USER 和 $POSTGRES_PASSWORD 凭据连接我的数据库:

❯  k exec -it pod/postgres-0 -- bash
bash-5.1$ psql --username=$POSTGRES_USER -W --host=localhost --port=5432 --dbname=tmp
Password:
psql (13.6)
Type "help" for help.

tmp=#

我列出了数据库:

tmp=# \l
                             List of databases
   Name    | Owner | Encoding |  Collate   |   Ctype    | Access privileges
-----------+-------+----------+------------+------------+-------------------
 postgres  | dave  | UTF8     | en_US.utf8 | en_US.utf8 |
 template0 | dave  | UTF8     | en_US.utf8 | en_US.utf8 | =c/dave          +
           |       |          |            |            | dave=CTc/dave
 template1 | dave  | UTF8     | en_US.utf8 | en_US.utf8 | =c/dave          +
           |       |          |            |            | dave=CTc/dave
 tmp       | dave  | UTF8     | en_US.utf8 | en_US.utf8 |
(4 rows)

我连接到“tmp”数据库​​:

tmp=# \c tmp
Password:
You are now connected to database "tmp" as user "dave".

成功。

我也试过使用IP连接数据库,如你所试:

bash-5.1$ ip a | grep /24
    inet 10.244.4.8/24 brd 10.244.4.255 scope global eth0
bash-5.1$ psql --username=$POSTGRES_USER -W --host=10.244.4.8 --port=5432 --dbname=tmp
Password:
psql (13.6)
Type "help" for help.

tmp=#

成功。

然后我下载了 dbeaver(从这里 https://dbeaver.io/download/ )来测试从集群外部的访问:

使用 kubectl port-forward:

kubectl port-forward statefulset/postgres 5432:5432

Forwarding from 127.0.0.1:5432 -> 5432
Forwarding from [::1]:5432 -> 5432

我在 dbeaver 上创建了连接,并且可以使用 dave:dave 凭据

从 localhost:5361 轻松访问数据库“tmp”
kubectl port-forward statefulset/postgres 5432:5432

Forwarding from 127.0.0.1:5432 -> 5432
Forwarding from [::1]:5432 -> 5432
Handling connection for 5432
Handling connection for 5432

完美。

和以前一样(使用 dbeaver),我尝试使用端口转发连接数据库,不是 pod 的,而是服务的:

❯ kubectl port-forward service/postgres-service 5432:5432
Forwarding from 127.0.0.1:5432 -> 5432
Forwarding from [::1]:5432 -> 5432
Handling connection for 5432
Handling connection for 5432

效果也不错!

我还创建了一个独立的 pod,基于我们的配置来访问另一个 pod 中的数据库(通过服务名称作为主机名),这是 pod 的清单:

apiVersion: v1
kind: Pod
metadata:
  name: postgres
  labels:
    app: test
spec:
  terminationGracePeriodSeconds: 20
  securityContext:
    runAsUser: 70
    fsGroup: 70
  containers:
  - name: kubia-postgres
    image: postgres:13-alpine
    env:
    - name: POSTGRES_PASSWORD
      valueFrom:
        secretKeyRef:
          name: postgres-secret
          key: password
    - name: POSTGRES_USER
      valueFrom:
        configMapKeyRef:
          name: postgres-config
          key: user
    - name: POSTGRES_DB
      valueFrom:
        configMapKeyRef:
          name: postgres-config
          key: db
    ports:
    - containerPort: 5432
      protocol: TCP
    volumeMounts:
    - name: postgres-test-volume
      mountPath: /var/lib/postgresql
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "128Mi"
        cpu: "500m"
  volumes:
  - name: postgres-test-volume
    emptyDir: {}

这是 podtest 内部的连接结果:

bash-5.1$ psql --username=$POSTGRES_USER -W --host=postgres-service --port=5432 --dbname=tmp
Password:
psql (13.6)
Type "help" for help.

tmp=#
  • 以下是从 pod/namespace 外部访问它的方法(确保没有阻止连接的网络规则):

StatefulSetName-Ordinal.Service.Namespace.svc.cluster.local

i.e: postgres-0.postgres-service.so-tests.svc.cluster.local
  • 从集群外部访问有状态集工作负载是一个好的开始:

希望这对您有所帮助。谢谢你的问题。 B猜

如果只有一 (1) 个副本,您不能(至少使用 minikube)从该服务“背后”的 pod 访问该服务的 IP。