Skip to content

Commit 85ea496

Browse files
authored
Merge branch 'main' into fix/testcontainers-ci
2 parents 218d3d1 + 33daa46 commit 85ea496

25 files changed

+825
-146
lines changed

.github/workflows/deploy_client.yml

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,35 @@ on:
88
- "client/**"
99
workflow_dispatch: # 수동 실행을 허용하는 이벤트
1010

11+
env:
12+
DIST_TARGET: /var/dist
13+
1114
jobs:
12-
deployment:
13-
runs-on: ubuntu-latest
15+
deploy:
16+
runs-on: [self-hosted, prod]
1417
steps:
15-
# public 서버로 ssh 접속
16-
- name: ssh connection
17-
uses: appleboy/[email protected]
18+
- name: 코드 체크아웃
19+
uses: actions/checkout@v4
20+
21+
- name: Node.js 설정
22+
uses: actions/setup-node@v4
1823
with:
19-
host: ${{ secrets.CLOUD_PUBLIC_INSTANCE_HOST }}
20-
username: ${{ secrets.CLOUD_PUBLIC_INSTANCE_USERNAME }}
21-
key: ${{ secrets.CLOUD_PUBLIC_INSTANCE_SSH_KEY }}
22-
port: ${{ secrets.CLOUD_PUBLIC_INSTANCE_PORT }}
23-
script: |
24-
export NVM_DIR=~/.nvm
25-
source ~/.nvm/nvm.sh
24+
node-version: "22"
25+
cache: "npm"
26+
cache-dependency-path: client/package-lock.json
27+
28+
- name: 의존성 설치
29+
working-directory: ./client
30+
run: npm ci
2631

27-
cd /var/web05-Denamu
28-
git pull origin main
29-
cd client/
32+
- name: 클라이언트 빌드
33+
working-directory: ./client
34+
run: npm run build
3035

31-
npm ci
32-
npm run build
36+
- name: 빌드 결과물 배포
37+
run: |
38+
sudo mkdir -p "$DIST_TARGET"
39+
sudo rm -rf "$DIST_TARGET"/*
40+
sudo cp -r ./client/dist/* "$DIST_TARGET"/
41+
sudo chown -R www-data:www-data "$DIST_TARGET"
42+
echo "✅ FE 빌드 결과물이 $DIST_TARGET 에 배포되었습니다."
Lines changed: 96 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,104 @@
1-
name: Feed-Crawler-Deployment
1+
name: Feed-Crawler Deployment
22

33
on:
44
push:
5-
branches:
6-
- main
7-
paths:
8-
- "feed-crawler/**"
9-
workflow_dispatch: # 수동 실행을 허용하는 이벤트
5+
branches: [main]
6+
paths: ["feed-crawler/**", "docker-compose/**"]
7+
workflow_dispatch:
8+
9+
permissions:
10+
contents: read
11+
packages: write
12+
13+
env:
14+
IMAGE_NAME: ghcr.io/boostcampwm-2024/web05-denamu/feed-crawler
15+
IMAGE_TAG: sha-${{ github.sha }}
16+
SERVICE: feed-crawler
17+
ENV_DIR: /var/prod_config/feed-crawler
18+
ENV_FILE: /var/prod_config/feed-crawler/.env.prod
19+
COMPOSE_FILE: docker-compose/docker-compose.prod.yml
1020

1121
jobs:
12-
deployment:
22+
build-and-push:
1323
runs-on: ubuntu-latest
1424
steps:
15-
# public 서버로 ssh 접속
16-
- name: ssh connection
17-
uses: appleboy/[email protected]
25+
- uses: actions/checkout@v4
26+
27+
- name: QEMU 멀티 아키텍쳐 에뮬레이터
28+
uses: docker/setup-qemu-action@v3
29+
30+
- name: Buildx 멀티 아키텍쳐 빌더
31+
uses: docker/setup-buildx-action@v3
32+
33+
- name: GHCR 로그인
34+
uses: docker/login-action@v3
35+
with:
36+
registry: ghcr.io
37+
username: ${{ github.actor }}
38+
password: ${{ secrets.GHCR_GITHUB_TOKEN }}
39+
40+
- name: Docker 이미지 Build 및 Push
41+
uses: docker/build-push-action@v6
42+
with:
43+
context: ./feed-crawler
44+
file: ./feed-crawler/docker/Dockerfile.prod
45+
push: true
46+
platforms: linux/amd64,linux/arm64
47+
tags: |
48+
${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }}
49+
${{ env.IMAGE_NAME }}:latest
50+
cache-from: type=gha
51+
cache-to: type=gha,mode=max
52+
53+
deploy:
54+
runs-on: [self-hosted, prod]
55+
needs: build-and-push # Build 및 Push가 끝나면 시작
56+
steps:
57+
- name: 코드 체크아웃
58+
uses: actions/checkout@v4
59+
60+
- name: GHCR 로그인 (prod)
61+
uses: docker/login-action@v3
1862
with:
19-
host: ${{ secrets.CLOUD_PUBLIC_INSTANCE_HOST }}
20-
username: ${{ secrets.CLOUD_PUBLIC_INSTANCE_USERNAME }}
21-
key: ${{ secrets.CLOUD_PUBLIC_INSTANCE_SSH_KEY }}
22-
port: ${{ secrets.CLOUD_PUBLIC_INSTANCE_PORT }}
23-
script: |
24-
cd /var/web05-Denamu
25-
git pull origin main
26-
cd /var/web05-Denamu/feed-crawler/
27-
28-
mkdir -p env
29-
echo "DB_PORT=${{ secrets.FEED_CRAWLER_DB_PORT }}" > env/.env.prod
30-
echo "DB_HOST=${{ secrets.FEED_CRAWLER_DB_HOST }}" >> env/.env.prod
31-
echo "DB_NAME=${{ secrets.FEED_CRAWLER_DB_NAME }}" >> env/.env.prod
32-
echo "DB_USER=${{ secrets.FEED_CRAWLER_DB_USER }}" >> env/.env.prod
33-
echo "DB_PASS=${{ secrets.FEED_CRAWLER_DB_PASSWORD }}" >> env/.env.prod
34-
echo "TIME_INTERVAL=${{ vars.FEED_CRAWLER_TIME_INTERVAL }}" >> env/.env.prod
35-
echo "REDIS_HOST=${{secrets.REDIS_HOST }}" >> env/.env.prod
36-
echo "REDIS_PORT=${{secrets.REDIS_PORT}}" >> env/.env.prod
37-
echo "REDIS_USERNAME=${{secrets.REDIS_USERNAME}}" >> env/.env.prod
38-
echo "REDIS_PASSWORD=${{secrets.REDIS_PASSWORD}}" >> env/.env.prod
39-
echo "AI_API_KEY=${{secrets.AI_API_KEY}}" >> env/.env.prod
40-
echo "AI_RATE_LIMIT_COUNT=${{ vars.AI_RATE_LIMIT_COUNT }}" >> env/.env.prod
41-
42-
cd /var/web05-Denamu
43-
docker-compose -f docker-compose/docker-compose.prod.yml up --build --no-deps --force-recreate -d feed-crawler
44-
docker image prune -f
45-
docker builder prune -f
63+
registry: ghcr.io
64+
username: ${{ github.actor }}
65+
password: ${{ secrets.GHCR_GITHUB_TOKEN }}
66+
67+
- name: 환경변수 최신화
68+
run: |
69+
sudo mkdir -p "$ENV_DIR"
70+
sudo install -m 600 /dev/null "$ENV_FILE"
71+
{
72+
echo "DB_PORT=${{ secrets.FEED_CRAWLER_DB_PORT }}"
73+
echo "DB_HOST=${{ secrets.FEED_CRAWLER_DB_HOST }}"
74+
echo "DB_NAME=${{ secrets.FEED_CRAWLER_DB_NAME }}"
75+
echo "DB_USER=${{ secrets.FEED_CRAWLER_DB_USER }}"
76+
echo "DB_PASS=${{ secrets.FEED_CRAWLER_DB_PASSWORD }}"
77+
echo "TIME_INTERVAL=${{ vars.FEED_CRAWLER_TIME_INTERVAL }}"
78+
echo "REDIS_HOST=${{ secrets.REDIS_HOST }}"
79+
echo "REDIS_PORT=${{ secrets.REDIS_PORT }}"
80+
echo "REDIS_USERNAME=${{ secrets.REDIS_USERNAME }}"
81+
echo "REDIS_PASSWORD=${{ secrets.REDIS_PASSWORD }}"
82+
echo "AI_API_KEY=${{ secrets.AI_API_KEY }}"
83+
echo "AI_RATE_LIMIT_COUNT=${{ vars.AI_RATE_LIMIT_COUNT }}"
84+
} | sudo tee "$ENV_FILE" >/dev/null
85+
86+
# 인프라용 환경변수 파일 생성 (Redis, MySQL 등)
87+
sudo mkdir -p /var/prod_config/infra
88+
sudo install -m 600 /dev/null /var/prod_config/infra/.env.prod
89+
{
90+
echo "REDIS_USER=${{ secrets.REDIS_USERNAME }}"
91+
echo "REDIS_PASSWORD=${{ secrets.REDIS_PASSWORD }}"
92+
echo "MYSQL_ROOT_PASSWORD=${{ secrets.PRODUCT_DB_PASSWORD }}"
93+
echo "MYSQL_DATABASE=${{ secrets.PRODUCT_DB_DATABASE }}"
94+
echo "MYSQL_USER=${{ secrets.PRODUCT_DB_USERNAME }}"
95+
echo "MYSQL_PASSWORD=${{ secrets.PRODUCT_DB_PASSWORD }}"
96+
} | sudo tee /var/prod_config/infra/.env.prod >/dev/null
97+
98+
- name: Docker 이미지 Pull & 서비스 재시작
99+
run: |
100+
docker pull "${IMAGE_NAME}:${IMAGE_TAG}" || true
101+
docker pull "${IMAGE_NAME}:latest" || true
102+
docker compose -f "$COMPOSE_FILE" pull "$SERVICE"
103+
docker compose -f "$COMPOSE_FILE" up -d --no-deps --force-recreate "$SERVICE"
104+
docker image prune -f || true

.github/workflows/deploy_infra.yml

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,31 @@ on:
88
- docker-compose/docker-compose.prod*.yml
99
workflow_dispatch:
1010

11+
env:
12+
COMPOSE_FILE: docker-compose/docker-compose.prod.yml
13+
1114
jobs:
1215
deployment:
13-
runs-on: ubuntu-latest
16+
runs-on: [self-hosted, prod]
1417
steps:
15-
# public 서버로 ssh 접속
16-
- name: ssh connection
17-
uses: appleboy/[email protected]
18-
with:
19-
host: ${{ secrets.CLOUD_PUBLIC_INSTANCE_HOST }}
20-
username: ${{ secrets.CLOUD_PUBLIC_INSTANCE_USERNAME }}
21-
key: ${{ secrets.CLOUD_PUBLIC_INSTANCE_SSH_KEY }}
22-
port: ${{ secrets.CLOUD_PUBLIC_INSTANCE_PORT }}
23-
script: |
24-
cd /var/web05-Denamu
25-
git pull origin main
26-
docker-compose -f docker-compose/docker-compose.prod.yml down
27-
docker-compose -f docker-compose/docker-compose.prod.yml up -d
18+
- name: 코드 체크아웃
19+
uses: actions/checkout@v4
20+
21+
- name: 인프라 환경변수 최신화
22+
run: |
23+
sudo mkdir -p /var/prod_config/infra
24+
sudo install -m 600 /dev/null /var/prod_config/infra/.env.prod
25+
{
26+
echo "REDIS_USER=${{ secrets.REDIS_USERNAME }}"
27+
echo "REDIS_PASSWORD=${{ secrets.REDIS_PASSWORD }}"
28+
echo "MYSQL_ROOT_PASSWORD=${{ secrets.PRODUCT_DB_PASSWORD }}"
29+
echo "MYSQL_DATABASE=${{ secrets.PRODUCT_DB_DATABASE }}"
30+
echo "MYSQL_USER=${{ secrets.PRODUCT_DB_USERNAME }}"
31+
echo "MYSQL_PASSWORD=${{ secrets.PRODUCT_DB_PASSWORD }}"
32+
} | sudo tee /var/prod_config/infra/.env.prod >/dev/null
33+
34+
- name: 인프라 서비스 재시작
35+
run: |
36+
docker compose -f "$COMPOSE_FILE" down
37+
docker compose -f "$COMPOSE_FILE" up -d
38+
docker image prune -f || true

.github/workflows/deploy_server.yml

Lines changed: 104 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -2,53 +2,112 @@ name: BE Deployment
22

33
on:
44
push:
5-
branches:
6-
- main
7-
paths:
8-
- "server/**"
9-
workflow_dispatch: # 수동 실행을 허용하는 이벤트
5+
branches: [main]
6+
paths: ["server/**", "docker-compose/**"]
7+
workflow_dispatch:
8+
9+
permissions:
10+
contents: read
11+
packages: write
12+
13+
env:
14+
IMAGE_NAME: ghcr.io/boostcampwm-2024/web05-denamu/server
15+
IMAGE_TAG: sha-${{ github.sha }}
16+
SERVICE: app
17+
ENV_DIR: /var/prod_config/server
18+
ENV_FILE: /var/prod_config/server/.env.prod
19+
COMPOSE_FILE: docker-compose/docker-compose.prod.yml
1020

1121
jobs:
12-
deployment:
22+
build-and-push:
1323
runs-on: ubuntu-latest
1424
steps:
15-
# public 서버로 ssh 접속
16-
- name: ssh connection
17-
uses: appleboy/[email protected]
25+
- uses: actions/checkout@v4
26+
27+
- name: QEMU 멀티 아키텍쳐 에뮬레이터
28+
uses: docker/setup-qemu-action@v3
29+
30+
- name: Buildx 멀티 아키텍쳐 빌더
31+
uses: docker/setup-buildx-action@v3
32+
33+
- name: GHCR 로그인
34+
uses: docker/login-action@v3
35+
with:
36+
registry: ghcr.io
37+
username: ${{ github.actor }}
38+
password: ${{ secrets.GHCR_GITHUB_TOKEN }}
39+
40+
- name: Docker 이미지 Build 및 Push
41+
uses: docker/build-push-action@v6
42+
with:
43+
context: ./server
44+
file: ./server/docker/Dockerfile.prod
45+
push: true
46+
platforms: linux/amd64,linux/arm64
47+
tags: |
48+
${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }}
49+
${{ env.IMAGE_NAME }}:latest
50+
cache-from: type=gha
51+
cache-to: type=gha,mode=max
52+
53+
deploy:
54+
runs-on: [self-hosted, prod]
55+
needs: build-and-push # Build 및 Push가 끝나면 시작
56+
steps:
57+
- name: 코드 체크아웃
58+
uses: actions/checkout@v4
59+
60+
- name: GHCR 로그인 (prod)
61+
uses: docker/login-action@v3
1862
with:
19-
host: ${{ secrets.CLOUD_PUBLIC_INSTANCE_HOST }}
20-
username: ${{ secrets.CLOUD_PUBLIC_INSTANCE_USERNAME }}
21-
key: ${{ secrets.CLOUD_PUBLIC_INSTANCE_SSH_KEY }}
22-
port: ${{ secrets.CLOUD_PUBLIC_INSTANCE_PORT }}
23-
script: |
24-
cd /var/web05-Denamu
25-
git pull origin main
26-
cd /var/web05-Denamu/server
27-
28-
mkdir -p env
29-
echo "PORT=${{ secrets.PRODUCT_PORT }}" > env/.env.prod
30-
echo "DB_TYPE=mysql" >> env/.env.prod
31-
echo "DB_DATABASE=${{ secrets.PRODUCT_DB_DATABASE }}" >> env/.env.prod
32-
echo "DB_HOST=${{ secrets.PRODUCT_DB_HOST }}" >> env/.env.prod
33-
echo "DB_PORT=${{ secrets.PRODUCT_DB_PORT }}" >> env/.env.prod
34-
echo "DB_USERNAME=${{ secrets.PRODUCT_DB_USERNAME }}" >> env/.env.prod
35-
echo "DB_PASSWORD=${{ secrets.PRODUCT_DB_PASSWORD }}" >> env/.env.prod
36-
echo "REDIS_HOST=${{secrets.REDIS_HOST }}" >> env/.env.prod
37-
echo "REDIS_PORT=${{secrets.REDIS_PORT}}" >> env/.env.prod
38-
echo "REDIS_USERNAME=${{secrets.REDIS_USERNAME}}" >> env/.env.prod
39-
echo "REDIS_PASSWORD=${{secrets.REDIS_PASSWORD}}" >> env/.env.prod
40-
echo "EMAIL_USER=${{secrets.EMAIL_USER}}" >> env/.env.prod
41-
echo "EMAIL_PASSWORD=${{secrets.EMAIL_PASSWORD}}" >> env/.env.prod
42-
echo "JWT_ACCESS_SECRET=${{secrets.JWT_ACCESS_SECRET}}" >> env/.env.prod
43-
echo "JWT_REFRESH_SECRET=${{secrets.JWT_REFRESH_SECRET}}" >> env/.env.prod
44-
echo "REFRESH_TOKEN_EXPIRE=${{secrets.REFRESH_TOKEN_EXPIRE}}" >> env/.env.prod
45-
echo "ACCESS_TOKEN_EXPIRE=${{secrets.ACCESS_TOKEN_EXPIRE}}" >> env/.env.prod
46-
echo "GOOGLE_CLIENT_ID=${{secrets.GOOGLE_CLIENT_ID}}" >> env/.env.prod
47-
echo "GOOGLE_CLIENT_SECRET=${{secrets.GOOGLE_CLIENT_SECRET}}" >> env/.env.prod
48-
echo "GITHUB_CLIENT_ID=${{secrets.GIT_CLIENT_ID}}" >> env/.env.prod
49-
echo "GITHUB_CLIENT_SECRET=${{secrets.GIT_CLIENT_SECRET}}" >> env/.env.prod
50-
51-
cd /var/web05-Denamu
52-
docker-compose -f docker-compose/docker-compose.prod.yml up --build --no-deps --force-recreate -d app
53-
docker image prune -f
54-
docker builder prune -f
63+
registry: ghcr.io
64+
username: ${{ github.actor }}
65+
password: ${{ secrets.GHCR_GITHUB_TOKEN }}
66+
67+
- name: 환경변수 최신화
68+
run: |
69+
sudo mkdir -p "$ENV_DIR"
70+
sudo install -m 600 /dev/null "$ENV_FILE"
71+
{
72+
echo "PORT=${{ secrets.PRODUCT_PORT }}"
73+
echo "DB_TYPE=mysql"
74+
echo "DB_DATABASE=${{ secrets.PRODUCT_DB_DATABASE }}"
75+
echo "DB_HOST=${{ secrets.PRODUCT_DB_HOST }}"
76+
echo "DB_PORT=${{ secrets.PRODUCT_DB_PORT }}"
77+
echo "DB_USERNAME=${{ secrets.PRODUCT_DB_USERNAME }}"
78+
echo "DB_PASSWORD=${{ secrets.PRODUCT_DB_PASSWORD }}"
79+
echo "REDIS_HOST=${{ secrets.REDIS_HOST }}"
80+
echo "REDIS_PORT=${{ secrets.REDIS_PORT }}"
81+
echo "REDIS_USERNAME=${{ secrets.REDIS_USERNAME }}"
82+
echo "REDIS_PASSWORD=${{ secrets.REDIS_PASSWORD }}"
83+
echo "EMAIL_USER=${{ secrets.EMAIL_USER }}"
84+
echo "EMAIL_PASSWORD=${{ secrets.EMAIL_PASSWORD }}"
85+
echo "JWT_ACCESS_SECRET=${{ secrets.JWT_ACCESS_SECRET }}"
86+
echo "JWT_REFRESH_SECRET=${{ secrets.JWT_REFRESH_SECRET }}"
87+
echo "REFRESH_TOKEN_EXPIRE=${{ secrets.REFRESH_TOKEN_EXPIRE }}"
88+
echo "ACCESS_TOKEN_EXPIRE=${{ secrets.ACCESS_TOKEN_EXPIRE }}"
89+
echo "GOOGLE_CLIENT_ID=${{ secrets.GOOGLE_CLIENT_ID }}"
90+
echo "GOOGLE_CLIENT_SECRET=${{ secrets.GOOGLE_CLIENT_SECRET }}"
91+
echo "GITHUB_CLIENT_ID=${{ secrets.GIT_CLIENT_ID }}"
92+
echo "GITHUB_CLIENT_SECRET=${{ secrets.GIT_CLIENT_SECRET }}"
93+
} | sudo tee "$ENV_FILE" >/dev/null
94+
95+
# 인프라용 환경변수 파일 생성 (Redis, MySQL 등)
96+
sudo mkdir -p /var/prod_config/infra
97+
sudo install -m 600 /dev/null /var/prod_config/infra/.env.prod
98+
{
99+
echo "REDIS_USER=${{ secrets.REDIS_USERNAME }}"
100+
echo "REDIS_PASSWORD=${{ secrets.REDIS_PASSWORD }}"
101+
echo "MYSQL_ROOT_PASSWORD=${{ secrets.PRODUCT_DB_PASSWORD }}"
102+
echo "MYSQL_DATABASE=${{ secrets.PRODUCT_DB_DATABASE }}"
103+
echo "MYSQL_USER=${{ secrets.PRODUCT_DB_USERNAME }}"
104+
echo "MYSQL_PASSWORD=${{ secrets.PRODUCT_DB_PASSWORD }}"
105+
} | sudo tee /var/prod_config/infra/.env.prod >/dev/null
106+
107+
- name: Docker 이미지 Pull & 서비스 재시작
108+
run: |
109+
docker pull "${IMAGE_NAME}:${IMAGE_TAG}" || true
110+
docker pull "${IMAGE_NAME}:latest" || true
111+
docker compose -f "$COMPOSE_FILE" pull "$SERVICE"
112+
docker compose -f "$COMPOSE_FILE" up -d --no-deps --force-recreate "$SERVICE"
113+
docker image prune -f || true

0 commit comments

Comments
 (0)