Server/CLOUD

[AWS, Github Action] Elastic Beanstalk에 SpringBoot 배포하기(2) - IAM 인증키 Github Action에서 사용하여 배포

EARTH_ROOPRETELCHAM 2021. 10. 14. 15:19
반응형

들어가기 전에

해당 글은 Elastic Beanstalk의 기본 세팅이 되어 있다는 가정하에 진행합니다. 만약, Elastic Beanstalk의 어플리케이션 및 환경 구성이 되어 있지 않다면 하기 글을 클릭하여 먼저 구성하고 이 포스팅을 읽는 것을 권해드립니다.

이전 포스팅

다음 포스팅

Github Action을 통해 SpringBoot 어플리케이션 EB에 배포하기

이번 포스팅에서 구현하려는 것은 Github Action을 통해 Elastic Beanstalk에 SpringBoot 어플리케이션을 배포하는 것입니다.

  • SpringBoot 어플리케이션을 jar로 말아 올릴 때에 SpringBoot 앞단에 Nginx를 띄우기 위한 과정 역시 포함되어 있습니다.
  • Elastic Beanstalk 환경 구성 시 ALB(Application Load Balancer)를 사용하도록 설정했다고 가정하고 진행합니다.
    • 해당 내용은 이전 포스팅에 있으니, EB 환경설정이 필요하신 경우 해당 포스팅을 먼저 확인하길 바랍니다.

Github Action을 통해 SpringBoot 어플리케이션 EB에 배포하기

IAM 인증키 Github Action에 사용하기

AWS 서비스가 아닌 Github Action을 통해 Elastic Beanstalk(AWS 서비스)에 명령을 하고자 한다면 권한이 있어야 합니다.

  • IAM 사용자를 이용한 인증키(accessKey, secretKey)를 이용해 외부 서비스가 AWS 서비스에 대한 명령 권한을 받을 수 있습니다.

IAM 인증키 발급받기

먼저, IAM 페이지에 접근하여 액세스 관리 > 사용자를 클릭합니다. 그 후, 사용자 추가를 눌러 IAM 사용자 추가를 진행합니다.

IAM 사용자 추가

평소 IAM 사용자 추가에서는 암호를 이용해 AWS 콘솔 엑세스를 진행했다면, github action에서 사용하기 위한 accessKey와 secretKey 발급을 위해 액세스 키 방식으로 IAM 사용자를 추가합니다.

액세스 키 방식의 IAM 사용자 추가

해당 사용자의 권한으로는 기존 정책 직접 연결 > AdministratorAccess-AWSElasticBeanstalk을 선택합니다.

기존 정책 직접 연결

그 후, 태그에서는 다른 IAM 사용자와 차이를 주기 위해 Name이라는 태그를 지정하고 사용자를 만듭니다.

IAM 사용자 만들기

사용자가 추가되면 아래와 같이 액세스 키 ID와 비밀 엑세스 키를 얻을 수 있습니다. 해당 값을 따로 메모장에 저장해둡니다.

액세스 키 ID와 비밀 액세스 키 발급

IAM 인증키 Github에 적용하기

먼저 Elastic Beanstalk과 연결하여 CD를 진행할 Repository에 접속합니다. 그 뒤 Settings > Secrets > New repository secret을 클릭합니다.

Github Secrets 세팅

위 과정이 완료되면, 하기와 같은 키가 모두 저장된 것입니다.

  • AWS_ACCESS_KEY_ID: 액세스 키 ID
  • AWS_SECRET_ACCESS_KEY: 비밀 액세스 키

이제는 위에서 등록한 Github Secrets를 Github Action에서 사용할 수 있도록 workflow 스크립트 내에 설정을 해보겠습니다.

Github Action CD 스크립트 작성하기

Beanstalk으로 배포하기 위한 스크립트이므로, Beanstalk Deploy라는 Github Action 플러그인을 사용해보겠습니다.

User latest version 클릭 후 installation 복사

위와 같이 Beanstalk Deploy Github Action 플러그인에 접근하여 최신 버전 설치 코드를 복사한 후 아래와 같이 Github Action에서 신규 workflows를 생성합니다. 자세한 코드 내용은 하단에 작성해두었습니다.

CD 용 Github Action workflows 생성

[ earth-cd.yml ]

name: earth-github-action-test CD

on:
  push:
    branches: [ develop ] # develop에 push될 때 CD가 일어나도록 핸들링

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v2

      - name: Set up JDK 11
        uses: actions/setup-java@v1 # 최신 버전을 쓰고 싶었으나 이슈가 생겨서 기존에 CI에서 쓰던 버전 사용
        with:
          java-version: 11

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

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

      - name: Get current time
        uses: 1466587594/get-current-time@v2
        id: current-time
        with:
          format: YYYY-MM-DDTHH-mm-ss # 다른 포맷으로 변경 가능(MomentJS format syntax)
          utcOffset: "+09:00" # 한국 시간에 맞추기 위함

        # grandle build를 통해 만들어진 jar를 beanstalk에 배포하기 위한 zip 파일로 만드는 것
      - name: Generate deployment package 
        run: |
          mkdir -p deploy
          cp build/libs/*.jar deploy/application.jar # 빌드 완료 시 jar 파일명을 application.jar로 변경
          cp Procfile deploy/Procfile
          cp -r .ebextensions deploy/.ebextensions
          cp -r .platform deploy/.platform
          cd deploy && zip -r deploy.zip . # Procfile, .ebextensions, .platform 포함하여 zip 생성

        # Beanstalk Deploy 플러그인 사용
      - name: Beanstalk Deploy
        uses: einaregilsson/beanstalk-deploy@v14
        with:
          aws_access_key: ${{ secrets.AWS_ACCESS_KEY_ID }} # github secrets로 등록한 값 사용
          aws_secret_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} # github secrets로 등록한 값 사용
          application-name: earth-github-action-test # EB application 이름
          environment_name: dev-earth-github-action-test # EB environment 이름
          version_label: Github Action-${{steps.current-time.outputs.formattedTime}} # 배포 버전은 타임스탬프를 이용하여 구분
          region: ap-northeast-2
          deployment_package: deploy/deploy.zip
          wait_for_environment_recovery: 180 # default wait time은 30초이며, 필자의 EB가 느려서 180초로 지정했습니다(지정 안하면 간혹 timeout 발생).

Procfile, .ebextensions, .platform 구성하기

기본적인 Github Action 세팅은 위에서 완료되었으며, deploy.zip을 생성할 때 함께 들어가는 Procfile, .ebextensions, .platform을 설정해보겠습니다.

먼저 EB로 배포할 프로젝트에 접근하여 루트에 하기와 같이 파일 및 디렉토리를 생성합니다.

Elastic Beanstalk을 위한 파일 및 디렉토리 생성

Elastic Beanstalk을 위해 생성한 파일들에 대해 하나씩 알아보도록 하겠습니다.

[ .ebextensions/00-makeFiles.config ]

files:
    "/sbin/appstart" :
        mode: "000755"
        owner: webapp
        group: webapp
        content: |
            #!/usr/bin/env bash
            JAR_PATH=/var/app/current/application.jar

            # run app
            killall java
            java -Dfile.encoding=UTF-8 -jar $JAR_PATH
  • /sbin으로 시작하여 전역에서 실행할 수 있기 때문에, /sbin 아래에 appstart라는 이름의 스크립트 파일을 만들고, 755 권한을 가진 webapp(user).webapp(group) 사용자가 content 내용을 가진 스크립트를 만들 수 있도록 스크립트를 구성하였습니다.
  • 추후 해당 springboot 프로젝트를 환경에 상관없이 동일한 VM options가 필요하다면, 00-makeFiles.config의 content 내에 추가하여 옵션 추가할 수 있습니다.
    • 예) java -Dfile.encoding=UTF-8 -DSpring.profiles.active=dev -jar $JAR_PATH

[ .ebextensions/00-set-timezone.config ]

commands:
  set_time_zone:
    command: ln -f -s /usr/share/zoneinfo/Asia/Seoul /etc/localtime
  • EC2를 default로 생성하면 timezone이 UTC로 생성되기 때문에 로컬 타임존인 Asiz/Seoul로 변경하기 위해 위와 같은 config를 추가하였습니다.

[ Procfile ]

Elastic Beanstalk은 Github Action으로부터 배포파일들을 전달받고 나면, .ebextensions을 비롯한 각종 설정 파일들을 실행한 뒤 어플리케이션을 실행합니다.

  • 이 어플리케이션 실행 단계란, Procfile을 실행하는 것입니다.
  • 따라서, 하기와 같이 appstart를 실행하기 위해 /sbin/appstart 발생 시 어떤 일을 할지에 대해 .ebextensions/00-makeFiles.config에 작성한 것입니다.
web: appstart

[ .platform/nginx/nginx.conf ]

이 부분은 넣어주지 않으면, default 값으로 nginx를 띄워줍니다. Nginx를 띄우는 이유는 Reverse Proxy로 사용하기 위함입니다.

  • 무중단 배포를 위한 역할은 nginx가 아닌, Elastic Beanstalk에 의해 추가된 로드밸런서(ALB)에 의해 진행됩니다.

이 경우 nginx에서 reverse proxy로 springboot에 트래픽을 보낼 때, default로 5000 포트를 이용하기 때문에, springBoot의 기본 포트를 통해 springboot를 사용하기 위해 하기와 같이 작성했습니다.

또한, 추후 static한 자원에 대해서는 SpringBoot까지 가지 않고 사용하고 싶을 때 해당 설정을 nginx를 통해 진행할 수도 있습니다.

user                    nginx;
error_log               /var/log/nginx/error.log warn;
pid                     /var/run/nginx.pid;
worker_processes        auto;
worker_rlimit_nofile    33282;

events {
    use epoll;
    worker_connections  1024;
}

http {
  include       /etc/nginx/mime.types;
  default_type  application/octet-stream;

  log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';

  include       conf.d/*.conf;

  map $http_upgrade $connection_upgrade {
      default     "upgrade";
  }

  upstream springboot {
    server 127.0.0.1:8080;
    keepalive 1024;
  }

  server {
      listen        80 default_server;

      location / {
          proxy_pass          http://springboot;
          proxy_http_version  1.1;
          proxy_set_header    Connection          $connection_upgrade;
          proxy_set_header    Upgrade             $http_upgrade;

          proxy_set_header    Host                $host;
          proxy_set_header    X-Real-IP           $remote_addr;
          proxy_set_header    X-Forwarded-For     $proxy_add_x_forwarded_for;
      }

      access_log    /var/log/nginx/access.log main;

      client_header_timeout 60;
      client_body_timeout   60;
      keepalive_timeout     60;
      gzip                  off;
      gzip_comp_level       4;

      # Include the Elastic Beanstalk generated locations
      include conf.d/elasticbeanstalk/healthd.conf;
  }
}

Github Action을 통해 Beanstalk에 배포하기

CD Github Action을 적용한 레포지토리의 develop 브랜치에 push를 하면 하기와 같이 Beanstalk에 배포가 되는 것을 확인할 수 있습니다.

  • 작성한 CD workflows의 경우, develop에 push될 경우 발생하도록 설정하였기 때문입니다.

CD github action 수행 완료

Github Action 수행 완료 시에만 캡쳐를 진행해서, Elastic Beanstalk에서 초록불이 뜨지 않았지만, 위 상황은 Beanstalk에 배포 파일이 넘어갔고, 해당 배포 파일을 통해 신규 EC2 인스턴스를 만들어 올리는 과정이라고 봐주시면 됩니다.

배포가 완료될 경우 Elastic Beanstalk 화면

위 화면은 테스트 환경이 아닌, 프로젝트 환경이어서 이름은 가려두었습니다. 위처럼 배포가 완료되면 상태가 초록 동그라미로 변경되며, 이 때 빨간 네모 박스에 적힌 도메인을 클릭하면, 배포가 완료된 환경으로 접속해볼 수 있습니다.

추가 내용

특정 사용자에 대해서만 EB 환경 도메인에 HTTP 접근하도록 설정하고 싶은 경우

기본적으로 사용자가 HTTP를 통해 Elastic Beanstalk 환경의 EC2 도메인을 접근할 때에는 하기와 같은 과정을 통해 접근합니다.

  • LB(Load Balancer)를 사용하는 EB(Elastic Beanstalk) 환경을 구성했다는 가정하의 구조입니다.

사용자가 EB로 생성한 EC2 접근하는 구조

따라서, EC2에 대한 HTTP 접근 허용을 자신의 IP에 대해서만 진행하면, 로드밸런서로 EC2 접근이 되지 않아 접근이 불가능합니다. 즉, 이 상황에서 보안 그룹 설정을 변경해주어야 하는 것은 Load Balancer에 대한 인바운드 규칙입니다.

Load Balancer에 설정된 보안 그룹의 인바운드 규칙을 수정하는 방법은 아래와 같습니다.

LB의 보안 그룹의 인바운드 규칙 추가

  • 어떤 보안 그룹이 Load Balancer에 사용되는지는 직접 로드밸런서 탭에서 확인할 수도 있지만, EB에 의해 자동생성된 LB에 대한 보안 그룹이라면 보안 그룹 이름에 EBLoadBalancer라는 부분이 있을 것이므로 해당 보안 그룹을 수정하셔도 무방합니다.
  • 인바운드 규칙의 소스를 특정 사용자의 IP로 두고, 유형을 HTTP로 지정하면 됩니다.

참고 자료

반응형