Systemd: 서비스/소켓을 올바르게 다시 시작하는 방법

Systemd: 서비스/소켓을 올바르게 다시 시작하는 방법

Django와 Gunicorn/Uvicorn을 사용하는 매우 간단한 웹 서비스가 있습니다.

foo.service

[Unit]
Description=Foo service
Requires=foo.socket
After=network.target

[Service]
User=foo
Group=www-data
Restart=on-failure
WorkingDirectory=/var/lib/foo/current/backend
ExecStart=/var/lib/foo/.local/bin/poetry run gunicorn \
--env DJANGO_SETTINGS_MODULE=foo.settings \
--capture-output \
--log-level info \
--bind unix:/run/foo.sock \
--worker-class uvicorn.workers.UvicornWorker \
--workers 4 \
foo.asgi:application

[Install]
WantedBy=multi-user.target

foo.socket

[Unit]
Description=Foo socket
[Socket]
ListenStream=/run/foo.sock
[Install]
WantedBy=sockets.target

서비스를 활성화하고 시작했습니다. 애플리케이션을 재배포할 때 애플리케이션을 오프라인 상태로 유지해야 하는 동안 데이터베이스를 마이그레이션하고 다른 작업을 수행합니다. 하지만 내가 발행할 때:

sudo systemctl restart foo.service

이 메시지를 받았습니다

Warning: Stopping foo.service, but it can still be activated by:
  foo.socket

소켓을 다시 시작해야 합니까? 서비스를 비활성화하고 소켓만 활성화하시겠습니까? (이 소켓은 nginx에서 사용됩니다.) 여기서 가장 좋은 방법은 무엇입니까? 데이터베이스를 마이그레이션할 때 소켓을 통해 서비스가 활성화되는 것을 원하지 않습니다.

답변1

여기에는 세 가지 옵션이 있습니다.

  1. 두 장치를 함께 시작/중지합니다. 이 작업을 수행해야 한다는 점을 기억해야 하므로 이는 최선의 솔루션은 아닙니다.
sudo systemctl stop foo.{service,socket}
  1. 관리 서비스만 가능합니다. 이를 위해서는 다음이 필요합니다.
    • [Install]소켓 부분을 내려 놓습니다 . 서비스가 이미 Requires=소켓이므로 이는 필요하지 않습니다. 서비스가 시작되면 소켓도 시작됩니다.
    • PartOf=foo.service소켓 섹션에 추가되었습니다 [Unit]. 이는 중지되거나 다시 시작될 때 foo.service명령이 소켓에 전파된다는 것을 의미합니다.
# foo.service
[Unit]
Requires=foo.socket
After=network.target

[Service]
...

[Install]
WantedBy=multi-user.target

#foo.socket
[Unit]
PartOf=foo.service
[Socket]
ListenStream=/run/foo.sock

이제 가능하며 sudo systemctl {restart,stop,start} foo.service소켓은 항상 동기화됩니다.

  1. 소켓만 관리합니다. 데이터가 소켓에 도착할 때만 서비스가 실행되기 때문에 이 옵션을 선호합니다. 이것을하기 위해:
    • Requires=서비스에서 제거되었습니다. 서비스를 직접 시작하지 않기 때문에 이것이 필요하지 않습니다.
    • [Install]서비스에서 이 부분을 제거하세요. 대신 소켓을 사용하겠습니다.
    • PartOf=foo.socket서비스 섹션에 추가되었습니다 [Unit]. 애플리케이션이 EOFstdin 또는 stdout에서 종료되는 경우 이는 필요하지 않을 수 있습니다.
    • 서비스 섹션 StandardInput=socket에 추가하세요 . [Service]이는 꼭 필요한 것은 아니지만 systemctl start foo.service소켓이 시작되지 않으면 실패합니다.
# foo.service
[Unit]
PartOf=foo.socket
After=network.target

[Service]
StandardInput=socket
...


#foo.socket
[Socket]
ListenStream=/run/foo.sock
[Install]
WantedBy=sockets.target

관련 정보