Мы запускаем приложение Golang, которое внутри запускает модуль автообновления для получения обновлений по воздуху. Во время нового обновления модуль автообновления загружает новую версию из s3 и вызывает bash-скрипт автообновления, находящийся в том же рабочем каталоге, что и исполняемый файл. Шаги, выполняемые сценарием автообновления bash, объясняются с точки зрения управления процессами, выполняемыми с использованием systemd и без него.
Выполнение без Systemd
- Убивает запущенное в данный момент приложение golang через PID
- Запускает недавно загруженный двоичный файл golang.
- Новая версия предоставляет API проверки работоспособности, который вызывается сценарием, чтобы убедиться, что эта версия работоспособна.
- Если не исправен, выполняется откат. Новая версия останавливается, а старая версия запускается.
В golang код выполнения скрипта написан таким образом, что при вызове скрипта автообновления он исключается из жизненного цикла приложения golang. то есть сценарий bash (дочерний процесс) продолжает выполнение даже после того, как родитель (приложение golang) будет убит. Он отлично работает при запуске из GoLand IDE.
Проблема: выполнение через Systemd
Нам нужна была более чистая система для управления функциями запуска, остановки и перезапуска при сбое. Поэтому мы решили запустить приложение как службу systemd. Шаги такие же, как и выше, но выполняются с использованием systemctl.
- Убивает запущенное в данный момент приложение golang: «systemctl stop goapp.service»
- Обновляет службу systemd с новым путем к исполняемому файлу: «systemctl daemon-reload».
- Перезапускает службу systemd: «systemctl перезапускает goapp.service»
- Если не исправен, выполняется откат. Новая версия останавливается, файл службы 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 и отключить/отсоединить его», были опубликованы, но не удалось найти никаких сообщений по этому типу проблемы. Пожалуйста, помогите мне решить проблему или поправьте меня, если есть какие-либо ошибки в моем понимании.