systemd 托管的进程热升级中,systemd的一些坑
发布日期:2021-09-16 04:36:45 浏览次数:3 分类:技术文章

本文共 2987 字,大约阅读时间需要 9 分钟。

问题

在我们对某些进程做升级时,并且这些进程是被systemd托管的,比如ovs热升级后发现有新ovs进程起来后又退出了,并且退出后,并没有被systemd重新拉起,这个比较严重,热升级后进程退出,还没有重新拉起,会导致虚拟机网络中断时间过长。

分析

分析退出原因:

1、首先分析什么原因退出的,分析 ovs 日志,并没有发现有报错。

2、手动起ovs进程,然后进行热升级,发现进程状态正常,但是用systemd起的ovs进程,只要热升级就退出。

3、查看日志,systemctl status ovs-vswitchd 能看到有报错 "Refusing to accept PID outside of service control group, acquired through unsafe symlink chain: /var/run/openvswitch/ovs-vswitchd-current.pid "

从以上可以粗略的得出是systemd杀掉 新  ovs 进程的

 

分析systemd代码流程

找到报错的函数  service_load_pid_file:

1、会发现先进行了个 symlink 的检查,如果symlink检查失败会给 questionable_pid_file 变量赋值为 true, 表示这是个有问题的pid 文件。

2、然后会调用 service_is_suitable_main_pid 去判断是否是一个正确的service服务,如果不是正常的service服务,就会去判断 questionable_pid_file ,如果pid file  也是有问题的,就会 return -EPERM 报错

service_load_pid_file

static int service_load_pid_file(Service *s, bool may_warn) {

 

        r = chase_symlinks(s->pid_file, NULL, CHASE_SAFE, NULL, &fd);

        if (r == -ENOLINK) {

                questionable_pid_file = true;

        }

 

        r = service_is_suitable_main_pid(s, pid, prio);

        if (r < 0)

                return r;

        if (r == 0) {

                struct stat st;

                if (questionable_pid_file) {

                        log_unit_error(UNIT(s), "Refusing to accept PID outside of service control group, acquired through unsafe symlink chain: %s", s->pid_file);

                        return -EPERM;

                }

}

 

分析 chase_symlinks 函数,只贴了部分代码,目前的FLAG只有CHASE_SAFE, 所以我们只分析部分和目前场景相关的代码, 函数大意就是会遍历整个 pid 文件的路径,比如 /var/run/openvswitch/openvswitch-current.pid,会遍历/var、/var/run、/var/run/openvswitch、/var/run/openvswitch/openvswitch-current.pid 整个路径。

1、只要以上其中路径一个有软链都会返回错误。

2、同时会调用 unsafe_transition 检查上下文件的所有者,如果文件的所有者不相同也会返回错误。

chase_symlinks 和 unsafe_transition 函数

int chase_symlinks(const char *path, const char *original_root, unsigned flags, char **ret_path, int *ret_fd) {

                if (fstat(child, &st) < 0)

                        return -errno;

                previous_stat = st;

                fd = open(root ?: "/", O_CLOEXEC|O_NOFOLLOW|O_PATH);     //O_NOFOLLOW表示如果是软链,打开失败

                if (fd < 0)

                    return -errno;

 

 

                if (flags & CHASE_SAFE) {

                    if (fstat(fd, &st) < 0)

                        return -errno;

 

 

                if (unsafe_transition(&previous_stat, &st))

                    return log_unsafe_transition(child, fd, path, flags);

                    previous_stat = st;

                }

}

 

static bool unsafe_transition(const struct stat *a, const struct stat *b) {

        /* Returns true if the transition from a to b is safe, i.e. that we never transition from unprivileged to

         * privileged files or directories. Why bother? So that unprivileged code can't symlink to privileged files

         * making us believe we read something safe even though it isn't safe in the specific context we open it in. */

 

        if (a->st_uid == 0/* Transitioning from privileged to unprivileged is always fine */

                return false;

 

        return a->st_uid != b->st_uid; /* Otherwise we need to stay within the same UID */

}

 

线上环境现状

从下面可以看出 目前这个 /var/run/openvswitch/ovs-vswitchd-current.pid 路径上的问题比较多,和systemd冲突比较大,所以需要按systemd的方式来修改。

 

解决办法

根据以上代码分析,只要pid文件上没有软链,并且整条pid文件的路径上用户都是同一个,即可解决问题。

平时启动服务都不会有这问题,因为我们热升级的特殊性,在新进程创建后,需要把新的pid写入pid文件,在老进程退出时,systemd会重新加载这个 pidfile,由于有老进程的退出,新进程的创建,所以会比较麻烦。

 

其实这里还会有其它问题,比如pid文件要做到写的原子性,不然 systemd 读的时候会出现问题,导致systemd又把新进程杀掉了,还有就是对应 systemd service的配置要准备,这些在这里不细讲了。

转载地址:https://blog.csdn.net/wllabs/article/details/110195639 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:基于diagnose-tools 学习字符设备
下一篇:ARM64的内核栈、用户栈、寄存器上下文【转】

发表评论

最新留言

初次前来,多多关照!
[***.249.79.50]2022年05月22日 10时16分39秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

最新文章

mysql实现评论盖楼的sql_mysql - 网易的评论盖楼设计,用php的话,应该怎样实现?怎样存入数据库?... 2022-02-03
java多线程生产者消费者问题_java多线程解决生产者消费者问题 2022-02-03
c 批量更新mysql数据库_MySql批量更新方式大全 2022-02-03
autowarid和resources_ÂÐÏØÈË´ó 2022-02-03
python函数的定义教程_Python函数定义、函数调用详解 2022-02-03
python合并相同索引列表_python – 按行和相同的索引pandas合并两个数据帧 2022-02-03
ssis抽MySQL数据_微软SSIS部署抽取数据的包报错 2022-02-03
whmcs 添加域名_WHMCS域名更换教程 2022-02-03
vue监听值有变化后调用接口_探索 Vue.js 响应式原理 2022-02-03
mysql数据库环境安装配置_windows环境安装配置MySQL数据库 2022-02-03
mysql 索引缓存_MySQL之变量、查询缓存和索引 2022-02-03
mysql建表规定年龄范围_MySQL建表规则 2022-02-03
mysql memcache 一键_NGINX + PHP + MySQL + Memcache 一键启动脚本(.bat + shell) 2022-02-03
mysql语法检查工具_sql语法分析器(sql语法分析工具) 2022-02-03
webpy mysql_webpy使用mysql数据库操作(web.database) 2022-02-03
golang mysql 简书_golang实现mysql数据库备份-Go语言中文社区 2022-02-03
近期你已授权登录过腾讯文档 自动登录中_JustAuth发布1.13.2版本,新增微信公众平台的授权登录... 2022-02-03
ai怎么标注尺寸_传统的正负公差好用吗?怎么用?探究一下正负尺寸公差的标注... 2022-02-03
execjs执行js出现window对象未定义时的解决_收好这份JS学习口诀干货,学习前端事半功倍~... 2022-02-03
mysql 强制排序_转!!mysql order by 中文排序 2022-02-03