Jenkins + CodeDeploy를 사용하여 자동배포 구현하기

Bluewind·2022년 5월 3일
0

서버 셋팅

목록 보기
5/6
post-thumbnail

기존에 Travis를 사용하여 CI를 구축했었습니다. 하지만 무료 크레딧이 끝나버려서 이번 기회에
구인 공고에서도 많이 보이는 Jenkins와 AWS CodeDeploy를 사용하여 자동배포를 구현해보도록 하겠습니다.

위의 아키텍쳐로 진행하기 위해서 Jenkins를 돌릴 EC2 서버를 하나 더 생성하여 진행하겠습니다. 두개의 EC2 인스턴스를 사용하기 때문에, 구별하기 쉽도록 '젠킨스 서버'와 '스프링 서버'라고 명명하여 구별하겠습니다.

  1. 사용자가 GitHub에 Push.
  2. Jenkins가 GitHub Repository 를 clone 받는다.
  3. Jenkins가 build하여 jar 파일을 만들고 Dockerfile, script file, yml file 등을 zip으로 압축하여 S3에 upload한다.
  4. Jenkins가 CodeDeploy에게 S3에 업로드된 압축파일을 서버에 배포하도록 요청.
  5. CodeDeploy가 S3에서 압축파일을 가져와 EC2에 배포.
  6. 무중단 배포를 위하여 Eginx가 배포

Jenkins 서버 설정

Docker 및 Jenkins 설치 및 실행

  • Docker 설치
sudo amazon-linux-extras install -y docker

docker --version 명령어로 잘 설치되었는지 확인할 수 있습니다.

  • Docker 실행
sudo service docker start
  • Docker 로 jenkins 설치하기
sudo docker run -d --name jenkins -p 32789:8080 jenkins/jenkins:jdk11
  • docker ps 명령어로 실행중인 컨테이너를 확인합니다.

(여기에서 permission denied 오류가 뜬다면 해결방법 참조)

Jenkins 설정

위의 사진처럼 잘 실행중이라면 브라우저에서 http://(EC2-탄력적-IP-주소):32789 로 접속합니다.

// jenkins bash 쉘 접속
$ sudo docker exec -it jenkins bash
$ cat /var/jenkins_home/secrets/initialAdminpassword

위의 명령어를 서버 터미널에 입력하여 initialAdminpassword를 알아내서 브라우저 패스워드 창에 복붙합니다.

그럼 아래와 같이 플러그인 설치 선택 창이 나옵니다. Install suggested plugins를 선택하겠습니다.

설치가 다 되었다면 계정을 등록하고 넘어가겠습니다. 계정 등록이 끝나면 Dashboard 페이지가 열립니다.

  • 좌측의 탭에서 Jenkins 관리 탭으로 진입합니다.

  • 맨 위의 'System Configuration' 에서 '플러그인 관리'에 들어갑니다.

codedeploy를 검색하여 위와 같이 체크한 뒤 'Install without restart' 버튼을 눌러 CodeDeploy 플러그인을 설치합니다.


Item 생성

설치가 모두 끝났다면 대시보드로 돌아가서 좌측의 '새로운 Item'탭으로 진입합니다.

아이템 이름을 자유롭게 설정해주시고 'Freestyle project'를 선택합니다.

1) 소스 코드 관리

'소스 코드 관리'에서 Git을 선택하고 Github 프로젝트 URL를 적어줍니다.

'Branches to build'에서는 메인 브랜치 명을 적어줍니다. (main이거나 master인 경우가 대부분입니다)

2) 빌드 유발

빌드 유발은 'GitHub hook trigger'로 설정하겠습니다.

3) Build

Build 설정에서는 Execute shell을 선택한 뒤 아래의 명령어로 jar 파일을 빌드하도록 설정하겠습니다.

  • chmod +x gradlew : ci cd ./gradlew: Permission denied 오류 해결을 위해서 미리 권한을 주도록 합니다.
  • ./gradlew clean build -x test : gradle build 명령어입니다. 뒤에 -x test를 붙이면 테스트를 건너뜁니다.

4) 빌드 후 조치

빌드 후 조치에는 Deploy an application to AWS CodeDeploy를 선택합니다.
저는 이미 사용하던 AWS CodeDeploy와 S3를 사용할 것이기 때문에 생성하는 부분은 건너뛰겠습니다.

  • AWS CodeDeploy Application Name : CodeDeploy 애플리케이션 이름
  • AWS CodeDeploy Deployment Group : CodeDeploy 배포 그룹 이름
  • AWS Region : 해당 리전을 선택합니다. 아마 보통 서울 리전으로 많이 하셨을꺼라 생각됩니다 (ap-northeast-2)
  • S3 Bucket : Amazon S3 버킷 이름
  • Include Files : **/*.jar, **/appspec.yml, **/scripts/*
  • Use Access/Secret keys : IAM 사용자의 Access 와 Secret Key를 적습니다.

스프링 서버 설정

CodeDeploy Agent 설치

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 11버전이 필요할 것이기 때문에 아래의 명령어로 java도 함께 설치해주겠습니다.

sudo yum install java-11-amazon-corretto.x86_64

프로젝트 설정

GitHub Webhooks

이제 사용자가 Github에 push를 할때마다 배포할 수 있도록 webhooks 설정을 하겠습니다.


(기존에 설정한 webhook은 Travis 무료 크레딧이 끝나서 경고표시가 나있습니다. 초록색 체크표시가 되어야 정상적인 것입니다.)

Github 프로젝트 > 'Settings' > 좌측의 'Webhooks' 탭 > 'Add webhook'

위와 같이 설정하여 webhook를 추가합니다.


설정 파일 작성

다음은 appspec.yml과 deploy.sh 파일을 작성해보겠습니다.
appspec.yml 파일은 CodeDeploy가 배포를 어디에 어떻게 할 것인지를 설정해주는 파일입니다.
deploy.sh 파일은 EC2 내부에서 어떻게 동작할 것인지 설정하는 스크립트 파일입니다.

다시 프로젝트의 내부로 들어와서 파일을 작성하겠습니다.

  • appspec.yml
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
  • deploy.sh
#!/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 denied 해결

새 인스턴스에서 처음 docker 명령어를 사용하다보면 아래와 같은 permission 에러가 발생합니다.

$ sudo usermod -aG docker $USER
$ newgrp docker

exit 명령어로 SSH 로그아웃 후에 다시 SSH를 접속하면 문제가 해결됩니다.


출처

profile
NO EFFORT, NO RESULTS

1개의 댓글

comment-user-thumbnail
2023년 11월 16일

감사합니다...!
덕분에 잘 됐어요
appspec.yml 내에서
hooks:
AfterInstall: # 배포가 끝나면 아래 명령어를 실행
- location: execute-deploy.sh < ----- location: deploy.sh 이거로 변경하시면 잘 되요
※(appspec.yml과 같은 루트있다 가정하에)※

답글 달기