기존에 Travis를 사용하여 CI를 구축했었습니다. 하지만 무료 크레딧이 끝나버려서 이번 기회에
구인 공고에서도 많이 보이는 Jenkins와 AWS CodeDeploy를 사용하여 자동배포를 구현해보도록 하겠습니다.
위의 아키텍쳐로 진행하기 위해서 Jenkins를 돌릴 EC2 서버를 하나 더 생성하여 진행하겠습니다. 두개의 EC2 인스턴스를 사용하기 때문에, 구별하기 쉽도록 '젠킨스 서버'와 '스프링 서버'라고 명명하여 구별하겠습니다.
sudo amazon-linux-extras install -y docker
docker --version
명령어로 잘 설치되었는지 확인할 수 있습니다.
sudo service docker start
sudo docker run -d --name jenkins -p 32789:8080 jenkins/jenkins:jdk11
docker ps
명령어로 실행중인 컨테이너를 확인합니다.(여기에서 permission denied 오류가 뜬다면 해결방법 참조)
위의 사진처럼 잘 실행중이라면 브라우저에서 http://(EC2-탄력적-IP-주소):32789 로 접속합니다.
// jenkins bash 쉘 접속
$ sudo docker exec -it jenkins bash
$ cat /var/jenkins_home/secrets/initialAdminpassword
위의 명령어를 서버 터미널에 입력하여 initialAdminpassword를 알아내서 브라우저 패스워드 창에 복붙합니다.
그럼 아래와 같이 플러그인 설치 선택 창이 나옵니다. Install suggested plugins를 선택하겠습니다.
설치가 다 되었다면 계정을 등록하고 넘어가겠습니다. 계정 등록이 끝나면 Dashboard 페이지가 열립니다.
codedeploy를 검색하여 위와 같이 체크한 뒤 'Install without restart' 버튼을 눌러 CodeDeploy 플러그인을 설치합니다.
설치가 모두 끝났다면 대시보드로 돌아가서 좌측의 '새로운 Item'탭으로 진입합니다.
아이템 이름을 자유롭게 설정해주시고 'Freestyle project'를 선택합니다.
'소스 코드 관리'에서 Git을 선택하고 Github 프로젝트 URL를 적어줍니다.
'Branches to build'에서는 메인 브랜치 명을 적어줍니다. (main이거나 master인 경우가 대부분입니다)
빌드 유발은 'GitHub hook trigger'로 설정하겠습니다.
Build 설정에서는 Execute shell
을 선택한 뒤 아래의 명령어로 jar 파일을 빌드하도록 설정하겠습니다.
chmod +x gradlew
: ci cd ./gradlew: Permission denied
오류 해결을 위해서 미리 권한을 주도록 합니다../gradlew clean build -x test
: gradle build 명령어입니다. 뒤에 -x test
를 붙이면 테스트를 건너뜁니다.빌드 후 조치에는 Deploy an application to AWS CodeDeploy
를 선택합니다.
저는 이미 사용하던 AWS CodeDeploy와 S3를 사용할 것이기 때문에 생성하는 부분은 건너뛰겠습니다.
**/*.jar, **/appspec.yml, **/scripts/*
CodeDeploy의 배포를 받기 위해서 스프링 서버에 CodeDeploy Agent를 설치합니다.
// ruby가 설치되어 있지 않다면 ruby 설치
$ sudo yum install ruby
$ sudo yum install -y aws-cli
$ cd /home/ec2-user/
$ wget https://aws-codedeploy-ap-northeast-2.s3.amazonaws.com/latest/install
$ chmod +x ./install
$ sudo ./install auto
sudo service codedeploy-agent status
명령어로 설치된 CodeDeploy 서비스가 제대로 실행 중인지 확인할 수 있습니다.
추가적으로 java 11버전이 필요할 것이기 때문에 아래의 명령어로 java도 함께 설치해주겠습니다.
sudo yum install java-11-amazon-corretto.x86_64
이제 사용자가 Github에 push를 할때마다 배포할 수 있도록 webhooks 설정을 하겠습니다.
(기존에 설정한 webhook은 Travis 무료 크레딧이 끝나서 경고표시가 나있습니다. 초록색 체크표시가 되어야 정상적인 것입니다.)
Github 프로젝트 > 'Settings' > 좌측의 'Webhooks' 탭 > 'Add webhook'
위와 같이 설정하여 webhook를 추가합니다.
다음은 appspec.yml과 deploy.sh 파일을 작성해보겠습니다.
appspec.yml 파일은 CodeDeploy가 배포를 어디에 어떻게 할 것인지를 설정해주는 파일입니다.
deploy.sh 파일은 EC2 내부에서 어떻게 동작할 것인지 설정하는 스크립트 파일입니다.
다시 프로젝트의 내부로 들어와서 파일을 작성하겠습니다.
version: 0.0
os: linux
files:
- source: / # 현재 프로젝트의 루트 경로
destination: /home/ec2-user/app/nonstop/ # EC2 내부 배포 할 위치
overwrite: yes # 덮어쓰기
hooks:
AfterInstall: # 배포가 끝나면 아래 명령어를 실행
- location: execute-deploy.sh
timeout: 60
# ApplicationStart: # ApplicationStart 단계에서 해당 파일을 실행
# - location: scripts/deploy.sh
# timeout: 60
# runas: ec2-user
permissions:
- object: /
pattern: "**"
owner: ec2-user
group: ec2-user
#!/bin/bash
# jar 위치 변수 지정
BUILD_JAR=$(ls /home/ec2-user/jenkins/build/libs/*.jar)
JAR_NAME=$(basename $BUILD_JAR)
echo ">>> build 파일명: $JAR_NAME" >> /home/ec2-user/deploy.log
echo ">>> build 파일 복사" >> /home/ec2-user/deploy.log
DEPLOY_PATH=/home/ec2-user/
cp $BUILD_JAR $DEPLOY_PATH
echo ">>> 현재 실행중인 애플리케이션 pid 확인" >> /home/ec2-user/deploy.log
CURRENT_PID=$(pgrep -f $JAR_NAME)
if [ -z $CURRENT_PID ]
then
echo ">>> 현재 구동중인 애플리케이션이 없으므로 종료하지 않습니다." >> /home/ec2-user/deploy.log
else
echo ">>> kill -15 $CURRENT_PID"
kill -15 $CURRENT_PID
sleep 5
fi
DEPLOY_JAR=$DEPLOY_PATH$JAR_NAME
echo ">>> DEPLOY_JAR 배포" >> /home/ec2-user/deploy.log
nohup java -jar $DEPLOY_JAR >> /home/ec2-user/deploy.log 2>/home/ec2-user/deploy_err.log &
프로젝트의 디렉토리는 아래와 같습니다.
새 인스턴스에서 처음 docker 명령어를 사용하다보면 아래와 같은 permission 에러가 발생합니다.
$ sudo usermod -aG docker $USER
$ newgrp docker
exit 명령어로 SSH 로그아웃 후에 다시 SSH를 접속하면 문제가 해결됩니다.
감사합니다...!
덕분에 잘 됐어요
appspec.yml 내에서
hooks:
AfterInstall: # 배포가 끝나면 아래 명령어를 실행
- location: execute-deploy.sh < ----- location: deploy.sh 이거로 변경하시면 잘 되요
※(appspec.yml과 같은 루트있다 가정하에)※