1- name : Deploy To EC2 (Blue-Green via SSM )
1+ name : Deploy To EC2 (Blue-Green via Bastion )
22
33on :
44 push :
@@ -8,10 +8,12 @@ permissions:
88 contents : read
99
1010jobs :
11+ # 1️⃣ BUILD JOB
1112 build :
1213 runs-on : ubuntu-latest
1314 steps :
1415 - uses : actions/checkout@v4
16+
1517 - uses : actions/setup-java@v4
1618 with :
1719 distribution : temurin
@@ -42,80 +44,105 @@ jobs:
4244 docker tag forday:latest 839983937363.dkr.ecr.ap-northeast-2.amazonaws.com/forday:latest
4345 docker push 839983937363.dkr.ecr.ap-northeast-2.amazonaws.com/forday:latest
4446
47+ # 2️⃣ DEPLOY JOB
4548 deploy :
4649 needs : build
4750 runs-on : ubuntu-latest
4851 steps :
49- - name : Configure AWS Credentials
50- uses : aws-actions/configure-aws-credentials@v4
51- with :
52- aws-region : ap-northeast-2
53- aws-access-key-id : ${{ secrets.AWS_ACCESS_KEY_ID }}
54- aws-secret-access-key : ${{ secrets.AWS_SECRET_ACCESS_KEY }}
52+ - name : Configure SSH (Bastion → Private)
53+ run : |
54+ mkdir -p ~/.ssh
55+ echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
56+ chmod 600 ~/.ssh/id_rsa
57+
58+ cat <<EOF >> ~/.ssh/config
59+ Host bastion
60+ HostName ${{ secrets.BASTION_HOST }}
61+ User ubuntu
62+ IdentityFile ~/.ssh/id_rsa
63+ StrictHostKeyChecking no
64+
65+ Host private
66+ HostName ${{ secrets.EC2_PRIVATE_HOST }}
67+ User ubuntu
68+ IdentityFile ~/.ssh/id_rsa
69+ ProxyJump bastion
70+ StrictHostKeyChecking no
71+ EOF
5572
56- - name : Blue-Green Deploy via SSM
73+ - name : Blue-Green Deploy
5774 run : |
58- COMMAND_ID=$(aws ssm send-command \
59- --document-name "AWS-RunShellScript" \
60- --instance-ids "${{ secrets.EC2_INSTANCE_ID }}" \
61- --parameters '{
62- "commands": [
63- "set -e",
64- "ENV_FILE=/etc/nginx/conf.d/service-env.inc",
65- "if [ ! -f $ENV_FILE ]; then sudo sh -c \"printf '\''set \\$service_url blue;'\'' > $ENV_FILE\"; fi",
75+ ssh private << 'EOF'
76+ set -e
6677
67- "if grep -q \"green\" $ENV_FILE; then TARGET=\"blue\"; TARGET_PORT=8080; OLD_TARGET=\"green\"; else TARGET=\"green\"; TARGET_PORT=8081; OLD_TARGET=\"blue\"; fi",
78+ echo "▶ Detect current upstream from nginx env file"
79+ if [ -f /etc/nginx/conf.d/service-env.inc ]; then
80+ CURRENT_VAL=$(grep -oP '(?<=set \$service_url ).*(?=;)' /etc/nginx/conf.d/service-env.inc || echo "blue")
81+ else
82+ CURRENT_VAL="blue"
83+ fi
6884
69- "echo \"▶ 배포 시작: $TARGET (포트: $TARGET_PORT)\"",
70- "aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin 839983937363.dkr.ecr.ap-northeast-2.amazonaws.com",
71- "docker pull 839983937363.dkr.ecr.ap-northeast-2.amazonaws.com/forday:latest",
85+ echo "현재 서비스 상태: $CURRENT_VAL"
7286
73- "docker stop $TARGET || true",
74- "docker rm $TARGET || true",
75- "docker run -d --name $TARGET --restart=always -e SPRING_PROFILES_ACTIVE=$TARGET -p $TARGET_PORT:8080 -e SPRING_DATA_REDIS_HOST=172.17.0.1 -e SPRING_DATA_REDIS_PORT=6379 839983937363.dkr.ecr.ap-northeast-2.amazonaws.com/forday:latest",
87+ if [ "$CURRENT_VAL" = "blue" ]; then
88+ TARGET="green"
89+ TARGET_PORT=8081
90+ OLD_TARGET="blue"
91+ else
92+ TARGET="blue"
93+ TARGET_PORT=8080
94+ OLD_TARGET="green"
95+ fi
7696
77- "echo \"▶ 헬스 체크 시작...\"",
78- "HEALTH_OK=false",
79- "for i in {1..20}; do",
80- " # curl 실패 시에도 스크립트가 중단되지 않도록 || true 추가",
81- " HTTP_CODE=$(curl -s -o /dev/null -w \"%{http_code}\" http://localhost:$TARGET_PORT/health_check || echo \"000\")",
82- " if [ \"$HTTP_CODE\" = \"200\" ] || [ \"$HTTP_CODE\" = \"401\" ]; then",
83- " echo \"✅ 서비스 응답 확인 (코드: $HTTP_CODE)\"",
84- " HEALTH_OK=true",
85- " break",
86- " fi",
87- " echo \"대기 중... ($i/20) 응답: $HTTP_CODE\"",
88- " sleep 10",
89- "done",
97+ echo "▶ Deploy target: $TARGET (port: $TARGET_PORT)"
98+ echo "▶ Old container: $OLD_TARGET"
9099
91- "if [ \"$HEALTH_OK\" = \"true\" ]; then",
92- " echo \"▶ Nginx 스위칭 실행\"",
93- " sudo sh -c \"printf '\''set \\$service_url $TARGET;'\'' > $ENV_FILE\"",
94- " sudo nginx -t && sudo nginx -s reload",
95- " echo \"▶ 이전 컨테이너 정리\"",
96- " docker stop $OLD_TARGET || true",
97- " docker rm $OLD_TARGET || true",
98- " docker image prune -af",
99- " echo \"✅ 배포 성공: $TARGET\"",
100- "else",
101- " echo \"❌ 헬스 체크 최종 실패\"",
102- " docker logs --tail 50 $TARGET",
103- " exit 1",
104- "fi"
105- ]
106- }' --query "Command.CommandId" --output text)
107-
108- echo "Command ID: $COMMAND_ID"
109-
110- # EC2 내부 실행 완료 대기
111- aws ssm wait command-executed --command-id "$COMMAND_ID" --instance-id "${{ secrets.EC2_INSTANCE_ID }}" || true
112-
113- # 상세 로그 출력 (스위칭 여부 확인용)
114- aws ssm list-command-invocations --command-id "$COMMAND_ID" --details --query "CommandInvocations[0].CommandPlugins[0].Output" --output text
100+ # ECR 로그인
101+ aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin 839983937363.dkr.ecr.ap-northeast-2.amazonaws.com
102+
103+ echo "▶ Pull image"
104+ docker pull 839983937363.dkr.ecr.ap-northeast-2.amazonaws.com/forday:latest
105+
106+ echo "▶ Stop & remove current $TARGET (if exists)"
107+ docker stop $TARGET || true
108+ docker rm $TARGET || true
109+
110+ echo "▶ Run new $TARGET"
111+ docker run -d \
112+ --name $TARGET \
113+ --restart=always \
114+ -e SPRING_PROFILES_ACTIVE=$TARGET \
115+ -p $TARGET_PORT:8080 \
116+ -e SPRING_DATA_REDIS_HOST=172.17.0.1 \
117+ -e SPRING_DATA_REDIS_PORT=6379 \
118+ 839983937363.dkr.ecr.ap-northeast-2.amazonaws.com/forday:latest
119+
120+ echo "▶ Health Check"
121+ for i in {1..20}; do
122+ if curl -sf http://localhost:$TARGET_PORT/health_check; then
123+ echo "Health OK"
124+ HEALTH_OK=true
125+ break
126+ fi
127+ echo "Waiting... ($i/20)"
128+ sleep 5
129+ done
130+
131+ if [ "$HEALTH_OK" != "true" ]; then
132+ echo "❌ Health check failed. Rollback."
133+ docker logs $TARGET
134+ exit 1
135+ fi
136+
137+ echo "▶ Switching Nginx upstream to $TARGET"
138+ echo "set \$service_url $TARGET;" | sudo tee /etc/nginx/conf.d/service-env.inc
139+
140+ sudo nginx -t
141+ sudo nginx -s reload
142+
143+ echo "▶ Stopping OLD container: $OLD_TARGET"
144+ docker stop $OLD_TARGET || true
145+ docker rm $OLD_TARGET || true
115146
116- # 최종 상태 확인
117- FINAL_STATUS=$(aws ssm get-command-invocation --command-id "$COMMAND_ID" --instance-id "${{ secrets.EC2_INSTANCE_ID }}" --query "Status" --output text)
118- if [ "$FINAL_STATUS" != "Success" ]; then
119- echo "Deployment failed with status: $FINAL_STATUS"
120- exit 1
121- fi
147+ echo "✅ Deployment complete. Now running: $TARGET"
148+ EOF
0 commit comments