프로세스·서비스 관리 (systemd)
3. 코드 예제
예제 1: PID·백그라운드·kill — 01_process.sh 발췌
echo "PID=$ PPID=$PPID"
sleep 30 & # 백그라운드
BG=$!
jobs # [1]+ Running sleep 30 &
kill "$BG" # TERM
sleep 1
kill -0 "$BG" 2>/dev/null && echo "살아 있음" || echo "종료됨"
wait "$BG"; echo "종료 코드=$?"PID=2061 PPID=2058
[1]+ Running sleep 30 &
종료됨
종료 코드=143kill -0 은 신호를 보내지 않고 프로세스 존재만 확인합니다. 종료 코드 143 이 TERM(15) 으로 끝났다는 증거입니다.
예제 2: trap 으로 신호 처리 — 01_process.sh 발췌
cat > worker.sh <<'EOF'
trap 'echo "TERM 받음: 정리하고 종료"; exit 0' TERM
echo "worker 시작 PID=$"
while true; do sleep 1; done
EOF
bash worker.sh &
W=$!
sleep 1; kill "$W"; wait "$W"; echo "worker 종료 코드=$?"worker 시작 PID=2076
TERM 받음: 정리하고 종료
worker 종료 코드=0trap 이 자바의 shutdown hook 에 해당합니다. 신호를 잡아 정리한 뒤 exit 0 으로 끝내면 종료 코드가 0 이 됩니다. 07 셸 스크립트 레슨에서 trap 을 더 다룹니다.
예제 3: 유닛 파일 — myapp.service
[Unit]
Description=MyApp Spring Boot service
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=myapp
Group=myapp
WorkingDirectory=/opt/myapp
EnvironmentFile=-/opt/myapp/conf/env
ExecStart=/usr/bin/java $JAVA_OPTS -jar /opt/myapp/current/app.jar
SuccessExitStatus=143
Restart=on-failure
RestartSec=5
TimeoutStopSec=30
LimitNOFILE=65536
StandardOutput=append:/var/log/myapp/stdout.log
StandardError=inherit
[Install]
WantedBy=multi-user.targetEnvironmentFile 의 env 파일에는 JAVA_OPTS=-Xms512m -Xmx1g 처럼 키=값 만 적습니다. export 나 따옴표 이스케이프는 셸 문법이라 동작이 다릅니다. 이 파일은 실행 환경이 없어 문법 검토만 했고, 서버에서는 systemd-analyze verify myapp.service 로 검사합니다.
예제 4: 서비스 등록부터 확인까지
sudo cp myapp.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now myapp
systemctl status myapp --no-pager
journalctl -u myapp -n 20 --no-pager
curl -s localhost:8080/actuator/health● myapp.service - MyApp Spring Boot service
Loaded: loaded (/etc/systemd/system/myapp.service; enabled)
Active: active (running) since Thu 2026-09-10 09:00:01 KST; 5s ago
Main PID: 12345 (java)
Tasks: 41
Memory: 412.0Mstatus 의 Loaded 줄에 enabled 가 보이면 부팅 시 자동 시작이 켜진 것입니다. Active 가 failed 면 바로 아래 최근 로그 줄에서 원인을 봅니다.