# 배포 가이드 (EC2 + systemd + Jenkins) slack-notifier 를 **EC2(리눅스)** 에 단일 정적 바이너리로 올리고, **systemd** 로 운영하며, **Jenkins** 로 빌드·배포를 자동화한다. 도커 레지스트리 불필요(바이너리 직접 배포). ``` [git push main] → Jenkins (golang:1.26 컨테이너) → go test/build → scp 바이너리 → EC2 → systemctl restart slack-notifier [Gitea/Notion] ──webhook(HTTPS)──→ Caddy(:443) ──→ slack-notifier(:8000) ──→ Slack ``` --- ## 1. EC2 최초 1회 셋업 ### 1-1. 설치 경로 / 환경파일 ```bash sudo mkdir -p /opt/slack-notifier/{logs,data} sudo chown -R $USER:$USER /opt/slack-notifier # Jenkins 배포 유저가 쓸 수 있게(또는 sudo 권한) # 비밀값/설정 — 서버에만 두고 절대 커밋하지 않음 sudo vi /opt/slack-notifier/.env.prod # SLACK_BOT_TOKEN=xoxb-... # DEFAULT_SLACK_CHANNEL=C... (브로드캐스트 채널, GITEA_BROADCAST=on 일 때) # GITEA_BROADCAST=off # MONITOR_SLACK_CHANNEL=C... (에러 알림) # GITEA_WEBHOOK_SECRET=... # NOTION_VERIFICATION_TOKEN=... # NOTION_API_TOKEN=... # LOG_RETENTION_DAYS=7 ``` > systemd 서비스는 `-env prod` 로 실행되어 `.env.prod` 를 읽고, 로그는 `/opt/slack-notifier/logs/app-YYYY-MM-DD.log` 로 날짜별 회전된다. ### 1-2. systemd 서비스 등록 ```bash sudo cp deploy/slack-notifier.service /etc/systemd/system/slack-notifier.service sudo systemctl daemon-reload sudo systemctl enable --now slack-notifier sudo systemctl status slack-notifier ``` 서비스는 `/opt/slack-notifier/slack-notifier` 바이너리를 실행한다(첫 배포 전이면 아직 없음 → Jenkins 첫 배포 후 정상 기동). ### 1-3. HTTPS 리버스 프록시(Caddy) 웹훅은 공개 HTTPS 가 필수. Caddy 가 Let's Encrypt 인증서를 자동 발급한다. ```bash sudo cp deploy/Caddyfile /etc/caddy/Caddyfile sudo vi /etc/caddy/Caddyfile # your-domain.com 을 실제 도메인으로 교체 sudo systemctl restart caddy ``` - 도메인 A 레코드 → EC2 퍼블릭 IP - 보안그룹 인바운드 **80, 443** 개방(ACME 검증 + 웹훅 수신) - 웹훅 등록 주소: `https://your-domain.com/webhooks/{gitea,notion}` --- ## 2. Jenkins 셋업 ### 2-1. 플러그인 / Go 도구 - 플러그인: **Go Plugin**, **SSH Agent** - **Manage Jenkins → Tools → Go installations** 에서 Go 추가: - Name: **`go-1.26`** (Jenkinsfile 의 `GO_TOOL` 과 일치, 다르면 Jenkinsfile 수정) - "Install automatically" 로 1.26.x 선택(또는 에이전트에 설치된 Go 경로 지정) - 컨테이너 없이 에이전트의 네이티브 Go 로 빌드 → 이미지 풀/디스크 오버헤드 없음 ### 2-2. 자격증명(SSH 키) - Jenkins → Credentials → **SSH Username with private key** 추가 - Username: EC2 SSH 유저(`ubuntu` 등) - Private key: EC2 접속 키(.pem) - **ID: `slack-notifier-ec2`** (Jenkinsfile 의 `SSH_CRED_ID` 와 일치, 다르면 Jenkinsfile 수정) - 배포 유저는 `/opt/slack-notifier` 쓰기 + `systemctl restart slack-notifier` 가능해야 함 (sudoers 에 무암호 허용 권장): ``` ubuntu ALL=(root) NOPASSWD: /bin/systemctl restart slack-notifier, /bin/systemctl is-active slack-notifier, /bin/mv, /bin/mkdir, /bin/chmod ``` ### 2-3. 파이프라인 잡 - **Pipeline script from SCM** → 이 저장소 → `Jenkinsfile` - 파라미터(첫 실행 시 생성됨): - `DEPLOY_HOST` = EC2 DNS/IP (비우면 빌드·테스트만, 배포 스킵) - `DEPLOY_USER` = `ubuntu`(또는 `ec2-user`) - `APP_DIR` = `/opt/slack-notifier` - `ARCH` = `arm64`(Graviton/t4g) 또는 `amd64`(x86) ← **인스턴스 아키텍처와 반드시 일치** 배포는 **main 브랜치 + DEPLOY_HOST 지정** 시에만 수행된다. ### 2-4. 파라미터 변경 시 (stale 가드) Jenkins 의 `parameters` 는 변경해도 **1빌드 늦게** 등록된다(step/environment 는 즉시 반영). 그 사이 옛 파라미터로 빌드·배포되는 사고를 막기 위해 `Guard: params sync` 스테이지가 있다. `parameters {}` 를 바꿀 때 규칙: 1. 파라미터를 수정하고 2. **`parameters` 의 `PARAMS_VERSION` 기본값**과 **`environment.PARAMS_VERSION`** 을 **둘 다 +1** 3. 커밋/푸시 → 첫 빌드는 `Guard` 에서 **의도적으로 실패**(파라미터 재등록만 됨) → **한 번 더 빌드**하면 정상 진행 즉 "파라미터가 실제로 적용된 빌드"에서만 배포가 일어나도록 강제된다. --- ## 3. 배포 동작 / 롤백 - 무중단 교체: 새 바이너리를 임시 전송 후 **같은 파일시스템에서 rename** 으로 교체(실행 중 `ETXTBSY` 회피) → `systemctl restart`. - 로그 확인: `journalctl -u slack-notifier -f` 또는 `tail -f /opt/slack-notifier/logs/app-$(date +%F).log` - 롤백: 이전 빌드의 바이너리로 다시 배포(Jenkins "Rebuild" 또는 이전 커밋으로 빌드). 필요하면 배포 전 `cp slack-notifier slack-notifier.bak` 단계를 추가해도 됨. --- ## 4. 수동 배포(참고, Jenkins 없이) ```bash make build-linux ARCH=arm64 # 정적 바이너리 생성 scp slack-notifier ubuntu@EC2:/tmp/sn.new ssh ubuntu@EC2 'sudo mv /tmp/sn.new /opt/slack-notifier/slack-notifier && sudo systemctl restart slack-notifier' ```