老哥们,问一个 Golang Go语言在 Linux 把自生加入开机自启的问题

发布于 1周前 作者 zlyuanteng 来自 Go语言

我的需求是 go 在启动的时候把自生加入开机自启,并且不依赖其他软件。

我在 windows 环境,go 可以新建一个文件(AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\start.bat),在脚本内可以调用 exe 程序 重启就会自动启动

但是在 linux 上,我把编译后的 go 文件进行执行,里面的代码有一句是 os.Create("/etc/init.d/start.sh") 在创建时 会创建失败,我以为是权限的问题 ,但是我是使用的是root用户,并且使用chmod 777了。 实际上 执行 os.Create("/tmp/start.sh")是成功的

查到的方案基本上都是通过用shell, 但是这样需要手动的添加

有没有办法解决linux执行 os.Create("/tmp/start.sh")失败的问题

linux 权限如下:

[root[@localhost](/user/localhost) etc]# pwd
/etc
[root[@localhost](/user/localhost) etc]# ll | grep init
drwxr-xr-x.  2 root root       24 Sep 27 23:42 gdbinit.d
lrwxrwxrwx.  1 root root       11 Sep 27 23:30 init.d -> rc.d/init.d
-rw-r--r--.  1 root root      511 Nov 16  2020 inittab

[root[@localhost](/user/localhost) application]# ll
total 2076
-rwxr-xr-x. 1 root root 2111964 Oct 17 11:05 start

老哥们,问一个 Golang Go语言在 Linux 把自生加入开机自启的问题

更多关于老哥们,问一个 Golang Go语言在 Linux 把自生加入开机自启的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

53 回复

更多关于老哥们,问一个 Golang Go语言在 Linux 把自生加入开机自启的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


你是打算跑 docker 还是?
init.d(openrc) 或者什么的是很古老写法,在现代的 Linux 现在应该使用 systemd 来守护,来启动进程。

直接加在 rc.local

我同意二楼同学的说法

建议参考一下/t/982696

这是正儿八经的需求。。跟这个没什么关系

不跑 docker ,如果用 systemd 也需要自己手动编写脚本把(我的意思是没办法在程序中自动加入开机自启)

正儿八经的需求,找一个并不懂这方面知识的人来做?并没觉得这需求有多么正儿八经

你在 windows 环境设置的那个是用户级自动启动吧,是登录之后才有的
服务器哪儿有机会让你登录啊

设置系统级自动启动需要系统级的权限,不是你想写就能随便往里写的

如果你还是想直接加 init.d 的话,你可以检查一下 selinux 是否阻止了你的程序往 /etc/init.d 加文件 用 dmesg 看最近几条日志就知道了。

=====

让进程守护是个复杂的操作,什么不需要写脚本呢?
让什么用户运行你的程序?
是不是要等待网络或者数据库启动后再运行?(优先级)
要不要限制什么权限?
原始的 /etc/init.d 里面也是有不少的配置选项呢,脚本量和 systemd 相比差不了多少(何况你系统基本也是 systemd 运行的,保留 /etc/init.d 只是为了兼容)

难道你的启动脚本就一行,用来启动 go 的程序就撒手不管了?
真的,跑服务有很多需要考虑的东西,不要只启动就行了,守护在哪里,日志放哪里…

大哥,我觉得你真是有点没事找事。公司有这个需求,我只是来实现而已。你为什么非要觉得我要搞一个最大权限?
意思是公司派了一个需求,又只有你适合去做这个事情,你不做吗?
不是每个公司都有专职的 DBA 和运维

你这个需求,客观上就是需要最大权限
但是你对这个不熟悉,掌握这个权限会有风险和错误
这才是问题

为什么不写在 shell 脚本去启动呢

写个 systemd 的 unit 不就好了,然后程序里把 unit 链接到/etc/systemd/system/multi-user.target.wants/

windows 下我用任务计划自启。
还能同时做到间隔几分钟自启,防止程序被杀掉。

linux 下对应的当然是 crontab 了。

你把程序放 Startup 里启动,那服务器每次重启是不是要进桌面才会启动?

你这个做法很腾讯
在 linux 里用 crontab 启动后台任务(尤其是用户级 crontab )是一个极其错误的行为
会导致后台服务使用的资源被计入用户的统计数据里去

那我可理解不了。
cron 不就是干这个用的?

你都有 root 了,可以写 /etc/systemd/system/ 里面,用 systemd 来管理。

> os.Create("/etc/init.d/start.sh") 失败

倒是检查下错误码啊

你这 windows 也要写个 bat 啊,并不是依靠自身,而且你这么写不能保活。

对比你的 bat 方案,linux 下直接创建 CronJob 最简单,用 .

如果是实体机,请你通过 systemd 的 service 做。由 systemd 完成自启动,自动拉起,日志管理等等。

emmm ,看到楼上的回复了,楼主你想怎么做就怎么做吧

如果是桌面程序,可以在~/.config/autostart 下创建一个.desktop 文件,基本对标 windows

如果是服务端程序,可以在/etc/systemd/system 下面创建一个.service 文件,需要 root

cron 是做短任务用的

没记错的话 systemd 是可以注册用户级别的服务的。

参考服务器被入侵挖矿的,用 cron 。

crontab ,每分钟执行一次 sh ,判断没有进程就启动,这不安全的多,兼容性极佳

加个&不就可以了吗?

是我在水木认识的那位大佬吗?

可以 用 supervisor

cron 定时任务
systemd/init.d 后台常驻进程(更偏系统层,随 Linux 启动而启动)
supervisor 后台常驻进程(更偏用户层,一般用来管理自己写的常驻脚本偏多)

> 我的需求是 go 在启动的时候把自生加入开机自启,并且不依赖其他软件。

“并且不依赖其他软件”? 要是 init 都不想依赖那就麻烦了,建议添加 init=你的程序 替代掉 init ,启动自身之后创建容器启动原来的 init 作为给用户的系统

开个玩笑

你得依赖点什么东西,要是 systemd 就创建 systemd unit: https://www.freedesktop.org/software/systemd/man/systemd.unit.html
要是 sysV init 就是/etc/rc.d/xxx.sh, /etc/init.d/,/etc/rc.d/init.d


写好一个可用的 systemd unit 没那么难。

以及就算创建文件失败至少给点失败的信息,不然大家水晶球也水晶不出来

systemd.service

注册服务然后自启动

shell 脚本写个,然后放到 rc.local 启动就拉起来。
想要中断后自动拉起,可以加到 crontab 定时任务。

放弃助人情结,尊重草台班子(们)

一楼的答案就是正解 如果用 Go 的话都是用这个第三方模块来实现

agLee with you

是吧

systemd 用户级别服务需要再另外运行一个 systemd 吧,还是需要用户先登录的吧



你这做法(每分钟 cron )很腾讯
在旧版本 systemd 里,大量使用 cron 、在 cron 里运行后台服务,会导致大量的 login session 累积,压垮 systemd-logind ,随随便便占十几 G 内存

&符号是由 shell 处理的。也就是首先你要有个 shell ,也就是会产生一个 login session



supervisorD 自己的启动和存活怎么保证呢?

不需要吧,至少通过 StartTransientUnit 创建临时 service 不需要特殊权限

StartTransientUnit 是指从 dbus 接口创建吗 user 级别的 unit 吧?
那由哪个程序来发这个消息呢?发消息的这个程序是怎么运行起来呢?

只是举例子说明可以免额外权限创建用户级的 service ,不是说一定要用这种方案。具体能否 enable 一个用户级的 service ,我没调查过,但我猜测是可以的。

但是 TransientUnit 不能“下次开机”的时候自动启动吧?那东西的 unit file 根本就不存盘吧
无法满足 OP 的需求

我已经说了“不是说一定要用这种方案”

进程退出后,login session 也不会退出?

旧版本 systemd 对于大量 session 累积的情况,会无法正常清理。“理论上”进程退出之后,session 应该退出,但实际上没做到

ok, 直接/etc/crontab 应该没这个问题

应该也会。session 是由/etc/pam.d/crond 生成的。
不过我没实际试过……

抛开 session 的问题不说,服务进程的“上级”是 crond 就够奇怪了,和上级是个 login shell 差不多奇怪

在Linux系统中,将Go语言程序设置为开机自启,可以通过以下几种方式实现:

  1. 使用systemd服务

    • 创建一个新的systemd服务文件,例如/etc/systemd/system/mygoapp.service
    • 编辑该文件,添加服务描述、执行命令、重启策略等配置。
    • 使用systemctl daemon-reload命令重新加载systemd配置。
    • 使用systemctl enable mygoapp.servicesystemctl start mygoapp.service命令启用并启动服务。
  2. 添加启动脚本到.bashrc或.profile

    • 打开并编辑~/.bashrc~/.profile文件。
    • 在文件末尾添加启动Go语言程序的命令。
    • 这种方法适用于个人用户,且程序将在用户登录时启动。
  3. 使用桌面环境的启动项

    • 对于使用GNOME或KDE等桌面环境的Linux系统,可以将Go语言程序的快捷方式添加到相应的启动项配置中。
    • GNOME可以使用gnome-session-properties添加启动程序,KDE则可以将程序快捷方式添加到~/.config/autostart目录。

请注意,选择适合自己操作系统和需求的方法,并确保程序路径正确且具有执行权限。测试配置是否生效,以确保Go语言程序能够在系统启动时自动运行。

回到顶部