一、环境准备

  1. kubenetes
  2. k8s
  3. harbor
  4. dnsmasq
  5. helm
  6. cert-manager
  7. traefik
  8. metallb

gitlab 占用了 ssh 22 端口,这里为了图方便,不换 ip 了,就改用默认的 2222 端口。

二、安装

2.1 traefik 配置

  1. 添加 helm 仓库
1
2
helm repo add jumpserver https://jumpserver.github.io/helm-charts
helm repo update jumpserver
  1. 给 traefik 添加端口的配置
1
vim /opt/selfhost/infra-deployment/traefik/v3-traefik-ssh.yaml
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
# v3-traefik-ssh.yaml
ingressClass:
enabled: true
isDefaultClass: true # 设为默认 ingressClass,Ingress 不写 class 也走 Traefik

api:
dashboard: true # 打开 dashboard(下一步用我们自己的 IngressRoute 暴露它)

ingressRoute:
dashboard:
enabled: false # 关掉自带的 dashboard 路由,避免和我们带 TLS 的那个冲突

# service 默认就是 LoadBalancer 类型,会自动向 MetalLB 要一个 IP
ports: # 新增的顶层块,顶格写
ssh:
port: 2222 # Traefik 容器内监听端口
exposedPort: 22 # 对外(MetalLB VIP)端口
protocol: TCP
expose:
default: true # 新版 chart 写法
jms-ssh:
port: 2223 # 容器内端口,必须和上面 ssh 的 2222 错开!
exposedPort: 2222 # 对外 VIP 端口
protocol: TCP
expose:
default: true
  1. 更新 traefik
1
helm upgrade traefik traefik/traefik -n traefik -f /opt/selfhost/infra-deployment/traefik/v3-traefik-ssh.yaml
  1. 验证
1
kubectl -n traefik get svc traefik -o wide

2.2 jms 依赖的组件

主要是 pgsql、redis、命名空间、ingress 等

  1. 编辑资源清单文件
1
vim jumpserver-stack.yaml
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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# ============================================================
# jumpserver-stack.yaml
# 集群内依赖 (PG + Redis) + Web Ingress + SSH 的 TCP 路由
#
# 改动点:
# - nfs-client -> 你的 StorageClass (k3s: local-path)
# - jms.qx.lab -> 你的域名
# - qx-ca-issuer -> 你的 cert-manager ClusterIssuer 名(已按你给的填好)
# 注意 PG/Redis 密码要和 values.yaml 完全一致(已预填好)。
#
# 应用顺序见聊天里的 runbook,不要一次性全 apply。
# ============================================================
apiVersion: v1
kind: Namespace
metadata:
name: jumpserver
---
# ========================= PostgreSQL =========================
apiVersion: v1
kind: Secret
metadata:
name: jms-postgresql
namespace: jumpserver
type: Opaque
stringData:
POSTGRES_DB: jumpserver
POSTGRES_USER: jumpserver
POSTGRES_PASSWORD: "u4bWW0RTZMFeqVPGI315"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: jms-postgresql-data
namespace: jumpserver
spec:
accessModes:
- ReadWriteOnce
storageClassName: nfs-client
resources:
requests:
storage: 10Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: jms-postgresql
namespace: jumpserver
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: jms-postgresql
template:
metadata:
labels:
app: jms-postgresql
spec:
containers:
- name: postgresql
image: postgres:16-alpine
envFrom:
- secretRef:
name: jms-postgresql
env:
# 数据放到子目录,避免挂载卷里的 lost+found 干扰初始化
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
ports:
- containerPort: 5432
readinessProbe:
exec:
command: ["pg_isready", "-U", "jumpserver", "-d", "jumpserver"]
initialDelaySeconds: 10
periodSeconds: 5
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
volumes:
- name: data
persistentVolumeClaim:
claimName: jms-postgresql-data
---
apiVersion: v1
kind: Service
metadata:
name: jms-postgresql
namespace: jumpserver
spec:
selector:
app: jms-postgresql
ports:
- port: 5432
targetPort: 5432
---
# =========================== Redis ===========================
apiVersion: v1
kind: Secret
metadata:
name: jms-redis
namespace: jumpserver
type: Opaque
stringData:
REDIS_PASSWORD: "62rnrIY03ilA8TZF3vI3"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: jms-redis
namespace: jumpserver
spec:
replicas: 1
selector:
matchLabels:
app: jms-redis
template:
metadata:
labels:
app: jms-redis
spec:
containers:
- name: redis
image: redis:7-alpine
args: ["--requirepass", "$(REDIS_PASSWORD)"]
env:
- name: REDIS_PASSWORD
valueFrom:
secretKeyRef:
name: jms-redis
key: REDIS_PASSWORD
ports:
- containerPort: 6379
readinessProbe:
exec:
command: ["sh", "-c", "redis-cli -a \"$REDIS_PASSWORD\" ping"]
initialDelaySeconds: 5
periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
name: jms-redis
namespace: jumpserver
spec:
selector:
app: jms-redis
ports:
- port: 6379
targetPort: 6379
---
# ===================== Web Ingress =====================
# 标准 Ingress:Traefik 接管 + cert-manager 按注解自动签发证书到 jms-qx-lab-tls
# Traefik 原生支持 WebSocket,JumpServer 终端无需额外注解
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: jms-web
namespace: jumpserver
annotations:
cert-manager.io/cluster-issuer: qx-ca-issuer
spec:
ingressClassName: traefik
tls:
- hosts:
- jms.qx.lab
secretName: jms-qx-lab-tls
rules:
- host: jms.qx.lab
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: jms-jumpserver-jms-web
port:
number: 80
---
# ===================== SSH 路由 =====================
# 普通 Ingress 转不了 SSH,这里用 Traefik 的 IngressRouteTCP
# 走自定义 TCP entrypoint jms-ssh(2222) -> koko 的 2222
# 非 TLS 的 TCP 必须 HostSNI(`*`)
apiVersion: traefik.io/v1alpha1
kind: IngressRouteTCP
metadata:
name: jms-ssh
namespace: jumpserver
spec:
entryPoints:
- jms-ssh
routes:
- match: HostSNI(`*`)
services:
- name: jms-jumpserver-jms-koko
port: 2222
  1. 创建资源
1
kubectl apply -f jumpserver-stack.yaml
  1. 验证
1
2
kubectl -n jumpserver rollout status deploy/jms-postgresql
kubectl -n jumpserver rollout status deploy/jms-redis

2.3 helm 安装 jumpserver

  1. 创建 values.yaml
1
vim values.yaml
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
82
83
84
# ============================================================
# JumpServer Helm values
# helm repo add jumpserver https://jumpserver.github.io/helm-charts
# helm install jms jumpserver/jumpserver -n jumpserver -f values.yaml
#
# 需要你改的地方只有两处:
# 1) 把所有 nfs-client 换成你集群的 StorageClass
# (k3s 默认是 local-path,用 `kubectl get sc` 查看)
# 2) 域名 jms.qx.lab 换成你自己的
# 密码/密钥已随机生成,和 jumpserver-stack.yaml 里的保持一致即可,不用改。
# ============================================================

# 关闭 chart 自带的 ingress(它是给 nginx-ingress 用的),改用 Traefik IngressRoute
ingress:
enabled: false

# ---- 集群内 PostgreSQL(由 jumpserver-stack.yaml 部署)----
externalDatabase:
engine: postgresql
host: jms-postgresql # 同 namespace 内的 Service 名
port: 5432
user: jumpserver
password: "u4bWW0RTZMFeqVPGI315"
database: jumpserver

# ---- 集群内 Redis(由 jumpserver-stack.yaml 部署)----
externalRedis:
host: jms-redis
port: 6379
password: "62rnrIY03ilA8TZF3vI3"

core:
config:
secretKey: "E4TbGLMRiSLSORtZpDaOeAFcZE4oppgKcsx1EZb55l169AY9WV"
bootstrapToken: "E0BQP33Vm6GQ2NNpwf037R1i"
log:
level: ERROR
env:
SESSION_EXPIRE_AT_BROWSER_CLOSE: true
# v3/v4 必须设置可信域名,否则登录报 CSRF 403
DOMAINS: "jms.qx.lab:443"
persistence:
storageClassName: nfs-client
accessModes:
- ReadWriteMany
size: 10Gi

koko:
service:
type: ClusterIP # 不直接暴露,交给 Traefik TCP 转发
web:
port: 5000
ssh:
port: 2222
persistence:
storageClassName: nfs-client
accessModes:
- ReadWriteMany
size: 10Gi

lion:
persistence:
storageClassName: nfs-client
accessModes:
- ReadWriteMany
size: 10Gi

chen:
persistence:
storageClassName: nfs-client
accessModes:
- ReadWriteMany
size: 5Gi

web:
persistence:
storageClassName: nfs-client
accessModes:
- ReadWriteMany
size: 1Gi

# 企业版组件,社区版保持关闭
xpack:
enabled: false
  1. 安装
1
helm install jms jumpserver/jumpserver -n jumpserver -f values.yaml
  1. 验证
1
kubectl -n jumpserver get pods -w

三、验证

  1. 浏览器访问验证
1
2
3
地址: https://jms.qx.lab
用户名: admin
密码: ChangeMe
  1. ssh验证
1
ssh -p 2222 admin@jms.qx.lab