Skip to content

Commit 3c9f7ec

Browse files
authored
Merge pull request #123 from umc-commit/refactor/122-non-stop-deploy
[REFACTOR] 배포 방식 수정
2 parents 429436c + f8ecb04 commit 3c9f7ec

File tree

8 files changed

+131
-50
lines changed

8 files changed

+131
-50
lines changed

.github/workflows/cd.yml

Lines changed: 51 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -11,64 +11,77 @@ jobs:
1111
runs-on: ubuntu-latest
1212

1313
steps:
14-
- name: Checkout
15-
uses: actions/checkout@v4
16-
1714
- name: Configure SSH
1815
run: |
1916
mkdir -p ~/.ssh
2017
echo "$EC2_SSH_KEY" > ~/.ssh/id_rsa
2118
chmod 600 ~/.ssh/id_rsa
2219
ssh-keyscan -H $EC2_HOST >> ~/.ssh/known_hosts
23-
24-
cat >>~/.ssh/config <<END
20+
cat >> ~/.ssh/config <<EOF
2521
Host ec2
2622
HostName $EC2_HOST
2723
User ubuntu
2824
IdentityFile ~/.ssh/id_rsa
2925
StrictHostKeyChecking no
30-
END
26+
EOF
3127
env:
3228
EC2_HOST: ${{ secrets.EC2_HOST }}
3329
EC2_SSH_KEY: ${{ secrets.EC2_SSH_KEY }}
3430

35-
- name: Copy code to EC2 (using rsync)
36-
run: |
37-
ssh ec2 "sudo mkdir -p /opt/app && sudo chown ubuntu:ubuntu /opt/app"
38-
rsync -avz --delete -e "ssh" ./ ec2:/opt/app
39-
40-
- name: Create .env file
41-
run: |
42-
ssh ec2 "echo '$ENV_FILE' > /opt/app/.env"
31+
- name: Create .env on EC2
32+
run: ssh ec2 "echo '$ENV_FILE' > /opt/app/.env"
4333
env:
4434
ENV_FILE: ${{ secrets.ENV_FILE }}
45-
46-
- name: Restore Firebase service account key
35+
36+
- name: Deploy with Blue-Green
4737
run: |
48-
ssh ec2 "mkdir -p /opt/app/config && echo $FIREBASE_SERVICE_ACCOUNT_BASE64 | base64 -d > /opt/app/config/service-account-key.json"
49-
env:
50-
FIREBASE_SERVICE_ACCOUNT_BASE64: ${{ secrets.FIREBASE_SERVICE_ACCOUNT_BASE64 }}
38+
ssh ec2 <<'EOF'
39+
echo "📦 Pulling latest image..."
40+
docker pull ${{ secrets.DOCKER_HUB_USERNAME }}/commit-api:latest
5141
52-
- name: Install dependencies
53-
run: ssh ec2 "cd /opt/app && npm install"
42+
echo "🔍 Checking current active environment..."
43+
CURRENT=$(readlink -f /opt/app/nginx/default.conf)
44+
if echo "$CURRENT" | grep -q "default-blue.conf"; then
45+
TARGET_COLOR=green
46+
TARGET_PORT=3001
47+
TARGET_CONF=/opt/app/nginx/default-green.conf
48+
else
49+
TARGET_COLOR=blue
50+
TARGET_PORT=3000
51+
TARGET_CONF=/opt/app/nginx/default-blue.conf
52+
fi
5453
55-
- name: Create systemd service
56-
run: |
57-
ssh ec2 "echo '[Unit]
58-
Description=Node.js App
59-
After=network.target
54+
echo "🚀 Deploying to $TARGET_COLOR container on port $TARGET_PORT..."
55+
docker run -d \
56+
--name node-app-$TARGET_COLOR \
57+
--env-file /opt/app/.env \
58+
-p $TARGET_PORT:3000 \
59+
--network=commit-networks \
60+
${{ secrets.DOCKER_HUB_USERNAME }}/commit-api:latest
6061
61-
[Service]
62-
Environment=NODE_ENV=production
63-
User=ubuntu
64-
ExecStart=/usr/bin/npm run start --prefix /opt/app/
65-
Restart=always
62+
echo "⏳ Health check for $TARGET_COLOR..."
63+
for i in {1..10}; do
64+
sleep 2
65+
if curl -s http://localhost:$TARGET_PORT/health | grep "ok" > /dev/null; then
66+
echo "✅ Health check passed. Switching traffic..."
6667
67-
[Install]
68-
WantedBy=multi-user.target' | sudo tee /etc/systemd/system/app.service"
68+
# Nginx 심볼릭 링크 교체
69+
ln -sf $TARGET_CONF /opt/app/nginx/default.conf
70+
docker exec nginx-proxy nginx -s reload
6971
70-
- name: Enable & Restart systemd service
71-
run: |
72-
ssh ec2 "sudo systemctl daemon-reload"
73-
ssh ec2 "sudo systemctl enable app"
74-
ssh ec2 "sudo systemctl restart app"
72+
# 이전 컨테이너 제거
73+
if [ "$TARGET_COLOR" = "blue" ]; then
74+
docker rm -f node-app-green || true
75+
else
76+
docker rm -f node-app-blue || true
77+
fi
78+
79+
docker rename node-app-$TARGET_COLOR node-app
80+
exit 0
81+
fi
82+
done
83+
84+
echo "❌ Health check failed. Rolling back..."
85+
docker rm -f node-app-$TARGET_COLOR || true
86+
exit 1
87+
EOF

.github/workflows/ci.yml

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,26 @@ on:
55
branches: [develop]
66

77
jobs:
8-
test:
8+
build-and-push:
99
runs-on: ubuntu-latest
10+
1011
steps:
1112
- name: Checkout code
1213
uses: actions/checkout@v4
1314

14-
- name: Setup Node.js
15-
uses: actions/setup-node@v4
16-
with:
17-
node-version: 20
18-
19-
- name: Install dependencies
20-
run: npm install
15+
- name: Set up Docker Buildx
16+
uses: docker/setup-buildx-action@v3
2117

22-
- name: Run Linter
23-
run: npm run lint
18+
- name: Log in to Docker Hub
19+
uses: docker/login-action@v3
20+
with:
21+
username: ${{ secrets.DOCKER_HUB_USERNAME }}
22+
password: ${{ secrets.DOCKER_HUB_TOKEN }}
2423

25-
- name: Run Tests
26-
run: npm test
24+
- name: Build and push Docker image
25+
uses: docker/build-push-action@v5
26+
with:
27+
context: .
28+
file: ./Dockerfile
29+
push: true
30+
tags: ${{ secrets.DOCKER_HUB_USERNAME }}/commit-api:latest

Dockerfile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
FROM node:20-alpine3.22
2+
WORKDIR /app
3+
RUN apk update && apk upgrade && rm -rf /var/cache/apk/*
4+
COPY package*.json ./
5+
RUN npm ci
6+
COPY . .
7+
CMD ["npm", "run", "start"]

docker-compose.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
services:
2+
nginx:
3+
image: nginx:latest
4+
container_name: nginx-proxy
5+
ports:
6+
- "80:80"
7+
- "443:443"
8+
volumes:
9+
- /etc/letsencrypt:/etc/letsencrypt
10+
- /opt/app/nginx/default.conf:/etc/nginx/conf.d/default.conf
11+
- /opt/app/nginx/default-blue.conf:/etc/nginx/conf.d/default-blue.conf
12+
- /opt/app/nginx/default-green.conf:/etc/nginx/conf.d/default-green.conf
13+
restart: always
14+
networks:
15+
- commit-networks
16+
17+
networks:
18+
commit-networks:
19+
driver: bridge

nginx/default-blue.conf

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
server {
2+
listen 443 ssl;
3+
server_name commit.n-e.kr www.commit.n-e.kr;
4+
5+
ssl_certificate /etc/letsencrypt/live/commit.n-e.kr/fullchain.pem;
6+
ssl_certificate_key /etc/letsencrypt/live/commit.n-e.kr/privkey.pem;
7+
include /etc/letsencrypt/options-ssl-nginx.conf;
8+
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
9+
10+
location / {
11+
proxy_pass http://127.0.0.1:3000;
12+
proxy_set_header Host $host;
13+
proxy_set_header X-Real-IP $remote_addr;
14+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
15+
proxy_set_header X-Forwarded-Proto $scheme;
16+
}
17+
}

nginx/default-green.conf

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
server {
2+
listen 443 ssl;
3+
server_name commit.n-e.kr www.commit.n-e.kr;
4+
5+
ssl_certificate /etc/letsencrypt/live/commit.n-e.kr/fullchain.pem;
6+
ssl_certificate_key /etc/letsencrypt/live/commit.n-e.kr/privkey.pem;
7+
include /etc/letsencrypt/options-ssl-nginx.conf;
8+
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
9+
10+
location / {
11+
proxy_pass http://127.0.0.1:3001;
12+
proxy_set_header Host $host;
13+
proxy_set_header X-Real-IP $remote_addr;
14+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
15+
proxy_set_header X-Forwarded-Proto $scheme;
16+
}
17+
}

nginx/default.conf

Whitespace-only changes.

src/index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,10 @@ app.get('/', (req, res) => {
113113
res.send('Hello World!')
114114
})
115115

116+
app.get('/health', (_, res) => {
117+
res.send('ok');
118+
});
119+
116120
/**
117121
* 전역 오류를 처리하기 위한 미들웨어
118122
*/

0 commit comments

Comments
 (0)