들어가기 전에
이번 포스팅은 ECR, Elastic Beanstalk 세팅이 완료되어 있다는 가정하에 진행합니다. 따라서, 해당 부분이 아직 완성되지 않았다면 하기 포스팅들을 먼저 보신 후 이번 포스팅을 읽어보시길 권해드립니다.
이전 포스팅
- [AWS, Github Action] Elastic Beanstalk에 SpringBoot 이미지 Docker로 배포하기(1) - 왜 Amazon ECS가 아닌 Elastic Beanstalk을 선택했고, Docker를 사용하려 할까?
- [AWS, Github Action] Elastic Beanstalk에 SpringBoot 이미지 Docker로 배포하기(2) - ECR 리포지토리 생성 및 권한 설정
- [AWS, Github Action] Elastic Beanstalk에 SpringBoot 이미지 Docker로 배포하기(3) - EB 기본 세팅(RDS 포함)
구성하고자 하는 최종 구조
이번 포스팅까지 진행하여 최종적으로 만들고자 하는 구조는 아래와 같습니다.
Github Action 스크립트 작성하기
하기 스크립트 상에서는 develop 브랜치에 push되었을 때 도커를 통해 Elastic Beanstalk에 배포하는 내용이지만, develop에서 테스트 완료 후에는 main을 위한 스크립트로 수정을 하였습니다.
- 실제 develop 버전은 springboot으로 바로 배포하여 ecr 비용을 절감하고 있습니다.
name: Upload Docker Image to ECR & Pull Image to Beanstalk
on:
push:
branches: [ develop ]
jobs:
deploy:
name: Deploy Dev
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up JDK 11
uses: actions/setup-java@v1
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: 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 }}
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v1
- name: Build, tag, and push image to Amazon ECR
id: build-image
env:
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
ECR_REPOSITORY: earth-demo
IMAGE_TAG: latest
run: |
docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
echo "::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG"
- name: Get current time
uses: 1466587594/get-current-time@v2
id: current-time
with:
format: YYYYMMDD_HH-mm-ss
utcOffset: "+09:00"
- name: Generate deployment package
run: |
mkdir -p deploy
cp -r .ebextensions deploy/.ebextensions
cp Dockerrun.aws.json deploy/Dockerrun.aws.json # Elastic Beanstalk에서 Docker 실행 시 체크하는 설정 파일
cd deploy && zip -r deploy.zip .
- name: Beanstalk Deploy
uses: einaregilsson/beanstalk-deploy@v14
with:
aws_access_key: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws_secret_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
application_name: earth-github-action-test
environment_name: earthDocker
version_label: earth-docker-${{steps.current-time.outputs.formattedTime}}
region: ap-northeast-2
deployment_package: deploy/deploy.zip
wait_for_environment_recovery: 200
위 Github Action 스크립트에 대해 간단히 설명해보자면, 아래와 같습니다.
Grant execute permission for gradlew
&Build with Gradle
- Docker Image를 생성하기 위해 먼저 Gradle 빌드 설정 및 실행을 하는 부분입니다.
Configure AWS credentials
&Login to Amazon ECR
&Build, tag, and push image to Amazon ECR
- ECR 리포지토리를 프라이빗으로 설정함에 따라 해당 리포지토리에 Push 권한을 가진 IAM 계정을 통해 인증하고 ECR에 로그인 후 이미지를 Push하는 부분입니다.
- 이 부분에 대한 자세한 설명은 해당 Github을 읽어보시는 것을 추천드리며, 하기 참고 자료에 해당 Github 주소를 남겨두었습니다.
Generate deployment package
&Beanstalk Deploy
- 기존에 개발환경에 대해 Docker가 아닌 SpringBoot 자체로 Elastic Beanstalk에 배포하는 과정을 담은 포스팅에 Generate deployment package에서 하는 일에 대해 정리해두었습니다. 필요하다면 참고하면 좋을 것 같습니다.
- 기존과 다른 점은 하기와 같습니다.
- nginx를 앞단에 두지 않고 실행하기 때문에, cp하는 항목 중 nginx 부분이 빠짐
- SpringBoot 실행을 위한 Procfile이 빠짐(Docker 실행으로 인해 필요없음)
- Dockerrun.aws.json이라는 Elastic Beanstalk에서 Docker 실행을 위해 설정하는 부분 추가
Github Secrets 생성하기
위 Github Action 스크립트에서 사용하는 Secrets들을 모두 생성해야 합니다. 아래 3가지에 대해 생성해주면 되며, AccessKey와 SecretKey의 경우 Elastic Beanstalk과 ECR 모두에 권한이 있는 계정으로 설정해야 위처럼 ECR 접근 시와 Beanstalk 접근 시 동일한 IAM 계정을 사용할 수 있습니다.
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
AWS_REGION
SpringBoot에 배포에 필요한 파일들 생성하기
Dockerfile 및 Dockerrun.aws.json 생성하기
Dockerfile
및 Dockerrun.aws.json
파일은 아래 보이는 것과 같이 SpringBoot 패키지 최상단에 위치하면 됩니다.
Dockerfile
FROM adoptopenjdk:11-jdk-hotspot
ARG JAR_FILE=build/libs/*.jar
COPY ${JAR_FILE} app.jar
EXPOSE 5000
ENTRYPOINT ["java", "-jar", "-Dspring.profiles.active=ebprod","/app.jar"]
- 8080 포트로 SpringBoot을 띄우려했으나, Dockerrun.aws.json 파일 내
CotntainerPort
와HostPort
를8080
으로 모두 지정해도 Elastic Beanstalk에서 제대로 해당 도커 프로세스를 띄우지 못하는 현상이 있어 Elastic Beanstalk의 default 포트인5000
을 사용했습니다.- 도커 로그상으로는 SpringBoot이 제대로 떴지만 로드밸런서가 8080에 접근하지 못하였습니다. 마치, docker run할 때 -p 옵션으로 hostPort와 containerPort를 지정하지 않아 도커가 떠있어도 제대로 찾지 못하는 것과 비슷했습니다.
- Docker 이미지를 생성할 때부터, 해당 환경의 profiles를 지정하기 위해 ENTRYPOINT에 -Dspring.profiles.active 설정을 추가하였습니다.
Dockerrun.aws.json
{
"AWSEBDockerrunVersion": "1",
"Image": {
"Name": "{AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-2.amazonaws.com/{REPOSITORY_NAME}:{TAG_NAME}",
"Update": "true"
},
"Ports": [
{
"ContainerPort": "5000",
"HostPort": "5000"
}
]
}
- Elastic Beanstalk이 읽어올 Docker 이미지 경로를 지정하는 부분으로, ECR Repository의 URI를 복사하여 넣고, tag까지 넣어주면 됩니다(예:
{AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-2.amazonaws.com/earth-demo:latest
).
.ebextensions
기존에 SpringBoot으로 Elastic Beanstalk 배포 시 사용한 .ebextensions
을 그대로 사용했습니다.
00-set-timezone.config
commands:
set_time_zone:
command: ln -f -s /usr/share/zoneinfo/Asia/Seoul /etc/localtime
- Elastic Beanstalk에 의해 생성될 EC2 서버의 timezone 설정을 변경하는 것입니다.
application-ebprod.yml
필자의 경우, DockerFile에 spring.profiles.active
설정을 ebprod
로 하였기 때문에 파일명이 ebprod
인 것이며, 다른 환경으로 설정한다면 다른 이름을 넣어 생성하면 됩니다.
spring:
datasource:
url: jdbc:postgresql://${rds.hostname}:${rds.port}/${rds.dbname}
username: ${rds.username}
password: ${rds.password}
driver-class-name: ${rds.driver}
jpa:
hibernate:
ddl-auto: create
# application 실행 시점에 기존에 갖고 있던 테이블을 다 지우고 다시 생성합니다.
properties:
hibernate:
# show_sql: true
# 모든 로그는 가급적 로거를 통해 남겨야 합니다. show_sql의 경우 System.out에 hibernate 실행 sql을 남기므로, org.hibernate.SQL 옵션을 통해 logger로 실행 SQL을 남기는 게 좋습니다.
format_sql: true
logging.level:
org.hibernate.SQL: debug
# 로거를 통해 로그 남기려면 org.hibernate.SQL을 사용합니다.
# org.hibernate.type: trace
# trace로 hibernate type을 지정함으로써 로그에 SQL 실행 파라미터를 표시할 수 있습니다.
server:
port: 5000
- 앞서 말한 것처럼, SpringBoot는 5000 포트로 띄울 것이기 때문에 server.port는 5000으로 설정하였습니다.
Github Action 실행해보기
위와 동일하게 세팅하였다면, develop에 push를 하면 해당 Github Action이 수행되고, 수행이 완료되면 하기와 같이 Elastic Beanstalk의 환경의 실행 버전이 변경됩니다.
회고
이번 포스팅까지 작업을 하면서, 아쉬웠던 점은 이미 ECR에 이미지가 존재하여 해당 이미지를 바로 Elastic Beanstalk으로 데려오지 못하고 S3에 저장했다는 점입니다. 사용하고 있는 Elastic Beanstalk 배포용 Github Action이 S3에 zip 파일 저장을 거치고 있어 어쩔 수 없이 선택한 부분인데, 추후 다른 방안이 생긴다면 수정하고 싶은 부분입니다.