一、核心定位
本文作为GitOps环境搭建系列的第五篇,聚焦基础组件(数据库和缓存)的部署与配置。在GitOps环境中,数据库和缓存是支撑核心组件(Gitea、ArgoCD、Tekton、Harbor等)运行的关键基础设施。
基础组件包括:
- PostgreSQL/MySQL:关系型数据库,用于存储Gitea、Harbor等组件的元数据
- Redis:内存缓存,用于提升组件性能和会话管理
本文采用独立命名空间规划,将PostgreSQL部署在postgres命名空间,Redis部署在redis命名空间,MySQL作为备选方案部署在mysql命名空间。所有配置均适配K3s轻量级环境,使用local-path存储类保障数据持久化,并通过Traefik的IngressRouteTCP实现服务访问。
二、部署前置检查
部署前需验证K3s集群状态及存储配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| kubectl get nodes
kubectl get storageclass kubectl describe storageclass local-path
kubectl get pods -n kube-system -l app=traefik
kubectl get ns postgres redis mysql 2>/dev/null || echo "命名空间不存在,将自动创建"
ping -c 3 8.8.8.8
|
前置条件检查清单:
三、创建独立命名空间
为实现数据库与缓存服务的资源隔离和精细化管理,分别创建专属命名空间:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| apiVersion: v1 kind: Namespace metadata: name: postgres --- apiVersion: v1 kind: Namespace metadata: name: redis --- apiVersion: v1 kind: Namespace metadata: name: mysql
|
应用配置:
1 2 3 4
| kubectl apply -f namespaces.yaml
kubectl get namespaces | grep -E "postgres|redis|mysql"
|
四、部署PostgreSQL
4.1 配置PostgreSQL
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
| apiVersion: v1 kind: ConfigMap metadata: name: postgres-config namespace: postgres data: POSTGRES_DB: "gitea" POSTGRES_USER: "gitea" POSTGRES_PASSWORD: "gitea123" POSTGRES_INITDB_ARGS: "--encoding=UTF8 --locale=C" PGDATA: "/var/lib/postgresql/data/pgdata" --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: postgres-pvc namespace: postgres spec: accessModes: - ReadWriteOnce storageClassName: local-path resources: requests: storage: 20Gi --- apiVersion: apps/v1 kind: StatefulSet metadata: name: postgres namespace: postgres spec: serviceName: postgres replicas: 1 selector: matchLabels: app: postgres template: metadata: labels: app: postgres spec: containers: - name: postgres image: postgres:15-alpine ports: - containerPort: 5432 envFrom: - configMapRef: name: postgres-config volumeMounts: - name: postgres-data mountPath: /var/lib/postgresql/data resources: requests: memory: "256Mi" cpu: "250m" limits: memory: "512Mi" cpu: "500m" volumes: - name: postgres-data persistentVolumeClaim: claimName: postgres-pvc --- apiVersion: v1 kind: Service metadata: name: postgres namespace: postgres spec: selector: app: postgres ports: - port: 5432 targetPort: 5432 type: ClusterIP
|
4.2 配置IngressRouteTCP(可选)
如需通过Traefik外部访问PostgreSQL,配置IngressRouteTCP:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| apiVersion: traefik.io/v1alpha1 kind: IngressRouteTCP metadata: name: postgres-ingressroute-tcp namespace: postgres spec: entryPoints: - postgres-tcp routes: - match: HostSNI(`*`) services: - name: postgres port: 5432
|
4.3 应用PostgreSQL配置
1 2 3 4 5 6 7 8 9 10
| kubectl apply -f postgresql.yaml
kubectl apply -f postgres-ingressroute-tcp.yaml
kubectl get pods -n postgres kubectl get pvc -n postgres kubectl get svc -n postgres
|
五、部署Redis
5.1 配置Redis
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
| apiVersion: v1 kind: ConfigMap metadata: name: redis-config namespace: redis data: redis.conf: | bind 0.0.0.0 protected-mode no port 6379 requirepass "redis123456" appendonly yes appendfsync everysec dir /data --- apiVersion: apps/v1 kind: StatefulSet metadata: name: redis namespace: redis spec: serviceName: redis replicas: 1 selector: matchLabels: app: redis template: metadata: labels: app: redis spec: containers: - name: redis image: redis:7-alpine command: ["redis-server", "/etc/redis/redis.conf"] ports: - containerPort: 6379 volumeMounts: - name: redis-config mountPath: /etc/redis - name: redis-data mountPath: /data resources: requests: memory: "128Mi" cpu: "100m" limits: memory: "256Mi" cpu: "200m" volumeClaimTemplates: - metadata: name: redis-data spec: accessModes: [ "ReadWriteOnce" ] storageClassName: "local-path" resources: requests: storage: 5Gi --- apiVersion: v1 kind: Service metadata: name: redis namespace: redis spec: selector: app: redis ports: - port: 6379 targetPort: 6379 type: ClusterIP
|
5.2 配置IngressRouteTCP(可选)
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| apiVersion: traefik.io/v1alpha1 kind: IngressRouteTCP metadata: name: redis-ingressroute-tcp namespace: redis spec: entryPoints: - redis-tcp routes: - match: HostSNI(`*`) services: - name: redis port: 6379
|
5.3 应用Redis配置
1 2 3 4 5 6 7 8 9
| kubectl apply -f redis.yaml
kubectl apply -f redis-ingressroute-tcp.yaml
kubectl get pods -n redis kubectl exec -it redis-0 -n redis -- redis-cli -a redis123456 ping
|
六、备选方案:部署MySQL
6.1 配置MySQL
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
| apiVersion: v1 kind: ConfigMap metadata: name: mysql-config namespace: mysql data: my.cnf: | [mysqld] default_authentication_plugin=mysql_native_password character-set-server=utf8mb4 collation-server=utf8mb4_unicode_ci --- apiVersion: v1 kind: Secret metadata: name: mysql-secret namespace: mysql type: Opaque data: mysql-root-password: cm9vdDEyMzQ1Ng== --- apiVersion: apps/v1 kind: StatefulSet metadata: name: mysql namespace: mysql spec: serviceName: mysql replicas: 1 selector: matchLabels: app: mysql template: metadata: labels: app: mysql spec: containers: - name: mysql image: mysql:8.0 ports: - containerPort: 3306 env: - name: MYSQL_ROOT_PASSWORD valueFrom: secretKeyRef: name: mysql-secret key: mysql-root-password volumeMounts: - name: mysql-data mountPath: /var/lib/mysql resources: requests: memory: "256Mi" cpu: "250m" limits: memory: "512Mi" cpu: "500m" volumeClaimTemplates: - metadata: name: mysql-data spec: accessModes: [ "ReadWriteOnce" ] storageClassName: "local-path" resources: requests: storage: 20Gi --- apiVersion: v1 kind: Service metadata: name: mysql namespace: mysql spec: selector: app: mysql ports: - port: 3306 targetPort: 3306 type: ClusterIP
|
6.2 配置IngressRouteTCP(可选)
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| apiVersion: traefik.io/v1alpha1 kind: IngressRouteTCP metadata: name: mysql-ingressroute-tcp namespace: mysql spec: entryPoints: - mysql-tcp routes: - match: HostSNI(`*`) services: - name: mysql port: 3306
|
6.3 应用MySQL配置
1 2 3 4 5 6 7 8
| kubectl apply -f mysql.yaml
kubectl apply -f mysql-ingressroute-tcp.yaml
kubectl get pods -n mysql
|
七、验证部署结果
7.1 验证组件状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| kubectl get pods -n postgres kubectl get pods -n redis kubectl get pods -n mysql 2>/dev/null || echo "MySQL未部署"
kubectl get svc -n postgres kubectl get svc -n redis kubectl get svc -n mysql 2>/dev/null || echo "MySQL未部署"
kubectl get pvc -n postgres kubectl get pvc -n redis kubectl get pvc -n mysql 2>/dev/null || echo "MySQL未部署"
|
7.2 测试连接功能
1 2 3 4 5 6 7 8 9 10 11
| kubectl run postgres-test --rm -it --image=postgres:15-alpine -n postgres -- \ psql -h postgres.postgres.svc.cluster.local -U gitea -d gitea -c "SELECT 1;"
kubectl run redis-test --rm -it --image=redis:7-alpine -n redis -- \ redis-cli -h redis.redis.svc.cluster.local -a redis123456 ping
kubectl run mysql-test --rm -it --image=mysql:8.0 -n mysql -- \ mysql -h mysql.mysql.svc.cluster.local -uroot -proot123456 -e "SELECT 1;"
|
7.3 验证IngressRouteTCP(如配置)
1 2 3 4
| kubectl get ingressroutetcps.traefik.containo.us -n postgres 2>/dev/null || echo "未配置" kubectl get ingressroutetcps.traefik.containo.us -n redis 2>/dev/null || echo "未配置" kubectl get ingressroutetcps.traefik.containo.us -n mysql 2>/dev/null || echo "未配置"
|
八、服务访问方式
8.1 集群内访问
- PostgreSQL:
postgres.postgres.svc.cluster.local:5432
- Redis:
redis.redis.svc.cluster.local:6379
- MySQL:
mysql.mysql.svc.cluster.local:3306
8.2 集群外访问(需配置IngressRouteTCP)
- PostgreSQL:
Traefik节点IP:5432(需Traefik配置postgres-tcp入口点)
- Redis:
Traefik节点IP:6379(需Traefik配置redis-tcp入口点)
- MySQL:
Traefik节点IP:3306(需Traefik配置mysql-tcp入口点)
九、日常运维命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| kubectl logs -f postgres-0 -n postgres kubectl logs -f redis-0 -n redis kubectl logs -f mysql-0 -n mysql 2>/dev/null || echo "MySQL未部署"
kubectl rollout restart statefulset postgres -n postgres kubectl rollout restart statefulset redis -n redis kubectl rollout restart statefulset mysql -n mysql 2>/dev/null || echo "MySQL未部署"
kubectl exec postgres-0 -n postgres -- pg_dump -U gitea gitea > gitea-backup-$(date +%Y%m%d).sql
kubectl exec -it postgres-0 -n postgres -- /bin/bash kubectl exec -it redis-0 -n redis -- /bin/sh kubectl exec -it mysql-0 -n mysql -- /bin/bash 2>/dev/null || echo "MySQL未部署"
|
十、常见问题修复
| 问题现象 |
排查方向 |
修复方案 |
| Pod一直Pending |
存储类/资源不足 |
检查local-path存储类,确认节点有足够资源 |
| 数据库连接失败 |
服务发现/认证 |
检查Service selector,验证用户名密码 |
| Redis认证失败 |
密码配置 |
确认redis.conf中的requirepass配置正确 |
| 数据持久化失败 |
PVC绑定问题 |
检查PVC状态:kubectl describe pvc -n <namespace> |
| IngressRouteTCP不生效 |
Traefik入口点配置 |
确认Traefik已配置对应TCP入口点 |
十一、配置参考
所有基础组件配置文件和部署脚本请参考:
https://gitee.com/Chemmy/kube-template/tree/master/devops
该目录包含:
- PostgreSQL完整配置
- Redis完整配置
- MySQL完整配置
- 生产环境优化配置
- 备份和恢复脚本
总结
本文完成了GitOps环境基础组件(PostgreSQL、Redis、MySQL)的标准化部署,采用独立命名空间实现资源隔离,使用StatefulSet保障有状态服务的稳定性,通过local-path存储类实现数据持久化。
基础组件部署完成后,GitOps环境已具备完整的数据存储和缓存能力。下一篇文章将部署Gitea代码仓库,为GitOps环境提供代码托管服务。