# 배포 가이드 (EC2 + start.sh + Jenkins) slack-notifier 를 **EC2(리눅스)** 에 단일 정적 바이너리로 올리고, **start.sh**(백그라운드, sudo/systemd 불필요) 로 운영하며, **Jenkins** 로 빌드·배포를 자동화한다. 도커 레지스트리 불필요(바이너리 직접 배포). ``` [git push] → Jenkins (네이티브 Go) → go vet/test/build → sshpass scp(바이너리+start.sh) → EC2 → start.sh restart [Gitea/Notion] ──webhook(HTTPS)──→ Caddy(:443) ──→ slack-notifier(:8000) ──→ Slack ``` 기본 경로: `APP_DIR=/data/app/notifier`, 유저 `ec2-user`, 아키텍처 `amd64` (Jenkins 파라미터로 조정). --- ## 1. EC2 최초 1회 셋업 ### 1-1. 설치 경로 / 환경파일 ```bash # 배포 계정(ec2-user)이 소유 → sudo 없이 배포/기동 가능 sudo mkdir -p /data/app/notifier sudo chown -R ec2-user:ec2-user /data/app/notifier # 비밀값/설정 — 서버에만 두고 절대 커밋하지 않음 vi /data/app/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 ``` > 앱은 `-env prod` 로 실행되어 `.env.prod` 를 읽고, 로그는 `/data/app/notifier/logs/app-YYYY-MM-DD.log` > 로 날짜별 회전된다(7일 보존). stdout/패닉은 `logs/console.log` 에 남는다. ### 1-2. 실행 스크립트(start.sh) `start.sh` 는 **Jenkins 배포 시 바이너리와 함께 자동 전송**되므로 수동 복사는 보통 불필요하다. 최초 수동 기동이 필요하면: ```bash # 바이너리·start.sh·.env.prod 를 /data/app/notifier 에 둔 뒤 cd /data/app/notifier ./start.sh start prod # 시작 (start|stop|restart|status) ./start.sh status ``` ### 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 을 실제 도메인으로 교체 (reverse_proxy localhost:8000) sudo systemctl restart caddy ``` - 도메인 A 레코드 → EC2 퍼블릭 IP - 보안그룹 인바운드 **80, 443**(ACME + 웹훅 수신), 그리고 **Jenkins → EC2 22(SSH)** 허용 - 웹훅 등록 주소: `https://your-domain.com/webhooks/{gitea,notion}` --- ## 2. Jenkins 셋업 ### 2-1. 플러그인 / Go 도구 / sshpass - 플러그인: **Go Plugin**, **Credentials Binding** - **Manage Jenkins → Tools → Go installations** 에 Go 추가: - Name: **`go-1.26.4`** (Jenkinsfile 의 `tools { go '...' }` 와 일치) - "Install automatically" 로 1.26.x (또는 에이전트의 Go 경로) - **빌드 에이전트에 `sshpass` 설치** (아이디/비번 SSH): `sudo yum install -y sshpass` / `apt install -y sshpass` ### 2-2. 자격증명(아이디/비번) - Jenkins → Credentials → **Username with password** 추가 - **ID: `palnet-dev-ops`** (Jenkinsfile 의 `DEPLOY_CRED_ID` 와 일치) - **Username = EC2 SSH 유저(ec2-user), Password = 접속 비밀번호** — 둘 다 파이프라인이 자격증명에서 가져옴 - (호스트 IP 는 자격증명에 없으므로 `DEPLOY_HOST` 파라미터로 받음) - 대상 EC2 는 **비밀번호 SSH 허용**(`/etc/ssh/sshd_config` 의 `PasswordAuthentication yes`) 필요 - 배포 계정이 `APP_DIR` 소유 → **sudo 불필요** ### 2-3. 파이프라인 잡 - **Pipeline script from SCM** → 이 저장소 → `Jenkinsfile` - 파라미터(첫 실행 시 생성됨): - `DEPLOY_HOST` = EC2 DNS/IP (비우면 빌드·테스트만, 배포 스킵) - `APP_DIR` = `/data/app/notifier` - `ARCH` = `amd64`(x86) 또는 `arm64`(Graviton/t4g) ← **인스턴스 아키텍처와 반드시 일치** - (SSH 유저는 `palnet-dev-ops` 자격증명의 username 사용 → 별도 파라미터 없음) 배포는 **main 브랜치 + DEPLOY_HOST 지정** 시에만 수행된다. (일반 Pipeline 잡은 `BRANCH_NAME` 이 비어 `branch 'main'` 매칭이 안 되므로, Multibranch Pipeline 권장 — 단일 잡으로 쓸 거면 Jenkinsfile 의 `when` 에서 `branch 'main'` 을 제거할 것.) ### 2-4. 파라미터 변경 시 (stale 가드) Jenkins 의 `parameters` 는 변경해도 **1빌드 늦게** 등록된다(step/environment 는 즉시 반영). 그 사이 옛 파라미터로 빌드·배포되는 사고를 막기 위해 `Guard: params sync` 스테이지가 있다. `parameters {}` 를 바꿀 때 규칙: 1. 파라미터를 수정하고 2. **`parameters` 의 `PARAMS_VERSION` 기본값**과 **`environment.PARAMS_VERSION`** 을 **둘 다 +1** 3. 커밋/푸시 → 첫 빌드는 `Guard` 에서 **의도적으로 실패**(파라미터 재등록만 됨) → **한 번 더 빌드**하면 정상 진행 --- ## 3. 배포 동작 / 롤백 - 교체 순서: 바이너리(임시명)·start.sh 전송 → `start.sh stop` → `mv` 로 교체(정지 상태라 `ETXTBSY` 없음) → `start.sh start prod` → `status`. - 로그 확인: `tail -f /data/app/notifier/logs/app-$(date +%F).log` (구조적 로그) / `logs/console.log` (stdout·패닉) - 롤백: 이전 커밋으로 다시 빌드/배포. 필요하면 배포 전 `cp slack-notifier slack-notifier.bak` 단계를 추가해도 됨. --- ## 4. 수동 배포(참고, Jenkins 없이) ```bash make build-linux ARCH=amd64 # 정적 바이너리 생성 sshpass -e scp -P 22 slack-notifier deploy/start.sh ec2-user@EC2:/data/app/notifier/ # SSHPASS 환경변수 사용 ssh ec2-user@EC2 'cd /data/app/notifier && chmod +x start.sh && ./start.sh restart prod && ./start.sh status' ```