找了一下午,网上文章有很多,但都不适用,因为我是通过容器进行部署服务,然后容器加载.so动态链接文件,所以网上大多数文章是设置Linux的动态链接目录,这里统一记录一下解决方法:
1、Linux设置LD_LIBRARY_PATH环境变量
普通的 Jar 包加载 .so 可以通过设置动态链接目录的方式来找到动态链接文件
$ vim /etc/profile
$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/oas/
$ source /etc/profile
假如动态链接文件名叫做 libauthd.so,Java代码中有两种方式加载,绝对路径方式可以添加上述动态链接库所在目录的环境变量,相对路径方式则必须指定上述动态链接库所在目录的环境变量
System.load("/usr/local/oas/library/auth/libauthd.so");
System.loadLibrary("authd");
2、容器加载.so文件
如果是容器部署,需要将.so文件加入到容器中,才可以找到这个.so文件,否则死活也不会找到的,k8s deploy资源文件中,我将宿主机和容器的.so所在目录都配置为 /usr/local/oas/library/auth,当然程序所需要的 .so 文件也需要在 /usr/local/oas/library/auth 下,这样就可以将 .so 文件挂载到容器中了,然后我 Java 代码使用 System.load("/usr/local/oas/library/auth/libauthd.so"); 的方式去加载容器中的 .so动态链接文件,下面是我的资源文件配置:
apiVersion: apps/v1
kind: Deployment
metadata:
name: openailab-security-auth-service
namespace: oas-dev
labels:
name: openailab-security-auth-service
spec:
replicas: 1
selector:
matchLabels:
name: openailab-security-auth-service
template:
metadata:
labels:
name: openailab-security-auth-service
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: env
operator: In
values:
- dev
containers:
- name: openailab-security-auth-service
image: 10.12.1.202:8088/oascloud/openailab-security-auth-service:latest
env:
- name: APOLLO_APP_ID
value: 'openailab-security-auth-service'
- name: APOLLO_EUREKA_URI
value: 'http://10.98.100.95:8080/'
- name: APOLLO_NAMESPACE
value: 'application'
- name: SPRING_EUREKA_URI
value: 'http://10.111.176.152:8080/eureka/'
- name: LD_LIBRARY_PATH
value: '$LD_LIBRARY_PATH:/usr/local/oas/library/auth'
volumeMounts:
- name: openailab-security-auth-service
mountPath: /usr/local/logs
- name: auth-library
mountPath: /usr/local/oas/library/auth
command: ['sh','-c','java -server -Xms512m -Xmx1024m -Djava.io.tmpdir=/var/tmp -Duser.timezone=Asia/Shanghai -jar openailab-security-auth-service-*.jar --server.port=8080 --spring.profiles.active=remote']
ports:
- containerPort: 8080
resources:
requests:
memory: 512Mi
cpu: 500m
limits:
memory: 1024Mi
cpu: 1000m
initContainers:
- name: init-apollo
image: busybox
command: ['sh', '-c']
args:
- echo Prepare to apollo initialize..;
until nc -w 1 -z 10.98.100.95 8080;
do echo Waiting for eureka initialization to complete..; sleep 10; done;
echo Eureka is ready.;
until nc -w 1 -z 10.98.100.95 8090;
do echo Waiting for admin initialization to complete..; sleep 10; done;
echo Admin is ready.;
echo Apollo Initialization successful!;
volumes:
- name: openailab-security-auth-service
hostPath:
path: /usr/local/logs
- name: auth-library
hostPath:
path: /usr/local/oas/library/auth
然后是我的Dockerfile文件,在最开始定位问题的时候,我一度怀疑是因为简易的基础镜像导致目标so依赖Linux资源不存在造成的,后来通过命令进入容器查看.so依赖资源发现并不是这个原因,相关文章传送门如下:
而是因为容器中环境变量 LD_LIBRARY_PATH 没有包含目标 .so 所在动态链接目录,导致目标 .so 依赖不到同级目录内的其他 .so 文件(如果是通过容器的方式部署服务,并且需要依赖 .so 动态链接文件的,则建议必须在容器中通过 LD_LIBRARY_PATH 添加动态链接文件所在目录,否则如果该 .so 文件依赖容器内同级目录中的其他 .so 文件,虽然是在同级目录,但依然会找不到依赖的同级 .so 文件,这里可以进入容器通过 ldd 命令查看 .so 所需依赖文件是否能够找到) ,解决办法就是在k8s资源文件中(上述配置)加入 $LD_LIBRARY_PATH:/usr/local/oas/library/auth 环境变量(如果刚才没注意,可以到上述配置文件中再仔细看一下),这里我选择简易版Jdk8环境作为基础镜像,若想用完整版Centos、Jdk8的Dockerfile来做基础镜像(制作出来的镜像大概680MB),传送门如下:
制作简易版Jdk8基础镜像Dockerfile(制作出来的镜像大概190MB),代码如下:
FROM frolvlad/alpine-java:jre8-slim
MAINTAINER oas.cloud
ARG JAR_FILE
COPY ${JAR_FILE} /usr/local/oas/
WORKDIR /usr/local/oas/
然后通过Jenkins再重新发布容器就可以了,到此问题解决,如果各位有解决不了的,可以评论区联系我。