-
Notifications
You must be signed in to change notification settings - Fork 8
refactor: CD 성능 개선 #552
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refactor: CD 성능 개선 #552
Changes from 6 commits
98b7c03
83d611f
216e83a
898d594
a76e446
59c0116
c86901a
595c6aa
63a16fa
ab3054e
01114c3
229d9aa
1b57e74
0c431df
7ae94b1
be3d47a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -10,6 +10,7 @@ jobs: | |||||||
| runs-on: ubuntu-latest | ||||||||
| permissions: | ||||||||
| contents: read | ||||||||
| packages: write | ||||||||
|
|
||||||||
| steps: | ||||||||
| - name: Checkout the code | ||||||||
|
|
@@ -18,81 +19,121 @@ jobs: | |||||||
| token: ${{ secrets.SUBMODULE_ACCESS_TOKEN }} | ||||||||
| submodules: true | ||||||||
|
|
||||||||
| # --- Java, Gradle 설정 --- | ||||||||
| - name: Set up JDK 17 | ||||||||
| uses: actions/setup-java@v4 | ||||||||
| with: | ||||||||
| java-version: '17' | ||||||||
| distribution: 'temurin' | ||||||||
|
|
||||||||
| # Configure Gradle for optimal use in GitHub Actions, including caching of downloaded dependencies. | ||||||||
| # See: https://github.com/gradle/actions/blob/main/setup-gradle/README.md | ||||||||
| - name: Setup Gradle | ||||||||
| uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0 | ||||||||
|
|
||||||||
| uses: gradle/actions/setup-gradle@v3 | ||||||||
| - name: Grant execute permission for Gradle wrapper(gradlew) | ||||||||
| run: chmod +x ./gradlew | ||||||||
|
|
||||||||
| - name: Build with Gradle | ||||||||
| run: ./gradlew bootJar | ||||||||
|
|
||||||||
| - name: Copy jar file to remote | ||||||||
| uses: appleboy/scp-action@master | ||||||||
| # --- Docker 설정 --- | ||||||||
| - name: Set up Docker Buildx | ||||||||
| uses: docker/setup-buildx-action@v3 | ||||||||
| with: | ||||||||
| host: ${{ secrets.DEV_HOST }} | ||||||||
| username: ${{ secrets.DEV_USERNAME }} | ||||||||
| key: ${{ secrets.DEV_PRIVATE_KEY }} | ||||||||
| source: "./build/libs/*.jar" | ||||||||
| target: "/home/${{ secrets.DEV_USERNAME }}/solid-connection-dev/" | ||||||||
|
|
||||||||
| - name: Copy docker file to remote | ||||||||
| uses: appleboy/scp-action@master | ||||||||
| platforms: linux/arm64 | ||||||||
| - name: Log in to GitHub Container Registry (GHCR) | ||||||||
| uses: docker/login-action@v3 | ||||||||
| with: | ||||||||
| host: ${{ secrets.DEV_HOST }} | ||||||||
| username: ${{ secrets.DEV_USERNAME }} | ||||||||
| key: ${{ secrets.DEV_PRIVATE_KEY }} | ||||||||
| source: "./Dockerfile" | ||||||||
| target: "/home/${{ secrets.DEV_USERNAME }}/solid-connection-dev/" | ||||||||
| registry: ghcr.io | ||||||||
| username: ${{ github.repository_owner }} | ||||||||
| password: ${{ secrets.GITHUB_TOKEN }} | ||||||||
|
|
||||||||
| - name: Copy docker compose file to remote | ||||||||
| uses: appleboy/scp-action@master | ||||||||
| with: | ||||||||
| host: ${{ secrets.DEV_HOST }} | ||||||||
| username: ${{ secrets.DEV_USERNAME }} | ||||||||
| key: ${{ secrets.DEV_PRIVATE_KEY }} | ||||||||
| source: "./docker-compose.dev.yml" | ||||||||
| target: "/home/${{ secrets.DEV_USERNAME }}/solid-connection-dev/" | ||||||||
| # --- 2. 이미지 메타데이터(이름, 태그) 정의 --- | ||||||||
| # 빌드/푸시 단계와 SSH 단계에서 공통으로 사용할 변수를 미리 정의합니다. | ||||||||
| - name: Define image name and tag | ||||||||
| id: image_meta | ||||||||
| run: | | ||||||||
| OWNER_LOWERCASE=$(echo "${{ github.repository_owner }}" | tr '[:upper:]' '[:lower:]') | ||||||||
| IMAGE_TAG=$(date +'%Y%m%d-%H%M%S') | ||||||||
| echo "image_name=ghcr.io/${OWNER_LOWERCASE}/solid-connection-dev" >> $GITHUB_OUTPUT | ||||||||
| echo "image_tag=${IMAGE_TAG}" >> $GITHUB_OUTPUT | ||||||||
|
|
||||||||
| - name: Copy alloy config file to remote | ||||||||
| uses: appleboy/scp-action@master | ||||||||
| # --- 3. Docker 이미지 빌드, 푸시, 캐시 --- | ||||||||
| # 'docker/build-push-action'을 사용하여 캐시 옵션을 적용합니다. | ||||||||
| - name: Build, push, and cache Docker image | ||||||||
| uses: docker/build-push-action@v5 | ||||||||
| with: | ||||||||
| host: ${{ secrets.DEV_HOST }} | ||||||||
| username: ${{ secrets.DEV_USERNAME }} | ||||||||
| key: ${{ secrets.DEV_PRIVATE_KEY }} | ||||||||
| source: "./docs/infra-config/config.alloy" | ||||||||
| target: "/home/${{ secrets.DEV_USERNAME }}/solid-connection-dev/" | ||||||||
| context: . | ||||||||
| platforms: linux/arm64 | ||||||||
| push: true | ||||||||
| tags: ${{ format('{0}:{1}', steps.image_meta.outputs.image_name, steps.image_meta.outputs.image_tag) }} | ||||||||
| cache-from: type=registry,ref=${{ steps.image_meta.outputs.image_name }}:buildcache | ||||||||
| cache-to: type=registry,ref=${{ steps.image_meta.outputs.image_name }}:buildcache,mode=max | ||||||||
|
|
||||||||
| - name: Copy nginx config to remote | ||||||||
| uses: appleboy/scp-action@master | ||||||||
| with: | ||||||||
| host: ${{ secrets.DEV_HOST }} | ||||||||
| username: ${{ secrets.DEV_USERNAME }} | ||||||||
| key: ${{ secrets.DEV_PRIVATE_KEY }} | ||||||||
| source: "./docs/infra-config/nginx.dev.conf" | ||||||||
| target: "/home/${{ secrets.DEV_USERNAME }}/solid-connection-dev/nginx" | ||||||||
| rename: "default.conf" | ||||||||
| # --- 4. 설정 파일들만 scp로 전송 --- | ||||||||
| - name: Copy config files to remote | ||||||||
| run: | | ||||||||
| echo "${{ secrets.DEV_PRIVATE_KEY }}" > deploy_key.pem | ||||||||
| chmod 600 deploy_key.pem | ||||||||
|
|
||||||||
| scp -i deploy_key.pem \ | ||||||||
| -o StrictHostKeyChecking=no \ | ||||||||
| ./docker-compose.dev.yml \ | ||||||||
| ./docs/infra-config/config.alloy \ | ||||||||
| ./docs/infra-config/nginx.dev.conf \ | ||||||||
| ${{ secrets.DEV_USERNAME }}@${{ secrets.DEV_HOST }}:/home/${{ secrets.DEV_USERNAME }}/solid-connection-dev/ | ||||||||
|
|
||||||||
| # --- 5. 서버에서 'docker pull' 및 서비스 재시작 --- | ||||||||
| - name: Run docker compose and apply nginx config | ||||||||
| uses: appleboy/ssh-action@master | ||||||||
| with: | ||||||||
| host: ${{ secrets.DEV_HOST }} | ||||||||
| username: ${{ secrets.DEV_USERNAME }} | ||||||||
| key: ${{ secrets.DEV_PRIVATE_KEY }} | ||||||||
| script_stop: true | ||||||||
| script: | | ||||||||
| sudo cp /home/${{ secrets.DEV_USERNAME }}/solid-connection-dev/nginx/default.conf /etc/nginx/conf.d/default.conf | ||||||||
| run: | | ||||||||
| echo "${{ secrets.DEV_PRIVATE_KEY }}" > deploy_key_ssh.pem | ||||||||
| chmod 600 deploy_key_ssh.pem | ||||||||
|
||||||||
|
|
||||||||
| ssh -i deploy_key_ssh.pem \ | ||||||||
| -o StrictHostKeyChecking=no \ | ||||||||
| ${{ secrets.DEV_USERNAME }}@${{ secrets.DEV_HOST }} \ | ||||||||
| ' | ||||||||
| set -e | ||||||||
|
|
||||||||
| # [수정] 1. 변수를 'image_meta' 단계의 출력값에서 가져옴 | ||||||||
| export OWNER_LOWERCASE=$(echo "${{ github.repository_owner }}" | tr '[:upper:]' '[:lower:]') | ||||||||
| export IMAGE_TAG_ONLY=${{ steps.image_meta.outputs.image_tag }} | ||||||||
| export FULL_IMAGE_NAME="ghcr.io/${OWNER_LOWERCASE}/solid-connection-dev:${IMAGE_TAG_ONLY}" | ||||||||
|
|
||||||||
| # 2. 서버가 GHCR에 로그인 (pull 받기 위해) | ||||||||
| echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.repository_owner }} --password-stdin | ||||||||
|
||||||||
| echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.repository_owner }} --password-stdin | |
| OWNER_LOWERCASE=$(echo "${{ github.repository_owner }}" | tr '[:upper:]' '[:lower:]') | |
| echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${OWNER_LOWERCASE} --password-stdin |
🤖 Prompt for AI Agents
.github/workflows/dev-cd.yml around line 100: the docker login uses ${{
github.repository_owner }} which may contain uppercase letters while the image
tag and OWNER_LOWERCASE are used elsewhere, causing GHCR auth failures; change
the login username to the already-computed OWNER_LOWERCASE variable (or compute
a lowercase owner just before login) so the docker login user matches the
lowercase image namespace, and apply the same change in prod-cd.yml.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이전에 lower_case로 통일하도록 이미지 메타데이터 정의 스텝에서 전처리를 해두었기에 문제가 나지 않을 것 같은데?
심지어 내 닉네임이 Hexeong인데, fork 레포에서 깃헙 액션을 실행시켰을 때에 문제가 발생하지 않았었어
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
맞습니다! 제가 잘못 지적했네요. 죄송합니다. 🙇
-
Docker/GHCR 로그인은 사용자명 대소문자를 구분하지 않습니다.
- Line 100의
docker login ghcr.io -u ${{ github.repository_owner }}는Hexeong이든hexeong이든 정상적으로 인증됩니다.
- Line 100의
-
이미지 경로는 올바르게 소문자를 사용하고 있습니다.
- Line 95에서
OWNER_LOWERCASE를 재계산하고 - Line 97에서
FULL_IMAGE_NAME에 소문자 버전을 사용하여 - Line 103의
docker pull이 정상 작동합니다.
- Line 95에서
실제 테스트에서 문제가 없었다는 것이 이를 증명하네요. 불필요한 수정 제안을 드려 혼란을 드려 죄송합니다!
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
지금 쓰기가 가능한 토큰이 서버로 전송되는데 보안상 취약하지 않을까요...? 읽기 전용 토큰을 따로 발급해서 사용하는 게 좋아보입니당
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SSH를 통해 GHCR에 접근하는 이 방식을 적용하려면, SUBMODULE_ACCESS_TOKEN처럼 Fine-grained Token을 사용하는 것이 보안상 가장 좋다고 생각합니다!
하지만 이 방식을 사용하려면 GHCR 읽기 권한이 있는 분이 직접 토큰을 발급해야 하는데, 이는 특정 계정에 파이프라인이 의존하게 되는 문제가 있어 망설여졌습니다.
그래서 일단은 임시로 GITHUB_TOKEN을 사용하는 방식을 적용했습니다만, 혹시 이 '개인 종속성' 문제를 해결할 더 좋은 방법이 있다면 의견 부탁드립니다! @lsy1307
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
machine user 개념으로 CI/CD용 계정을 따로 만들어서 사용하는 건 어떨까요? Github Docs에도 나와있는 내용입니다!
참고 : https://docs.github.com/en/get-started/learning-about-github/types-of-github-accounts#user-accounts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
machine user 대신 최근 Github 추천하는 방식인 Github App을 사용해서 Repository에서 임시 토큰을 발급할 수 있도록 개선했습니다! 해당 문제는 해결된 것 같아요!
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
image-names 를 solid-connection-dev 로 설정해야 할 듯 합니다 ~!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
반영했습니다!
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
개행 하나 부탁드려요~
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
반영했습니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
github.repository_owner로 설정하면 레포 소유자 이름(e.g. whqtker)으로 고정되는 건가요 ? 만약 그렇다면,solid-connection과 같이 사용자에 종속되지 않는 이름으로 설정하는 게 좋을 거 같습니다 !There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Organization에 속한 레포의 워크플로우 실행의 경우
github.repository_owner은 Organization 이름인solid-connection이 됩니다! 때문에 사용자 이름으로 종속되지는 않아 해당 문제는 없을 것 같아요!There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
확인했습니다 ~!