TGTGInsighttelegram intelligenceLIVE / telegram public index
← Welcome to the Black Parade
Welcome to the Black Parade avatar

TGINSIGHT POST

Post #25

@TheB1ackParade

Welcome to the Black Parade

Views130Post view count
PostedFeb 1802/18/2020, 02:53 PM
Post content

Post content

先说问题吧, 一个月前 techops 找过来问我为什么他部署 etcd by systemd 跑不起来, 我一看 service file 是这样的: [Unit] Description=etcd key-value store Documentation=https://github.com/etcd-io/etcd After=network.target [Service] User=etcd Type=notify Environment=ETCD_DATA_DIR=/var/lib/etcd Environment=ETCD_NAME=%m ExecStart=/bin/sh -c '/usr/bin/etcd gateway start --endpoints=http://10.143.203.164:2379 --listen-addr 127.0.0.1:2388' Restart=always RestartSec=10s LimitNOFILE=40000 [Install] WantedBy=multi-user.target 本质上就是把官方仓库里的 service file 改成了运行 etcd gateway 而已, 但是出现的问题是 systemctl start etcd会卡住, 命令不输出, 不返回, 只能打断退出. 那么这里的问题有两点, 第一是 /bin/sh -c, 把它删掉, 或者换成 /bin/bash -c 都能解决问题. 第二个问题是 Type=notify, 先说这个吧. systemd 的 service type 分为几类, 默认是 simple, 然后常用的有 forking, exec, notify, oneshot, 这里说 notify 类型, 简单来说它要求 ExecStart= 的进程通过 sd_notify (https://www.freedesktop.org/software/systemd/man/sd_notify.html#)来通知 systemd "我好了", 然后 systemd 才认为服务是 running, 否则一直是 activating, 而且 systemctl start 也不会返回; 这一点和默认的类型 simple 不一样, simple 可不管死活, 从 systemd 进程 fork 成功就 running 状态了, 甚至不管 exec 是否失败. etcd 本身是实现了 sd_notify 那一套的, 可以看这里: https://github.com/etcd-io/etcd/blob/master/etcdmain/main.go#L50, sd_notify 呢又要求读到环境变量 $NOTIFY_SOCKET 来报告状态, 这些都没问题. 但是问题出在 /bin/sh 也就是 dash(1) 上面, 和 bash 不一样, 对于 -c这个 option, dash 会 fork 子进程而 bash 原地 exec, 这一点不论是通过查看进程树还是 strace(1) 都很容易确认; 而偏偏 systemd 只接收来自自己 fork 出来的子进程的状态, 对于 sh 又 fork 出来的 etcd 的消息是无视了的, 这一点可以通过 systemctl status 确认; 所以就导致了始终无法启动, 但是改成 /bin/bash -c 或者裸跑就可以了. systemd 也算是博大茎深了, 里面对进程的各种处理方式非常值得学习, 如果你高兴的话甚至可以通过 ExecPreStart= 集成 CNM 或者 CNI 来做 SDN, 非常有趣了, 我还在一点点实践当中, 后续应该会有更多的记录.