V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
leegoo
V2EX  ›  Go 编程语言

老哥们,问一个 go 在 Linux 把自生加入开机自启的问题

  •  
  •   leegoo · 2023-10-17 16:11:13 +08:00 · 2924 次点击
    这是一个创建于 370 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我的需求是 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 etc]# pwd
    /etc
    [root@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 application]# ll
    total 2076
    -rwxr-xr-x. 1 root root 2111964 Oct 17 11:05 start
    
    第 1 条附言  ·  2023-10-17 20:18:05 +08:00
    感谢大家,我先研究一下
    52 条回复    2023-11-01 16:38:00 +08:00
    exkernel
        1
    exkernel  
       2023-10-17 16:24:21 +08:00   ❤️ 1
    xiao201261
        2
    xiao201261  
       2023-10-17 16:24:53 +08:00   ❤️ 1
    你是打算跑 docker 还是?
    init.d(openrc) 或者什么的是很古老写法,在现代的 Linux 现在应该使用 systemd 来守护,来启动进程。
    bg7lgb
        3
    bg7lgb  
       2023-10-17 16:27:25 +08:00
    直接加在 rc.local
    liarsa
        4
    liarsa  
       2023-10-17 16:28:13 +08:00
    我同意二楼同学的说法
    julyclyde
        5
    julyclyde  
       2023-10-17 16:36:40 +08:00
    建议参考一下/t/982696
    leegoo
        6
    leegoo  
    OP
       2023-10-17 16:42:03 +08:00
    @julyclyde 这是正儿八经的需求。。跟这个没什么关系
    leegoo
        7
    leegoo  
    OP
       2023-10-17 16:43:36 +08:00
    @xiao201261 不跑 docker ,如果用 systemd 也需要自己手动编写脚本把(我的意思是没办法在程序中自动加入开机自启)
    julyclyde
        8
    julyclyde  
       2023-10-17 16:45:05 +08:00
    @leegoo 正儿八经的需求,找一个并不懂这方面知识的人来做?并没觉得这需求有多么正儿八经

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

    设置系统级自动启动需要系统级的权限,不是你想写就能随便往里写的
    xiao201261
        9
    xiao201261  
       2023-10-17 16:51:05 +08:00
    @leegoo 如果你还是想直接加 init.d 的话,你可以检查一下 selinux 是否阻止了你的程序往 /etc/init.d 加文件 用 dmesg 看最近几条日志就知道了。

    =====

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

    难道你的启动脚本就一行,用来启动 go 的程序就撒手不管了?
    真的,跑服务有很多需要考虑的东西,不要只启动就行了,守护在哪里,日志放哪里.....
    leegoo
        10
    leegoo  
    OP
       2023-10-17 16:54:36 +08:00
    @julyclyde 大哥,我觉得你真是有点没事找事。公司有这个需求,我只是来实现而已。你为什么非要觉得我要搞一个最大权限?
    意思是公司派了一个需求,又只有你适合去做这个事情,你不做吗?
    不是每个公司都有专职的 DBA 和运维
    julyclyde
        11
    julyclyde  
       2023-10-17 17:07:13 +08:00
    @leegoo 你这个需求,客观上就是需要最大权限
    但是你对这个不熟悉,掌握这个权限会有风险和错误
    这才是问题
    rimutuyuan
        12
    rimutuyuan  
       2023-10-17 17:08:51 +08:00
    为什么不写在 shell 脚本去启动呢
    XiLingHost
        13
    XiLingHost  
       2023-10-17 17:11:40 +08:00   ❤️ 1
    写个 systemd 的 unit 不就好了,然后程序里把 unit 链接到/etc/systemd/system/multi-user.target.wants/
    purrgil
        14
    purrgil  
       2023-10-17 17:15:30 +08:00
    windows 下我用任务计划自启。
    还能同时做到间隔几分钟自启,防止程序被杀掉。

    linux 下对应的当然是 crontab 了。
    purrgil
        15
    purrgil  
       2023-10-17 17:20:17 +08:00
    你把程序放 Startup 里启动,那服务器每次重启是不是要进桌面才会启动?
    julyclyde
        16
    julyclyde  
       2023-10-17 17:21:26 +08:00
    @purrgil 你这个做法很腾讯
    在 linux 里用 crontab 启动后台任务(尤其是用户级 crontab )是一个极其错误的行为
    会导致后台服务使用的资源被计入用户的统计数据里去
    purrgil
        17
    purrgil  
       2023-10-17 17:31:13 +08:00
    @julyclyde 那我可理解不了。
    cron 不就是干这个用的?
    zmaplex
        18
    zmaplex  
       2023-10-17 17:36:15 +08:00 via Android
    你都有 root 了,可以写 /etc/systemd/system/ 里面,用 systemd 来管理。
    hsfzxjy
        19
    hsfzxjy  
       2023-10-17 17:47:08 +08:00 via Android
    > os.Create("/etc/init.d/start.sh") 失败

    倒是检查下错误码啊
    stephenxiaxy
        20
    stephenxiaxy  
       2023-10-17 17:51:32 +08:00
    systemd
    tairan2006
        21
    tairan2006  
       2023-10-17 18:35:13 +08:00
    你这 windows 也要写个 bat 啊,并不是依靠自身,而且你这么写不能保活。

    对比你的 bat 方案,linux 下直接创建 CronJob 最简单,用 @reboot.
    aisk
        22
    aisk  
       2023-10-17 18:40:58 +08:00
    @purrgil 不是。
    kkocdko
        23
    kkocdko  
       2023-10-17 19:04:00 +08:00
    如果是实体机,请你通过 systemd 的 service 做。由 systemd 完成自启动,自动拉起,日志管理等等。
    kkocdko
        24
    kkocdko  
       2023-10-17 19:05:55 +08:00
    emmm ,看到楼上的回复了,楼主你想怎么做就怎么做吧
    X4hB5a
        25
    X4hB5a  
       2023-10-17 19:35:00 +08:00
    liberize
        26
    liberize  
       2023-10-17 19:38:41 +08:00 via Android
    如果是桌面程序,可以在~/.config/autostart 下创建一个.desktop 文件,基本对标 windows

    如果是服务端程序,可以在/etc/systemd/system 下面创建一个.service 文件,需要 root
    julyclyde
        27
    julyclyde  
       2023-10-17 19:39:22 +08:00
    @purrgil cron 是做短任务用的
    ysc3839
        28
    ysc3839  
       2023-10-17 19:42:27 +08:00 via Android
    @liberize 没记错的话 systemd 是可以注册用户级别的服务的。
    expy
        29
    expy  
       2023-10-17 19:48:49 +08:00
    参考服务器被入侵挖矿的,用 cron 。
    kingfalse
        30
    kingfalse  
       2023-10-17 20:03:06 +08:00 via Android
    crontab ,每分钟执行一次 sh ,判断没有进程就启动,这不安全的多,兼容性极佳
    kingfalse
        31
    kingfalse  
       2023-10-17 20:04:07 +08:00 via Android
    @julyclyde 加个&不就可以了吗?
    phpfpm
        32
    phpfpm  
       2023-10-17 20:21:15 +08:00
    @julyclyde 是我在水木认识的那位大佬吗?
    ksc010
        33
    ksc010  
       2023-10-17 20:22:21 +08:00
    可以 用 supervisor
    skywalkerfc
        34
    skywalkerfc  
       2023-10-17 20:50:43 +08:00
    cron 定时任务
    systemd/init.d 后台常驻进程(更偏系统层,随 Linux 启动而启动)
    supervisor 后台常驻进程(更偏用户层,一般用来管理自己写的常驻脚本偏多)
    yanqiyu
        35
    yanqiyu  
       2023-10-17 21:15:58 +08:00
    > 我的需求是 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 没那么难。

    以及就算创建文件失败至少给点失败的信息,不然大家水晶球也水晶不出来
    SenLief
        36
    SenLief  
       2023-10-17 23:07:34 +08:00 via iPhone
    systemd.service
    voidmnwzp
        37
    voidmnwzp  
       2023-10-18 00:03:49 +08:00
    注册服务然后自启动
    pyu77
        38
    pyu77  
       2023-10-18 09:57:40 +08:00
    shell 脚本写个,然后放到 rc.local 启动就拉起来。
    想要中断后自动拉起,可以加到 crontab 定时任务。
    adoal
        39
    adoal  
       2023-10-18 10:06:04 +08:00 via iPhone   ❤️ 1
    @julyclyde 放弃助人情结,尊重草台班子(们)
    tangtang369
        40
    tangtang369  
       2023-10-18 11:27:38 +08:00
    一楼的答案就是正解 如果用 Go 的话都是用这个第三方模块来实现
    julyclyde
        41
    julyclyde  
       2023-10-18 12:18:06 +08:00
    @adoal agLee with you

    @phpfpm 是吧
    julyclyde
        42
    julyclyde  
       2023-10-18 12:22:17 +08:00
    @ysc3839 systemd 用户级别服务需要再另外运行一个 systemd 吧,还是需要用户先登录的吧

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

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

    @ksc010
    @skywalkerfc
    supervisorD 自己的启动和存活怎么保证呢?
    ysc3839
        43
    ysc3839  
       2023-10-18 13:01:29 +08:00 via Android
    @julyclyde 不需要吧,至少通过 StartTransientUnit 创建临时 service 不需要特殊权限
    julyclyde
        44
    julyclyde  
       2023-10-18 13:07:29 +08:00
    @ysc3839 StartTransientUnit 是指从 dbus 接口创建吗 user 级别的 unit 吧?
    那由哪个程序来发这个消息呢?发消息的这个程序是怎么运行起来呢?
    ysc3839
        45
    ysc3839  
       2023-10-18 13:22:39 +08:00 via Android
    @julyclyde 只是举例子说明可以免额外权限创建用户级的 service ,不是说一定要用这种方案。具体能否 enable 一个用户级的 service ,我没调查过,但我猜测是可以的。
    julyclyde
        46
    julyclyde  
       2023-10-18 13:38:29 +08:00
    @ysc3839 但是 TransientUnit 不能“下次开机”的时候自动启动吧?那东西的 unit file 根本就不存盘吧
    无法满足 OP 的需求
    ysc3839
        47
    ysc3839  
       2023-10-18 13:42:42 +08:00 via Android
    @julyclyde 我已经说了“不是说一定要用这种方案”
    gejigeji
        48
    gejigeji  
       2023-10-18 15:30:00 +08:00
    @julyclyde 进程退出后,login session 也不会退出?
    julyclyde
        49
    julyclyde  
       2023-10-18 20:06:03 +08:00
    @gejigeji 旧版本 systemd 对于大量 session 累积的情况,会无法正常清理。“理论上”进程退出之后,session 应该退出,但实际上没做到
    gejigeji
        50
    gejigeji  
       2023-10-19 22:45:07 +08:00
    @julyclyde ok, 直接/etc/crontab 应该没这个问题
    julyclyde
        51
    julyclyde  
       2023-10-20 21:55:13 +08:00
    @gejigeji 应该也会。session 是由/etc/pam.d/crond 生成的。
    不过我没实际试过……

    抛开 session 的问题不说,服务进程的“上级”是 crond 就够奇怪了,和上级是个 login shell 差不多奇怪
    alsas
        52
    alsas  
       355 天前
    systemd
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3230 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 11:46 · PVG 19:46 · LAX 04:46 · JFK 07:46
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.