主题
JumpServer 集群内部署指南:通过堡垒机连接 KubeVirt 虚拟机
环境基线: RKE2 v1.35.6(6 节点)+ KubeVirt v1.9.0,Rocky Linux 9.8,Calico VXLAN(Pod CIDR
10.22.0.0/16,natOutgoing: true) 入口节点:root@192.168.122.31(sza122031.local) 镜像仓库: Harbor192.168.122.156:30000JumpServer 版本: v4.10.x LTS(官方 Chart appVersion v4.10.19;安全基线 ≥ v4.10.17) 关联文档:./kubevirt-practical-operations-guide.md(3.4 固定 IP 与热迁移)、./kubevirt-tutorial-beginner-to-master.md(第 8 章网络)、../rke2-kubevirt-deployment-guide.md(2.1 Harbor 代理缓存)
目录
- 方案总览
- 组件架构
- 前置准备
- 部署 JumpServer
- 把 KubeVirt 虚拟机接入 JumpServer
- 日常使用方式
- 运维:备份、升级、排障
- 安全注意事项
- 入口变体:固定 ClusterIP 与固定物理网段 IP(测试场景)
1. 方案总览
在 RKE2 集群内部署 JumpServer(开源堡垒机),通过它统一连接、授权、审计 对 KubeVirt 虚拟机(物理网段固定 IP,如 192.168.122.102)的访问:
运维人员 ──浏览器/SSH 客户端──> JumpServer(K8s Pod,NodePort 入口)
│
│ koko 组件发起 SSH(Pod CIDR → 物理网段)
▼
VM eth1 固定 IP 192.168.122.102:22(Multus br-vm)1.1 为什么用官方 Helm Chart
- JumpServer 官方提供 Kubernetes Helm 部署方式(
jumpserver/helm-charts), 组件拆分清晰,比 docker-compose 更适合已有 K8s 集群的环境; - 会话录像、配置落盘到 PVC,可直接使用现网
vm-nas(NFS)存储; - 与虚拟机同集群部署:JumpServer Pod 到 VM 固定 IP 一跳直达,无需网域/代理。
1.2 网络可达性(关键点)
JumpServer Pod 在 Calico Pod 网络(10.22.0.0/16)内,目标是物理网段 192.168.122.0/24 上的 VM 固定 IP:
- 现网 IPPool 已配置
natOutgoing: true,Pod → 物理网段的流量会被 SNAT 为 节点 IP,VM 回包可达——无需任何额外路由; - 验证方法(部署后执行):
bash
kubectl -n jumpserver exec deploy/jumpserver-jms-koko -- \
python3 -c "import socket; s=socket.create_connection(('192.168.122.102',22),5); print('OK'); s.close()"- 若 VM 只有 masquerade Pod 网络(无固定 IP),Pod→Pod 互通同样可行, 但 Pod IP 会随重建变化,资产记录会失效——因此接入堡垒机的 VM 必须使用 Multus 第二网卡固定 IP(见实战手册 3.4)。
2. 组件架构
官方 Chart(v4.10.19)包含以下组件,不自带数据库——PostgreSQL 与 Redis 必须外部提供(第 3.3 节给出部署清单):
| 组件 | 镜像(CE 版) | 作用 | 本场景 |
|---|---|---|---|
| core(含 celery 任务) | docker.io/jumpserver/core | Web 控制台、API、任务队列 | 必需 |
| koko | docker.io/jumpserver/koko | SSH 接入、Web 终端、文件传输 | 必需(连 VM 的核心) |
| web | docker.io/jumpserver/web | Nginx 统一入口 | 必需 |
| lion | docker.io/jumpserver/lion | RDP/VNC Web 连接(Guacamole) | 可选 |
| chen | docker.io/jumpserver/chen | 数据库 Web 客户端 | 可选 |
| magnus | docker.io/jumpserver/magnus | 数据库客户端代理(端口 5525) | 可选 |
| razor | registry.fit2cloud.com/jumpserver/razor | RDP 原生客户端代理 | 可选 |
| nec | registry.fit2cloud.com/jumpserver/nec | VNC 原生客户端代理 | 可选 |
| video | registry.fit2cloud.com/jumpserver/video | 会话录像处理 | 可选 |
| facelive | registry.fit2cloud.com/jumpserver/facelive | 人脸识别(企业合规) | 建议关闭 |
| xrdp | registry.fit2cloud.com/jumpserver/xrdp | RDP 应用发布 | 默认关闭 |
⚠️ 注意:Chart 模板里
global.imageRegistry会覆盖所有组件的镜像仓库, 而razor/nec/video/facelive/xrdp的镜像在registry.fit2cloud.com上 (docker.io 没有)。因此不能只设一个全局镜像仓库,必须按组件分别指定image.registry(见 4.2 节 values),或者把用不到的组件enabled: false。
对外端口(官方网络端口说明,v4.10.x):
| 端口 | 作用 |
|---|---|
| 80/443 | Web 控制台(本方案以 NodePort 30080 映射) |
| 2222 | SSH 客户端接入(koko,本方案 NodePort 32222) |
| 5525 | Magnus 数据库代理(v4.10.19 起统一;本场景用不到) |
| 15900 | NEC(VNC,可选) |
3. 前置准备
3.1 Harbor 新增代理缓存项目
沿用现网 kubevirt 项目(代理 quay.io/kubevirt)的做法,在 192.168.122.156:30000 上新增两个代理缓存项目:
项目名 类型 上游
dockerhub Proxy Cache docker.io(不填子路径)
fit2cloud Proxy Cache registry.fit2cloud.com/jumpserver镜像映射(首次 helm install 时 containerd 经 Harbor 自动拉取缓存):
原始镜像 → Harbor 代理
docker.io/jumpserver/core:v4.10.19-ce → 192.168.122.156:30000/dockerhub/jumpserver/core:v4.10.19-ce
docker.io/jumpserver/koko:v4.10.19-ce → .../dockerhub/jumpserver/koko:v4.10.19-ce
docker.io/jumpserver/web:v4.10.19-ce → .../dockerhub/jumpserver/web:v4.10.19-ce
docker.io/jumpserver/{lion,chen,magnus}:v4.10.19-ce → .../dockerhub/jumpserver/<组件>:v4.10.19-ce
registry.fit2cloud.com/jumpserver/{razor,nec,video}:v4.10.19-ce
→ .../fit2cloud/<组件>:v4.10.19-ce
docker.io/library/postgres:16 → 192.168.122.156:30000/dockerhub/postgres:16
docker.io/library/redis:7 → 192.168.122.156:30000/dockerhub/redis:7说明:Docker Hub 官方镜像(postgres/redis)在 Harbor 代理缓存中直接用
<项目名>/<镜像名>引用,Harbor 会自动解析library/前缀。 若确认不需要 Windows RDP / VNC / 录像处理,可将razor/nec/video/facelive/xrdp全部关闭,则fit2cloud项目可不建。
3.2 获取 Helm Chart
方式 A(节点可访问 github.io):
bash
helm repo add jumpserver https://jumpserver.github.io/helm-charts
helm repo update
helm search repo jumpserver/jumpserver --versions | head -5方式 B(离线:chart 包托管在 GitHub Releases):
bash
# 在任一台可上外网的机器下载后传入集群入口节点
curl -L -o jumpserver-v4.10.19.tgz \
https://github.com/jumpserver/helm-charts/releases/download/jumpserver-v4.10.19/jumpserver-v4.10.19.tgz
scp jumpserver-v4.10.19.tgz root@192.168.122.31:/root/
# 后续 helm install 直接引用本地文件 /root/jumpserver-v4.10.19.tgz3.3 部署 PostgreSQL 与 Redis(Chart 外部依赖)
创建命名空间与凭据(密码务必替换,后文统一引用这两个 Secret):
bash
kubectl create namespace jumpserver
kubectl -n jumpserver create secret generic jms-postgresql \
--from-literal=POSTGRES_USER=jumpserver \
--from-literal=POSTGRES_PASSWORD='xxx' \
--from-literal=POSTGRES_DB=jumpserver
kubectl -n jumpserver create secret generic jms-redis \
--from-literal=REDIS_PASSWORD='xxx'PostgreSQL 16(单实例 + vm-nas 持久化):
yaml
# jms-postgresql.yaml
apiVersion: v1
kind: Service
metadata:
name: jms-postgresql
namespace: jumpserver
spec:
selector: { app: jms-postgresql }
ports: [{ port: 5432, targetPort: 5432 }]
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: jms-postgresql
namespace: jumpserver
spec:
serviceName: jms-postgresql
replicas: 1
selector:
matchLabels: { app: jms-postgresql }
template:
metadata:
labels: { app: jms-postgresql }
spec:
containers:
- name: postgres
image: 192.168.122.156:30000/dockerhub/postgres:16
args: ["-c", "max_connections=1000"] # JumpServer 连接数需求较高
envFrom:
- secretRef: { name: jms-postgresql }
ports: [{ containerPort: 5432 }]
volumeMounts:
- { name: data, mountPath: /var/lib/postgresql/data }
resources:
requests: { cpu: 200m, memory: 512Mi }
limits: { cpu: "2", memory: 2Gi }
volumes:
- name: data
persistentVolumeClaim:
claimName: jms-postgresql-data
volumeClaimTemplates:
- metadata: { name: data }
spec:
storageClassName: vm-nas # 单实例,RWO 即可
accessModes: [ReadWriteOnce]
resources: { requests: { storage: 50Gi } }Redis 7:
yaml
# jms-redis.yaml
apiVersion: v1
kind: Service
metadata:
name: jms-redis
namespace: jumpserver
spec:
selector: { app: jms-redis }
ports: [{ port: 6379, targetPort: 6379 }]
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: jms-redis
namespace: jumpserver
spec:
serviceName: jms-redis
replicas: 1
selector:
matchLabels: { app: jms-redis }
template:
metadata:
labels: { app: jms-redis }
spec:
containers:
- name: redis
image: 192.168.122.156:30000/dockerhub/redis:7
command: ["/bin/sh", "-c", "exec redis-server --requirepass \"$REDIS_PASSWORD\" --appendonly yes"]
envFrom:
- secretRef: { name: jms-redis }
ports: [{ containerPort: 6379 }]
volumeMounts:
- { name: data, mountPath: /data }
resources:
requests: { cpu: 100m, memory: 256Mi }
limits: { cpu: "1", memory: 1Gi }
volumes:
- name: data
persistentVolumeClaim:
claimName: jms-redis-data
volumeClaimTemplates:
- metadata: { name: data }
spec:
storageClassName: vm-nas
accessModes: [ReadWriteOnce]
resources: { requests: { storage: 10Gi } }bash
kubectl apply -f jms-postgresql.yaml -f jms-redis.yaml
kubectl -n jumpserver rollout status statefulset/jms-postgresql --timeout=300s
kubectl -n jumpserver rollout status statefulset/jms-redis --timeout=300s4. 部署 JumpServer
4.1 生成密钥
bash
SECRET_KEY=$(cat /dev/urandom | tr -dc A-Za-z0-9 | head -c 50)
BOOTSTRAP_TOKEN=$(cat /dev/urandom | tr -dc A-Za-z0-9 | head -c 24)
echo "SECRET_KEY=$SECRET_KEY"; echo "BOOTSTRAP_TOKEN=$BOOTSTRAP_TOKEN"4.2 准备 values 文件
values-jumpserver.yaml(按组件分别指定镜像仓库,原因见第 2 章注意事项):
yaml
# values-jumpserver.yaml
global:
imageOwner: jumpserver # 镜像组织名
storageClass: vm-nas # 全局覆盖各组件 PVC 的 StorageClass
imagePullSecrets: [] # Harbor 代理缓存项目为公开读,无需凭据
ingress:
enabled: false # 现网无 Ingress 控制器,统一走 NodePort
externalDatabase:
engine: postgresql
host: jms-postgresql.jumpserver.svc.cluster.local
port: 5432
user: jumpserver
password: "xxx" # 与 jms-postgresql Secret 保持一致
database: jumpserver
externalRedis:
host: jms-redis.jumpserver.svc.cluster.local
port: 6379
password: "xxx" # 与 jms-redis Secret 保持一致
core:
config:
secretKey: "<4.1 生成的 SECRET_KEY>"
bootstrapToken: "<4.1 生成的 BOOTSTRAP_TOKEN>"
env:
# CSRF 信任来源:NodePort 访问入口(换节点访问时需同步追加)
DOMAINS: "192.168.122.31:30080"
image:
registry: 192.168.122.156:30000/dockerhub
persistence:
size: 50Gi
resources:
requests: { cpu: 500m, memory: 1Gi }
limits: { cpu: "4", memory: 4Gi }
koko:
image:
registry: 192.168.122.156:30000/dockerhub
service:
type: NodePort # 模板取 nodePort = ssh.port
web: { port: 5000 }
ssh: { port: 32222 } # SSH 客户端接入端口(30000-32767 范围内)
persistence:
size: 10Gi
resources:
requests: { cpu: 200m, memory: 256Mi }
limits: { cpu: "2", memory: 2Gi }
web:
image:
registry: 192.168.122.156:30000/dockerhub
service:
type: NodePort # 模板取 nodePort = web.port
web: { port: 30080 } # Web 控制台入口
persistence:
size: 1Gi
# ---- 可选组件:不需要的直接 enabled: false ----
lion: # RDP/VNC Web 连接(Linux VM 用不上可关)
enabled: true
image: { registry: 192.168.122.156:30000/dockerhub }
chen: # 数据库 Web 客户端
enabled: false
magnus: # 数据库客户端代理
enabled: false
razor: # 以下组件镜像在 fit2cloud 仓库
enabled: false
nec:
enabled: false
video:
enabled: false # 需要会话录像处理时开启(需 fit2cloud 代理项目)
facelive:
enabled: false
xrdp:
enabled: false说明:
web/koko服务模板在type: NodePort时以端口值作为 nodePort,所以 端口必须直接落在 30000-32767 区间;koko默认securityContext.privileged: true(官方 chart 默认), 见第 8 章安全说明;- 需要会话录像回放时把
video.enabled改为true,并确保 3.1 的fit2cloud代理项目已建好。
4.3 安装与验证
bash
# 离线包方式
helm -n jumpserver install jumpserver /root/jumpserver-v4.10.19.tgz \
-f values-jumpserver.yaml
# 或在线仓库方式
# helm -n jumpserver install jumpserver jumpserver/jumpserver \
# --version v4.10.19 -f values-jumpserver.yaml
# 观察 Pod 启动(core 首次初始化数据库需 2~5 分钟)
kubectl -n jumpserver get pods -w
kubectl -n jumpserver logs deploy/jumpserver-jms-core -f # 首次建表/迁移日志验证:
bash
# 1. 组件健康(入口节点执行)
curl -s http://192.168.122.31:30080/api/health/
# 2. koko 到 VM 固定 IP 的连通性(部署后最关键的一步)
kubectl -n jumpserver exec deploy/jumpserver-jms-koko -- \
python3 -c "import socket; socket.create_connection(('192.168.122.102',22),5); print('OK')"
# 3. 首次登录
# 浏览器: http://192.168.122.31:30080
# 默认账号: xxx / ChangeMe(登录后立即改密)5. 把 KubeVirt 虚拟机接入 JumpServer
5.1 创建主机资产
控制台 → 资产管理 → 资产列表 → 创建 → 主机:
| 字段 | 值 | 说明 |
|---|---|---|
| 资产名称 | rocky9-vm2 | 与 VM 名保持一致便于对应 |
| 地址 | 192.168.122.102 | VM 的 Multus 固定 IP(不是 Pod IP) |
| 平台 | Linux | |
| 协议 | ssh / 22 | |
| 节点 | Default | 可按业务建节点树 |
账号页签添加特权账号:xxx root、密码即 VM 登录密码 (来自 ../kubevirt-network-ssh-password-guide.md 的配置)。 保存后点 测试——显示可连通即代表 koko → VM:22 链路正常。
💡 建议:把各 VM 密码改为互不相同的强密码并交由 JumpServer 托管, 配合 账号管理 → 账号改密 定期轮换;这样即使某台 VM 泄露也不横向扩散。
5.2 批量接入
多台 VM 时不必逐台手填:资产列表 → 导入 下载 CSV 模板, 每行一台(名称、地址、平台、协议、账号、密码),一次导入即可。 新增 VM 的固定 IP 规划建议与网络指南保持一致(如 192.168.122.110+ 递增)。
5.3 用户与授权
- 控制台 → 用户管理 → 用户列表:为每位运维人员创建账号 (建议开启 MFA:个人设置/安全设置);
- 授权管理 → 资产授权:创建规则,把用户(或用户组)与 资产(或节点)绑定,并指定可用的系统账号(如 root);
- 需要审批的场景可在 访问控制 → 命令过滤/命令组 中配置 高危命令拦截(如
rm -rf /、shutdown)。
6. 日常使用方式
| 方式 | 操作 | 适用 |
|---|---|---|
| Web 控制台 | 浏览器打开 http://192.168.122.31:30080 → 我的资产 → 连接 → Web CLI | 最常用,无需装客户端 |
| SSH 客户端 | ssh -p 32222 <jms用户名>@192.168.122.31,交互菜单中选择资产 | Xshell/PuTTY/MobaXterm |
| SFTP 文件传输 | sftp -P 32222 <jms用户名>@192.168.122.31,或 Web 终端内上传/下载 | 向 VM 传文件 |
| 审计回放 | 审计台 → 会话审计 → 会话记录(录像/命令) | 事后追溯 |
会话录像存储在
jumpserver-jms-core-dataPVC(vm-nasNFS)上, 随 NAS 备份策略一同保护(见第 7 章)。
7. 运维:备份、升级、排障
7.1 备份
bash
# PostgreSQL(核心数据,务必定期)
kubectl -n jumpserver exec statefulset/jms-postgresql -- \
pg_dump -U jumpserver jumpserver | gzip > jms-db-$(date +%F).sql.gz
# PVC 数据(录像/上传文件):对 NAS 侧目录做快照/同步
# jms-postgresql-data / jms-core-data / jms-koko-data ...7.2 升级
bash
helm repo update # 在线仓库方式时
helm -n jumpserver upgrade jumpserver jumpserver/jumpserver \
--version <新版本> -f values-jumpserver.yaml⚠️ 官方安全通告基线:v4 ≥ v4.10.17(fastjson RCE、koko SFTP 路径遍历等 漏洞已在此版本修复)。升级前先在测试环境验证,并备份数据库。
7.3 常见问题
| 现象 | 原因与处理 |
|---|---|
Pod ImagePullBackOff | Harbor 代理项目未建/名字不对:核对 dockerhub、fit2cloud 项目与 3.1 的映射;crictl pull 手动验证 |
core 反复 CrashLoopBackOff | 数据库连不上:核对 externalDatabase 密码与 Secret;max_connections 是否 1000;查 kubectl -n jumpserver logs deploy/jumpserver-jms-core |
| 资产测试失败(koko 连不上 VM) | ① VM sshd 是否监听 ② 1.2 的连通性验证是否通过(natOutgoing)③ 中间防火墙;在 koko Pod 内 python3 -c "import socket; socket.create_connection(('IP',22),5)" 定位 |
| 登录页 403 / CSRF 报错 | core.env.DOMAINS 未包含实际访问的 节点IP:30080,补充后 helm upgrade |
PVC Pending | vm-nas provisioner 是否正常:kubectl get pods -A | grep nfs-subdir |
| Web 终端空白/转圈 | koko 与 core 之间令牌不一致(改过 bootstrapToken 需全组件一致重装/升级);查 deploy/jumpserver-jms-koko 日志 |
| NodePort 无法访问 | 确认使用入口节点 192.168.122.31;任一节点 30080/32222 理论可达,但 DOMAINS 只信任已登记入口 |
8. 安全注意事项
- 默认口令:
admin/ChangeMe首次登录必须修改,并为所有用户启用 MFA; - 入口收敛:JumpServer NodePort 只允许运维网段访问,例如在节点上:
firewall-cmd --add-rich-rule='rule family="ipv4" source address="运维网段/24" port port="30080" protocol="tcp" accept' --permanent; 其余来源由 RKE2 网络策略或防火墙拒绝; - koko 特权容器:官方 chart 默认
privileged: true,属已知设计; 应将jumpserver命名空间与业务命名空间隔离,RBAC 最小授权; - 版本基线:保持 ≥ v4.10.17 LTS 并及时跟进官方安全通告;
- 审计留痕:开启命令记录与会话录像,录像保留策略结合合规要求设置;
- 密码托管:VM root 密码尽量交由 JumpServer 托管并定期改密, 避免多人共用同一密码直连(绕过堡垒机直连属于违规行为,可用网络策略 限制只有
jumpserver命名空间可访问 VM 的 22 端口来强制收口—— 注意物理网段资产不受 K8s NetworkPolicy 管辖,需配合交换机/防火墙策略)。
9. 入口变体:固定 ClusterIP 与固定物理网段 IP(测试场景)
第 4 章的 NodePort 之外,还有两种"固定入口"玩法,适合集群安装验收、 内部互访等测试场景。两者对比:
| 方案 A:固定 ClusterIP | 方案 B:组件钉节点 + 辅助网络固定物理 IP | |
|---|---|---|
| 固定的是 | Service VIP(如 10.43.100.10),永不变 | web/koko Pod 的第二网卡物理网段 IP |
| 谁能直达 | 集群内 Pod + 所有节点本机(kube-proxy) | 物理网段任何机器 + VM |
| 物理机/外部 | 不可达,仍需 NodePort 兜底 | ✅ 直达,可完全替代 NodePort |
| 放弃什么 | 无 | 放弃 HA:组件钉死单节点,该节点故障即中断 |
| 适用 | 服务间互访、集群安装冒烟测试 | 测试环境要"像传统堡垒机一样有固定物理 IP" |
⚠️ 先纠正一个常见思路:"放弃热迁移、把 masquerade 主网络改成 bridge 来固定 Pod IP"是走不通的——Pod IP 由 CNI 分配,重建即变,与绑定方式无关。 要固定入口只能靠:Service VIP(方案 A) 或 辅助网络 + 固定分配(方案 B)。
9.1 方案 A:追加固定 ClusterIP Service
Chart 模板不支持自定义 clusterIP,直接手写一个与 jms-web Pod 标签匹配的 Service(与 Helm 托管对象共存,helm upgrade 不受影响):
yaml
# jms-web-vip.yaml
apiVersion: v1
kind: Service
metadata:
name: jms-web-vip
namespace: jumpserver
spec:
type: ClusterIP
clusterIP: 10.43.100.10 # 在 10.43.0.0/16 内选一个未占用地址
sessionAffinity: ClientIP
selector: # 与 chart 的 web Service selector 一致
app.kubernetes.io/name: jumpserver
app.kubernetes.io/instance: jumpserver
app.jumpserver.org/name: jms-web
ports:
- { name: web, port: 80, targetPort: web }
---
apiVersion: v1
kind: Service
metadata:
name: jms-koko-vip
namespace: jumpserver
spec:
type: ClusterIP
clusterIP: 10.43.100.11
sessionAffinity: ClientIP
selector:
app.kubernetes.io/name: jumpserver
app.kubernetes.io/instance: jumpserver
app.jumpserver.org/name: jms-koko
ports:
- { name: ssh, port: 2222, targetPort: ssh }bash
kubectl get svc -A | grep 10.43.100 || true # 先确认地址没被占用
kubectl apply -f jms-web-vip.yaml可达性矩阵(现网:service-cidr 10.43.0.0/16,kube-proxy 每节点运行):
| 来源 | curl http://10.43.100.10/api/health/ |
|---|---|
| 集群内 Pod(含 virt-launcher) | ✅ |
| 任一 RKE2 节点本机 | ✅(可直接作为集群安装冒烟测试项) |
| 只有 masquerade 网络的 VM | ✅(借道所在节点转发) |
| 物理网段直连的 PC / 二次网络 VM | ❌ ClusterIP 不出集群 → 用 NodePort |
集群安装验收脚本可直接引用:
bash
# 在任一节点执行:JumpServer 作为集群应用部署的验收项
curl -sf http://10.43.100.10/api/health/ && echo "jms OK"
ssh -p 2222 -o ConnectTimeout=5 admin@10.43.100.11 exit 2>/dev/null; echo "koko tcp=$?"9.2 方案 B:钉节点 + 辅助网络固定物理 IP(替代 NodePort)
前提:所选节点上已建好 br-vm 网桥(与虚拟机同桥,见网络指南)。
① NAD——用 host-local 且把地址范围夹到只剩一个地址,保证永远分到 同一个 IP(host-local 按节点本地记账,配合钉节点即"重建不变"):
yaml
# jms-physnet-nad.yaml
apiVersion: k8s.cni.cncf.io/v1
kind: NetworkAttachmentDefinition
metadata:
name: jms-physnet
namespace: jumpserver
spec:
config: '{
"cniVersion": "0.3.1",
"name": "jms-physnet",
"type": "bridge",
"bridge": "br-vm",
"vlan": 0,
"ipam": {
"type": "host-local",
"subnet": "192.168.122.144/28",
"rangeStart": "192.168.122.150",
"rangeEnd": "192.168.122.150"
}
}'② values 调整(相对第 4 章基础 values 的增量)——注意 web 容器监听端口 等于 web.service.web.port,物理直达入口要走 80 端口就得把它改回 80:
yaml
web:
image:
registry: 192.168.122.156:30000/dockerhub
nodeSelector: # ★ 钉到建了 br-vm 的节点
kubernetes.io/hostname: <节点名>
service:
type: ClusterIP # 物理入口改由第二网卡承载
web: { port: 80 }
koko:
nodeSelector:
kubernetes.io/hostname: <节点名> # SSH 入口 2222 也走第二网卡③ 注入 Multus 注解(chart 不支持 podAnnotations,安装后用 patch; 每次 helm upgrade 后需重新执行):
bash
kubectl apply -f jms-physnet-nad.yaml
kubectl -n jumpserver patch deployment jumpserver-jms-web --type=json -p '[
{"op":"add","path":"/spec/template/metadata/annotations",
"value":{"k8s.v1.cni.cncf.io/networks":"jms-physnet"}}]'
kubectl -n jumpserver patch deployment jumpserver-jms-koko --type=json -p '[
{"op":"add","path":"/spec/template/metadata/annotations",
"value":{"k8s.v1.cni.cncf.io/networks":"jms-physnet"}}]'
kubectl -n jumpserver rollout status deploy/jumpserver-jms-web④ 验证:
bash
kubectl -n jumpserver exec deploy/jumpserver-jms-web -- ip -4 addr show
# 应看到 eth1: 192.168.122.150/28
# 物理机上:
curl -s http://192.168.122.150/api/health/ # Web 入口(:80)
ssh -p 2222 admin@192.168.122.150 # SSH 客户端入口提示:方案 B 下 VM 资产测试方向不变(koko → VM:22);反过来物理机/其他 VM 也能以固定地址
192.168.122.150直达堡垒机——这就是传统堡垒机的 网络形态。节点<节点名>用kubectl get node查询。
附录:部署检查清单
- [ ] Harbor
dockerhub(+ 按需fit2cloud)代理缓存项目已建 - [ ] Helm chart v4.10.19 包已就位(在线仓库或离线 tgz)
- [ ]
jumpserver命名空间、PG/Redis Secret 已创建 - [ ] PostgreSQL/Redis StatefulSet Running,PVC Bound(vm-nas)
- [ ]
SECRET_KEY/BOOTSTRAP_TOKEN已生成并写入 values - [ ]
helm install后全部 Pod Ready,/api/health/返回正常 - [ ] koko → VM:22 连通性验证通过
- [ ] 资产创建 + 账号测试通过,授权规则配置完成
- [ ]
admin默认密码已修改,MFA 已启用 - [ ] 备份任务(pg_dump + NAS 快照)已纳入例行运维