본문 바로가기
서버 인프라 실무

systemd 서비스로 스프링부트 배포: 로그 분리·자동 재시작까지

by yamoojin83 2025. 10. 7.

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) 적용

👉 2편: UFW 방화벽 실전 규칙

👉 3편: systemd 서비스로 스프링부트 배포

👉 4편: Tomcat 10 설치+튜닝 체크리스트

👉 5편: Gradle 빌드 최적화로 빌드 50% 줄이기

👉 6편: Spring Security 6 JWT 로그인/리프레시 토큰

👉 7편: JPA N+1 완전 정복: 자동 감지부터 fetch join·EntityGraph·batch_size 실전 해결 전략

👉 8편: Docker로 PostgreSQL 운영(백업/복구/업그레이드)

👉 9편: Micrometer+Prometheus+Grafana 대시보드

👉 10편: Testcontainers로 DB 통합테스트