JumperServer部署

开源 4A 运维安全审计平台,统一管控服务器、数据库、K8s 等资产,实现账号统一管理、登录权限控制、操作全程录像审计,满足等保合规,所有运维走堡垒机中转

系统Ubuntu 24.04 LTS

系统初始化

# 更新系统
apt update && apt upgrade -y
# 安装基础工具
apt install -y wget curl vim chrony iputils-ping openssh-server
# 时区同步
timedatectl set-timezone Asia/Shanghai
systemctl enable --now chronyd
# 关闭防火墙
ufw disable
systemctl stop ufw
systemctl disable ufw
# 关闭swap
swapoff -a
sed -i '/swap/s/^/#/' /etc/fstab
free -h

环境参数

# MySQL配置
MYSQL_IMAGE=mysql:8.0
MYSQL_CONTAINER=jms-mysql
MYSQL_ROOT_PASSWORD=Jump@123456
MYSQL_DATABASE=jumpserver
MYSQL_USER=jms
MYSQL_PASSWORD=Jump@654321
MYSQL_PORT=3306
# Redis配置
REDIS_IMAGE=redis:7-alpine
REDIS_CONTAINER=jms-redis
REDIS_PORT=6379
# JumpServer配置
JMS_IMAGE=jumpserver/jms-core:latest
JMS_CONTAINER=jms-core
JMS_PORT=80
# 宿主机持久化目录
mkdir -p /opt/jms/mysql /opt/jms/redis /opt/jms/core

安装 Docker 环境

安装 docker-ce、docker-compose

# 卸载旧版本
apt remove -y docker docker-engine docker.io containerd runc
# 安装依赖
apt install -y ca-certificates gnupg lsb-release
# 添加docker官方源
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
# 安装docker
apt update && apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
# 开机自启
systemctl enable --now docker
# 验证docker安装
docker -v
docker compose version
# 配置国内镜像加速
cat > /etc/docker/daemon.json <<EOF
{
  "registry-mirrors": ["https://mirror.baidubce.com"]
}
EOF
systemctl restart docker

验证命令

docker run --rm hello-world

出现 Hello from Docker! 代表 Docker 环境正常。

安装 MySQL 服务

下载 MySQL 镜像查看默认配置

# 拉取镜像
docker pull ${MYSQL_IMAGE}
# 查看镜像内置环境变量默认配置
docker inspect ${MYSQL_IMAGE} | grep -i env

在宿主机准备 MySQL 配置文件

# 创建my.cnf配置
cat > /opt/jms/mysql/my.cnf <<EOF
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
default-time_zone = '+8:00'
max_connections=1000
innodb_buffer_pool_size=1G
EOF

启动 MySQL 容器

docker run -d \
--name ${MYSQL_CONTAINER} \
--restart always \
-p ${MYSQL_PORT}:3306 \
-v /opt/jms/mysql:/var/lib/mysql \
-v /opt/jms/mysql/my.cnf:/etc/mysql/conf.d/my.cnf \
-e MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} \
-e MYSQL_DATABASE=${MYSQL_DATABASE} \
-e MYSQL_USER=${MYSQL_USER} \
-e MYSQL_PASSWORD=${MYSQL_PASSWORD} \
${MYSQL_IMAGE}
# 等待30秒初始化完成
sleep 30

验证 MySQL

# 进入容器连接数据库
docker exec -it ${MYSQL_CONTAINER} mysql -uroot -p${MYSQL_ROOT_PASSWORD}
# 执行验证SQL
show databases;
select user,host from mysql.user;

看到 jumpserver 库、jms 用户即正常,输入 exit 退出 MySQL

安装 Redis 服务

启动 Redis

# 拉取镜像
docker pull ${REDIS_IMAGE}
# 启动容器
docker run -d \
--name ${REDIS_CONTAINER} \
--restart always \
-p ${REDIS_PORT}:6379 \
-v /opt/jms/redis:/data \
${REDIS_IMAGE} redis-server --appendonly yes

验证 Redis 连接

# 进入redis客户端验证
docker exec -it ${REDIS_CONTAINER} redis-cli
# 测试写入读取
set test_key 123
get test_key

返回 123 代表 Redis 可用

部署 JumpServer

生成 key 和 token

# 生成SECRET_KEY
docker run --rm ${JMS_IMAGE} python -c "import secrets; print(secrets.token_urlsafe(48))"
# 生成BOOTSTRAP_TOKEN
docker run --rm ${JMS_IMAGE} python -c "import secrets; print(secrets.token_urlsafe(16))"

将两条输出字符串复制保存,下面启动容器需要填入。

SECRET_KEY="生成的48位密钥"
BOOTSTRAP_TOKEN="生成的16位token"

运行 JumpServer 核心容器

docker run -d \
--name ${JMS_CONTAINER} \
--restart always \
-p ${JMS_PORT}:80 \
-v /opt/jms/core:/opt/jumpserver/data \
-e SECRET_KEY=${SECRET_KEY} \
-e BOOTSTRAP_TOKEN=${BOOTSTRAP_TOKEN} \
-e DB_ENGINE=mysql \
-e DB_HOST=172.17.0.1 \
-e DB_PORT=${MYSQL_PORT} \
-e DB_USER=${MYSQL_USER} \
-e DB_PASSWORD=${MYSQL_PASSWORD} \
-e DB_NAME=${MYSQL_DATABASE} \
-e REDIS_HOST=172.17.0.1 \
-e REDIS_PORT=${REDIS_PORT} \
${JMS_IMAGE}

172.17.0.1 是 Docker 默认网桥宿主机网关,容器内可访问宿主机映射的 MySQL/Redis 端口。

验证是否成功

# 实时跟踪日志,等待初始化完成
docker logs -f ${JMS_CONTAINER}

出现 Application startup complete 代表服务启动完成

查看 MySQL 中生成相关表

# 登录MySQL查看jumpserver库数据表
docker exec -it ${MYSQL_CONTAINER} mysql -u${MYSQL_USER} -p${MYSQL_PASSWORD} ${MYSQL_DATABASE}
# 查看表
show tables;

查看端口

# 查看宿主机端口监听
ss -tlnp | grep -E "80|3306|6379"
# 查看容器端口映射
docker port ${JMS_CONTAINER}
docker port ${MYSQL_CONTAINER}
docker port ${REDIS_CONTAINER}

验证登录

  • 浏览器访问:http://服务器IP
  • 默认账号:admin,默认密码:ChangeMe
  • 登录后强制修改初始密码,进入后台即部署完成。

案例:基于自定义网络利用 Docker 部署 JumpServer

创建自定义 docker 网络

docker network create jms-net

启动 MySQL 时加入自定义网络

docker run -d \
--name ${MYSQL_CONTAINER} \
--restart always \
--network jms-net \
-v /opt/jms/mysql:/var/lib/mysql \
-v /opt/jms/mysql/my.cnf:/etc/mysql/conf.d/my.cnf \
-e MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} \
-e MYSQL_DATABASE=${MYSQL_DATABASE} \
-e MYSQL_USER=${MYSQL_USER} \
-e MYSQL_PASSWORD=${MYSQL_PASSWORD} \
${MYSQL_IMAGE}

启动 Redis 加入自定义网络

docker run -d \
--name ${REDIS_CONTAINER} \
--restart always \
--network jms-net \
-v /opt/jms/redis:/data \
${REDIS_IMAGE} redis-server --appendonly yes

启动 JumpServer,使用容器名直接通信(DB_HOST=jms-mysql,无需 IP)

docker run -d \
--name ${JMS_CONTAINER} \
--restart always \
-p ${JMS_PORT}:80 \
--network jms-net \
-v /opt/jms/core:/opt/jumpserver/data \
-e SECRET_KEY=${SECRET_KEY} \
-e BOOTSTRAP_TOKEN=${BOOTSTRAP_TOKEN} \
-e DB_ENGINE=mysql \
-e DB_HOST=${MYSQL_CONTAINER} \
-e DB_PORT=3306 \
-e DB_USER=${MYSQL_USER} \
-e DB_PASSWORD=${MYSQL_PASSWORD} \
-e DB_NAME=${MYSQL_DATABASE} \
-e REDIS_HOST=${REDIS_CONTAINER} \
-e REDIS_PORT=6379 \
${JMS_IMAGE}

查看全部容器状态

docker ps -a

重置 admin 密码

docker exec -it ${JMS_CONTAINER} python manage.py reset_admin

jumperserver配置解析

核心密钥

SECRET_KEY:全局加密密钥,加密密码、录像、会话

BOOTSTRAP_TOKEN:组件通信令牌

2. MySQL 数据库

DB_ENGINE:数据库类型

DB_HOST:数据库地址

DB_PORT:数据库端口

DB_NAME:数据库库名

DB_USER:数据库账号

DB_PASSWORD:数据库密码

3. Redis 缓存

REDIS_HOST:Redis 地址

REDIS_PORT:Redis 端口

REDIS_PASSWORD:Redis 密码

4. Web 站点

HTTP_PORT:网页访问端口

SITE_URL:系统对外访问地址

5. 安全登录

SESSION_COOKIE_AGE:闲置会话超时时间

AUTH_MAX_FAILED:密码错误锁定次数

PASSWORD_MIN_LENGTH:密码最小长度

PASSWORD_COMPLEXITY:开启密码复杂度校验

ENABLE_CAPTCHA:登录验证码开关

6. 日志

LOG_LEVEL:日志输出级别(INFO/DEBUG)

7. 邮件告警

EMAIL_HOST:邮箱 SMTP 服务器

EMAIL_PORT:邮箱端口

EMAIL_HOST_USER:发件邮箱账号

EMAIL_HOST_PASSWORD:邮箱授权码

8. 终端连接

ASSET_CONNECT_TIMEOUT:资产连接超时

TERMINAL_MAX_SESSION:最大在线终端会话数

高可用K8S的部署

节点分配(3Master+3Worker 标准高可用)

主机 IP角色主机名
192.168.9.101Master1 / 控制平面k8s-m01
192.168.9.102Master2 / 控制平面k8s-m02
192.168.9.103Master3 / 控制平面k8s-m03
192.168.9.104Worker 业务节点k8s-w01
192.168.9.105Worker 业务节点k8s-w02
192.168.9.106Worker 业务节点k8s-w03

控制面 VIP:192.168.9.100(Keepalived 漂移,统一 apiserver 入口)

所有节点统一初始化系统、关闭 swap、内核转发、安装 containerd+k8s 组件

Master 节点部署 HAProxy+Keepalived 实现 apiserver 高可用

网络插件:Calico Pod 网段 192.168.0.0/16

存储:外置共享存储 Ceph/NFS 提供 StorageClass

集群搭建

全节点统一初始化(101-106 全部执行)

apt update && apt upgrade -y
# 关闭防火墙
ufw disable
systemctl stop ufw && systemctl disable ufw
# 永久关闭swap
swapoff -a
sed -i '/swap/s/^/#/' /etc/fstab
# 内核网络转发
modprobe overlay
modprobe br_netfilter
cat > /etc/sysctl.d/k8s.conf <<EOF
net.bridge.bridge-nf-call-iptables=1
net.bridge.bridge-nf-call-ip6tables=1
net.ipv4.ip_forward=1
EOF
sysctl --system
# 设置主机名(分别执行对应主机名)
hostnamectl set-hostname k8s-m01
# 同步hosts解析
cat >> /etc/hosts <<EOF
192.168.9.101 k8s-m01
192.168.9.102 k8s-m02
192.168.9.103 k8s-m03
192.168.9.104 k8s-w01
192.168.9.105 k8s-w02
192.168.9.106 k8s-w03
EOF

全节点安装 containerd、kubeadm/kubelet/kubectl

统一版本安装,配置 cgroup 驱动为 systemd

# 安装依赖
apt install ca-certificates curl gnupg lsb-release -y
# docker源安装containerd
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list
apt update
apt install containerd.io -y
# 生成默认配置
containerd config default > /etc/containerd/config.toml
# 修改cgroup驱动为systemd
sed -i 's/SystemdCgroup \= false/SystemdCgroup \= true/g' /etc/containerd/config.toml
# 重启开机自启
systemctl restart containerd
systemctl enable containerd

安装 kubeadm/kubelet/kubectl 统一版本

# 添加k8s官方源
curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg
echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | tee /etc/apt/sources.list.d/kubernetes.list
apt update
# 固定v1.30.0版本
K8S_VER=1.30.0
apt install kubeadm=${K8S_VER}-00 kubelet=${K8S_VER}-00 kubectl=${K8S_VER}-00 -y
# 锁定版本防止自动更新
apt-mark hold kubeadm kubelet kubectl
# 验证版本
kubeadm version
kubectl version --client

三台 Master 部署 HAProxy+Keepalived(101/102/103 执行)

安装软件

apt install haproxy keepalived -y
systemctl enable haproxy keepalived

配置 HAProxy

vim  /etc/haproxy/haproxy.cfg

global
    log /dev/log local0
    maxconn 10000
defaults
    log global
    mode tcp
    retries 3
    timeout connect 5s
    timeout client 30s
    timeout server 30s
frontend k8s-api
    bind 192.168.9.100:6443
    default_backend k8s-master
backend k8s-master
    balance roundrobin
    server m01 192.168.9.101:6443 check
    server m02 192.168.9.102:6443 check
    server m03 192.168.9.103:6443 check

Keepalived 配置(区分优先级,只改 state/priority)

m01(主节点 /etc/keepalived/keepalived.conf)

global_defs {
    router_id LVS_M01
}
vrrp_instance VI_1 {
    state MASTER
    interface eth0 # 修改为本机网卡名
    virtual_router_id 51
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 123456
    }
    virtual_ipaddress {
        192.168.9.100/24 dev eth0
    }
}

m02

state BACKUP
priority 90

m03

state BACKUP
priority 80

重启生效

systemctl restart haproxy keepalived
# 验证VIP
ip a

Master1(101)初始化集群

kubeadm init --control-plane-endpoint 192.168.9.100:6443 \
--apiserver-advertise-address=192.168.9.101 \
--pod-network-cidr=192.168.0.0/16 \
--kubernetes-version=v1.30.0

执行完成输出两段命令,保存好:

  1. Master 扩容命令(带--control-plane --certificate-key,给 m02/m03 用)
  2. Worker 加入命令(给 w01/w02/w03 用)

拷贝管理员 kubeconfig

mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config

节点加入集群

Master2、Master3(102、103)执行 Master 加入命令

复制 kubeadm init 输出的 master join 命令

kubeadm join 192.168.9.100:6443 --token xxx \
--discovery-token-ca-cert-hash sha256:xxx \
--control-plane --certificate-key xxx

Worker 节点(104/105/106)执行 Worker 加入命令

kubeadm join 192.168.9.100:6443 --token xxx \
--discovery-token-ca-cert-hash sha256:xxx

token 过期重置:kubeadm token create --print-join-command

部署 Calico 网络插件(m01 执行)

kubectl apply -f https://docs.projectcalico.org/v3.28/manifests/calico.yaml
# 等待所有节点Ready
kubectl get nodes -w
# 全部状态Ready代表集群搭建完成

高可用通用部署规范(yaml 模板)

# 指定资源API版本,Deployment属于apps/v1分组
apiVersion: apps/v1
# 资源类型:控制器,用于无状态业务高可用部署
kind: Deployment
metadata:
  # 控制器名称
  name: demo-app
  # 资源归属命名空间,隔离集群业务
  namespace: prod
spec:
  # Pod副本数量3个,多副本实现故障自动迁移
  replicas: 3
  selector:
    # 匹配Pod标签,关联控制器与后端Pod
    matchLabels:
      app: demo
  # Pod模板,定义Pod运行规范
  template:
    metadata:
      # Pod自身标签,用于Service/Selector匹配
      labels:
        app: demo
    spec:
      # Pod亲和策略:反亲和,强制副本分散到不同节点
      affinity:
        podAntiAffinity:
          # 硬策略,不满足条件则不调度Pod
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              # 匹配标签app=demo的Pod
              - key: app
                operator: In
                values: [demo]
            # 以宿主机节点为调度隔离维度
            topologyKey: kubernetes.io/hostname
      # 容器列表,一个Pod可包含多个容器
      containers:
      - name: demo # 容器名称
        image: 业务镜像 # 业务镜像地址
        # 从Secret批量注入环境变量,存放账号密码等敏感信息
        envFrom:
        - secretRef:
            name: app-secret
        # 容器资源配额,防止抢占集群资源引发雪崩
        resources:
          # 调度最低资源需求,调度器依据此分配节点
          requests:
            cpu: 100m
            memory: 256Mi
          # 资源硬上限,超出会被限流/杀死
          limits:
            cpu: 1000m
            memory: 1Gi
        # 存活探针:检测容器是否崩溃卡死,失败则重启Pod
        livenessProbe:
          httpGet:
            path: /health # 健康检测接口路径
            port: 80      # 容器服务端口
          initialDelaySeconds: 5 # 容器启动5秒后开始检测
          periodSeconds: 10      # 每10秒执行一次检测
        # 就绪探针:检测业务是否可对外提供流量,失败则从Service剔除
        readinessProbe:
          httpGet:
            path: /ready
            port: 80
          initialDelaySeconds: 3
          periodSeconds: 5
        # 存储挂载配置,将PVC绑定到容器内目录
        volumeMounts:
        - name: data # 存储卷名称,与下方volumes对应
          mountPath: /data # 容器内持久化目录
      # Pod挂载存储卷定义
      volumes:
      # 共享分布式存储卷,多Pod共用一份持久化数据
      - name: data
        persistentVolumeClaim:
          claimName: app-pvc # 绑定提前创建的PVC资源

配套 Service+Ingress 负载均衡

# Service资源API版本
apiVersion: v1
# 资源类型:Service,实现Pod负载均衡与固定访问入口
kind: Service
metadata:
  # Service名称
  name: demo-svc
  # 归属业务命名空间
  namespace: prod
spec:
  # 通过标签匹配后端Pod,流量转发至标签app=demo的Pod
  selector:
    app: demo
  ports:
  # 端口映射配置
  - port: 80        # Service集群内部访问端口
    targetPort: 80  # 后端Pod容器监听端口
  # 服务类型:ClusterIP仅集群内部可访问,不暴露宿主机端口
  type: ClusterIP
---
# Ingress网络资源API版本
apiVersion: networking.k8s.io/v1
# 资源类型:Ingress,提供集群外部域名访问入口
kind: Ingress
metadata:
  name: demo-ing
  namespace: prod
spec:
  # 指定Ingress控制器,使用nginx-ingress组件处理流量
  ingressClassName: nginx
  # 域名路由规则列表
  rules:
  - host: demo.test.com  # 外部访问域名
    http:
      paths:
      # 路径匹配规则
      - path: /                 # 匹配所有根路径请求
        pathType: Prefix        # 前缀匹配,/xxx全部命中
        backend:
          # 流量转发后端Service
          service:
            name: demo-svc      # 关联上方创建的Service名称
            port:
              number: 80        # Service暴露端口

k8s资源作用

Deployment 无状态业务控制器,多副本、滚动更新、故障自动重建,实现高可用。

Service 给 Pod 固定访问入口,内置负载均衡,屏蔽 Pod IP 变化。

Ingress 域名反向代理,统一外部流量入口,支持域名 / 路径路由。

Secret 存放密码、密钥等敏感配置,明文不写入 YAML。

ConfigMap 普通配置文件、环境变量,非敏感参数。

PVC/PV 持久化存储,容器销毁数据不丢失,高可用集群用共享存储。

Namespace 资源隔离,区分不同业务环境。

Pod 最小运行单元,容器载体。

StatefulSet 有状态服务(MySQL/Redis),稳定网络标识、有序持久存储。

DaemonSet 每个节点运行一个 Pod,日志采集、监控代理专用。

yaml的字段含义

通用公共字段

apiVersion:资源所属 API 版本

kind:资源类型(Deployment/Service/Ingress)

metadata:元数据

name:资源名称

namespace:命名空间,资源隔离

labels:标签,用于 Service 筛选 Pod

spec:资源核心配置段

Deployment 字段

replicas:Pod 副本数量

selector.matchLabels:匹配 Pod 标签,关联控制器与 Pod

template:Pod 模板

spec.affinity:Pod 调度亲和 / 反亲和策略

containers:容器列表

image:业务镜像地址

envFrom:从 Secret/ConfigMap 读取环境变量

resources:容器 CPU、内存配额限制

livenessProbe:存活探针,卡死自动重启 Pod

readinessProbe:就绪探针,未就绪不接入流量

volumeMounts:PVC 挂载到容器内路径

volumes:定义持久化存储卷

persistentVolumeClaim:绑定 PVC 存储资源

Service 字段

selector:通过标签匹配后端 Pod

port:Service 集群访问端口

targetPort:Pod 容器监听端口

type:服务访问模式(ClusterIP 仅集群内访问)

Ingress 字段

ingressClassName:指定 nginx-ingress 控制器

rules.host:对外访问域名

path:请求匹配路径

pathType:匹配规则(Prefix 前缀匹配)

backend.service:流量转发目标 Service

更多推荐