Приложение Go запускается как служба systemd

Мы запускаем приложение Golang, которое внутри запускает модуль автообновления для получения обновлений по воздуху. Во время нового обновления модуль автообновления загружает новую версию из s3 и вызывает bash-скрипт автообновления, находящийся в том же рабочем каталоге, что и исполняемый файл. Шаги, выполняемые сценарием автообновления bash, объясняются с точки зрения управления процессами, выполняемыми с использованием systemd и без него.

Выполнение без Systemd

  1. Убивает запущенное в данный момент приложение golang через PID
  2. Запускает недавно загруженный двоичный файл golang.
  3. Новая версия предоставляет API проверки работоспособности, который вызывается сценарием, чтобы убедиться, что эта версия работоспособна.
  4. Если не исправен, выполняется откат. Новая версия останавливается, а старая версия запускается.

В golang код выполнения скрипта написан таким образом, что при вызове скрипта автообновления он исключается из жизненного цикла приложения golang. то есть сценарий bash (дочерний процесс) продолжает выполнение даже после того, как родитель (приложение golang) будет убит. Он отлично работает при запуске из GoLand IDE.

Проблема: выполнение через Systemd

Нам нужна была более чистая система для управления функциями запуска, остановки и перезапуска при сбое. Поэтому мы решили запустить приложение как службу systemd. Шаги такие же, как и выше, но выполняются с использованием systemctl.

  1. Убивает запущенное в данный момент приложение golang: «systemctl stop goapp.service»
  2. Обновляет службу systemd с новым путем к исполняемому файлу: «systemctl daemon-reload».
  3. Перезапускает службу systemd: «systemctl перезапускает goapp.service»
  4. Если не исправен, выполняется откат. Новая версия останавливается, файл службы systemd обновляется более старой версией и запускается более старая версия.

При выполнении приложения через systemd скрипт завершает работу, как только служба systemctl останавливается с помощью команды «sudo systemctl stop goapp.service» на шаге 1, упомянутом выше. Это означает, что жизненный цикл скрипта, выполняемого приложением golang, явно связан с жизненным циклом службы systemd. Как я могу отделить его от службы systemd?

Служебный файл systemd

[Unit]
Description=Goapp
After=docker.service
Requires=docker.service
Requires=docker-mysql.service
Requires=docker-redis.service
StartLimitInterval=200
StartLimitBurst=5

[Service]
User=root
Environment=AWS_SHARED_CREDENTIALS_FILE=/home/username/.aws/credentials
Restart=on-failure
RestartSec=30
WorkingDirectory=/home/username/go/src/goapp-v2.0.0
ExecStart=/home/username/go/src/goapp-v2.0.0/goexecutable --autoupdate=true

[Install]
WantedBy=multi-user.target

Раздел кода Golang, который вызывает башскрипт автообновления

func scriptExecutor(argsliceString []string, remoteVersion *semver.Version, localVersion *semver.Version) {

newVersion := fmt.Sprint(remoteVersion)
previousVersion := fmt.Sprint(localVersion)
argslice := append(argsliceString, newVersion, previousVersion)
scriptParams := append([]string{"./autoupdate-script.sh"}, argslice...)
Info("Autoupdater - New version ", newVersion)
Info("Autoupdater - Existing Version ", previousVersion)
Info("Autoupdater - Executing shell script to upgrade go app.Passing parameters ", scriptParams) // ./autoupdate-script.sh goexecutable 7.1.0 7.0.0
cmd := exec.Command("sudo", scriptParams...)
err := cmd.Start()
if err!=nil{
    Info(err)
}
cmd.Process.Release()

}

Сообщения о том, «как запустить скрипт в Golang и отключить/отсоединить его», были опубликованы, но не удалось найти никаких сообщений по этому типу проблемы. Пожалуйста, помогите мне решить проблему или поправьте меня, если есть какие-либо ошибки в моем понимании.


person achilles    schedule 09.07.2019    source источник
comment
Итак, ваш вопрос просто в том, как я могу отделить его от сферы действия службы systemd ??   -  person Flimzy    schedule 09.07.2019
comment
@Flimzy Да, но я чувствовал, что важно подробно остановиться на этом вопросе.   -  person achilles    schedule 09.07.2019


Ответы (1)


вызывает скрипт автообновления bash, находящийся в том же рабочем каталоге, что и исполняемый файл.

Я бы рекомендовал запустить его с systemd-run. Выдержка из справочной страницы:

Он будет работать в чистой и автономной среде выполнения.

person Fabian    schedule 09.07.2019
comment
systemd-run заставляет меня использовать абсолютные пути в сценарии, и я чувствую, что это неправильный путь. Кажется, у него нет опции --working-dir, такой как systemctl - person achilles; 10.07.2019
comment
--working-directory документирован на странице руководства и, похоже, не работает, по крайней мере, не в моем случае. Вы можете указать скрипту путь к текущему рабочему каталогу в качестве аргумента и указать его там, прежде чем делать что-либо еще. - person Fabian; 10.07.2019
comment
Фабиан спасибо за решение. systemd-run решает проблему, но имеет несколько недостатков. В настоящее время я изучаю, как я могу перенести журналы модуля systemd-run и службы systemctl в один и тот же модуль. - person achilles; 15.07.2019
comment
@achilles Я не знаю, как бы ты связал их вместе. Но другое решение может заключаться в том, чтобы сделать средство обновления доминирующим процессом, который запускает приложение Golang и отправляет ему сигнал прерывания, если оно должно завершить работу. Затем подождите, пока он выключится, обновите двоичный файл и запустите его снова, все из модуля systemd средства обновления. Или вы можете попробовать KillMode для программа обновления не умирает? - person Fabian; 15.07.2019
comment
Фабиан Я смог связать их вместе с помощью команды: journalctl _SYSTEMD_UNIT=cantizconnect.service + SYSLOG_IDENTIFIER=cantizconnect - person achilles; 16.07.2019
comment
@ахиллес хорош! - person Fabian; 16.07.2019