systemd 서비스로 스프링부트 배포: 로그 분리·자동 재시작까지
SSH로 접속해 수동으로 java -jar를 띄우면 재부팅/장애 상황에 취약합니다. systemd 서비스로 등록하면 부팅 자동 시작, 죽으면 재시작이 보장되고, 로그도 체계적으로 남길 수 있습니다. 이 글은 Ubuntu 24.04 기준으로 전용 계정, 서비스 유닛, 로그 분리, 재배포 흐름까지 한 번에 정리합니다.
1) 전용 계정/디렉터리
sudo adduser --system --no-create-home --group app
sudo mkdir -p /opt/app/myservice /var/log/myservice
sudo chown -R app:app /opt/app/myservice /var/log/myservice
2) 실행 JAR & 환경 변수
JAR와 환경 파일을 배치합니다.
# 배포 예시
sudo cp build/libs/myservice-1.0.0.jar /opt/app/myservice/app.jar
sudo tee /etc/myservice.env > /dev/null <<'EOF'
JAVA_OPTS="-Xms256m -Xmx512m -XX:+UseG1GC"
SPRING_PROFILES_ACTIVE=prod
SERVER_PORT=8080
EOF
sudo chown root:root /etc/myservice.env
sudo chmod 0640 /etc/myservice.env
3) systemd 서비스 유닛
sudo tee /etc/systemd/system/myservice.service > /dev/null <<'EOF'
[Unit]
Description=My Spring Boot Service
After=network-online.target
Wants=network-online.target
[Service]
User=app
Group=app
WorkingDirectory=/opt/app/myservice
EnvironmentFile=/etc/myservice.env
ExecStart=/usr/bin/env bash -c 'exec /usr/bin/java $JAVA_OPTS -jar app.jar'
SuccessExitStatus=143
Restart=always
RestartSec=5
# 파일 디스크립터 여유
LimitNOFILE=65535
# (선택) 파일 로그로 분리하려면 아래 두 줄 사용 (Ubuntu 24.04 systemd에서 지원)
# StandardOutput=append:/var/log/myservice/app.out.log
# StandardError=append:/var/log/myservice/app.err.log
# journald만 쓴다면 생략(권장: journalctl로 열람)
# StandardOutput=journal
# StandardError=journal
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now myservice
sudo systemctl status myservice --no-pager
4) 로그 보기
journald를 쓸 경우:
journalctl -u myservice -f
파일로 분리했다면 /var/log/myservice/*.log 로테이션을 설정합니다.
sudo tee /etc/logrotate.d/myservice > /dev/null <<'EOF'
/var/log/myservice/*.log {
size 50M
rotate 7
compress
missingok
copytruncate
}
EOF
5) 재배포(무중단에 근접하게)
# 새 버전 업로드
sudo cp build/libs/myservice-1.0.1.jar /opt/app/myservice/app.jar
# 구성 변경 반영
sudo systemctl daemon-reload
# 끊김 최소화(짧은 다운타임)
sudo systemctl restart myservice
무중단이 필요하면 Nginx/로드밸런서에서 Blue-Green/Rolling을 구성하세요.
6) 헬스체크 & 리버스 프록시
애플리케이션에 /actuator/health가 있다면, Nginx 프록시에서 확인하도록 설정합니다.
sudo tee /etc/nginx/sites-available/myservice-proxy > /dev/null <<'EOF'
upstream myservice_upstream {
server 127.0.0.1:8080;
keepalive 32;
}
server {
listen 80;
server_name api.example.com;
location /healthz { proxy_pass http://myservice_upstream/actuator/health; }
location / {
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://myservice_upstream;
}
}
EOF
sudo ln -s /etc/nginx/sites-available/myservice-proxy /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
7) 점검 체크리스트
- 서비스 자동 시작:
systemctl is-enabled myservice - 비정상 종료 후 Restart=always로 자동 복구
- 로그 열람/로테이션 정상
- 환경변수/프로필 분리(
/etc/myservice.env) - 권한/소유자: 실행 디렉터리/로그 디렉터리
app:app
👉 1편: Ubuntu 24.04에서 Nginx로 무료 SSL(HTTPS) 적용
👉 5편: Gradle 빌드 최적화로 빌드 50% 줄이기
👉 6편: Spring Security 6 JWT 로그인/리프레시 토큰
👉 7편: JPA N+1 완전 정복: 자동 감지부터 fetch join·EntityGraph·batch_size 실전 해결 전략
👉 8편: Docker로 PostgreSQL 운영(백업/복구/업그레이드)
'서버 인프라 실무' 카테고리의 다른 글
| JPA N+1 완전 정복: 자동 감지부터 fetch join·EntityGraph·batch_size 실전 해결 전략 (0) | 2025.10.09 |
|---|---|
| Gradle 빌드 캐시/병렬/Configuration Cache로 빌드 50% 줄이기 (0) | 2025.10.08 |
| Tomcat 10 운영자 튜닝 가이드(커넥터·스레드풀·압축·헤더 최적화) (0) | 2025.10.07 |
| UFW 방화벽 실전 규칙: SSH 잠그고, 웹만 열고, 포트스캔 막기 (0) | 2025.10.06 |
| Ubuntu 24.04에서 Nginx로 무료 SSL(HTTPS) 적용(이중 인증서 자동갱신) (0) | 2025.10.06 |