序
在设置动态链接的方法中,rpath
有其自身的问题1 , ld.so.conf
为 OS 全局配置,可能会因为单一服务的动态库版本而影响到其他服务,不是一个优雅的方法。
那如何才能不借助 rpath
和 ld.so.conf
,即能使目标服务找到对应的动态链接库,又能不影响其他服务呢?
LD_LIBRARY_PATH
对于动态链接库的路径配置而言,除了 rpath
和 ld.so.conf
,还有 LD_LIBRARY_PATH
。只要在二进制启动的环境中设置 LD_LIBRARY_PATH
变量,则 glibc
会将该变量中的路径配置作为动态链接库的查找路径之一,使得二进制可执行文件能够正常链接到其依赖的动态链接库。
LD_LIBRARY_PATH
会在当前 shell session 中“全局”生效,不过,由于笔者服务采用 systemd 来管理其生命周期,按照上述思路,应该只需要在服务启动前,将 LD_LIBRARY_PATH
注入启动环境即可,这样还能够借助 systemd 来实现一定程度的环境“隔离”。systemd 服务配置中的 Environment
字段是用于描述启动环境的环境变量的,我们先在这里加入 LD_LIBRARY_PATH
(如下),重新加载 systemd 配置并重启服务,观察效果。
|
|
事实上,对于大多数服务,只需要加入环境变量即可解决问题。但很不幸的是,由于我们的服务需要监听 1024 及以下端口(如 80、443),笔者对二进制可执行文件进行了 setcap
操作,赋予其监听低位端口的能力。
Capability
由于该文件含有 capability,glibc
会将 LD_LIBRARY_PATH
忽略2 3,导致服务还是无法正确链接到动态库上。
了解原因之后,接下来要做的事情也很清晰了:一是先将二进制可执行文件上的 capability 移除(chown
就可以将其移除, setcap -ep
亦可),二是利用 systemd 的服务配置来实现配置 capability (如下)。
|
|
再次重新加载 systemd 配置并重启服务,问题完美解决。
RpathIssue
https://wiki.debian.org/RpathIssue ↩︎Use of file capabilities disables LD_LIBRARY_PATH - Red Hat Bugzilla
https://bugzilla.redhat.com/show_bug.cgi?id=448594 ↩︎shared libraries - Linux capabilities (setcap) seems to disable LD_LIBRARY_PATH - Stack Overflow
https://stackoverflow.com/questions/9843178/linux-capabilities-setcap-seems-to-disable-ld-library-path ↩︎
本作品采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。