들어가기 전에
해당 글은 Elastic Beanstalk의 기본 세팅이 되어 있다는 가정하에 진행합니다. 만약, Elastic Beanstalk의 어플리케이션 및 환경 구성이 되어 있지 않다면 하기 글을 클릭하여 먼저 구성하고 이 포스팅을 읽는 것을 권해드립니다.
이전 포스팅
다음 포스팅
Github Action을 통해 SpringBoot 어플리케이션 EB에 배포하기
이번 포스팅에서 구현하려는 것은 Github Action을 통해 Elastic Beanstalk에 SpringBoot 어플리케이션을 배포하는 것입니다.
- SpringBoot 어플리케이션을 jar로 말아 올릴 때에 SpringBoot 앞단에 Nginx를 띄우기 위한 과정 역시 포함되어 있습니다.
- Elastic Beanstalk 환경 구성 시 ALB(Application Load Balancer)를 사용하도록 설정했다고 가정하고 진행합니다.
- 해당 내용은 이전 포스팅에 있으니, EB 환경설정이 필요하신 경우 해당 포스팅을 먼저 확인하길 바랍니다.
IAM 인증키 Github Action에 사용하기
AWS 서비스가 아닌 Github Action을 통해 Elastic Beanstalk(AWS 서비스)에 명령을 하고자 한다면 권한이 있어야 합니다.
- IAM 사용자를 이용한 인증키(
accessKey
,secretKey
)를 이용해 외부 서비스가 AWS 서비스에 대한 명령 권한을 받을 수 있습니다.
IAM 인증키 발급받기
먼저, IAM 페이지에 접근하여 액세스 관리 > 사용자
를 클릭합니다. 그 후, 사용자 추가를 눌러 IAM 사용자 추가를 진행합니다.
평소 IAM 사용자 추가에서는 암호를 이용해 AWS 콘솔 엑세스를 진행했다면, github action에서 사용하기 위한 accessKey와 secretKey 발급을 위해 액세스 키 방식으로 IAM 사용자를 추가합니다.
해당 사용자의 권한으로는 기존 정책 직접 연결 > AdministratorAccess-AWSElasticBeanstalk
을 선택합니다.
그 후, 태그에서는 다른 IAM 사용자와 차이를 주기 위해 Name이라는 태그를 지정하고 사용자를 만듭니다.
사용자가 추가되면 아래와 같이 액세스 키 ID와 비밀 엑세스 키를 얻을 수 있습니다. 해당 값을 따로 메모장에 저장해둡니다.
IAM 인증키 Github에 적용하기
먼저 Elastic Beanstalk과 연결하여 CD를 진행할 Repository에 접속합니다. 그 뒤 Settings > Secrets > New repository secret
을 클릭합니다.
위 과정이 완료되면, 하기와 같은 키가 모두 저장된 것입니다.
AWS_ACCESS_KEY_ID
: 액세스 키 IDAWS_SECRET_ACCESS_KEY
: 비밀 액세스 키
이제는 위에서 등록한 Github Secrets를 Github Action에서 사용할 수 있도록 workflow 스크립트 내에 설정을 해보겠습니다.
Github Action CD 스크립트 작성하기
Beanstalk으로 배포하기 위한 스크립트이므로, Beanstalk Deploy
라는 Github Action 플러그인을 사용해보겠습니다.
- Beanstalk Deploy(https://github.com/marketplace/actions/beanstalk-deploy)
위와 같이 Beanstalk Deploy Github Action 플러그인에 접근하여 최신 버전 설치 코드를 복사한 후 아래와 같이 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 발생).
- Get current time 스탭에서 사용하는 시간 format은 MomentJS format syntax를 따릅니다. 따라서, 하기 사이트를 통해 포맷 변경이 가능합니다.
Procfile, .ebextensions, .platform 구성하기
기본적인 Github Action 세팅은 위에서 완료되었으며, deploy.zip
을 생성할 때 함께 들어가는 Procfile
, .ebextensions
, .platform
을 설정해보겠습니다.
먼저 EB로 배포할 프로젝트에 접근하여 루트에 하기와 같이 파일 및 디렉토리를 생성합니다.
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될 경우 발생하도록 설정하였기 때문입니다.
Github Action 수행 완료 시에만 캡쳐를 진행해서, Elastic Beanstalk에서 초록불이 뜨지 않았지만, 위 상황은 Beanstalk에 배포 파일이 넘어갔고, 해당 배포 파일을 통해 신규 EC2 인스턴스를 만들어 올리는 과정이라고 봐주시면 됩니다.
위 화면은 테스트 환경이 아닌, 프로젝트 환경이어서 이름은 가려두었습니다. 위처럼 배포가 완료되면 상태가 초록 동그라미로 변경되며, 이 때 빨간 네모 박스에 적힌 도메인을 클릭하면, 배포가 완료된 환경으로 접속해볼 수 있습니다.
추가 내용
특정 사용자에 대해서만 EB 환경 도메인에 HTTP 접근하도록 설정하고 싶은 경우
기본적으로 사용자가 HTTP를 통해 Elastic Beanstalk 환경의 EC2 도메인을 접근할 때에는 하기와 같은 과정을 통해 접근합니다.
- LB(Load Balancer)를 사용하는 EB(Elastic Beanstalk) 환경을 구성했다는 가정하의 구조입니다.
따라서, EC2에 대한 HTTP 접근 허용을 자신의 IP에 대해서만 진행하면, 로드밸런서로 EC2 접근이 되지 않아 접근이 불가능합니다. 즉, 이 상황에서 보안 그룹 설정을 변경해주어야 하는 것은 Load Balancer에 대한 인바운드 규칙입니다.
Load Balancer에 설정된 보안 그룹의 인바운드 규칙을 수정하는 방법은 아래와 같습니다.
- 어떤 보안 그룹이 Load Balancer에 사용되는지는 직접 로드밸런서 탭에서 확인할 수도 있지만, EB에 의해 자동생성된 LB에 대한 보안 그룹이라면 보안 그룹 이름에 EBLoadBalancer라는 부분이 있을 것이므로 해당 보안 그룹을 수정하셔도 무방합니다.
- 인바운드 규칙의 소스를 특정 사용자의 IP로 두고, 유형을 HTTP로 지정하면 됩니다.