本文主要演示如何通过Kubernetes提供的持久化卷(PV)和Statefulset来部署Pg数据库容器。
镜像准备
我们打算使用官方提供的Postgresql 12.1版本:https://hub.docker.com/_/postgres 版本的镜像作为我们的部署镜像,这个版本的镜像提供了齐全的功能,并且支持我们使用编排文件配置环境变量,如用户名、密码、默认数据库、pgdata路径等。
下面我们可以正式开始实例的演示了…
创建PV
这个步骤里我们编写第一份配置声明:pg-pv.yaml
下面是主要例子,这里我们创建一个名字为 postgresql-pv的持久化卷,并使用hostpath
作为pv的持久化类型,你也可以根据需要配置为gce或nfs等。作为测试的例子,我们先配置一个10G的大小。
apiVersion: v1
kind: PersistentVolume
metadata:
name: postgresql-pv
labels:
type: local
spec:
storageClassName: manual
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/data/svr/pgdb"
然后通过kubectl执行创建命令
$ kubectl create -f pg-pv.yaml
创建PVC
接下来,我们再创建pvc配置– pg-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgresql-pv-claim
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
执行创建命令
$ kubectl create -f pg-pvc.yaml
到了这里,我们可以从环境中检查刚刚创建的资源情况:
$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
postgresql-pv 10Gi RWO Retain Bound default/postgresql-pv-claim manual 63m
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
postgresql-pv-claim Bound postgresql-pv 10Gi RWO manual 60m
从上面的环境信息输出可以看到,postgresql-pv 的状态已经处于 Bound,这表明我们的pv已经我pvc绑定成功。
创建 Deployment
我们可以通过 Kubernetes Deployment 的方式来创建一个有状态服务,然后使用PVC(PersistentVolumeClaim)来连接已经存在的PV。
下面我们通过编写Deployment 的YAML文件描述了一个运行PostgreSQL并使用PVC的Deployment。文件定义了一个mount到/var/lib/postgresql/data的卷(因为官方Pg容器initdb的时候数据会创建在此)
注意:密码定义在YAML配置文件中,这是不安全的,建议使用ConfigMap的方式,这里只是方便测试,所以就直接定义在配置文件中。
pg-deployment.yaml 配置如下:
apiVersion: apps/v1
kind: Deployment
metadata:
name: postgresql-deployment
spec:
strategy:
type: Recreate
selector:
matchLabels:
app: postgresql
template:
metadata:
labels:
app: postgresql
spec:
containers:
- image: postgres:12.1
name: postgresql
env:
- name: POSTGRES_PASSWORD
value: pgsql@123
ports:
- containerPort: 5432
name: postgresql
volumeMounts:
- name: postgresql-persistent-storage
mountPath: /var/lib/postgresql/data
volumes:
- name: postgresql-persistent-storage
persistentVolumeClaim:
claimName: postgresql-pv-claim
通过kubectl创建Deployment
$ kubectl create -f pg-deployment.yaml
$ kubectl get deployment -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
postgresql-deployment 1/1 1 1 1m postgresql postgres:12.1 app=postgresql
此时,我们目标的pod也会被创建
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
postgresql-deployment-7cfb6c95db-5r2v8 1/1 Running 0 1m
创建Service
为了能正常访问deployment或者容器,我们还需要暴露一个Servive。
Kubernetes提供了不同的Service访问类型,如:ClusterIP、NodePort、LoadBlancer、NodePort。
本例子,我们利用NodePort暴露一个服务端口,用于外部服务能正常访问我们的数据库。
pg-service.yaml定义如下,我们定义nodePort为30432,这样集群里外的服务都能使用这个端口进行访问。
apiVersion: v1
kind: Service
metadata:
name: postgresql-client-service
labels:
app: postgresql
spec:
type: NodePort
ports:
- port: 5432
targetPort: 5432
nodePort: 30432
protocol: TCP
selector:
app: postgresql
接下来,就可以创建Service了:
$ kubectl apply -f pg-service.yaml
$ kubectl get service -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 12d <none>
postgresql-client-service NodePort 10.96.41.96 <none> 5432:30432/TCP 1m app=postgresql
连接数据库
这里我们使用psql客户端进行测试连接
集群内
$ psql -U postgres -h 10.96.41.96 -p 5432
或
$ psql -U postgres -h localhost -p 30432
正常情况下,我们可以顺利连接上:
Password for user postgres:
psql (10.1, server 12.1 (Debian 12.1-1.pgdg100+1))
WARNING: psql major version 10, server major version 12.
Some psql features might not work.
Type "help" for help.
postgres=#
为了继续测试环境是否有状态,我们接下来会创建一个新的datase和表,并插入数据,再销毁pod。
然后观察新的pod是否能继续持有之前的数据,达到数据状态持久化的目的?
create database pgtest
连接测试数据库
$ psql -U postgres -h localhost -p 30432 pgtest
或
$ psql -U postgres -h 10.96.41.96 -p 5432 pgtest
再创建测试表,并插入数据
CREATE TABLE test(
ID INT PRIMARY KEY NOT NULL,
NAME TEXT NOT NULL
);
insert into test (id, name) values (1, "tom");
删除 pod
下面,我们开始删除刚刚通过Deployment的pod
kubectl delete pod/postgresql-deployment-7cfb6c95db-5r2v8
pod "postgresql-deployment-7cfb6c95db-5r2v8" deleted
这时,我们再观察环境中pod的情况可以发现,通过deployment,一个新的pg pod被创建出来了
kubectl get pods
NAME READY STATUS RESTARTS AGE
postgresql-deployment-7cfb6c95db-hd8ks 1/1 Running 0 13s
这个时候,我们通过上面的psql客户端工具,重新连接我们的db,观察我们之前维护的数据是否还正常保持?
$ ./psql -U postgres -h localhost -p 30432 pgtest -c "select * from test"
id | name
----+------
1 | tom
(1 row)
跟我们预期一样,哪怕pod被删除了,我们的K8s环境依旧有能力通过持久化卷恢复数据。