Skip to content

Commit 4dbc07e

Browse files
authored
refactor: CD 성능 개선 (#552)
* fix: deprecated된 base image를 eclipse-temurin:17-jdk로 변경 * refactor: scp 파일 전송하는 방식에서 GHCR로 push/pull하도록 변경 * fix: GHCR image 제거시 Org의 GITHUB_TOKEN 사용하도록 변경 * refactor : scp 파일 전송하는 방식에서 GHCR로 push/pull하도록 prod-cd.yml과 docker-compose.prod.yml 변경 * fix: prod 인스턴스 old image 이름 통일 * fix: prod-cd.yml StrictHostKeyChecking 옵션 문법 오류 수정 * fix: prod-cd.yml StrictHostKeyChecking 옵션 문법 오류 수정 * fix: dev-cd.yml Old images 정리 작업 중 이미지 이름 불일치 문제 해결 * chore: 마지막 줄 개행 추가 * chore: 마지막 줄 개행 추가 * feat: stage 인스턴스에 대한 최신 이미지 5개 유지 기능 및 old 이미지 제거 기능 추가 * chore: 중복된 환경변수 지정 제거 * chore: 중복된 pem키 생성 로직 제거 * fix: 잘못된 pem키 이름 수정 * refactor: 원격 호스트에서 pull할 경우, 최소 권한으로 실행하도록 Github App으로 임시토큰 발급하도록 수정
1 parent 6b9fb2b commit 4dbc07e

5 files changed

Lines changed: 244 additions & 140 deletions

File tree

.github/workflows/dev-cd.yml

Lines changed: 110 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ jobs:
1010
runs-on: ubuntu-latest
1111
permissions:
1212
contents: read
13+
packages: write
1314

1415
steps:
1516
- name: Checkout the code
@@ -18,81 +19,135 @@ jobs:
1819
token: ${{ secrets.SUBMODULE_ACCESS_TOKEN }}
1920
submodules: true
2021

22+
# --- Java, Gradle 설정 ---
2123
- name: Set up JDK 17
2224
uses: actions/setup-java@v4
2325
with:
2426
java-version: '17'
2527
distribution: 'temurin'
26-
27-
# Configure Gradle for optimal use in GitHub Actions, including caching of downloaded dependencies.
28-
# See: https://github.com/gradle/actions/blob/main/setup-gradle/README.md
2928
- name: Setup Gradle
30-
uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0
31-
29+
uses: gradle/actions/setup-gradle@v3
3230
- name: Grant execute permission for Gradle wrapper(gradlew)
3331
run: chmod +x ./gradlew
34-
3532
- name: Build with Gradle
3633
run: ./gradlew bootJar
3734

38-
- name: Copy jar file to remote
39-
uses: appleboy/scp-action@master
35+
# --- Docker 설정 ---
36+
- name: Set up Docker Buildx
37+
uses: docker/setup-buildx-action@v3
4038
with:
41-
host: ${{ secrets.DEV_HOST }}
42-
username: ${{ secrets.DEV_USERNAME }}
43-
key: ${{ secrets.DEV_PRIVATE_KEY }}
44-
source: "./build/libs/*.jar"
45-
target: "/home/${{ secrets.DEV_USERNAME }}/solid-connection-dev/"
46-
47-
- name: Copy docker file to remote
48-
uses: appleboy/scp-action@master
39+
platforms: linux/arm64
40+
- name: Log in to GitHub Container Registry (GHCR)
41+
uses: docker/login-action@v3
4942
with:
50-
host: ${{ secrets.DEV_HOST }}
51-
username: ${{ secrets.DEV_USERNAME }}
52-
key: ${{ secrets.DEV_PRIVATE_KEY }}
53-
source: "./Dockerfile"
54-
target: "/home/${{ secrets.DEV_USERNAME }}/solid-connection-dev/"
43+
registry: ghcr.io
44+
username: ${{ github.repository_owner }}
45+
password: ${{ secrets.GITHUB_TOKEN }}
5546

56-
- name: Copy docker compose file to remote
57-
uses: appleboy/scp-action@master
58-
with:
59-
host: ${{ secrets.DEV_HOST }}
60-
username: ${{ secrets.DEV_USERNAME }}
61-
key: ${{ secrets.DEV_PRIVATE_KEY }}
62-
source: "./docker-compose.dev.yml"
63-
target: "/home/${{ secrets.DEV_USERNAME }}/solid-connection-dev/"
47+
# --- 2. 이미지 메타데이터(이름, 태그) 정의 ---
48+
# 빌드/푸시 단계와 SSH 단계에서 공통으로 사용할 변수를 미리 정의합니다.
49+
- name: Define image name and tag
50+
id: image_meta
51+
run: |
52+
OWNER_LOWERCASE=$(echo "${{ github.repository_owner }}" | tr '[:upper:]' '[:lower:]')
53+
IMAGE_TAG=$(date +'%Y%m%d-%H%M%S')
54+
echo "image_name=ghcr.io/${OWNER_LOWERCASE}/solid-connection-dev" >> $GITHUB_OUTPUT
55+
echo "image_tag=${IMAGE_TAG}" >> $GITHUB_OUTPUT
6456
65-
- name: Copy alloy config file to remote
66-
uses: appleboy/scp-action@master
57+
# --- 3. Docker 이미지 빌드, 푸시, 캐시 ---
58+
# 'docker/build-push-action'을 사용하여 캐시 옵션을 적용합니다.
59+
- name: Build, push, and cache Docker image
60+
uses: docker/build-push-action@v5
6761
with:
68-
host: ${{ secrets.DEV_HOST }}
69-
username: ${{ secrets.DEV_USERNAME }}
70-
key: ${{ secrets.DEV_PRIVATE_KEY }}
71-
source: "./docs/infra-config/config.alloy"
72-
target: "/home/${{ secrets.DEV_USERNAME }}/solid-connection-dev/"
62+
context: .
63+
platforms: linux/arm64
64+
push: true
65+
tags: ${{ format('{0}:{1}', steps.image_meta.outputs.image_name, steps.image_meta.outputs.image_tag) }}
66+
cache-from: type=registry,ref=${{ steps.image_meta.outputs.image_name }}:buildcache
67+
cache-to: type=registry,ref=${{ steps.image_meta.outputs.image_name }}:buildcache,mode=max
7368

74-
- name: Copy nginx config to remote
75-
uses: appleboy/scp-action@master
69+
# --- 4. Github App으로 임시 토큰 생성 ---
70+
- name: Create installation token
71+
id: app
72+
uses: actions/create-github-app-token@v2
7673
with:
77-
host: ${{ secrets.DEV_HOST }}
78-
username: ${{ secrets.DEV_USERNAME }}
79-
key: ${{ secrets.DEV_PRIVATE_KEY }}
80-
source: "./docs/infra-config/nginx.dev.conf"
81-
target: "/home/${{ secrets.DEV_USERNAME }}/solid-connection-dev/nginx"
82-
rename: "default.conf"
74+
app-id: ${{ secrets.GH_APP_ID }}
75+
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
76+
77+
# --- 5. 설정 파일들만 scp로 전송 ---
78+
- name: Copy config files to remote
79+
run: |
80+
echo "${{ secrets.DEV_PRIVATE_KEY }}" > deploy_key.pem
81+
chmod 600 deploy_key.pem
82+
83+
scp -i deploy_key.pem \
84+
-o StrictHostKeyChecking=no \
85+
./docker-compose.dev.yml \
86+
./docs/infra-config/config.alloy \
87+
./docs/infra-config/nginx.dev.conf \
88+
${{ secrets.DEV_USERNAME }}@${{ secrets.DEV_HOST }}:/home/${{ secrets.DEV_USERNAME }}/solid-connection-dev/
8389
90+
# --- 6. 서버에서 'docker pull' 및 서비스 재시작 ---
8491
- name: Run docker compose and apply nginx config
85-
uses: appleboy/ssh-action@master
86-
with:
87-
host: ${{ secrets.DEV_HOST }}
88-
username: ${{ secrets.DEV_USERNAME }}
89-
key: ${{ secrets.DEV_PRIVATE_KEY }}
90-
script_stop: true
91-
script: |
92-
sudo cp /home/${{ secrets.DEV_USERNAME }}/solid-connection-dev/nginx/default.conf /etc/nginx/conf.d/default.conf
92+
run: |
93+
ssh -i deploy_key.pem \
94+
-o StrictHostKeyChecking=no \
95+
${{ secrets.DEV_USERNAME }}@${{ secrets.DEV_HOST }} \
96+
'
97+
set -e
98+
99+
# 1. 변수를 'image_meta' 단계의 출력값에서 가져옴
100+
export OWNER_LOWERCASE=$(echo "${{ github.repository_owner }}" | tr '[:upper:]' '[:lower:]')
101+
export IMAGE_TAG_ONLY=${{ steps.image_meta.outputs.image_tag }}
102+
export FULL_IMAGE_NAME="ghcr.io/${OWNER_LOWERCASE}/solid-connection-dev:${IMAGE_TAG_ONLY}"
103+
104+
# 2. 서버가 GHCR에 로그인 (pull 받기 위해)
105+
echo "${{ steps.app.outputs.token }}" | docker login ghcr.io -u ${{ github.repository_owner }} --password-stdin
106+
107+
# 3. docker pull (전체 이미지 이름 사용)
108+
echo "Pulling new image layer from GHCR..."
109+
docker pull $FULL_IMAGE_NAME
110+
111+
# 4. 작업 디렉토리로 이동 및 Nginx 설정 이동
112+
cd /home/${{ secrets.DEV_USERNAME }}/solid-connection-dev
113+
mkdir -p ./nginx
114+
mv ./nginx.dev.conf ./nginx/default.conf
115+
116+
# 5. Nginx 재시작
117+
sudo cp ./nginx/default.conf /etc/nginx/conf.d/default.conf
93118
sudo nginx -t
94119
sudo nginx -s reload
95-
96-
cd /home/${{ secrets.DEV_USERNAME }}/solid-connection-dev
120+
121+
# 6. Docker Compose 재시작
122+
echo "Restarting Docker Compose with tag: $IMAGE_TAG_ONLY"
97123
docker compose -f docker-compose.dev.yml down
98-
docker compose -f docker-compose.dev.yml up -d --build
124+
IMAGE_TAG=$IMAGE_TAG_ONLY docker compose -f docker-compose.dev.yml up -d
125+
126+
# 7. <none> 이미지 정리
127+
echo "Pruning dangling docker images..."
128+
docker image prune -f
129+
130+
# 8. stage 인스턴스의 오래된 태그 이미지 정리 (최신 5개 유지)
131+
echo "Cleaning up old tagged images on host, keeping last 5..."
132+
IMAGE_NAME_BASE="ghcr.io/${OWNER_LOWERCASE}/solid-connection-dev"
133+
134+
docker images "${IMAGE_NAME_BASE}" --format "{{.Tag}}" | \
135+
sort -r | \
136+
tail -n +6 | \
137+
xargs -I {} docker rmi "${IMAGE_NAME_BASE}:{}" || true
138+
139+
echo "Deploy and Docker Compose restart finished."
140+
'
141+
142+
# --- 6. 이미지 정리 ---
143+
- name: Clean up old image versions from GHCR
144+
if: success()
145+
uses: snok/container-retention-policy@v2
146+
with:
147+
token: ${{ secrets.GITHUB_TOKEN }}
148+
image-names: solid-connection-dev
149+
delete-untagged: true
150+
keep-n-tags: 5
151+
account-type: org
152+
org-name: ${{ github.repository_owner }}
153+
cut-off: '7 days ago UTC'

0 commit comments

Comments
 (0)