基于K3s搭建GitOps环境5-部署基础组件

一、核心定位

本文作为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
# 1. 验证K3s集群状态
kubectl get nodes

# 2. 验证存储类配置
kubectl get storageclass
kubectl describe storageclass local-path

# 3. 验证Traefik运行状态
kubectl get pods -n kube-system -l app=traefik

# 4. 检查命名空间
kubectl get ns postgres redis mysql 2>/dev/null || echo "命名空间不存在,将自动创建"

# 5. 验证网络连通性
ping -c 3 8.8.8.8

前置条件检查清单:

  • K3s集群运行正常
  • local-path存储类可用
  • Traefik Pod处于Running状态
  • 网络可访问外网(用于拉取镜像)
  • 具备集群管理权限

三、创建独立命名空间

为实现数据库与缓存服务的资源隔离和精细化管理,分别创建专属命名空间:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# namespaces.yaml
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
# postgresql.yaml
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
# postgres-ingressroute-tcp.yaml
apiVersion: traefik.io/v1alpha1
kind: IngressRouteTCP
metadata:
name: postgres-ingressroute-tcp
namespace: postgres
spec:
entryPoints:
- postgres-tcp # 需在Traefik中配置此TCP入口点
routes:
- match: HostSNI(`*`)
services:
- name: postgres
port: 5432

4.3 应用PostgreSQL配置

1
2
3
4
5
6
7
8
9
10
# 部署PostgreSQL
kubectl apply -f postgresql.yaml

# 可选:部署IngressRouteTCP
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
# redis.yaml
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
# redis-ingressroute-tcp.yaml
apiVersion: traefik.io/v1alpha1
kind: IngressRouteTCP
metadata:
name: redis-ingressroute-tcp
namespace: redis
spec:
entryPoints:
- redis-tcp # 需在Traefik中配置此TCP入口点
routes:
- match: HostSNI(`*`)
services:
- name: redis
port: 6379

5.3 应用Redis配置

1
2
3
4
5
6
7
8
9
# 部署Redis
kubectl apply -f redis.yaml

# 可选:部署IngressRouteTCP
kubectl apply -f redis-ingressroute-tcp.yaml

# 验证Redis运行状态
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
# mysql.yaml
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== # root123456 base64编码
---
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
# mysql-ingressroute-tcp.yaml
apiVersion: traefik.io/v1alpha1
kind: IngressRouteTCP
metadata:
name: mysql-ingressroute-tcp
namespace: mysql
spec:
entryPoints:
- mysql-tcp # 需在Traefik中配置此TCP入口点
routes:
- match: HostSNI(`*`)
services:
- name: mysql
port: 3306

6.3 应用MySQL配置

1
2
3
4
5
6
7
8
# 部署MySQL(备选方案)
kubectl apply -f mysql.yaml

# 可选:部署IngressRouteTCP
kubectl apply -f mysql-ingressroute-tcp.yaml

# 验证MySQL运行状态
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
# 测试PostgreSQL连接
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;"

# 测试Redis连接
kubectl run redis-test --rm -it --image=redis:7-alpine -n redis -- \
redis-cli -h redis.redis.svc.cluster.local -a redis123456 ping

# 测试MySQL连接(如部署)
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
# 查看IngressRouteTCP状态
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未部署"

# 数据备份(PostgreSQL示例)
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环境提供代码托管服务。