개발한 서버를 ec2로 배포하는 방식은 다양하다.
elastic beanstalk을 써서 aws한테 "해 줘"를 시전할 수도 있고, docker image로 만들어서 컨테이너로 배포할 수도 있는 등 매우 다양하다.
docker로 띄운다면 eks를 쓸 수도 있을거고 ecs를 쓸 수도 있을거고 docker compose를 사용할 수도 있을거고..
더 나열하면 끝도 없으니 이 쯤하고 오늘의 주제로 넘어가자.
오늘은 ec2에 배포한 패키지를 service로 등록하여 systemd가 모니터링 하게 하고, systemctl로 start/stop 하는 과정을 다뤄보려 한다. ec2에 배포는 깃에서 클론을 받을 수도 있고 whl 패키지로 만들어 인스톨 할 수도 있는데, 이번 포스트에서는 다루지 않으려고 한다.
Service Script 작성
systemd 가 service를 모니터링하게 하기 위해서는 .service script(이하 유닛 파일)를 작성해야 하고, script 의 각 옵션에 대한 부분은 공식 문서에서 확인할 수 있다.
[Unit]
Description=Main Service
After=network.target
[Service]
Type=notify
User=ubuntu
Group=ubuntu
RuntimeDirectory=gunicorn
WorkingDirectory=/opt/main
ExecStart=/opt/main/venv/bin/gunicorn --workers=8 --worker-class=egg:meinheld#gunicorn_worker maf_core.site.wsgi:application
ExecReload=/bin/kill -s HUP $MAINPID
KillMode=mixed
TimeoutStopSec=5
PrivateTmp=true
Restart=on-failure
RestartSec=3
[Install]
Wnated=multi-user.target
편의상 service 명은 main으로 명명했고, 패키지를 다운로드하는 디렉토리역시 /opt/main 으로 했다.
유닛 파일들의 옵션들을 살펴보자.
[Unit]
스크립트의 확장자가 .service 이긴 하지만 통상적으로 unit file이라고 부른다. systemd가 모니터링 하고 있는 서비스들의 목록을 볼 때 systemctl list-units 를 사용하는 것도 같은 이유이다.
Description
unit file 에 대한 설명이다.
After
서비스의 의존성을 나타내는 부분이며, 아래의 표와 같이 After 말고도 다양한 선택지가 있다. 자세히 알고 싶다면 공식 문서를 참고하자.
예제에서는 .network.target 이 시작됐는지 체크한다.
여기서 .target 이라는 부분이 조금 생소한데, .target 은 공식문서 에 따르면 linux가 시작되면서 유닛들을 grouping 하는 데에 사용되는 systemd 의 target uni 들이라고 한다.
해당 부분에는 target 이 아닌 service 를 줄 수도 있는데, 쉽게 말해 group unit 이 아닌 개별 유닛 과 의존 관계를 맺을 수도 있다는 뜻이다.
아래와 같이 명령어를 통해 target unit list 를 전부 조회할 수 있다. target unit은 시스템의 run level 과도 관련이 있는데, 추후에 다뤄보려 한다.
systemctl list-units --type=target
UNIT LOAD ACTIVE SUB DESCRIPTION
basic.target loaded active active Basic System
cloud-config.target loaded active active Cloud-config availability
cloud-init.target loaded active active Cloud-init target
cryptsetup.target loaded active active Local Encrypted Volumes
getty.target loaded active active Login Prompts
graphical.target loaded active active Graphical Interface
local-fs-pre.target loaded active active Local File Systems (Pre)
local-fs.target loaded active active Local File Systems
multi-user.target loaded active active Multi-User System
network-online.target loaded active active Network is Online
network-pre.target loaded active active Network (Pre)
network.target loaded active active Network
nss-lookup.target loaded active active Host and Network Name Lookups
nss-user-lookup.target loaded active active User and Group Name Lookups
paths.target loaded active active Paths
remote-fs-pre.target loaded active active Remote File Systems (Pre)
remote-fs.target loaded active active Remote File Systems
slices.target loaded active active Slices
sockets.target loaded active active Sockets
sound.target loaded active active Sound Card
swap.target loaded active active Swap
sysinit.target loaded active active System Initialization
time-set.target loaded active active System Time Set
time-sync.target loaded active active System Time Synchronized
timers.target loaded active active Timers
마찬가지로, 아래와 같이 등록된 service 들도 조회할 수 있다.
systemctl list-units --type=service
UNIT LOAD ACTIVE SUB DESCRIPTION >
accounts-daemon.service loaded active running Accounts Service >
apparmor.service loaded active exited Load AppArmor profiles >
apport.service loaded active exited LSB: automatic crash report generation >
atd.service loaded active running Deferred execution scheduler >
blk-availability.service loaded active exited Availability of block devices >
cloud-config.service loaded active exited Apply the settings specified in cloud-config >
cloud-final.service loaded active exited Execute cloud user/final scripts >
cloud-init-local.service loaded active exited Initial cloud-init job (pre-networking) >
cloud-init.service loaded active exited Initial cloud-init job (metadata service crawler) >
console-setup.service loaded active exited Set console font and keymap
...
[Service]
Type
유닛 타입을 선언한다.
- simple (기본값): 유닛이 시작된 경우 즉시 systemd 는 유닛의 시작이 완료되었다고 판단한다. 다른 유닛과 통신하기 위해 소켓을 사용하는 경우 이러한 설정을 사용하면 안된다.
- forking: 자식 프로세스를 생성이 완료되는 단계까지를 systemd 가 시작이 완료되었다고 판단하게 된다. 부모 프로세스를 추적할 수 있도록 PIDFile= 필드에 PID 파일을 선언해 주어야 한다.
- oneshot: simple 과 다소 유사하지만 단일 작업을 수행하는데 적합한 타입이다. 또한 실행 이후 해당 실행이 종료되더라도 RemainAfterExit=yes 옵션을 통해 유닛이 활성화 상태로 간주할 수 있다.
- notify: simple 과 동일하다. 다만 유닛이 구동되면 systemd 에 시그널을 보낸다. 이때 시그널에 대한 내용은 libsystemd-daemon.so 에 선언 되어 있다.
- dbus: DBUS 에 지정된 BusName 이 준비될때까지 대기한다. 즉 DBUS 준비가 완료된 이후 유닛이 시작되었다고 간주한다.
User
해당 서비스를 등록할 유닉스 유저이다. root 유저로 등록하겠다면 root로 명시하면 된다. 포스팅의 예제에서는 ubuntu os 의 기본 유저인 ubuntu를 사용했다. aws linux 2 를 썼다면 기본 유저가 ec2-user 였을 것이다.
Group
유저의 그룹을 명시한다. 사실상 유닉스에서 그룹은 권한과 직결되어 있기 때문에, 서비스를 수행할 권한으로 이해해도 될 듯 하다.
WorkingDirectory
앱이 구동후 작업이 실행되는 영역의 위치, path
별도의 지정이 없으면 / 디렉토리를 작업 디렉토리로 사용한다.
ExecStart
systemctl start 시 실행할 구문으로, 이 때 uwsgi, gunicorn 처럼 설치된 명령어를 직접 사용하는 경우 설치된 절대 경로를 필요로 하기 때문에 주의해야 한다.
다중 명령어를 지원한다.
ex) ExecStart = command1; commnad2; commnad3
ExecReload
systemctl reload 시 실행할 구문으로, ExecStart와 마찬가지로 절대 경로를 필요로 한다.
ExecStop
systemctl stop 시 실행할 구문이다. 중지 방식은 KilllMode 로 지정한다.
RestartSec
재시작 명령을 수행할때 중지 이후 다시 시작하는데 대기(sleep)하는 시간을 설정한다. 기본값은 100ms 이다. 각각 min, s, ms 단위로 설정한다. 해당 설정은 Restart= 옵션이 있는 경우에만 적용된다.
TimeoutStartSec
유닛이 시작하는데 대기하는 시간을 설정한다. 기본값은 90초(90s)이다. 만일 Type=oneshot 인 경우 해당 설정이 해당 설정이 적용되지 않는다. 만일 시작 시간을 대기하지 않고 무한정 리턴값을 기다리게 설정할려면 TimeoutStartSec=0 으로 설정해 주면 된다.
TimeoutStopSec
옵션을 중지하는데 대기하는 시간을 설정한다. 기본값은 90초(90s)로 위의 TimeoutStartSec= 옵션과 동일하게 TimeoutStopSec=0 으로 설정하면 무한정 리턴값을 기다리게 된다. TimeoutStopSec 옵션에 설정된 값 안에 종료되지 않으면 SIGKILL 시그널을 보내서 강제로 종료하게 된다.
TimeoutSec
TimeoutStartSec 와 TimeoutStopSec 을 동시에 설정한다.
WatchdogSec
유닛이 시작된 이후 유닛 상태 감시(keep-alive ping)할때의 상태 값을 리턴하는데 대기하는 시간을 설정한다.
Restart 옵션이 on-failure, always 인 경우 유닛을 자동으로 재시작하게되고 이때 WatchdogSec 설정을 해주어야 한다. 기본값은 "0" 으로 유닛 상태 감시를 사용하지 않는다.
Restart
유닛이 죽었을때나 혹은 WatchdogSec 만큼의 시간 동안 응답이 없는 경우 재시작한다.
- no (기본값): 유닛을 다시 시작하지 않는다.
- on-success: 는 유닛이 정상적으로 종료되었을 때만 재시작한다. 종료시에 0 을 리턴하여 종료되었거나 SIGHUP, SIGINT, SIGTERM, SIGPIPE 등과 같은 시그널 또는 SuccessExitStatus 설정에서 지정된 리턴 코드 목록에 따른 시그널에 대해서 모두 성공으로 인식해 재시작을 하게 된다.
- on-failure: 유닛이 비정상적으로 종료되었을때 재시작한다. 리턴값이 "0" 이 아닌 경우, core dump 와 같이 비정상적인 시그널을 받고 종료된 경우, 타임 아웃값내 응답이 없는 경우 등일때 재시작 하게 된다.
- on-watchdog: WatchdogSec 에 설정된 시간내 응답이 없는 경우에만 재시작 한다.
- on-abort: 지정되지 않은 리턴값을 받은 경우 재시작을 한다.
- always: 종료 상태 등과 무관하게 무조건 재시작한다.
여담이지만, Restart 옵션은 잘 생각해서 줘야 한다. ec2 내부에서 vpn 서비스 설정을 잘못 주어 인스턴스 접속이 불가했던 적이 있는데, Restart=always 로 옵션을 줘버려서 인스턴스를 재시작 해도 접속을 할 수가 없었다...
[Install]
Alias
유닛의 별칭을 지정한다. systemctl enable 명령어를 통해서 별칭으로 생성할 수 있다. 별칭은 유닛 파일 확장자(유닛 타입)를 가지고 있어야 한다.
ex) httpd.service 의 Alias=apache.service
WantedBy, RequiredBy
systemctl enable 명령어로 유닛을 등록할때 등록에 필요한 유닛을 지정한다. 해당 유닛을 등록하기위한 종속성 검사 단계로 보면 된다. 따라서 해당 설정은 [Unit] 섹션의 Wants 와 Requires 옵션과 관계 있다.
Also
systemctl enable, systemctl disable 로 유닛을 등록하거나 해제할때 다른 유닛 또한 같이 등록, 해제를 하도록 구성할 수 있다.
References
https://www.freedesktop.org/software/systemd/man/systemd.service.html
systemd.service
Similarly to the oneshot services, there are sometimes units that need to execute a program to set up something and then execute another to shut it down, but no process remains active while they are considered "started". Network configuration can sometimes
www.freedesktop.org
https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=forioso&logNo=220890354096
[systemctl] 시스템서비스
systemctl 은 /etc/systemd/system/ 폴더에 서비스 설정파일이 생성된다. systemctl daemon-reload s...
blog.naver.com
https://fmd1225.tistory.com/93
systemd unit 등록 관련 옵션 정리
- RHEL 7 의 OS 적인 가장 큰 변화는 3.x 커널을 사용한다는 점(물론 2.6.x 커널에서 큰 차이가 있는 것은 아니다.) 그리고 정통적인 init 데몬에서 systemd 데몬으로 변경이 되었다는 점이다. systemd 에 대
fmd1225.tistory.com
'기타' 카테고리의 다른 글
RabbitMQ - Cluster 적용 (0) | 2023.07.07 |
---|---|
웹 개발자를 위한 대규모 서비스를 지탱하는 기술 서평 (0) | 2023.06.19 |
인프라 - Docker Compose 로 무중단 배포하기(blue-green) (0) | 2023.05.06 |
세션, 쿠키, 토큰 (0) | 2021.10.04 |
xAPI 찍먹하기 (0) | 2021.09.25 |