개발 프로젝트

AWS S3/code deploy로 CI/CD 구축기(플리보따리) 2023-12-16

최동훈1 2023. 12. 15. 23:37

결과

내 첫 서버 아키텍쳐이다 ! 감격스러움 ㅠㅠ

1. 우선 가장 많이 참고한 블로그이다 

Spring Boot + GitHub Actions + AWS CodeDeploy를 활용한 CI/CD 구축 (tistory.com)

 

Spring Boot + GitHub Actions + AWS CodeDeploy를 활용한 CI/CD 구축

서론 지금까지 매번 프로젝트를 구축할 때마다 이전 코드들을 번거롭게 봐가면서 CI/CD를 구축했었는데, 이번 기회에 한번 문서화를 해보고자 글을 작성하게 되었습니다. [CI/CD] CI/CD란?, 지속적

dkswnkk.tistory.com

이 블로그 없었다면 실패했을지도 모른다.

1. 마주했던 에러들 

우선 블로그 첫 부분처럼 workflows에 직접 파일 추가해도 되지만 나는 Action에 들어가서 new workflow로 CI.yml을 작성하였다. 

참고 블로그->Action에서 workflow 생성과정을 따라한 부분:  [주의점 (앞부분 new workflow 생성과정만 참고함)]

Github Action을 활용한 SpringBoot 프로젝트 CI/CD (tistory.com)

특히 맨 앞부분  name 을 이용해서 생성하면 자동으로 만들어주는 java CI and gradel 어쩌구 아니라 CI로 설정하면 Action work flow에 내가 설정한 이름대로 나온다 .

# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
# This workflow will build a Java project with Gradle and cache/restore any dependencies to improve the workflow execution time
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-gradle

name:  CI

on:
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]

permissions:
  contents: read

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v3
      - name: Set up JDK 17
        uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: 'temurin'
          #application.yml 파일을 감추고 빌드할때 githubsecret에 저장된 application.yml을 복사해서 생성한뒤
          #빌드에 포함시킴
      - name: Set YML
        run: |
          mkdir -p src/main/resources
          echo "${{ secrets.APPLICATION_YML }}" | base64 --decode > src/main/resources/application.yml
        #gradlew 실행을 위한 권한 추가
      - name: Grant execute permission for gradlew
        run: chmod +x gradlew
      - name: Build with Gradle
        run: ./gradlew build -x test
        #uses: gradle/gradle-build-action@bd5760595778326ba7f1441bcf7e88b49de61a25 # v2.6.0

내가 설정한 CI 최종본이다

 

CI를 순차적으로 변경했던 과정이다. 

 

0.가장 첫번째 빌드가 안됬던 원인은 ./gradlew 실행권한이 없기 때문이다. 그래서 이 권한을 추가하는 코드를 빌드 하기전 step 에 작성하였다. 

#gradlew 실행을 위한 권한 추가
      - name: Grant execute permission for gradlew
        run: chmod +x gradlew

 

1.마주한 첫번째 난관 과연 Application.yml을 어떻게 적용시켜서 빌드 해야 할까 ?? 

알다싶이 application.yml이 없으면 빌드 자체가 안되고 이런 오류가 뜬다. 또한 민감한 정보 때문에(DB정보랑 비번, AccessToken 정보 등) github에 안올리는게 원칙이다 

이점을 찾아봤는데 아래의 방법대로 했다. 

[Spring/TIL] Github Actions 배포환경에서 Github Submodule로 application.yml 관리하기. (tistory.com)

 

[Spring/TIL] Github Actions 배포환경에서 Github Submodule로 application.yml 관리하기.

현재 프로젝트의 핵심 기능 구현이 어느 정도 마무리가 되면서 이제 배포환경을 고려해야 했습니다. 가장 흔하게 사용하는 Jenkins 말고 이번에는 Github Actions를 사용해 보기로 결정했는데요. 여러

resilient-923.tistory.com

여기서 소개하는 방법중에 Github Secret을 이용한 방법을 했다. 그래서 내용이 부실해서 다른 블로그에서 도움을 받았다. 

Github Secret 으로 yml 파일 관리하기 (velog.io)

 

Github Secret 으로 yml 파일 관리하기

민감한 정보(유출되면 안 되는 비밀번호 등)를 Github에 올리게 되면 피똥을 쌀 수도 있으므로, 이를 암호화 해서 관리하는 방법에 대해서 알아보자.

velog.io

이렇게 한 다음에 Set YML 단계를 만들고 해당 단계에서 mkdir로 파일을 만들고 복사하는 방법을 사용하였다. 

- name: Set YML
        run: |
          mkdir -p src/main/resources
          echo "${{ secrets.APPLICATION_YML }}" | base64 --decode > src/main/resources/application.yml

Application yml 설정후 추가한 CI

 

--(추가) 

이렇게 application.yml 전체를 githubsecrets로 해 버리는 경우에는 협업할때, yml 내용 변경에 팀원들이 수동으로 공유해야만 하는 상황이 발생한다. 그래서 이 블로그 내용 : YML 설정 파일 암호화에서 Github Repository secrets으로 변경 :: 고민의 흔적 (tistory.com) 처럼 해당 DB의 주소나 PW 같은 정보를 intelliJ내에 Configuration에서 설정 해준다음, github secrets에는 이런 변수들만 저장해서 배포 스크립트에서 추가해주는 식으로 바꾼다면 조금더 협업하기 쉽고, application.yml 도 github에 문제없이 공유 가능하다.  

 

2. 이렇게 1차적인 CI는 성공하였다. 

그다음 발생한 문제는 IAM 설정후에 액세스 키가 안나온 것이다. 정책이 바꼈는가 아니면 그당시 블로그에 나오는 것과 다르게  바로 AccessKey를 다운하는 게 아니라 이런 게 다운받아졌다.

donghun-deploy_credentials.csv
0.00MB

 

그래서 4.GItHub Actions secrets 설정을 할때 해당 정보가 없어서 당황했지만 아래의 블로그를 보고 IAM 사용자별 AccessKey를 확인하는 방법을 발견후 제대로 저장하였다. 

 

[AWS] AWS Access Key란? (엑세스 키 생성 방법) — 현기의 개발블로그 (tistory.com)

 

[AWS] AWS Access Key란? (엑세스 키 생성 방법)

Access Key는 AWS 계정에 액세스하기 위한 인증 정보 중 하나입니다. Access Key ID와 Secret Access Key 두 부분으로 구성되어 있습니다. AWS 자원에 접근하거나, API를 호출할 때 사용됩니다. 보통 백엔드에서

hyunki99.tistory.com

이렇게 생성뒤 제대로된 Accesskey를 다운하였다.

 

3. 그다음 일어난 문제인데 파일을 추가할때 CD 로 작성하고 CD.yml으로 작성 안해서 배포WorkFlow에 반영이 안됬었다. ㅠㅠㅠ 그래서 이름 수정하고는 2개의 CI Flow와 CD Flow가 정상적으로 반영 되었다. !! 또 내 intelliJ에서 workflow 디렉토리에 바로 생성해도 되고 0번 과정처럼 Action의 new Workflow 에서 생성해도 된다. 주의 점은 아래 env: 부분에서 S3_Bucket_Name을 내가 앞전에 만들어놓은 이름으로 해야 된다 

#workflow의 이름
name: CD

# 해당 workflow가 언제 실행될 것인지에 대한 트리거를 지정
on:
  push:
    branches: [ main ] # main branch로 push 될 때 실행됩니다.


# 해당 yml 내에서 사용할 key - value
env:
  S3_BUCKET_NAME: donghun-bucket
  PROJECT_NAME: cicd

# workflow는 한개 이상의 job을 가지며, 각 job은 여러 step에 따라 단계를 나눌 수 있습니다.
jobs:
  build:
    name: CD
    # 해당 jobs에서 아래의 steps들이 어떠한 환경에서 실행될 것인지를 지정합니다.
    runs-on: ubuntu-latest

    steps:
      # 작업에서 액세스할 수 있도록 $GITHUB_WORKSPACE에서 저장소를 체크아웃합니다.
      - uses: actions/checkout@v3
      - name: Set up JDK 17
        uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: 'temurin'

      - name: Set YML
        run: |
          mkdir -p src/main/resources
          echo "${{ secrets.APPLICATION_YML }}" | base64 --decode > src/main/resources/application.yml

      - name: Grant execute permission for gradlew
        run: chmod +x ./gradlew
        shell: bash

      - name: Build with Gradle
        run: ./gradlew clean build -x test
        shell: bash

      - name: Make zip file
        run: zip -r ./$GITHUB_SHA.zip .
        shell: bash

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ${{ secrets.AWS_REGION }}

      # script files 복사
      - name: Copy script
        run: cp ./scripts/*.sh ./deploy

      # S3에 업로드
      - name: Upload to S3
        run: aws s3 cp --region ap-northeast-2 ./$GITHUB_SHA.zip s3://$S3_BUCKET_NAME/$PROJECT_NAME/$GITHUB_SHA.zip

      # Deploy
      - name: Deploy
        run: |
          aws deploy create-deployment \
          --application-name donghun-CICD-plypack \
          --deployment-config-name CodeDeployDefault.AllAtOnce \
          --deployment-group-name donghun-cicd \
          --file-exists-behavior OVERWRITE \
          --s3-location bucket=donghun-bucket,bundleType=zip,key=cicd/$GITHUB_SHA.zip \
          --region ap-northeast-2 \

내 CD.yml 파일 최종본이다. 

여기서 주의점은 

*매우중요* 
CI 뿐만아니라 CD 파일에도 github에 올라와있지 않은 yml 파일에 대한 설정을 추가해 놓아야 된다는 것이다.  그래서 CI.yml 폴더에서 적어 놓았던 아래의 코드를 빌드 순서에 맞게 넣어놓았다. 

      - name: Set YML
        run: |
          mkdir -p src/main/resources
          echo "${{ secrets.APPLICATION_YML }}" | base64 --decode > src/main/resources/application.yml

 

 

4. 그다음 마주한 에러 내가 생성한 IAM의 역할을 EC2로 설정한 뒤 지금 돌아가고 있는 인스턴스에 IAM 역할을 부여하는 과정이다 그런데 블로그에서 나오는것처럼 아무리 찾아도 인스턴스설정-IAM 역할 연결/바꾸기 이 것이 안나오는 것이다. 그래서 또 검색한 결과 보안 탭에서 IAM역할을 설정할 수 있었다. 

아래는 이때 참고한 블로그이다.

[EC2 기초] EC2 인스턴스 역할 - ssunw (tistory.com)

 

[EC2 기초] EC2 인스턴스 역할

EC2 인스턴스 역할 EC2 인스턴스에 IAM 역할을 사용하는 법을 익혀보자. SSH 를 사용하여 EC2 인스턴스에 접근하거나 EC2 인스턴스 연결을 사용해서 EC2 인스턴스에 접근할 수 있다. 둘 중 편한 방법을

ssunw.tistory.com

 

5. 그다음오류는 아니고 살짝 헷갈릴수 있는 것인데 , 아래의 값들을 내가 쭉 따라오면서 설정했던 값들로 다 설정해야 한다. 

여기서 Application-name은 codedeploy에서 내가 생성한 application 이름이다.

6. 그런데 문제가 생겼다. 이상태에서 Push 하면 바로 배포가 이루어져야 하는데 배포가 되지 않은 것이다. 첫번째 문제는 can't find user for ec2-user 이런 문제가 발생한 것이다. 그래서 Chat GPT에게 물어본 결과 아래와 같은 결론을 얻었다. 
"can't find user for ec2-user"라는 오류는 AWS CodeDeploy에서 EC2 인스턴스에 배포를 시도할 때, EC2 인스턴스에 `ec2-user` 사용자가 없을 때 발생할 수 있습니다. 

AWS CodeDeploy는 기본적으로 `ec2-user` 사용자를 대상으로 하며, 대상 EC2 인스턴스에서 이 사용자가 없으면 배포 중에 문제가 발생할 수 있습니다. 

해결 방법은 다음과 같습니다:

1. **사용자 추가:**
   - EC2 인스턴스에 `ec2-user`라는 사용자를 수동으로 추가합니다. 이를 위해서는 SSH를 사용하여 EC2 인스턴스에 로그인하고 `ec2-user`를 추가하면 됩니다.

   ```bash
   sudo adduser ec2-user
   ```

2. **IAM 역할 및 권한 확인:**
   - EC2 인스턴스에 CodeDeploy 에이전트가 설치되어 있어야 합니다. 이를 확인하고 없으면 설치하세요.
   - IAM 역할 및 권한이 올바르게 구성되어 있는지 확인하세요. CodeDeploy 역할이 EC2 인스턴스에 할당되어 있어야 합니다.

3. **SSH 키 관리:**
   - EC2 인스턴스에 대한 SSH 키가 올바르게 설정되어 있는지 확인하세요. CodeDeploy는 배포를 위해 SSH를 사용하며, SSH 키가 올바르게 구성되어 있어야 합니다.

4. **CodeDeploy 설정 확인:**
   - CodeDeploy 애플리케이션 및 배포 그룹 설정이 올바른지 확인하세요. 특히, 대상 EC2 인스턴스 및 배포 구성이 정확한지 확인하세요.

이러한 단계를 따라 오류를 해결할 수 있습니다. 또한, CodeDeploy 배포를 수행하는 동안 발생하는 로그를 확인하여 추가적인 문제를 식별할 수 있습니다.

 

그래서 1번째 방법으로 ec2-user라는 사용자를 추가하니까 빌드가 되고 배포는 성공이였다. 

--(추가)

여기서 ec2-user 란 로그인 할 User의 ID를 뜻하는 말인것 같다.  즉, 만약 처음 디폴트 값은 mobaXterm의 login 할때의 이름처럼 :ubuntu 인것 같다. 

 

 

그런데 문제가 또 생겼다. 

 

7. -Plain.jar 가 생성되서 배포 스크립트 상에서 해당 jar가 실행되는 문제가 발생되는 것이다. 왜냐하면 clean build를 하면 실행executable 파일 외에 plain 이라는 파일이 하나 더 생기는데 이것이 실행되서 실행이 안됬던 것이다. 

엉뚱한 jar가 실행되는 모습

그래서 배포시에 plain 파일이 생기지 않도록 build.gradle에 해당 설정을 추가하니까 정상적으로 배포가 되었다. 

//배포시 -plain.jar 생성 안되게 하는 코드
jar.enabled = false

 

 

또한 만약 배포가 실패되었으면, aws-codeDeploy-배포-배포ID-View events에 들어가면 배포 과정에 이상이 없는지 확인할 수 있다. 여기서 재배포 라는 기능도 있어서 애러 수정한 다음에 바로 재배포도 가능하다. 

 

장장 5시간 걸린거 같다.. 그래도 내 첫 CI/CD 아키텍쳐를 만들어본거라 서 매우 가치있었고 뿌듯하다. !! 

CI CD 래퍼런스.pdf
3.69MB