본인은 비교적 짧은 일정 동안 프로젝트를 진행하고 있다.
초기 환경 설정을 하면서 EC2
도 생성한 김에 자동 배포를 진행해보고 기록해보려고 한다.
필자는 다양한 배포 툴을 써봤다. 내가 생각한 장단점이 있다.
- 개인 프로젝트를 진행할 때 무료라서 사용한 Travis CI
- 무료 아님
- 회사에서 남는 EC2가 있어서 사용한 Jenkins
- 배포하는데
EC2
가 개입- 크레딧이 여유로워서 사용한 AWS Pipeline, AWS CodeBuild
- 좋지만 좀 느리고, 크레딧은 이제 이전만큼 여유롭지 못함
그래서 이번에는 Github Actions
로 사용하려고 한다.
필자는 되도록이면 여러가지의 툴을 하나로 보고 싶어한다. 그래서 MySQL workbench
와 같은 DB 툴을 따로 사용하지 않고, Intellij DB
를 사용하고 있으며 다른 팀원들에게 업무 관리를 Github Project
를 사용하자고 제안했었다.(다른 직무의 팀원들은 Github
가 익숙치 않아 현재는 그냥 JIRA
를 사용하고 있다.)
Github Actions
의 장점은 내가 생각했을때
1. 서버 리소스 불필요
2. 설정 yaml
파일로 구성해서 편리
3. 비동기 CI/CD
4. Github
와의 접근성
5. 체감상 빠름
이러한 이유로 이번 프로젝트는 Github Actions로 정했다!
본격적으로 Github Actions
자동 배포를 할 준비를 해보자
(EC2
는 올려놓았고, IAM
을 부여한 상태이다.)
참고 : AWS를 이용한 Spring Boot 서버 배포 - 자동. 배포를 위한 S3, CodeDeploy 연결
일단 EC2에 접속해서
sudo apt update
sudo apt install ruby-full
sudo apt install wget
wget https://aws-codedeploy-ap-northeast-2.3.ap-northeast-2.amazonaws.com/latest/install
를 차례로 입력해주었고
chmod +x ./install
sudo ./install auto
그리고 권한을 주고 설치해주었다.
설치가 됐는지 확인해주고
systemctl status codedeploy-agent
결과는
잘 설치되어 동작하는걸 확인할 수 있었다.
이제 CodeDeploy를 생성해보자
1. 애플리케이션 생성
2. 배포 그룹 생성
3. 서비스 역할 IAM
4. 환경 구성(EC2 인스턴스 추가)
5. 배포 설정에 규칙을 제외한 나머지 디폴트로 배포 그룹 생성
완료 화면에서 위와 같은 문제가 있어보이지만 CodeDeploy-agent
생성 문제인것 같아
EC2
에서 CodeDeploy-agent
가 돌아가는지 확인해보니 문제가 없어 그냥 이후 진행
Github 리포지토리에 들어가
Actions
->new Workflow
->set up a workflow yourself
deploy.yml
을 수정해주자
deploy.yml
name: Build and Deploy for miri_mart release server to AWS EC2
on:
push:
branches: [ develop ]
env:
# 버킷에 저장할 폴더 이름
PROJECT_NAME: project_name
# S3 버킷 이름
BUCKET_NAME: bucket_name
# CodeDeploy의 애플리케이션 이름
CODE_DEPLOY_APP_NAME: code_deploy_app_name
# CodeDeploy의 배포그룹 이름
DEPLOYMENT_GROUP_NAME: deploy_group_name
jobs:
build:
# 실행 환경 설정
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v2
# 버전에 맞는 SDK 버전 설치 (필자는 17)
- name: Set up JDK 17
uses: actions/setup-java@v1
with:
java-version: '17'
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build with Gradle no Test
run: ./gradlew clean build -x test
# 압축 파일 만들기
- name: Make Zip File
run: zip -qq -r ./$GITHUB_SHA.zip .
shell: bash
# AWS 인증
- 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: ap-northeast-2
# S3 버킷으로 파일을 업로드
- name: Upload to S3
run: aws s3 cp --region ap-northeast-2 ./$GITHUB_SHA.zip s3://$BUCKET_NAME/$PROJECT_NAME/$GITHUB_SHA.zip
# S3 버킷에 업로드 된 파일을 대상으로 codeDeploy에서 배포 요청
- name: Code Deploy
run: aws deploy create-deployment --application-name $CODE_DEPLOY_APP_NAME --deployment-config-name CodeDeployDefault.OneAtATime --deployment-group-name $DEPLOYMENT_GROUP_NAME --s3-location bucket=$BUCKET_NAME,bundleType=zip,key=$PROJECT_NAME/$GITHUB_SHA.zip
Github Actions secrets
에 AWS_ACCESS_KEY_ID
, AWS_SECRET_ACCESS_KEY
를 각각 등록
EC2에서 실행될 appspec.yml을 추가
# appspec.yml
version: 0.0 # version은 반드시 0.0이어야 함
os: linux
files:
- source: /
destination: /home/ec2-user
overwrite: yes
permissions:
- object: /
pattern: "**"
owner: ec2-user
group: ec2-user
hooks:
AfterInstall:
- location: scripts/stop.sh
timeout: 60
runas: ec2-user
ApplicationStart:
- location: scripts/start.sh
timeout: 60
runas: ec2-user
scripts/stop.sh
추가
PROJECT_ROOT="/home/ec2-user/app"
JAR_FILE="$PROJECT_ROOT/server-0.0.1-SNAPSHOT.jar"
DEPLOY_LOG="$PROJECT_ROOT/deploy.log"
TIME_NOW=$(date +%c)
# 현재 구동 중인 애플리케이션 pid 확인
CURRENT_PID=$(pgrep -f $JAR_FILE)
# 프로세스가 켜져 있으면 종료
if [ -z $CURRENT_PID ]; then
echo "$TIME_NOW > 현재 실행중인 애플리케이션이 없습니다" >> $DEPLOY_LOG
else
echo "$TIME_NOW > 실행중인 $CURRENT_PID 애플리케이션 종료 " >> $DEPLOY_LOG
kill -15 $CURRENT_PID
fi
``scripts/start.sh
추가
PROJECT_ROOT="/home/ec2-user"
JAR_FILE="$PROJECT_ROOT/server-0.0.1-SNAPSHOT.jar"
APP_LOG="$PROJECT_ROOT/application.log"
ERROR_LOG="$PROJECT_ROOT/error.log"
DEPLOY_LOG="$PROJECT_ROOT/deploy.log"
TIME_NOW=$(date +%c)
# build 파일 복사
echo "$TIME_NOW > $JAR_FILE 파일 복사" >> $DEPLOY_LOG
cp $PROJECT_ROOT/build/libs/*.jar $JAR_FILE
# jar 파일 실행
echo "$TIME_NOW > $JAR_FILE 파일 실행" >> $DEPLOY_LOG
source ~/.bashrc
nohup java -jar $JAR_FILE > $APP_LOG 2> $ERROR_LOG &
CURRENT_PID=$(pgrep -f $JAR_FILE)
echo "$TIME_NOW > 실행된 프로세스 아이디 $CURRENT_PID 입니다." >> $DEPLOY_LOG
바로 실패
S3에 업로드 확인
s3에는 잘 올라기있는 것 확인
codeDeploy
의 오류 내용은
An error occurred (AccessDeniedException) when calling the CreateDeployment operation: User: arn:aws:iam::***:user/s3_access_account is not authorized to perform: codedeploy:CreateDeployment on resource: arn:aws:codedeploy:ap-northeast-2:***:deploymentgroup:{CodeDeploy-name}/{CodeDeploy-group-name} because no identity-based policy allows the codedeploy:CreateDeployment action
Error: Process completed with exit code 254.
AWS_ACCESS_KEY_ID
와 AWS_SECRET_ACCESS_KEY
의 권한이 S3까지만 있는 것으로 추정되는데 EC2
, CodeDeploy
접근 권한 동시 필요
IAM
S3, CodeDeploy 권한 부여로 빌드 문제 해결
이후 CodeDeploy
확인 결과 배포 상태 무한 진행중
이벤트 로그
CodeDeploy agent log
확인
# vim /var/log/aws/codedeploy-agent/codedeploy-agent.log
InstanceAgent::Plugins::CodeDeployPlugin::CommandPoller: Error polling for host commands: Aws::Errors::MissingCredentialsError - unable to sign request without credentials set
구글링 결과 원인은
IAM 역할을 지정하지 않고 인스턴스를 실행
이때 설치된 CodeDeploy에는 해당 역할을 실행 할 수 있는 자격증명이 없기에 위와 같은 에러 발생
codedeploy-agent
재시작
sudo systemctl stop codedeploy-agent
sudo systemctl start codedeploy-agent
그래도 무한로딩
EC2 IAM 역할 확인
역할이 비어있음 -> IAM 권한 (test_ec2_codedeploy(AmazonEC2RoleforAWSCodeDeploy)) 부여
Codedeploy- agent
재시작 -> 무한로딩 해결
확인 결과 SCRIPT 경로 오류
경로를 다시 설정해주고 동작 재시작시
모두 성공
로그 확인 결과
3개의 로그 모두 잘 생성
error.log
확인 결과
생각해보니 ubuntu에 java를 설치를 안했으니 버전에 맞는 jdk17
을 설치
- $ sudo apt update
- $ sudo apt install openjdk-17-jdk
그리고 CodeDeploy 배포 재시도
하지만
application.yml
을 gitignore
처리했기 때문에
뒤에는 다음과 같은 에러가 발생한다
해당 프로젝트는 로컬
, 테스트
, 운영
profile
별 자동 배포 처리를 다르게 하는 이슈가 있기 때문이다.
깃액션
은 이 문제를 어떻게 처리할까?