Kubernetes 服务无法访问
Kubernetes Service unreachable
我在 2 个 Rasberry Pis(Model 3 和 3B+)上创建了一个 Kubernetes 集群,用作 Kubernetes 游乐场。
我已经部署了一个 postgresql 和一个 spring 启动应用程序(称为 meal-planer)来试用。
meal-planer 应该从 postgresql 读取和写入数据。
但是,应用无法访问数据库。
这是 postgresql 的部署描述符:
kind: Service
apiVersion: v1
metadata:
name: postgres
namespace: home
labels:
app: postgres
spec:
selector:
app: postgres
ports:
- port: 5432
targetPort: 5432
name: postgres
---
kind: Deployment
apiVersion: apps/v1
metadata:
name: postgres
namespace: home
spec:
replicas: 1
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:13.2
imagePullPolicy: IfNotPresent
env:
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: dev-db-secret
key: username
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: dev-db-secret
key: password
- name: POSTGRES_DB
value: home
ports:
- containerPort: 5432
volumeMounts:
- mountPath: /var/lib/postgresql/data
name: postgres-data
volumes:
- name: postgres-data
persistentVolumeClaim:
claimName: postgres-pv-claim
---
这是餐具的部署描述符
kind: Service
apiVersion: v1
metadata:
name: meal-planner
namespace: home
labels:
app: meal-planner
spec:
type: ClusterIP
selector:
app: meal-planner
ports:
- port: 8080
name: meal-planner
---
kind: Deployment
apiVersion: apps/v1
metadata:
name: meal-planner
namespace: home
spec:
replicas: 1
selector:
matchLabels:
app: meal-planner
template:
metadata:
labels:
app: meal-planner
spec:
containers:
- name: meal-planner
image: 08021986/meal-planner:v1
imagePullPolicy: Always
ports:
- containerPort: 8080
---
餐盘镜像是一个 arm32v7 镜像 运行 一个 jar 文件。
在集群内部,膳食规划器使用连接字符串 jdbc:postgresql://postgres:5432/home
连接到数据库。
我绝对确定数据库凭据是正确的,因为我可以在端口转发服务时访问数据库。
部署这两个应用程序时,我可以kubectl exec -it <<podname>> -n home -- bin/sh
进入其中。如果我从那里调用 wget -O- postgres
或 wget -O- postgres.home
,我总是得到 Connecting to postgres (postgres)|10.43.62.32|:80... failed: Network is unreachable
.
我不知道,为什么网络无法访问,我不知道我能做些什么。
首先,不要将部署工作负载用于需要保存状态的应用程序。这可能会给您带来麻烦甚至数据丢失。
为此,您应该使用 statefulset
StatefulSet is the workload API object used to manage stateful
applications.
Manages the deployment and scaling of a set of Pods, and provides
guarantees about the ordering and uniqueness of these Pods.
Like a Deployment, a StatefulSet manages Pods that are based on an
identical container spec. Unlike a Deployment, a StatefulSet maintains
a sticky identity for each of their Pods. These pods are created from
the same spec, but are not interchangeable: each has a persistent
identifier that it maintains across any rescheduling.
同样对于数据库,存储应该尽可能靠近引擎(由于延迟)最好是 hostpath storageClass
和 ReadWriteOnce
。
现在关于您的问题,我的猜测是您在应用程序中连接到数据库的方式有问题,或者远程连接可能被 pg_hba.conf
中的定义拒绝
这是一个可以帮助您入门的最小工作示例:
kind: Namespace
apiVersion: v1
metadata:
name: test
labels:
name: test
---
kind: Service
apiVersion: v1
metadata:
name: postgres-so-test
namespace: test
labels:
app: postgres-so-test
spec:
selector:
app: postgres-so-test
ports:
- port: 5432
targetPort: 5432
name: postgres-so-test
---
kind: StatefulSet
apiVersion: apps/v1
metadata:
namespace: test
name: postgres-so-test
spec:
replicas: 1
serviceName: postgres-so-test
selector:
matchLabels:
app: postgres-so-test
template:
metadata:
labels:
app: postgres-so-test
spec:
containers:
- name: postgres
image: postgres:13.2
imagePullPolicy: IfNotPresent
env:
- name: POSTGRES_USER
value: johndoe
- name: POSTGRES_PASSWORD
value: thisisntthepasswordyourelokingfor
- name: POSTGRES_DB
value: home
ports:
- containerPort: 5432
现在我们来测试一下。注意:我还将从 Postgres 映像创建一个部署,只是为了在这个命名空间中有一个 pod,它将具有 pg_isready 二进制文件,以便测试与创建的数据库的连接。
pi@rsdev-pi-master:~/test $ kubectl apply -f test_db.yml
namespace/test created
service/postgres-so-test created
statefulset.apps/postgres-so-test created
pi@rsdev-pi-master:~/test $ kubectl apply -f test_container.yml
deployment.apps/test-container created
pi@rsdev-pi-master:~/test $ kubectl get pods -n test
NAME READY STATUS RESTARTS AGE
postgres-so-test-0 1/1 Running 0 19s
test-container-d77d75d78-cgjhc 1/1 Running 0 12s
pi@rsdev-pi-master:~/test $ sudo kubectl get all -n test
NAME READY STATUS RESTARTS AGE
pod/postgres-so-test-0 1/1 Running 0 26s
pod/test-container-d77d75d78-cgjhc 1/1 Running 0 19s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/postgres-so-test ClusterIP 10.43.242.51 <none> 5432/TCP 30s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/test-container 1/1 1 1 19s
NAME DESIRED CURRENT READY AGE
replicaset.apps/test-container-d77d75d78 1 1 1 19s
NAME READY AGE
statefulset.apps/postgres-so-test 1/1 27s
pi@rsdev-pi-master:~/test $ kubectl exec -it test-container-d77d75d78-cgjhc -n test -- /bin/bash
root@test-container-d77d75d78-cgjhc:/# pg_isready -d home -h postgres-so-test -p 5432 -U johndoe
postgres-so-test:5432 - accepting connections
如果您仍然无法连接到数据库,请附上以下内容:
kubectl describe pod <<postgres_pod_name>>
kubectl logs <<postgres_pod_name>>
理想情况下,您已尝试连接到它
kubectl exec -it <<postgres_pod_name>> -- cat /var/lib/postgresql/data/pg_hba.conf
也是K8s算子的研究课题。它们对于部署更复杂的生产就绪应用程序堆栈很有用(例如,具有主数据库 + 副本 + LB 的数据库)
我在 2 个 Rasberry Pis(Model 3 和 3B+)上创建了一个 Kubernetes 集群,用作 Kubernetes 游乐场。
我已经部署了一个 postgresql 和一个 spring 启动应用程序(称为 meal-planer)来试用。 meal-planer 应该从 postgresql 读取和写入数据。
但是,应用无法访问数据库。
这是 postgresql 的部署描述符:
kind: Service
apiVersion: v1
metadata:
name: postgres
namespace: home
labels:
app: postgres
spec:
selector:
app: postgres
ports:
- port: 5432
targetPort: 5432
name: postgres
---
kind: Deployment
apiVersion: apps/v1
metadata:
name: postgres
namespace: home
spec:
replicas: 1
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:13.2
imagePullPolicy: IfNotPresent
env:
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: dev-db-secret
key: username
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: dev-db-secret
key: password
- name: POSTGRES_DB
value: home
ports:
- containerPort: 5432
volumeMounts:
- mountPath: /var/lib/postgresql/data
name: postgres-data
volumes:
- name: postgres-data
persistentVolumeClaim:
claimName: postgres-pv-claim
---
这是餐具的部署描述符
kind: Service
apiVersion: v1
metadata:
name: meal-planner
namespace: home
labels:
app: meal-planner
spec:
type: ClusterIP
selector:
app: meal-planner
ports:
- port: 8080
name: meal-planner
---
kind: Deployment
apiVersion: apps/v1
metadata:
name: meal-planner
namespace: home
spec:
replicas: 1
selector:
matchLabels:
app: meal-planner
template:
metadata:
labels:
app: meal-planner
spec:
containers:
- name: meal-planner
image: 08021986/meal-planner:v1
imagePullPolicy: Always
ports:
- containerPort: 8080
---
餐盘镜像是一个 arm32v7 镜像 运行 一个 jar 文件。
在集群内部,膳食规划器使用连接字符串 jdbc:postgresql://postgres:5432/home
连接到数据库。
我绝对确定数据库凭据是正确的,因为我可以在端口转发服务时访问数据库。
部署这两个应用程序时,我可以kubectl exec -it <<podname>> -n home -- bin/sh
进入其中。如果我从那里调用 wget -O- postgres
或 wget -O- postgres.home
,我总是得到 Connecting to postgres (postgres)|10.43.62.32|:80... failed: Network is unreachable
.
我不知道,为什么网络无法访问,我不知道我能做些什么。
首先,不要将部署工作负载用于需要保存状态的应用程序。这可能会给您带来麻烦甚至数据丢失。 为此,您应该使用 statefulset
StatefulSet is the workload API object used to manage stateful applications.
Manages the deployment and scaling of a set of Pods, and provides guarantees about the ordering and uniqueness of these Pods.
Like a Deployment, a StatefulSet manages Pods that are based on an identical container spec. Unlike a Deployment, a StatefulSet maintains a sticky identity for each of their Pods. These pods are created from the same spec, but are not interchangeable: each has a persistent identifier that it maintains across any rescheduling.
同样对于数据库,存储应该尽可能靠近引擎(由于延迟)最好是 hostpath storageClass
和 ReadWriteOnce
。
现在关于您的问题,我的猜测是您在应用程序中连接到数据库的方式有问题,或者远程连接可能被 pg_hba.conf
中的定义拒绝这是一个可以帮助您入门的最小工作示例:
kind: Namespace
apiVersion: v1
metadata:
name: test
labels:
name: test
---
kind: Service
apiVersion: v1
metadata:
name: postgres-so-test
namespace: test
labels:
app: postgres-so-test
spec:
selector:
app: postgres-so-test
ports:
- port: 5432
targetPort: 5432
name: postgres-so-test
---
kind: StatefulSet
apiVersion: apps/v1
metadata:
namespace: test
name: postgres-so-test
spec:
replicas: 1
serviceName: postgres-so-test
selector:
matchLabels:
app: postgres-so-test
template:
metadata:
labels:
app: postgres-so-test
spec:
containers:
- name: postgres
image: postgres:13.2
imagePullPolicy: IfNotPresent
env:
- name: POSTGRES_USER
value: johndoe
- name: POSTGRES_PASSWORD
value: thisisntthepasswordyourelokingfor
- name: POSTGRES_DB
value: home
ports:
- containerPort: 5432
现在我们来测试一下。注意:我还将从 Postgres 映像创建一个部署,只是为了在这个命名空间中有一个 pod,它将具有 pg_isready 二进制文件,以便测试与创建的数据库的连接。
pi@rsdev-pi-master:~/test $ kubectl apply -f test_db.yml
namespace/test created
service/postgres-so-test created
statefulset.apps/postgres-so-test created
pi@rsdev-pi-master:~/test $ kubectl apply -f test_container.yml
deployment.apps/test-container created
pi@rsdev-pi-master:~/test $ kubectl get pods -n test
NAME READY STATUS RESTARTS AGE
postgres-so-test-0 1/1 Running 0 19s
test-container-d77d75d78-cgjhc 1/1 Running 0 12s
pi@rsdev-pi-master:~/test $ sudo kubectl get all -n test
NAME READY STATUS RESTARTS AGE
pod/postgres-so-test-0 1/1 Running 0 26s
pod/test-container-d77d75d78-cgjhc 1/1 Running 0 19s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/postgres-so-test ClusterIP 10.43.242.51 <none> 5432/TCP 30s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/test-container 1/1 1 1 19s
NAME DESIRED CURRENT READY AGE
replicaset.apps/test-container-d77d75d78 1 1 1 19s
NAME READY AGE
statefulset.apps/postgres-so-test 1/1 27s
pi@rsdev-pi-master:~/test $ kubectl exec -it test-container-d77d75d78-cgjhc -n test -- /bin/bash
root@test-container-d77d75d78-cgjhc:/# pg_isready -d home -h postgres-so-test -p 5432 -U johndoe
postgres-so-test:5432 - accepting connections
如果您仍然无法连接到数据库,请附上以下内容:
kubectl describe pod <<postgres_pod_name>>
kubectl logs <<postgres_pod_name>>
理想情况下,您已尝试连接到它kubectl exec -it <<postgres_pod_name>> -- cat /var/lib/postgresql/data/pg_hba.conf
也是K8s算子的研究课题。它们对于部署更复杂的生产就绪应用程序堆栈很有用(例如,具有主数据库 + 副本 + LB 的数据库)