Приложение Java как сервис systemd

Я пытаюсь запустить Java-приложение как системную службу в CentOS7. Банку следует запускать с конкретным пользователем: appuser. У меня есть сценарий оболочки, который запускает банку с помощью следующей команды. Весь скрипт намного больше, потому что он также обрабатывает остановку, перезапуск и статус, но это начальная часть:

servicename = "myservice"
user = "appuser"
pid_file = "/var/run/$servicename.pid"
get_pid_from_file() {
  cat "$pid_file"
}
get_pids() {
  (ps -ef | grep myjar | grep $user | grep -v grep | awk '{print $2}')
}

is_running() {
  ! [ -z "`get_pids`" ] || ([ -f "$pid_file" ] && ps `get_pid_from_file` > /dev/null 2>&1)
}
case "$1" in
  start)
    if is_running; then
      echo "Already started"
    else
      case "$2" in
        *)
    su -s /bin/sh $user -c "cd /app/myworkingdir ; java -jar myjar.jar >> /var/log/systemout.log 2>> /var/log/systemerr.log" &
    pid=`ps -ef | grep myjar | grep $user | grep -v grep | awk '{print $2}' | tail -1`
    echo $pid
    echo $pid > $pid_file

Когда я запускаю сценарий из командной строки, он запускает банку и записывает файл pid. Я использую хвост в команде, чтобы получить PID, потому что на самом деле у меня есть 3 процесса: su, / bin / sh и фактическая команда java -jar.

Теперь у меня также есть сценарий systemctl в /etc/systemd/system/multi-user.target.wants/myservice.service, который выглядит так:

[Unit]
Description=myservice
After=syslog.target
After=network.target

[Service]
Type=simple

WorkingDirectory=/app/myworkingdir/run

PIDFile=/var/run/myservice.pid
ExecStart=/app/myworkingdir/run/myscript.sh start
ExecStop=/app/myworkingdir/run/myscript.sh stop

User=appuser
Group=appgrp

Restart=always
RestartSec=30
StartLimitInterval=60
StartLimitBurst=5
TimeoutStartSec=30

LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

Проблема в том, что systemctl start myservice.service не запускает службу правильно.

Я вижу это, когда запускаю journeyctl -xe:

May 21 13:03:23 myserver.com systemd[1]: Starting my service...
-- Subject: Unit myservice.service has begun start-up
-- Defined-By: systemd
-- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
--
-- Unit myservice.service has begun starting up.
May 21 13:03:23 myserver.com polkitd[619]: Unregistered Authentication Agent for unix-process:19329:16
May 21 13:03:23 myserver.com myscript.sh[19335]: Already started
May 21 13:03:24 myserver.com myscript.sh[19345]: Stopping myscript.sh..

А вот запись в / var / log / messages:

[root@myserver run]# systemctl start myservice.service
May 21 13:34:00 myserver systemd: myservice.service holdoff time over, scheduling restart.
May 21 13:34:00 myserver systemd: Started myservice.
May 21 13:34:00 myserver systemd: Starting myservice...
[root@myserver run]# May 21 13:34:00 ctor-app52 myscript.sh: Already started
May 21 13:34:00 myserver denver.sh: Stopping myscript.sh..
May 21 13:34:31 myserver systemd: myservice.service holdoff time over, scheduling restart.
May 21 13:34:31 myserver systemd: Started myservice.
May 21 13:34:31 myserver systemd: Starting myservice...
May 21 13:34:31 myserver myscript.sh: Already started
May 21 13:34:31 myserver myscript.sh: Stopping myscript.sh..
May 21 13:35:01 myserver systemd: Started Session 122559 of user root.
May 21 13:35:01 myserver systemd: Starting Session 122559 of user root.
May 21 13:35:01 myserver su: (to appuser) root on none
May 21 13:35:01 myserver systemd: LPdenver.service holdoff time over, scheduling restart.
May 21 13:35:01 myserver systemd: Started myservice.
May 21 13:35:01 myserver systemd: Starting myservice...
May 21 13:35:01 myserver myscript.sh: Already started
May 21 13:35:01 myserver myscript.sh: Stopping myscript.sh..
May 21 13:35:31 myserver systemd: myservice.service holdoff time over, scheduling restart.
May 21 13:35:31 myserver systemd: Started myservice.
May 21 13:35:31 myserver systemd: Starting myservice...
May 21 13:35:31 myserver myscript.sh: Already started
May 21 13:35:31 myserver myscript.sh: Stopping myscript.sh..
May 21 13:36:01 myserver systemd: myservice.service holdoff time over, scheduling restart.
May 21 13:36:01 myserver systemd: Started myservice.
May 21 13:36:01 myserver systemd: Starting myservice...
May 21 13:36:01 myserver myscript.sh: Already started
May 21 13:36:02 myserver myscript.sh: Stopping myscript.sh..

Что я делаю неправильно?

unix.stackexchange.com/a/437461/5132
JdeBP 13.11.2018 19:43
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
1
2 573
1

Ответы 1

Вы указываете пользователя в своем файле .service, поэтому вам не нужно выполнять какие-либо действия с su в своем скрипте.

Замените это:

su -s /bin/sh $user -c "cd /app/myworkingdir ; java -jar myjar.jar >> /var/log/systemout.log 2>> /var/log/systemerr.log"

с этим:

cd /app/myworkingdir
java -jar myjar.jar >> /var/log/systemout.log 2>> /var/log/systemerr.log"

Кроме того, в вашем сценарии я вижу еще две проблемы:

  • Вы просматриваете таблицу процессов, чтобы найти PID для своей службы. Это может привести к сбою, если есть другой запущенный процесс с командной строкой, содержащей те же символы (система может в конечном итоге выбрать неправильный процесс для завершения). echo $!>$pid_file сразу после запуска java - более безопасный способ сделать это.

  • Тип сервиса - simple, но ваш скрипт разветвляет его как отдельный процесс, а затем возвращает. Это запутает systemd, и ваша служба не запустится.

И то, и другое может быть легко решить. Я предполагаю, что вам нужен PID только для остановки службы, и это так же просто, как отправить ему SIGINT. В этом случае вы можете воспользоваться тем фактом, что в отсутствие ExecStop systemd просто отправит SIGINT процессу службы, чтобы остановить его.

  • Отбросьте амперсанд после вызова java и вместо этого добавьте к нему префикс exec. Таким образом, java-процесс будет рассматриваться systemd как демон-процесс.

  • Отбросьте магию PID после вызова java вообще.

  • В файле .service удалите запись ExecStop.

  • Вместо этого также в [Service] добавьте SuccessExitStatus=143. (При завершении с сигналом JVM выйдет с ненулевым статусом выхода, а именно 128 плюс сигнал. По умолчанию systemd обрабатывает статус выхода 143 как сбой; эта запись сообщит systemd, что 143 означает постепенный выход.)

Вы можете сделать еще один шаг и полностью отказаться от скрипта:

  • Укажите командную строку java как ExecStart
  • Передайте полный путь к двоичному файлу java (как сообщает which java)
  • Отбросьте перенаправления: по умолчанию systemd перенаправляет stdout и stderr в журнал. (Это также можно настроить в файле .service.)

Другие вопросы по теме