AWS Elastic Beanstalk와 Github Action을 통합하고 CI/CD 생성을 완료해 봅시다.
먼저 AWS Elastic BeanStalk, VPC 및 보안 그룹의 개념부터 시작하겠습니다.
(탄성콩나무)
Elastic Beanstalk는 EC2 인스턴스, 데이터베이스, 로드 밸런서 및 기타 서비스를 포함한 환경을 구성하고 소프트웨어가 업데이트되면 환경을 자동으로 관리합니다.
(VPC)
Amazon Virtual Private Cloud(VPC)는 AWS 클라우드에서 논리적으로 격리된 영역입니다. VPC를 사용하면 고객 정의 가상 네트워크에서 AWS 리소스를 시작할 수 있습니다. 아래와 같이 ElasticBeanstalk 인스턴스 또는 RDS를 생성하면 기본 VPC가 자동으로 할당됩니다. 할당은 지역마다 다릅니다.

단, 아래와 같이 VPC가 동일한 경우에도 인스턴스(EC2, EB, RDS..)간 통신이 불가능합니다. 통신을 위해 보안 그룹을 설정해야 합니다.

(보안 그룹)
보안 그룹은 인바운드 및 아웃바운드 트래픽을 제어하여 트래픽을 열거나 닫을 수 있습니다. 똑같은 것 VPC 내 AWS 서비스 간의 통신을 위해 동일한 VPC의 모든 트래픽을 허용하도록 보안 그룹 구성할 수 있어요.
- 인바운드: 외부에서 EC2 인스턴스 또는 EB 인스턴스로 요청을 보내는 트래픽(HTTP, HTTPS, SSH ..)
- 아웃바운드: 여기에는 인스턴스(EC2, EB…)의 아웃바운드 트래픽, 파일 다운로드 또는 인바운드 트래픽 처리 및 응답이 포함됩니다.

1. AWS Elastic Beanstalk 환경 생성

여러 컨테이너가 있는 환경(Nginx, 스프링 부트) 플랫폼 브랜치로 “64비트 Amazon Linux2에서 실행되는 ECS”를 선택해야 합니다.
다중 컨테이너 앱을 위한 Elastic Beanstalk 환경 생성에 대한 자습서의 마지막 이미지를 첨부합니다.
EB의 로드 밸런싱!
2. MySQL용 AWS RDS 구축
데이터베이스의 경우 개발 환경에서는 Docker 컨테이너를 사용하고 프로덕션 환경에서는 AWS RDS 서비스를 사용하는 것이 좋습니다. DB 작업은 중요한 데이터를 저장하고 사용하는 부분이므로 실제 데이터를 처리하는 운영 환경에서 보다 안정적인 AWS RDS로 DB를 구성하는 것이 좋습니다.
표준 MySQL 엔진 버전을 사용할 수 있습니다.

마스터 사용자 이름과 마스터 비밀번호를 입력합니다. (원하는 값을 입력하세요)

템플릿은 사례별로 선택되므로 현재 테스트에 사용 중인 프리 티어를 선택했습니다.
실습용이므로 가장 낮은 인스턴스 사양을 선택했습니다.

EB 인스턴스를 생성할 때 기본 VPC가 할당되므로 해당 VPC를 선택합니다.

Spring Boot 애플리케이션에서 사용할 데이터베이스 이름을 입력한 후 Create RDS 버튼을 클릭합니다.

아래와 같이 RDS 생성이 성공적으로 완료되었습니다!

3. VPC 및 보안 그룹 설정
현재 RDS(MySQL) 및 EB 인스턴스는 기본 VPC에 속합니다. RDS 및 EB 인스턴스가 통신하려면 보안 그룹을 구성해야 합니다. 따라서 동일한 VPC에서 오는 모든 트래픽을 허용하는 보안 그룹을 생성한 후 RDS 및 EB 인스턴스에 적용해 보겠습니다.
3-1 보안 그룹 생성
1. 보안 그룹 생성(VPC – 보안 그룹 – 보안 그룹 생성)

2. 인바운드 규칙 추가

포트 범위를 0.0.0.0/0으로 설정하면 모든 포트를 개발할 수 있지만 실제로 필요한 mysql 포트 3306번만 열린다.
보안 그룹에서 위에서 생성한 보안 그룹(DockerSecurityGroup)을 선택하고 규칙 저장을 클릭합니다.

들어오는 규칙을 추가했습니다!

3-2 보안 그룹 적용
1. 보안 그룹을 RDS에 적용

RDS 보안 그룹에 위에서 생성한 보안 그룹을 추가한 후 Modify DB Instance 버튼을 클릭합니다.
그후에 변경 사항을 적용하려면 즉시 적용을 선택합니다.

이로써 RDS에 대한 보안 그룹 적용이 완료됩니다.

2. EB 인스턴스에 보안 그룹 적용
Elastic Beanstalk – 구성 – 인스턴스 편집 클릭

위에서 생성한 보안 그룹을 선택한 후 수정 완료를 클릭합니다(경고는 무시해도 됩니다).

동일한 VPC 내에서 AWS 서비스 통신을 위한 보안 그룹을 생성하여 RDS와 EB에 적용했습니다. 결과 구조는 아래와 같습니다.

4. EB와 RDS 통신을 위한 환경 변수 설정
모든 보안 그룹이 구성되었습니다. 그러나 Elastic BeanStalk의 컨테이너가 RDS와 통신할 때 RDS의 환경 변수를 인식하지 못합니다. 이제 Elastic BeanStalk에서 환경 변수를 설정해 보겠습니다.
Elastic Beanstalk – 구성 – 소프트웨어 편집 클릭

환경 속성에 RDS 환경 변수를 입력해야 합니다. MYSQL_HOST, MYSQL_USER, MYSQL_ROOT_PASSWORD, MYSQL_DATABASE, MYSQL_PORT
- MYSQL_USER 및 MYSQL_ROOT_PASSWORD에는 RDS 생성 시 입력한 마스터 사용자 이름과 마스터 사용자 비밀번호를 입력합니다.
- MYSQL_HOST의 경우 아래 이미지와 같이 RDS 엔드포인트를 입력합니다.

5. IAM 인증 키 받기
(그래요)
IAM은 리소스에 대한 액세스를 안전하게 제어할 수 있는 웹 서비스입니다. 리소스를 사용합니다. 인증 및 승인 대상을 제어합니다. 루트 사용자 AWS 서비스 및 리소스에 대한 전체 액세스 권한이 있습니다. IAM 사용자는 루트 사용자에게만 권한이 부여됩니다. 보안상의 이유로 항상 IAM 사용자를 생성하고 사용하는 것이 좋습니다.
동일한 AWS 서비스가 아닌 경우 AWS 서비스에 명령을 실행할 수 있는 권한을 얻어야 합니다. IAM 사용자를 사용하여 권한을 얻는 인증 키(accessKey, secretKey)가 있습니다.
5-1 IAM 사용자 추가

정책 직접 연결을 클릭하여 Elastic BeanStalk를 제어한 후 AdministratorAccess-AWSElasticBeanstalk 허용하다

아래와 같이 IAM 사용자가 생성되었습니다!

5-2 비밀키 발급
(IAM 사용자 보안 자격 증명 – 액세스 키 생성) 다음과 같이 선택합니다.

나머지는 기본값으로 설정하고 액세스 키를 발급합니다. 액세스 키는 한 번만 조회할 수 있으므로 다른 곳에 저장해야 합니다.

위에서 발급받은 access key와 secret access key 비밀 키가 있는 Github 저장소 등록하다

6. Github Action yml 배포 부분 작성
이전 글에서 작성한 Github Action YML 파일에 다음 코드를 추가합니다. Elastic BeanStalk 플러그인을 사용한 코드입니다. 이전에 생성한 IAM 인증 키를 사용합니다. 현재 시간 플러그인을 통해 Beanstalk를 배포할 때 고유한 버전 관리를 보장하기 위해 version_label을 추가했습니다.
- name: Deploy to EB
uses: einaregilsson/beanstalk-deploy@v21
with:
aws_access_key: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws_secret_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
application_name: docker-springboot-app
environment_name: Dockerspringbootapp-env
version_label: deploy-${{steps.current-time.outputs.formattedTime}}
region: ap-northeast-2
deployoment_package: Dockerrun.aws.json
최종 완성된 Github Action YML 파일은 다음과 같습니다.
name: deploy
on:
push:
branches:
- 'main'
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
- name: Grant execute permission for gradlew
run: |
cd docker-nginx
chmod +x ./gradlew
- name: Build with Gradle
run: |
cd docker-nginx
./gradlew clean build -x test
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build Docker Image & Push to Docker Hub
run: |
docker build . -t twoosky/docker-springboot
docker build ./nginx -t twoosky/docker-nginx
docker push twoosky/docker-springboot
docker push twoosky/docker-nginx
- name: 현재 시간 가져오기
uses: 1466587594/get-current-time@v2
id: current-time
with:
format: YYYY-MM-DDTHH-mm-ss
utcOffset: "+09:00"
- name: Deploy to EB
uses: einaregilsson/beanstalk-deploy@v21
with:
aws_access_key: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws_secret_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
application_name: docker-springboot-app
environment_name: Dockerspringbootapp-env
version_label: deploy-${{steps.current-time.outputs.formattedTime}}
region: ap-northeast-2
deployoment_package: Dockerrun.aws.json