5

通过 systemd 服务配置链接动态库

 2 years ago
source link: https://blog.triplez.cn/posts/systemd-binary-service-dynamic-linking/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

#

在设置动态链接的方法中,rpath 有其自身的问题1ld.so.conf 为 OS 全局配置,可能会因为单一服务的动态库版本而影响到其他服务,不是一个优雅的方法。

那如何才能不借助 rpathld.so.conf ,即能使目标服务找到对应的动态链接库,又能不影响其他服务呢?

LD_LIBRARY_PATH#

对于动态链接库的路径配置而言,除了 rpathld.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 配置并重启服务,观察效果。

 [Unit]
 Description=Nginx
 After=syslog.target network.target remote-fs.target nss-lookup.target

 [Service]
 User=triplez
 Group=triplez
 Type=forking
+Environment="LD_LIBRARY_PATH=/your/path/to/openssl/lib:/your/path/to/jemalloc/lib:/your/path/to/luajit/lib"
 PIDFile=/run/nginx/nginx.pid
 RuntimeDirectory=nginx
 RuntimeDirectoryMode=0755
 ExecStartPre=/your/path/to/nginx -t
 ExecStart=/your/path/to/nginx
 ExecReload=/bin/kill -s HUP $MAINPID
 ExecStop=/bin/kill -s QUIT $MAINPID

 PrivateTmp=true
 Restart=always

 [Install]
 WantedBy=multi-user.target
$ sudo systemctl daemon-reload
$ sudo systemctl restart nginx.service

事实上,对于大多数服务,只需要加入环境变量即可解决问题。但很不幸的是,由于我们的服务需要监听 1024 及以下端口(如 80、443),笔者对二进制可执行文件进行了 setcap 操作,赋予其监听低位端口的能力。

$ sudo getcap /your/path/to/nginx
/your/path/to/nginx = cap_net_bind_service+ep

Capability#

由于该文件含有 capability,glibc 会将 LD_LIBRARY_PATH 忽略2 3,导致服务还是无法正确链接到动态库上。

了解原因之后,接下来要做的事情也很清晰了:一是先将二进制可执行文件上的 capability 移除(chown 就可以将其移除, setcap -ep 亦可),二是利用 systemd 的服务配置来实现配置 capability (如下)。

 [Unit]
 Description=Nginx
 After=syslog.target network.target remote-fs.target nss-lookup.target

 [Service]
 User=triplez
 Group=triplez
 Type=forking
 Environment="LD_LIBRARY_PATH=/your/path/to/openssl/lib:/your/path/to/jemalloc/lib:/your/path/to/luajit/lib"
 PIDFile=/run/nginx/nginx.pid
 RuntimeDirectory=nginx
 RuntimeDirectoryMode=0755
 ExecStartPre=/your/path/to/nginx -t
 ExecStart=/your/path/to/nginx
 ExecReload=/bin/kill -s HUP $MAINPID
 ExecStop=/bin/kill -s QUIT $MAINPID

+CapabilityBoundingSet=CAP_NET_BIND_SERVICE
+AmbientCapabilities=CAP_NET_BIND_SERVICE
 PrivateTmp=true
 Restart=always

 [Install]
 WantedBy=multi-user.target

再次重新加载 systemd 配置并重启服务,问题完美解决。


知识共享许可协议
本作品采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK