☰
XXL-JOB 上 K8S 部署实战:验证版 YAML 一次跑通与避坑指南
2026/10/8 23:51:34 网站建设 项目流程

简介:这份资源面向需要在 Kubernetes 集群中落地 XXL-JOB 的运维与后端开发人员,提供一份经过实际部署验证的 YAML 编排文件,可直接用于容器化环境下的任务调度平台搭建,省去从零编写与反复调试清单的麻烦。压缩包内共 1 个文件,为单个 yaml 类型清单,体积约 782B,内容精炼,涵盖 XXL-JOB 调度中心与执行器在 K8S 中的核心部署定义,适合直接套用或按需微调。目前已有 646 人学习下载,说明其在同类部署场景中具备一定参考价值。对于正在做 XXL-JOB 容器化迁移、希望快速验证集群可用性的读者,这份验证版清单能帮助理清资源对象组织方式,减少因配置疏漏导致的启动失败,也可作为后续扩展副本数、调整镜像与端口配置的基础模板。

1. XXL-JOB 上 K8S:为什么验证版 YAML 能一次跑通

很多团队把 XXL-JOB 从虚拟机搬到 K8S 时,第一反应是「不就是把 jar 包塞进镜像吗」,结果调度中心起不来、执行器注册不上、日志查不到,来回折腾两三天。问题不在 XXL-JOB 本身,而在于它的调度中心(admin)和执行器(executor)对网络标识、持久化、时区这三件事有硬性要求,而 K8S 默认的滚动更新、Service 抽象、容器时区恰好会踩到这些点。所谓「验证版 YAML」,指的是一套已经把这些约束提前固化进去的编排文件:调度中心用固定副本数加数据库外置,执行器用 Deployment 加注册地址显式声明,日志走 PVC 或对象存储而不是容器内临时目录。它解决的是「部署即验证」——你不需要先理解全部 K8S 概念,先把集群跑起来,再回头调参数。适合正在做调度系统容器化、又不想在 YAML 细节上反复翻车的后端和运维同学。

2. 部署前必须想清楚的三个选型:镜像、数据库、注册方式

2.1 调度中心镜像怎么选:官方包还是自构建

XXL-JOB 官方发布的是可执行 jar,不是镜像。常见做法有两种:一是用基础 JDK 镜像加挂载 jar,二是自己写 Dockerfile 把 jar 打进去。验证阶段我一般推荐第二种,因为挂载方式在 K8S 里要额外处理 ConfigMap 或 hostPath,反而增加变量。自构建镜像的核心是固定 JDK 版本和时区,下面是一个最小可用的 Dockerfile。

# 基于稳定版 JDK 8,避免高版本 JDK 的模块化问题 FROM openjdk:8-jre-slim # 统一时区,否则调度时间会差 8 小时 ENV TZ=Asia/Shanghai RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone WORKDIR /app # 假设 jar 已放在构建上下文当前目录 COPY xxl-job-admin.jar /app/app.jar # 调度中心默认端口 8080 EXPOSE 8080 ENTRYPOINT ["java", "-jar", "/app/app.jar"]

逻辑说明:openjdk:8-jre-slim体积小且兼容 XXL-JOB 主流版本;TZ环境变量和localtime软链解决容器内时间与宿主机不一致的问题,这是调度时间错乱的常见根因。参数上,-jar后面可以追加--spring.profiles.active等启动参数,但验证阶段先不加,保持最小变量。构建命令是docker build -t xxl-job-admin:verify .,镜像名和标签自己定,后面 YAML 里引用要一致。

2.2 数据库外置:为什么不能用容器内 MySQL

XXL-JOB 的调度中心依赖数据库存任务、日志、锁信息。如果把 MySQL 也放进同一个 Pod 或用容器内嵌数据库,Pod 重启数据就没了,调度记录直接丢失。验证版 YAML 的做法是数据库外置——可以是集群内的独立 MySQL StatefulSet,也可以是外部 RDS。关键是把连接信息通过 ConfigMap 或 Secret 注入,而不是写死在镜像里。下面是一段调度中心连接数据库的配置片段,通常放在application.properties或环境变量里。

# 调度中心 ConfigMap 中的数据库配置片段 spring: datasource: url: jdbc:mysql://mysql-service:3306/xxl_job?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai username: xxl_job password: ${DB_PASSWORD} driver-class-name: com.mysql.cj.jdbc.Driver

逻辑说明:serverTimezone=Asia/Shanghai必须显式指定,否则 JDBC 驱动可能按 UTC 解析,导致任务触发时间偏移。${DB_PASSWORD}从 Secret 注入,不要明文写在 ConfigMap 里。参数上,连接池大小在验证阶段用默认即可,等压测时再调spring.datasource.hikari.maximum-pool-size。数据库需要提前建好xxl_job库并导入官方 SQL 脚本,这一步不能省。

2.3 执行器注册方式:自动注册还是手动指定

执行器启动后会向调度中心注册自己的地址。在 K8S 里,Pod IP 是动态的,如果执行器上报的是容器内 IP,调度中心可能无法回连。验证版 YAML 通常用两种方式之一:一是执行器配置xxl.job.executor.address显式指定一个可被调度中心访问的地址(比如 Service 名加端口),二是让执行器上报宿主机网络地址。前者更可控,推荐验证阶段使用。下面是对应的环境变量配置。

# 执行器 Deployment 中的环境变量片段 env: - name: XXL_JOB_ADMIN_ADDRESSES value: "http://xxl-job-admin-service:8080/xxl-job-admin" - name: XXL_JOB_EXECUTOR_ADDRESS value: "http://xxl-job-executor-service:9999" - name: XXL_JOB_EXECUTOR_IP value: "" - name: XXL_JOB_EXECUTOR_PORT value: "9999"

逻辑说明:XXL_JOB_ADMIN_ADDRESSES告诉执行器调度中心在哪;XXL_JOB_EXECUTOR_ADDRESS是执行器对外声明的地址,调度中心会用这个地址回调执行器。把XXL_JOB_EXECUTOR_IP留空,避免执行器自动取容器 IP。参数上,端口 9999 是 XXL-JOB 执行器默认端口,如果改了要同步改 Service 的 targetPort。这一步配错,现象就是调度中心里执行器显示离线,但 Pod 明明是 Running。

3. 验证版 YAML 逐段拆解:从 Namespace 到 Ingress

3.1 Namespace 与配置分离:把可变参数抽出来

验证版 YAML 的第一段通常是 Namespace 和 ConfigMap/Secret。把数据库地址、密码、调度中心地址这些可变参数抽出来,后面 Deployment 只引用名字,改配置不用动编排逻辑。下面是一个完整的 Namespace 加 ConfigMap 示例。

apiVersion: v1 kind: Namespace metadata: name: xxl-job --- apiVersion: v1 kind: ConfigMap metadata: name: xxl-job-config namespace: xxl-job data: admin-addresses: "http://xxl-job-admin-service:8080/xxl-job-admin" executor-address: "http://xxl-job-executor-service:9999" db-url: "jdbc:mysql://mysql-service:3306/xxl_job?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai" --- apiVersion: v1 kind: Secret metadata: name: xxl-job-secret namespace: xxl-job type: Opaque stringData: db-password: "your-password"

逻辑说明:ConfigMap 存非敏感配置,Secret 存密码。stringData让写入时不用手动 base64 编码,K8S 会自动转换。参数上,db-url里的mysql-service要和你实际数据库 Service 名一致,如果数据库在集群外,换成外部地址。Namespace 统一用xxl-job,后面所有资源都放这个命名空间,方便清理。

3.2 调度中心 Deployment 与 Service:固定副本与健康检查

调度中心是有状态的调度节点,验证阶段副本数建议设为 1,避免多副本竞争调度锁导致重复触发。等验证通过再考虑用数据库锁做多副本。下面是对应的 Deployment 和 Service。

apiVersion: apps/v1 kind: Deployment metadata: name: xxl-job-admin namespace: xxl-job spec: replicas: 1 selector: matchLabels: app: xxl-job-admin template: metadata: labels: app: xxl-job-admin spec: containers: - name: admin image: xxl-job-admin:verify ports: - containerPort: 8080 env: - name: SPRING_DATASOURCE_URL valueFrom: configMapKeyRef: name: xxl-job-config key: db-url - name: SPRING_DATASOURCE_PASSWORD valueFrom: secretKeyRef: name: xxl-job-secret key: db-password readinessProbe: httpGet: path: /xxl-job-admin/toLogin port: 8080 initialDelaySeconds: 30 periodSeconds: 10 --- apiVersion: v1 kind: Service metadata: name: xxl-job-admin-service namespace: xxl-job spec: selector: app: xxl-job-admin ports: - port: 8080 targetPort: 8080

逻辑说明:replicas: 1是验证阶段的关键约束,多副本需要额外配置调度锁,先不引入。readinessProbe探测登录页路径,确保应用真正就绪后再接流量,避免执行器注册到还没启动完的调度中心。参数上,initialDelaySeconds: 30给 Spring Boot 启动留时间,机器慢可以调到 60。Service 用 ClusterIP 即可,外部访问靠 Ingress 或端口转发。

3.3 执行器 Deployment 与 Service:注册地址显式声明

执行器通常需要多副本,因为任务要并行执行。验证阶段可以先起 1 个副本,确认注册成功后再扩容。下面是执行器的编排片段。

apiVersion: apps/v1 kind: Deployment metadata: name: xxl-job-executor namespace: xxl-job spec: replicas: 1 selector: matchLabels: app: xxl-job-executor template: metadata: labels: app: xxl-job-executor spec: containers: - name: executor image: xxl-job-executor:verify ports: - containerPort: 9999 env: - name: XXL_JOB_ADMIN_ADDRESSES valueFrom: configMapKeyRef: name: xxl-job-config key: admin-addresses - name: XXL_JOB_EXECUTOR_ADDRESS valueFrom: configMapKeyRef: name: xxl-job-config key: executor-address - name: XXL_JOB_EXECUTOR_IP value: "" - name: XXL_JOB_EXECUTOR_PORT value: "9999" --- apiVersion: v1 kind: Service metadata: name: xxl-job-executor-service namespace: xxl-job spec: selector: app: xxl-job-executor ports: - port: 9999 targetPort: 9999

逻辑说明:执行器通过环境变量拿到调度中心地址和自身声明地址。XXL_JOB_EXECUTOR_IP留空是关键,否则执行器可能上报容器 IP,调度中心回连失败。参数上,XXL_JOB_EXECUTOR_PORT要和容器端口、Service 端口一致。如果执行器镜像里用的是application.properties,这些环境变量需要能被 Spring 识别,通常用xxl.job.admin.addresses等对应键名,或者启动脚本里做映射。

3.4 Ingress 与日志持久化:让调度中心可访问、日志可检索

调度中心需要暴露给浏览器访问,执行器日志需要持久化以便检索。验证版 YAML 通常包含一个 Ingress 和一个 PVC。下面是示例。

apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: xxl-job-admin-ingress namespace: xxl-job spec: rules: - host: xxl-job.example.com http: paths: - path: /xxl-job-admin pathType: Prefix backend: service: name: xxl-job-admin-service port: number: 8080 --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: xxl-job-executor-logs namespace: xxl-job spec: accessModes: - ReadWriteOnce resources: requests: storage: 10Gi

逻辑说明:Ingress 把调度中心暴露到域名,pathType: Prefix匹配/xxl-job-admin开头的请求。PVC 给执行器日志用,需要在执行器 Deployment 里挂载到日志目录。参数上,storage: 10Gi按日志量调整,验证阶段够用。如果集群没有默认 StorageClass,PVC 会一直 Pending,需要先确认存储供给。

4. 避坑排查:验证版 YAML 部署时最容易翻车的五件事

4.1 执行器显示离线,但 Pod 是 Running

现象:调度中心「执行器管理」页面里执行器一直离线,Pod 日志没有明显报错。原因:执行器上报的地址调度中心访问不到,常见是上报了容器 IP 或端口不对。解决:检查XXL_JOB_EXECUTOR_ADDRESS是否配成 Service 名加端口,XXL_JOB_EXECUTOR_IP是否留空;在调度中心 Pod 里用curl测一下执行器地址是否通。

4.2 任务触发时间差 8 小时

现象:配置了每天 9 点执行,实际 17 点才跑。原因:容器时区是 UTC,JDBC 连接串没指定时区。解决:镜像里设置TZ=Asia/Shanghai,JDBC URL 加serverTimezone=Asia/Shanghai,数据库本身时区也确认一下。

4.3 调度中心启动报数据库连接失败

现象:Pod 反复重启,日志显示Communications link failure。原因:数据库 Service 名写错、密码不对、或者数据库还没就绪。解决:确认 ConfigMap 里的db-url主机名和 Namespace 匹配;Secret 里的密码和数据库实际密码一致;给调度中心加initContainer等待数据库端口可通。

4.4 多副本调度中心导致任务重复触发

现象:把replicas改成 2 后,同一个任务被触发两次。原因:XXL-JOB 调度中心多副本需要依赖数据库锁协调,默认配置可能不生效。解决:验证阶段保持replicas: 1;确实要多副本,确认数据库锁配置正确,并观察调度日志是否有重复。

4.5 执行器日志在容器重启后丢失

现象:任务报错后想看日志,发现容器重启后日志没了。原因:日志写在容器内临时目录,没有挂载 PVC。解决:把执行器日志目录挂载到 PVC,或者配置日志输出到外部存储;验证阶段至少挂一个 PVC 保住日志。

5. 验证通过后怎么调:副本扩容与日志检索的实操技巧

验证版 YAML 跑通只是起点,接下来要让它扛住真实调度量。执行器扩容最直接:把replicas从 1 改成 3,K8S 会滚动创建新 Pod,每个 Pod 启动后自动向调度中心注册。注意扩容后要在调度中心确认执行器列表里出现了多个地址,否则可能是注册地址配成了同一个 Service 名导致覆盖。调度中心本身不建议急着扩,先观察数据库连接池和任务触发延迟,如果单副本 CPU 长期高于 70% 再考虑。

日志检索是另一个高频需求。XXL-JOB 的调度日志存在数据库里,执行器日志在本地文件。验证阶段可以把执行器日志目录挂到 PVC,然后用kubectl logs看实时输出,用kubectl exec进容器 grep 历史文件。更工程化的做法是接一个日志采集边车,把日志推到集中存储。下面是一个快速检索执行器日志的命令示例。

# 查看执行器 Pod 名称 kubectl get pods -n xxl-job -l app=xxl-job-executor # 实时查看某个执行器日志 kubectl logs -f <executor-pod-name> -n xxl-job # 进入容器检索历史日志中的错误关键字 kubectl exec -it <executor-pod-name> -n xxl-job -- grep -r "ERROR" /app/logs/

逻辑说明:-l app=xxl-job-executor按标签筛选,避免手动找 Pod 名。-f实时跟踪,适合观察任务执行过程。grep -r在容器内递归搜索日志目录,验证阶段够用。参数上,日志目录路径要和执行器配置一致,常见是/app/logs或/data/applogs。

还有一个容易忽略的点:调度中心的xxl.job.accessToken要和执行器一致,否则注册会被拒绝。验证版 YAML 里通常通过环境变量注入同一个 token,改的时候两边一起改。另外,K8S 的namespace隔离要利用好,把 XXL-JOB 相关资源都放在独立 namespace,排查时kubectl get all -n xxl-job一目了然,不会和别的服务混在一起。

我自己踩过最深的坑是执行器地址配成了容器 IP,调度中心一直显示离线,查了两小时才发现是环境变量没生效。后来养成的习惯是:每次改完 YAML,先kubectl describe pod看环境变量有没有注入成功,再去看调度中心页面。这个顺序能省很多时间。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询