K8S部署postgresql全过程
1.集群准备工作
[root@mast ~]# kubectl label nodes node1 postgres-env=dev # 添加节点标签
node/node1 labeled
[root@mast ~]# kubectl label nodes node1 disk-type=ssd # 可选:扩展标签用于高级调度
node/node1 labeled
[root@mast ~]# kubectl create namespace postgres-dev # 隔离开发环境
namespace/postgres-dev created
2.创建持久卷
持久卷(Persistent Volume,PV)
PV 是集群层面的存储资源,由集群管理员创建和管理。它是对底层存储系统(如 NFS、iSCSI、Ceph 等)的抽象,为 Pod 提供了独立于节点的持久化存储,他独立与pod ,后台可以用多种存储模式,确的存储容量和访问模式,如 ReadWriteOnce(单节点读写)、ReadOnlyMany(多节点只读)和 ReadWriteMany(多节点读写)
持久卷声明(Persistent Volume Claim,PVC)
PVC 是用户对存储资源的请求,由普通用户创建。它类似于 Pod 对计算资源(CPU 和内存)的请求,PVC 对存储资源(如 PV)提出请求,请求指定的存储容量和访问模式。 Kubernetes 会自动将 PVC 绑定到满足其请求的 PV 上,如果没有合适的 PV,也可以通过动态存储供应(Dynamic Provisioning)来创建新的 PV。
[root@mast ~]# kubectl apply -f pv-pvc.yaml -n postgres-dev
persistentvolume/postgres-pv-dev created
persistentvolumeclaim/postgres-pvc-dev created
[root@mast ~]# cat pv-pvc.yaml
#PV
apiVersion: v1
kind: PersistentVolume
metadata:
name: postgres-pv-dev
namespace: postgres-dev
labels:
app: postgres-dev # 标签用于亲和性调度关联
spec:
capacity:
storage: 5Gi # 存储容量(开发环境建议5Gi)
storageClassName: manual
accessModes:
- ReadWriteOnce
hostPath:
path: /data/postgres-dev # 节点本地路径(需提前创建)
nodeAffinity: # 关键:PV与节点绑定
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values: [node1] # 严格绑定到node1
---
#PVC
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-pvc-dev
namespace: postgres-dev
spec:
storageClassName: manual
accessModes: [ReadWriteOnce]
resources:
requests:
storage: 5Gi # 与PV容量一致
selector: # 显式选择带标签的PV
matchLabels:
app: postgres-dev
[root@mast ~]#
3.创建secret configmap
ConfigMap
ConfigMap
是一种用于存储非敏感配置数据的键值对集合。它允许你将配置信息和容器镜像解耦,使得配置可以在不重新构建镜像的情况下进行修改和更新。可以用于环境变量配置 命令行参数配置和 配置文件挂载
Secret
Secret
也是用于存储键值对数据的对象,但主要用于存储敏感信息,如密码、令牌、SSH 密钥等。Secret
提供了比 ConfigMap
更安全的存储方式,数据在存储和传输过程中会进行加密处理。主要用于认证信息 和加密密钥
[root@mast ~]# vim secret.yaml
[root@mast ~]# kubectl apply -f secret.yaml -n postgres-dev
secret/postgres-secret-dev created
[root@mast ~]# cat secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: postgres-secret-dev
namespace: postgres-dev
type: Opaque
stringData: # 开发环境简化处理
POSTGRES_USER: "dev_admin"
POSTGRES_PASSWORD: "d3v!P@ss"
data: # 可选手动编码字段
# echo -n "backup" | base64 → YmFja3Vw
# POSTGRES_BACKUP_USER: YmFja3Vw
[root@mast ~]#
4.创建pg数据库yaml 文件
Pod是容器运行的最小单位,也是最重要的单位,在yaml 中定义了很多重要的信息,对pod 进行限制,如下
[root@mast ~]# kubectl apply -f deployment.yaml -n postgres-dev
deployment.apps/postgres-deployment-dev created
[root@mast ~]# cat deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: postgres-deployment-dev
namespace: postgres-dev
spec:
replicas: 1
selector:
matchLabels:
app: postgres-dev
template:
metadata:
labels:
app: postgres-dev # 服务选择器标识
env: dev
spec:
affinity: # 亲和性调度配置
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: postgres-env # 匹配节点标签 节点有一个 postgres-env 标签
operator: In
values: [dev]
- key: disk-type # 多标签匹配 节点有一个 disk-type 标签。
operator: Exists
containers:
- name: postgres #Pod 中只运行一个postgres容器
image: postgres:15-alpine
imagePullPolicy: IfNotPresent #本地没有该镜像时 才从仓库中拉取镜像
ports:
- containerPort: 5432
envFrom: # 批量加载环境变量
- secretRef: #envFrom 用于从外部资源(ConfigMap Secret)中批量加载环境变量到容器中
name: postgres-secret-dev
env:
- name: POSTGRES_DB
value: "dev_core" #,POSTGRES_DB 环境变量通常指定数据库的名称,将数据库名设置dev_core。
volumeMounts: #volumeMounts 用于将卷(Volume)挂载到容器内的指定路径
- name: postgres-data
mountPath: /var/lib/postgresql/data
resources:
limits:
cpu: "1" # 硬限制(必须≤节点容量)
memory: "1Gi"
requests:
cpu: "0.7" # 弹性请求(总和≤节点容量)
memory: "768Mi"
volumes:
- name: postgres-data
persistentVolumeClaim:
claimName: postgres-pvc-dev
[root@mast ~]#
5.创建service
Service:Service 为 Pod 提供了稳定的网络访问入口。它可以将多个 Pod 抽象成一个统一的服务,使得外部应用或其他 Pod 可以通过 Service 访问这些 Pod,而无需关心具体的 Pod 实例。
[root@mast ~]# kubectl apply -f service.yaml -n postgres-dev
service/postgres-service-dev created
[root@mast ~]# cat service.yaml
apiVersion: v1
kind: Service
metadata:
name: postgres-service-dev
namespace: postgres-dev
spec:
type: ClusterIP
selector:
app: postgres-dev
ports:
- name: postgres
port: 5432
targetPort: 5432
6.查验pod
[root@mast ~]# kubectl get pods -n postgres-dev -o wide | grep -E "NAME|postgres"
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
postgres-deployment-dev-69475b468c-9w5sl 1/1 Running 0 41s 10.244.1.23 node1 <none> <none>
[root@mast ~]# kubectl describe pod postgres-deployment-dev-69475b468c-9w5sl -n postgres-dev
Name: postgres-deployment-dev-69475b468c-9w5sl
Namespace: postgres-dev
Priority: 0
Node: node1/10.0.0.27
Start Time: Wed, 19 Mar 2025 15:06:29 +0800
Labels: app=postgres-dev
env=dev
pod-template-hash=69475b468c
Annotations: <none>
Status: Running
IP: 10.244.1.23
IPs:
IP: 10.244.1.23
Controlled By: ReplicaSet/postgres-deployment-dev-69475b468c
Containers:
postgres:
Container ID: docker://a012f1f0116d6357b48fed82a3f91100d9547b117f49c0a701a1d5c884e939b9
Image: postgres:15-alpine
Image ID: docker-pullable://postgres@sha256:ef9d1517df69c4d27dbb9ddcec14f431a2442628603f4e9daa429b92ae6c3cd1
Port: 5432/TCP
Host Port: 0/TCP
State: Running
Started: Wed, 19 Mar 2025 15:06:29 +0800
Ready: True
Restart Count: 0
Limits:
cpu: 1
memory: 1Gi
Requests:
cpu: 700m
memory: 768Mi
Environment Variables from:
postgres-secret-dev Secret Optional: false
Environment:
POSTGRES_DB: dev_core
Mounts:
/var/lib/postgresql/data from postgres-data (rw)
/var/run/secrets/kubernetes.io/serviceaccount from default-token-tr7gt (ro)
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
postgres-data:
Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
ClaimName: postgres-pvc-dev
ReadOnly: false
default-token-tr7gt:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-tr7gt
Optional: false
QoS Class: Burstable
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled <unknown> default-scheduler Successfully assigned postgres-dev/postgres-deployment-dev-69475b468c-9w5sl to node1
Normal Pulled 4m35s kubelet, node1 Container image "postgres:15-alpine" already present on machine
Normal Created 4m35s kubelet, node1 Created container postgres
Normal Started 4m35s kubelet, node1 Started container postgres
[root@mast ~]#
[root@mast ~]# kubectl exec -it postgres-deployment-dev-69475b468c-9w5sl -n postgres-dev -- psql -U dev_admin -d dev_core
psql (15.12)
Type "help" for help.
dev_core=# \l
List of databases
Name | Owner | Encoding | Collate | Ctype | ICU Locale | Locale Provider | Access privileges
-----------+-----------+----------+------------+------------+------------+-----------------+-------------------------
dev_core | dev_admin | UTF8 | en_US.utf8 | en_US.utf8 | | libc |
postgres | dev_admin | UTF8 | en_US.utf8 | en_US.utf8 | | libc |
template0 | dev_admin | UTF8 | en_US.utf8 | en_US.utf8 | | libc | =c/dev_admin +
| | | | | | | dev_admin=CTc/dev_admin
template1 | dev_admin | UTF8 | en_US.utf8 | en_US.utf8 | | libc | =c/dev_admin +
| | | | | | | dev_admin=CTc/dev_admin
(4 rows)
dev_core=#
[root@mast ~]# kubectl edit pod postgres-deployment-dev-69475b468c-9w5sl -n postgres-dev
Edit cancelled, no changes made.
root@mast ~]# kubectl get pod postgres-deployment-dev-69475b468c-9w5sl -n postgres-dev -o yaml
7.单机部署完成,如果需要集群的时候就需要configmap
# postgres-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: postgres-config
namespace: postgres-dev
data:
# 主库专用配置
postgresql-master.conf: |
wal_level = replica
max_wal_senders = 3
hot_standby = on
# 从库专用配置
postgresql-replica.conf: |
hot_standby = on
primary_conninfo = 'host=postgres-master user=repluser password=${REPL_PASSWORD}'
# 初始化脚本(创建复制用户)
init-replication.sql: |
CREATE ROLE repluser WITH REPLICATION LOGIN PASSWORD '${REPL_PASSWORD}';
今天朋友问我pg数据库和nginx 的pod 区别是什莫?
答:
pg数据库应该是有状态服务 ,需要做持久化。必须挂载postgresql/data,而nginx 只需要经常备份配置文件,nginx一般需要外部通信,需要https,而pg经常内部通讯,只需要tcp