DevOps/Git

[GitHub] GitHub Actions로 Spring Boot 애플리케이션을 AWS EC2에 배포하기 - 컴도리돌이

컴도리돌이 2025. 2. 22. 21:00
728x90
728x90

이번 글에서는 GitHub Actions를 사용하여 Spring Boot 애플리케이션을 AWS EC2에 배포하는 과정을 자동화한 경험을 공유하고자 합니다. main 브랜치에 push가 발생하면 자동으로 실행되는 워크플로우는 어떻게 구성되어 있을까요? 전체 과정은 코드 체크아웃, Java 환경 설정, 환경 변수 복원, AWS 인증 및 보안 설정, Gradle 빌드, JAR 파일 전송, 그리고 EC2에서 애플리케이션 실행으로 이루어져 있습니다.

 

GitHub Actions가 실행되면 가장 먼저 수행되는 작업은 무엇일까요? 바로 저장소의 코드를 가져오는 것입니다. 이를 위해 actions/checkout@v3를 사용하여 최신 버전의 코드를 runner 환경으로 다운로드합니다.

steps:
  - name: Checkout Repository
    uses: actions/checkout@v3

  - name: Set up JDK 21
    uses: actions/setup-java@v3
    with:
      distribution: 'temurin'
      java-version: '21'

 

위 코드는 GitHub Actions가 현재 리포지토리의 코드를 가져오고, Java 21 환경을 설정하는 과정을 보여줍니다. Java 버전은 필요에 따라 변경될 수 있겠죠?

 

다음으로, 애플리케이션 실행에 필요한 환경 변수를 복원하는 과정이 필요합니다. GitHub Secrets에서 application.yml 파일을 가져와 src/main/resources/ 경로에 저장하는 방식으로 이루어집니다. 보안상의 이유로 환경 변수는 base64로 인코딩되어 있으며, 이를 디코딩하여 원래의 설정 파일로 변환합니다.

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

이 단계를 통해 GitHub Secrets에 저장된 설정 파일을 안전하게 사용할 수 있습니다. 보안 정보를 외부에 노출하지 않고도 말이죠.

 

보안 그룹 설정을 위해서는 GitHub Actions의 Public IP를 확인해야 합니다. haythem/public-ip@v1.3을 사용하여 현재 실행 중인 GitHub Actions Runner의 IPv4 주소를 가져온 후 출력하여 확인할 수 있습니다.

  - name: Get Public IP
    id: ip
    uses: haythem/public-ip@v1.3

  - name: Print Public IP
    run: echo "Current GitHub Actions IP is ${{ steps.ip.outputs.ipv4 }}"

이렇게 확인한 Public IP는 AWS 보안 그룹 설정에 활용될 수 있습니다. 이를 통해 EC2에 접근할 수 있도록 필요한 네트워크 설정을 적용할 수 있습니다.

 

이제 AWS EC2에 접근하기 위한 인증 설정을 해야 합니다. aws-actions/configure-aws-credentials@v3 액션을 사용하여 GitHub Secrets에서 제공한 AWS 액세스 키 및 시크릿 키를 활용하여 인증을 수행합니다. 이후 AWS CLI 명령어를 통해 보안 그룹 설정을 변경할 수 있습니다.

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

이 과정을 통해 GitHub Actions가 AWS 리소스에 접근할 수 있도록 권한을 설정합니다.

 

GitHub Actions의 Public IP를 확인했다면, 이제 AWS 보안 그룹에서 EC2의 22번 포트(SSH 접속 허용)를 해당 IP에서 접근할 수 있도록 허용해야 합니다. aws ec2 authorize-security-group-ingress 명령어를 사용하여 현재 GitHub Actions Runner의 IP를 추가합니다.

  - name: Allow SSH access from GitHub Actions IP
    run: |
      aws ec2 authorize-security-group-ingress \
        --group-id ${{ secrets.AWS_SECURITY_GROUP_ID }} \
        --protocol tcp --port 22 --cidr ${{ steps.ip.outputs.ipv4 }}/32 \
        --region ${{ secrets.AWS_REGION }} || true

이렇게 설정하면 EC2의 22번 포트에 대한 SSH 접속이 허용됩니다.

 

이제 SSH 키를 설정하고, EC2에 접속할 준비를 해야 합니다. 먼저 ~/.ssh 디렉토리를 생성한 후, GitHub Secrets에서 제공된 개인 키를 id_rsa 파일로 저장하고, 접근 권한을 600으로 설정하여 보안을 강화합니다. 이후 ssh-keyscan을 사용하여 EC2의 호스트를 known_hosts에 추가하여 SSH 접속 시 경고를 방지합니다.

  - name: Set up SSH key
    run: |
      mkdir -p ~/.ssh
      echo "${{ secrets.EC2_SSH_KEY }}" | tr -d '\r' > ~/.ssh/id_rsa
      chmod 600 ~/.ssh/id_rsa
      ssh-keyscan -H ${{ secrets.EC2_HOST }} >> ~/.ssh/known_hosts

이제 안전하게 EC2에 접속할 수 있습니다.

 

프로젝트 빌드를 위해 Gradle을 실행하는 과정도 필요합니다. 먼저 실행 권한을 부여한 후, 빌드를 진행합니다.

  - name: Build with Gradle
    run: |
      chmod +x gradlew
      ./gradlew clean build

 

빌드가 완료되면 생성된 JAR 파일을 EC2로 전송합니다.

  - name: Transfer JAR to AWS EC2
    uses: appleboy/scp-action@v0.1.7
    with:
      host: ${{ secrets.EC2_HOST }}
      username: ${{ secrets.EC2_USER }}
      port: ${{ secrets.EC2_PORT }}
      key: ${{ secrets.EC2_SSH_KEY }}
      source: "build/libs/"
      target: "/home/${{ secrets.EC2_USER }}/app"
      strip_components: 2

이렇게 하면 최신 JAR 파일이 EC2의 지정된 경로로 업로드됩니다.

 

배포가 완료되었으면, 기존 애플리케이션을 종료하고 새 버전을 실행해야 합니다. appleboy/ssh-action@v1.2.0을 사용하여 EC2에 SSH로 접속한 후, app.pid 파일을 확인하여 기존 프로세스를 종료하고, JAR 파일에 실행 권한을 부여한 후, nohup을 이용하여 백그라운드에서 실행합니다. 실행된 프로세스의 PID를 app.pid 파일에 저장하여 이후 종료할 수 있도록 합니다.

  - name: Deploy and Run JAR on EC2
    uses: appleboy/ssh-action@v1.2.0
    with:
      host: ${{ secrets.EC2_HOST }}
      username: ${{ secrets.EC2_USER }}
      key: ${{ secrets.EC2_SSH_KEY }}
      port: ${{ secrets.EC2_PORT }}
      script: |
        if [ -f /home/${{ secrets.EC2_USER }}/app/app.pid ]; then
          kill $(cat /home/${{ secrets.EC2_USER }}/app/app.pid) || true
          rm -f /home/${{ secrets.EC2_USER }}/app/app.pid
        fi
        chmod +x /home/${{ secrets.EC2_USER }}/app/*.jar
        nohup java -jar /home/${{ secrets.EC2_USER }}/app/*SNAPSHOT.jar > /home/${{ secrets.EC2_USER }}/app/app.log 2>&1 & echo $! > /home/${{ secrets.EC2_USER }}/app/app.pid

 

마지막으로, 보안을 위해 GitHub Actions의 IP를 AWS 보안 그룹에서 제거해야 합니다. aws ec2 revoke-security-group-ingress 명령을 사용하여 22번 포트에 대한 접근 권한을 삭제하여 불필요한 SSH 접근을 차단합니다.

  - name: Remove GitHub Actions IP from Security Group
    run: |
      aws ec2 revoke-security-group-ingress \
        --group-id ${{ secrets.AWS_SECURITY_GROUP_ID }} \
        --protocol tcp --port 22 \
        --cidr ${{ steps.ip.outputs.ipv4 }}/32 \
        --region ${{ secrets.AWS_REGION }} || true

 

728x90
728x90