在 Docker 容器中运行服务#
最近正在写的某个容器升级了一下架构,在启动容器时需要同时运行一个 frps 服务。根据我的习惯,一开始打算使用 systemctl 添加 frps 服务,然后 enable 一下以实现开机自启。但在我实际使用时,发现服务没有跑起来。查了一下日志,发现了这条报错:
ERROR:systemctl: frps.service: Executable path is not absolute, ignoring: ./frps -c /frps.ini
ERROR:systemctl: Exec is not an absolute path: ExecStart=./frps -c /frps.ini
ERROR:systemctl: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
ERROR:systemctl: Found 1 problems in /etc/systemd/system/frps.service
ERROR:systemctl: The SystemD commands must always be absolute paths by definition.
ERROR:systemctl: Earlier versions of systemctl.py did use a subshell thus using $PATH
ERROR:systemctl: however newer versions use execve just like the real SystemD daemon
ERROR:systemctl: so that your docker-only service scripts may start to fail suddenly.
ERROR:systemctl: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
去官网稍微找了下,发现了这段解释:
This is by design. Docker should be running a process in the foreground in your container and it will be spawned as PID 1 within the container’s pid namespace. Docker is designed for process isolation, not for OS virtualization, so there are no other OS processes and daemons running inside the container (like systemd, cron, syslog, etc), only your entrypoint or command you run.
If they included systemd commands, you’d find a lot of things not working since your entrypoint replaces init. Systemd also makes use to cgroups which docker restricts inside of containers since the ability to change cgroups could allow a process to escape the container’s isolation. Without systemd running as init inside your container, there’s no daemon to process your start and stop commands.
大意就是:docker 只是提供了进程隔离,不是操作系统的虚拟,所以不能运行 systemd。
如果只想同时运行两个服务,应该用什么办法呢?其实很简单:在 Dockerfile CMD 内运行 start.sh,然后再用 nohup 挂起 frps 服务就好了:
nohup ./frps -c /frps.ini &
python3 /main.py
顺利运行 frps 服务。