SAP JCo 报错:UnsatisfiedLinkError
文档编号: igo-20260701-001
服务: igo-mes-auth-center
命名空间: ns-igo-prod-a
集群: 基地-A K8s
报告日期: 2026-07-01
ENV
| 类别 | 项目 | 版本/信息 |
|---|---|---|
| 操作系统 | K8s 节点 | Ubuntu 20.04.6 LTS,Kernel 5.4.0-216-generic |
| 容器运行时 | 基地-A 集群 | docker://25.0.5 |
| Kubernetes | 基地-A 集群 | v1.24.6(Client/Server) |
| 对照集群 | 基地-B K8s | v1.26.7,docker://23.0.6,Ubuntu 20.04.6 LTS |
| 应用运行时 | Java | OpenJDK 8u342(容器内 JAVA_HOME=/usr/local/openjdk-8) |
| 故障镜像 | 基地-A | harbor-a.igozhang.cn/igo-project-a/igo-mes-auth-center:20260423_085858-eb02109 |
| 修复镜像 | 基地-A | harbor-a.igozhang.cn/igo-project-a/igo-mes-auth-center:20260630_182454-eb02109d |
| 对照镜像 | 基地-B(正常) | harbor-b.igozhang.cn/igo-project-b/igo-mes-auth-center:20260620_171442-4e53f021 |
| 硬件/节点 | 基地-A 控制面 | k8s-master-01/02/03(4C/16G) |
| 基地-A 工作节点 | k8s-worker-01~06(16C/64G) | |
| 故障 Pod 节点 | k8s-worker-02 | |
| SAP JCo 原生库 | 标准文件 | /usr/lib/libsapjco3.so(约 5,379,810 字节) |
本问题与 GPU/网卡驱动、固件无关,属应用镜像构建层缺失原生库。
1. 现象
XXL-Job 触发 SAP 部门同步时,igo-mes-auth-center 报错,Readiness 探针偶发超时,Pod 多次重启。
关键报错:
java.lang.UnsatisfiedLinkError: no sapjco3 in java.library.path
at com.sap.conn.jco.rt.DefaultJCoRuntime.loadJCoLibrary(...)
at com.igo.mes.auth.center.starter.sap.conn.SapConnection.connect(...)
at com.igo.mes.auth.center.starter.sap.sync.SyncDepartmentHandler.sync(...)
当时 Pod 状态:
| Pod | 镜像 tag | 重启次数 | 状态 |
|---|---|---|---|
igo-mes-auth-center-xxxxx-yyyyy |
20260423_085858-eb02109 |
14 | Running(不健康) |
K8s 事件(节选):
Warning Unhealthy Readiness probe failed: Get "http://10.0.0.12:8080/management/health": context deadline exceeded
2. 结论与根因
2.1 结论
| 项目 | 结论 |
|---|---|
| 故障状态 | 已修复(2026-06-30 发版后验证通过) |
| Deploy 变更 | 仅更新镜像 tag(revision 22 → 23),无其他 K8s 配置变更 |
| 修复方式 | 开发发版新镜像,非 initContainer / java.library.path 临时方案 |
| 当前状态 | /usr/lib/libsapjco3.so 存在,依赖正常,日志无 UnsatisfiedLinkError |
2.2 根因
20260423 镜像构建回退: libsapjco3.so 仅打包在 Spring Boot fat jar(app.jar)内,未复制到文件系统 /usr/lib/。
JCo 通过 System.loadLibrary("sapjco3") 加载原生库,Linux 在 /usr/lib 等系统路径查找,无法从 jar 内部读取,因此报 UnsatisfiedLinkError: no sapjco3 in java.library.path。
镜像版本对比:
| 镜像 tag | /usr/lib/libsapjco3.so |
|---|---|
20260416_132446-eb02109d |
有(正常) |
20260423_085858-eb02109 |
无(故障) |
20260630_182454-eb02109d |
有(已修复) |
2.3 问题形成原因推测
开发/CI 构建负责人 在
20260423发版时,基于代码提交eb02109重新构建镜像,Dockerfile 或 CI 脚本中复制libsapjco3.so到/usr/lib/的步骤被遗漏或覆盖(20260416版本该步骤正常,基地-B 正常镜像亦有此文件)。运维按流程仅更新了 Deployment 镜像 tag,未变更 K8s 其他配置。结果:基地-A 集群运行的20260423镜像文件系统缺少原生库,SAP 同步任务触发 JCo 初始化时报错,Pod 反复重启、Readiness 探针超时。
3. 定位推导过程
步骤 1:确认 K8s 配置是否特殊
执行位置: k8s-master-01
kubectl get pod igo-mes-auth-center-xxxxx-yyyyy -n ns-igo-prod-a -o jsonpath='节点={.spec.nodeName}{"\n"}镜像={.spec.containers[0].image}{"\n"}' && echo '---环境变量---' && kubectl get pod igo-mes-auth-center-xxxxx-yyyyy -n ns-igo-prod-a -o jsonpath='{range .spec.containers[0].env[*]}{.name}{"="}{.value}{"\n"}{end}' | grep -iE 'JAVA|LIBRARY|SAP|LD_|PATH' && echo '---挂载点---' && kubectl get pod igo-mes-auth-center-xxxxx-yyyyy -n ns-igo-prod-a -o jsonpath='{range .spec.containers[0].volumeMounts[*]}{.name}{" -> "}{.mountPath}{"\n"}{end}'
关键输出:
节点=k8s-worker-02
镜像=harbor-a.igozhang.cn/igo-project-a/igo-mes-auth-center:20260423_085858-eb02109
JAVA_OPTS=-Dspring.profiles.active=igo-site-a-prod -Dserver.port=8080 -Xms2G -Xmx2G -XX:+UseG1GC -Xss256k
挂载: vol1-properties -> /flydiy/bootstrap.properties
推导: 无 initContainer、无 java.library.path、无 JCo Volume → 排除 K8s 层面临时配置问题,转向镜像/容器内排查。
步骤 2:对比基地-B 正常环境
执行位置: k8s-master-ref(基地-B 集群)
基地-B Pod 配置与基地-A 一致,均无 JCo 相关 K8s 配置,差异在镜像版本。
kubectl exec -n ns-igo-prod-b igo-mes-auth-center-aaaaa-bbbbb -- sh -c 'find /flydiy /app /usr/lib /opt -maxdepth 5 -name "*sapjco*" 2>/dev/null'
关键输出:
/usr/lib/libsapjco3.so
推导: 正常环境文件系统有原生库,进一步确认基地-A 应检查 /usr/lib/。
步骤 3:基地-A 故障 Pod 容器内检查
执行位置: k8s-master-01
kubectl exec -n ns-igo-prod-a igo-mes-auth-center-xxxxx-yyyyy -- sh -c 'find /flydiy /app /usr/lib /opt -maxdepth 5 -name "*sapjco*" 2>/dev/null; ls -la /usr/lib/libsapjco3.so 2>&1'
关键输出:
ls: /usr/lib/libsapjco3.so: No such file or directory
补充:确认 jar 内有库
kubectl exec -n ns-igo-prod-a igo-mes-auth-center-xxxxx-yyyyy -- sh -c 'jar tf /flydiy/app.jar | grep -i sapjco | head -10'
关键输出:
BOOT-INF/lib/sapjco3.jar
BOOT-INF/classes/lib/libsapjco3.so
推导: 库在 jar 内、文件系统缺失 → 定位到镜像构建问题。
步骤 4:确认 Deploy 修复项
执行位置: k8s-master-01
echo '=== revision 22 (故障版) ===' && kubectl rollout history deployment/igo-mes-auth-center -n ns-igo-prod-a --revision=22 | grep -iE 'Image:|JAVA_OPTS|initContainer|Replicas|volume|mountPath' && echo '=== revision 23 (修复版) ===' && kubectl rollout history deployment/igo-mes-auth-center -n ns-igo-prod-a --revision=23 | grep -iE 'Image:|JAVA_OPTS|initContainer|Replicas|volume|mountPath'
关键输出:
revision 22: Image: .../igo-mes-auth-center:20260423_085858-eb02109
revision 23: Image: .../igo-mes-auth-center:20260630_182454-eb02109d
JAVA_OPTS / Volume / initContainer: 无变化
推导: Deploy 仅换镜像 tag,修复在镜像构建层;发版后 initContainer 方案未保留。
步骤 5:修复后验证
执行位置: k8s-master-01
kubectl exec -n ns-igo-prod-a igo-mes-auth-center-zzzzz-wwwww -- sh -c 'ls -la /usr/lib/libsapjco3.so 2>&1'
关键输出:
-rw-rw-rw- 1 root root 5379810 Jun 30 12:25 /usr/lib/libsapjco3.so
kubectl logs igo-mes-auth-center-zzzzz-wwwww -n ns-igo-prod-a 2>&1 | grep -iE 'UnsatisfiedLinkError|no sapjco3' | tail -10
关键输出: 无匹配(修复后无 JCo 加载错误)
4. 方案
4.1 已实施修复(开发发版)
Deployment revision 22 → 23,仅更新镜像:
# 变更前
image: harbor-a.igozhang.cn/igo-project-a/igo-mes-auth-center:20260423_085858-eb02109
# 变更后
image: harbor-a.igozhang.cn/igo-project-a/igo-mes-auth-center:20260630_182454-eb02109d
发版命令(运维侧,参考):
kubectl set image deployment/igo-mes-auth-center igo-mes-auth-center=harbor-a.igozhang.cn/igo-project-a/igo-mes-auth-center:20260630_182454-eb02109d -n ns-igo-prod-a
kubectl rollout status deployment/igo-mes-auth-center -n ns-igo-prod-a
4.2 镜像构建修复(开发侧,永久方案)
Dockerfile 固化:
RUN mkdir -p /usr/lib && \
cd /tmp && \
jar xf /flydiy/app.jar BOOT-INF/classes/lib/libsapjco3.so && \
cp BOOT-INF/classes/lib/libsapjco3.so /usr/lib/libsapjco3.so && \
rm -rf /tmp/BOOT-INF
CI 构建后校验:
test -f /usr/lib/libsapjco3.so || (echo "FAIL: libsapjco3.so missing" && exit 1)
4.3 临时应急方案(未采用,备查)
initContainer 解压 + java.library.path(会变更 Deployment,仅应急):
kubectl patch deployment igo-mes-auth-center -n ns-igo-prod-a --type=strategic --patch '
spec:
template:
spec:
initContainers:
- name: extract-sapjco3
image: <当前镜像>
command: ["sh","-c","cd /tmp && jar xf /flydiy/app.jar BOOT-INF/classes/lib/libsapjco3.so && cp BOOT-INF/classes/lib/libsapjco3.so /jco/libsapjco3.so"]
volumeMounts:
- name: sapjco-lib
mountPath: /jco
containers:
- name: igo-mes-auth-center
env:
- name: JAVA_OPTS
value: "<原JAVA_OPTS> -Djava.library.path=/jco"
volumeMounts:
- name: sapjco-lib
mountPath: /jco
volumes:
- name: sapjco-lib
emptyDir: {}
'
4.4 验证命令
A. kubectl 服务器完整检查(推荐)
执行位置: k8s-master-01
echo "========== igo-mes-auth-center JCo 诊断 ==========" && \
echo "" && \
echo "[1/4] Pod 基本信息" && \
kubectl get pod -n ns-igo-prod-a -l app=igo-mes-auth-center -o custom-columns='POD:.metadata.name,NODE:.spec.nodeName,STATUS:.status.phase,RESTARTS:.status.containerStatuses[0].restartCount,IMAGE:.spec.containers[0].image' && \
echo "" && \
echo "[2/4] Deployment 镜像" && \
kubectl get deployment igo-mes-auth-center -n ns-igo-prod-a -o jsonpath='镜像={.spec.template.spec.containers[0].image}{"\n"}' && \
echo "" && \
POD=$(kubectl get pod -n ns-igo-prod-a -l app=igo-mes-auth-center -o jsonpath='{.items[0].metadata.name}') && \
echo "[3/4] 容器内 JCo 原生库检查 (Pod: ${POD})" && \
kubectl exec -n ns-igo-prod-a ${POD} -- sh -c 'if [ -f /usr/lib/libsapjco3.so ]; then ls -la /usr/lib/libsapjco3.so; ldd /usr/lib/libsapjco3.so 2>&1 | grep "not found" && echo "容器内结论: FAIL — 依赖库缺失" || echo "容器内结论: OK — 原生库存在且依赖正常"; else echo "容器内结论: FAIL — /usr/lib/libsapjco3.so 不存在"; fi' && \
echo "" && \
echo "[4/4] 最近日志 JCo 错误检查 (tail 60)" && \
kubectl logs ${POD} -n ns-igo-prod-a --tail=60 2>&1 | grep -iE 'UnsatisfiedLinkError|no sapjco3|SapConnection|SyncDepartment' || echo "日志结论: 未发现 JCo 加载错误" && \
echo "" && \
echo "========== 总 结 ==========" && \
kubectl exec -n ns-igo-prod-a ${POD} -- sh -c 'test -f /usr/lib/libsapjco3.so && ldd /usr/lib/libsapjco3.so 2>&1 | grep -q "not found" && echo "最终结论: FAIL — JCo 原生库异常,需修复镜像" || (test -f /usr/lib/libsapjco3.so && echo "最终结论: OK — JCo 原生库正常,SAP 同步不应因缺库报错") || echo "最终结论: FAIL — 缺少 /usr/lib/libsapjco3.so,需更新镜像"'
正常输出:
容器内结论: OK — 原生库存在且依赖正常
最终结论: OK — JCo 原生库正常,SAP 同步不应因缺库报错
B. 容器内检查
进入容器(kubectl 服务器):
POD=$(kubectl get pod -n ns-igo-prod-a -l app=igo-mes-auth-center -o jsonpath='{.items[0].metadata.name}') && kubectl exec -it -n ns-igo-prod-a ${POD} -- sh
容器内执行:
echo "========== 容器内 JCo 检查 ==========" && \
echo "[1/3] 原生库文件" && ls -la /usr/lib/libsapjco3.so 2>&1 && \
echo "[2/3] 动态库依赖" && ldd /usr/lib/libsapjco3.so 2>&1 && \
echo "[3/3] JVM 库搜索路径" && java -XshowSettings:properties -version 2>&1 | grep "java.library.path" && \
if [ -f /usr/lib/libsapjco3.so ]; then ldd /usr/lib/libsapjco3.so 2>&1 | grep -q "not found" && echo "最终结论: FAIL" || echo "最终结论: OK"; else echo "最终结论: FAIL — 文件不存在"; fi
5. 后续预防措施
| 措施 | 责任方 | 说明 |
|---|---|---|
| Dockerfile 固化 JCo 库复制 | 开发/CI | 构建阶段 COPY 或 RUN jar xf ... cp /usr/lib/ |
| CI 构建后校验 | CI/DevOps | test -f /usr/lib/libsapjco3.so,缺失则构建失败 |
| 镜像发布前冒烟 | 测试/运维 | 部署后执行 4.4 验证命令 |
| 多基地构建脚本统一 | 开发 | 避免各基地 Dockerfile 分叉导致回退 |
| 发版 Checklist | 运维 | SAP 相关服务发版时,确认 JCo 库检查通过 |
6. 建议数值
| 配置项 | 当前值 | 建议值 | 原因/后果 |
|---|---|---|---|
| Deployment 镜像 | 20260630_182454-eb02109d(已修复) |
保持 ≥ 20260630 且含 /usr/lib/libsapjco3.so |
低于此版本或构建未校验可能再次缺库 |
/usr/lib/libsapjco3.so |
存在,5,379,810 字节 | 必须存在,大小约 5.1~5.4MB | 缺失则 UnsatisfiedLinkError,SAP 同步失败 |
JAVA_OPTS |
-Dspring.profiles.active=igo-site-a-prod -Dserver.port=8080 -Xms2G -Xmx2G -XX:+UseG1GC -Xss256k |
无需加 -Djava.library.path(镜像正确时) |
库在 /usr/lib/ 时 Linux 可正常加载;仅应急 initContainer 方案才需加 |
| initContainer | 无 | 无(正常情况) | 永久修复应靠镜像,不应依赖 initContainer |
| replicas | 1 | 按业务负载配置(历史曾用 2~3) | 与 JCo 无关 |
| CI 构建校验 | 无(推测) | 增加 test -f /usr/lib/libsapjco3.so |
防止 20260423 类构建回退再次发生 |
| Readiness 探针 timeout | 2s | 保持 2s;SAP 初始化慢时可评估 5s | JCo 缺库会导致健康检查超时,根因仍是镜像 |
附录 A:时间线
| 时间 | 事件 |
|---|---|
| 2026-04-16 | 镜像 20260416 含 /usr/lib/libsapjco3.so(正常) |
| 2026-04-23 | 镜像 20260423 发版,丢失 /usr/lib/libsapjco3.so |
| 2026-06-27 | 基地-A 运行 20260423,Pod 多次重启,SAP JCo 报错 |
| 2026-06-30 | 开发发版 20260630_182454-eb02109d,恢复原生库 |
| 2026-07-01 | 验证通过,JCo 原生库正常 |
附录 B:igo 标识对照
| 公开版标识 | 含义 |
|---|---|
| 基地-A | 故障发生集群 |
| 基地-B | 对照正常集群 |
k8s-master-01 |
基地-A kubectl 控制节点 |
k8s-master-ref |
基地-B kubectl 控制节点 |
k8s-worker-02 |
故障 Pod 所在工作节点 |
ns-igo-prod-a |
基地-A 应用命名空间 |
ns-igo-prod-b |
基地-B 应用命名空间 |
igo-mes-auth-center-xxxxx-yyyyy |
故障 Pod 名称(示例占位) |
igo-mes-auth-center-zzzzz-wwwww |
修复后 Pod 名称(示例占位) |
harbor-a.igozhang.cn/igo-project-a |
基地-A 镜像仓库 |
harbor-b.igozhang.cn/igo-project-b |
基地-B 镜像仓库 |
igo-site-a-prod |
基地-A Spring Profile |
10.0.0.12 |
Pod IP(示例占位) |
文档编号 igo-20260701-001