AWS CodeDeploy + Jenkins를 이용한 Spring boot 자동화 + Jenkins CodeDeploy plugin 오류 해결

slee2·2022년 6월 26일
3

main

목록 보기
9/12
post-thumbnail

이 글에서 다룰 전체 프로세스이다.
0. 프로젝트를 githubpush한다. (main 브렌치)
1. github webhook을 통해 Jenkins가 호출된다.
2. Jenkins에서 빌드를 진행한다.
3. Jenkins가 빌드한 파일을 s3에 업로드한다.
4. JenkinsCodeDeploy로 배포를 요청한다.
5. CodeDeploys3에서 업로드된 빌드 파일을 가져온다.
6. CodeDeployEC2에 배포를 진행한다.

Jenkins 이용 방식 선택

선택에는 두 가지 방법이 있는데,

  • Jenkins를 로컬에서 실행 시킨 후에, sshec2를 연결하는 방식
    • 로컬에 Jenkins 설치 후, ssh 연결만 하면 됨.
    • 자동화를 위해서 로컬에서 Jenkins를 계속 켜야함.
    • 하나의 로컬에 여러 ssh를 연결할 수 있으므로, 관리가 편함.
  • ec2 내부에 Jenkins를 설치하여 모든 것을 ec2에 맡기는 방식
    • ec2에 모든것을 위임하므로 ec2를 여러개 사용할 경우, 모든 서버에 Jenkins를 설치해야함.
    • 자동화를 ec2에서 알아서 맡아서 해줌.

이러한 이유로 두 번째 방법으로 하기로 하였다. 설치방법과 실행은 더 복잡하지만, 자동화를 해준다는 큰 장점이 있다.

CodeDeploy란?

CodeDeployAWS에서 운영환경에 자동 배포하는 역할을 수행하는 AWS Service이다. 즉, CD 지속적 배포 서비스이다.

먼저 CodeDeploy를 이용하기 위해 IAM에서 권한을 줘야한다.

IAM - 역할

IAM - 역할 - 역할 만들기

정책 중에
AmazonS3FullAccess
AWSCodeDeployFullAccess 를 찾아 추가한다.

정책 이름 확인 후에 생성한다.
이렇게 EC2에 대한 역할이 생성되었다.

이번에는 CodeDeploy 역할을 생성할 것이다.
똑같이 역할 만들기를 누른다.

이전과 다르게 사용 사례CodeDeploy를 선택한다.

정책은 이렇게 자동으로 선택되어있다.

최종으로 이렇게 2개의 역할을 생성하였다.

S3

S3 - 버킷 - 버킷 만들기

AmazonS3FullAccess 권한이 이미 EC2에 부여되었기 때문에 엑세스 차단을 해도 된다.

EC2

생성하는 과정은 생략하겠다.
인스턴스를 선택하고,
작업 - 보안 - IAM 역할 수정

이전에 생성했던 역할을 선택한다.
그리고 인스턴스를 재부팅 한다.

그리고 보안 그룹에서 사용자 TCP90008080을 열어준다.(Jenkins, Spring boot)

CodeDeploy

CodeDeploy - 배포 - 애플리케이션 - 애플리케이션 생성

생성 후에 배포 그룹에서 배포 그룹 생성을 누른다.
혹시나 나가졌다면
CodeDeploy - 배포 - 애플리케이션 - 생성된 애플리케이션 선택 - 세부 정보 보기


EC2 접속

시간 동기화

EC2는 기본적으로 시간을 UTC로 설정되어 있습니다.

그렇기 때문에 실제 시간과 맞지 않습니다.

# 현재 시간 확인 # 현재 시간은 14:28:05
$> date
2022. 06. 26. () 05:28:05 UTC

# 해당 ec2가 실행될 때마다 chrony 방식으로 시간을 동기화하도록 요청
sudo chkconfig chronyd on
알림: 'systemctl enable chronyd.service'에 요청을 전송하고 있습니다.

$> chronyc tracking
Reference ID    : A9FEA97B (169.254.169.123)
Stratum         : 4
Ref time (UTC)  : Sun Jun 26 05:34:11 2022
System time     : 0.000001262 seconds slow of NTP time
Last offset     : -0.000001123 seconds
RMS offset      : 0.000000901 seconds
Frequency       : 24.053 ppm slow
Residual freq   : -0.000 ppm
Skew            : 0.021 ppm
Root delay      : 0.000449654 seconds
Root dispersion : 0.000277246 seconds
Update interval : 16.2 seconds
Leap status     : Normal

# 타임존 설정
$> sudo vim /etc/sysconfig/clock
# 다음과 같이 변경
ZONE="Asia/Seoul"
KST=True

# 기존 설정 삭제
$> sudo rm /etc/localtime

# 대한민국 표준 시간대 정보를 심볼릭 링크로 설정
$> sudo ln -s /usr/share/zoneinfo/Asia/Seoul /etc/localtime

# ec2 시간 확인
$> date
2022. 06. 26. () 14:30:02 KST

Java 설치

# aws coreetto 다운로드
$> sudo curl -L https://corretto.aws/downloads/latest/amazon-corretto-11-x64-linux-jdk.rpm -o jdk11.rpm

# java 11 설치
$> sudo yum localinstall jdk11.rpm -y

# java version 선택
$> sudo /usr/sbin/alternatives --config java
# Enter

# java version 확인
$> java --version
openjdk 11.0.15 2022-04-19 LTS
OpenJDK Runtime Environment Corretto-11.0.15.9.1 (build 11.0.15+9-LTS)
OpenJDK 64-Bit Server VM Corretto-11.0.15.9.1 (build 11.0.15+9-LTS, mixed mode)

# 설치 파일 삭제
$> rm -rf jdk11.rpm

Swap 메모리

EC2 를 프리티어로 사용하고 있다면, 1GBJenkins와 함께 어플리케이션을 실행하기에는 부족한 메모리입니다.
Jenkins와 어플리케이션 인스턴스를 분리한다면 괜찮지만, 현재는 테스트용 인스턴스 하나만 사용할 예정이므로, Swap 메모리를 통해 하드 디스크 일부를 RAM으로 가져옵니다.

# dd 명령어를 통해 swap 메모리 할당
# 시간이 1분 ~ 5분정도 걸릴 수 있음
# 크기는 2GB(128MB x 16)
$> sudo dd if=/dev/zero of=/swapfile bs=128M count=16
16+0 records in
16+0 records out
2147483648 bytes (2.1 GB) copied, 30.8159 s, 69.7 MB/s

$> sudo chmod 600 /swapfile

# Linux swap 영역 설정
$> sudo mkswap /swapfile
Setting up swapspace version 1, size = 2 GiB (2147479552 bytes)
no label, UUID=8a00cd88-62cf-4d33-b2a4-6b771ab70526

# swap 공간에 swap file을 추가해 즉시 사용할 수 있도록 설정
$> sudo swapon /swapfile

$> sudo swapon -s
Filename				Type		Size	Used	Priority
/swapfile               file    	2097148	0	    -2

# fstab에 /swapfile 설정 추가
$>sudo vi /etc/fstab
/swapfile swap swap defaults 0 0

$> free
              total        used        free      shared  buff/cache   available
Mem:         988672       79840      184684         436      724148      769820
Swap:       2097148           0     2097148

이로써 용량이 늘어난 것을 확인할 수 있습니다.

codedeploy-agent

codedeploy를 이용하기 위해서는 AWS 보안 자격 증명에서 엑세스 키가 있어야 합니다.

$> sudo aws configure
AWS Access Key ID [None]: 엑세스 키 ID
AWS Secret Access Key [None]: 엑세스 키 Secret
Default region name [None]: ap-northeast-2
Default output format [None]: json

# codedeploy-agent 설치 파일 다운로드
# 자신의 region에 맞는 설치 파일을 다운로드 받아야 함(ap-northeast-2)
$> wget https://aws-codedeploy-ap-northeast-2.s3.amazonaws.com/latest/install

# codedeploy-agent를 설치하기 위한 의존성 설정
$> sudo yum install ruby -y


$> chmod +x ./install
# codedeploy-agent 설치
$> sudo ./install auto

$> sudo service codedeploy-agent status
The AWS CodeDeploy agent is running as PID

Docker

Jenkins는 일반 애플리케이션과 같은 포트를 사용합니다. 그 외에 설치의 편리성 등등 장점을 이용하기 위해 Docker를 설치합니다.

# yum 업데이트
$> sudo yum update -y

# 도커 설치
$> sudo amazon-linux-extras install -y docker

# 도커 실행
$> sudo service docker start
Redirecting to /bin/systemctl start docker.service

# 도커에 jenkins 실행
# -p : jenkins의 기본 포트 8080을 외부 포트 9000으로 바인딩
# -e : 도커 컨테이너에 타임존 설정 
$> sudo docker run -d --name jenkins -p 9000:8080 -e TZ=Asia/Seoul jenkins/jenkins:jdk11

$> sudo docker ps -a
CONTAINER ID   IMAGE                   COMMAND                  CREATED          STATUS          PORTS                                                  NAMES
796fac7ed384   jenkins/jenkins:jdk11   "/usr/bin/tini -- /u…"   15 seconds ago   Up 14 seconds   50000/tcp, 0.0.0.0:9000->8080/tcp, :::9000->8080/tcp   jenkins

Jenkins

http://인스턴스퍼블릭IP:9000
로 접속합니다.

Administrator password 를 입력하기 위해 기존 비밀번호를 찾아야 합니다.
기본 비밀번호는 docker에서 jenkins로 접속하여 확인할 수 있습니다.

# 도커에 실행중인 jenkins 컨테이너에 bash를 통해 접속
$> sudo docker exec -it jenkins bash

# 비밀번호 출력
$> cat /var/jenkins_home/secrets/initialAdminPassword
<비밀번호>


Dashboard - Jankins 관리 - 플러그인 관리 - 설치 가능


플러그인 설치 과정을 진행한다.
이 때 잠시 바로 밑에 이슈를 먼저 확인하라.


이 설치과정에서 현재 dependency 이슈로 설치가 진행되지 않아서 잠시 중지했다.

CodeDeploy 플로그인을 설치하려고 하면 필수 플러그인 AWS SDK :: All을 설치하게 된다. 그런데, dependency 관련 이슈로 인해 설치가 실패한다. 이와 관련하여 삽질을 하다가 스터디 일원중의 한명이 해결법을 가져왔다!

https://plugins.jenkins.io/aws-java-sdk/#releases

이 사이트는 Jenkins 플러그인을 직접 다운받을 수 있는 사이트이다. 그중에 AWS: All 플러그인을 다운받는 곳이다.

다운을 하고,

플러그인 관리 - 고급 - Deploy Plugin

에 다운받았던 .hpi 파일을 넣고 Deploy를 한다.

이후에 다시 플러그인 관리로 돌아가서 CodeDeploy 플러그인을 다운받으면

이렇게 완료된다.

다운을 완료했다면
Dashboard -> new Item -> Freestyle project 로 이동

Username : 깃허브

깃허브 브렌치 설정

gralde을 따로 설치하지 않으므로 gradlew 설정을 해준다.

Application Name : AWS CodeDeploy에 설정한 Application 이름
Deployment Group : Application에 설정된 배포 그룹 이름

S3 Bucket : S3 Bucket 이름

**/*.jar, **/appspec.yml, **/scripts/*

S3에서 CodeDeploy를 통해 EC2로 복사할 파일

.jar : 어플리케이션
appspec.yml : CodeDeploy 가 참조
scripts : appspec.yml을 통해 실행할 스크립트 디렉토리

Access Key, Secret Key

그리고 저장

Github Webhook

Jenkins와 연동한 깃허브 리포지토리 -> Settings -> Webhooks

URL : Pulic IP:9000/github-webhook/
마지막에 /를 붙이지 않으면 302 Redirect 가 발생함

Build 설정

파일 생성

이 내용은 CodeDeploy 생명주기이다.
appspec.yml에서 회색 부분은 설정할 수 없고,
나머지 부분은 해당 순서에 어떤 행동을 할지 결정할 수 있다.

appspec.yml

version: 0.0
os: linux
files:
  - source:  /
    destination: /home/ec2-user/cicd-test
    overwrite: yes

permissions:
  - object: /
    pattern: "**"
    owner: ec2-user
    group: ec2-user

hooks:
  ApplicationStart:
    - location: scripts/deploy.sh
      timeout: 60
      runas: ec2-user

version: 0.0 : 고정
os : EC2window가 아니라면 linux
files : CodeDeploy가 작업할 파일을 선택한다.
source : 어떤 디렉토리를 기준으로 파일을 작업할지 선택한다. 전체를 가져오기 위해 /로 지정한다.
destination : CodeDeploy가 빌드된 파일을 복사할 때, 어느 디렉토리에 복사할지를 지정한다.
permissions : EC2/온프레미스에서만 작성한다.
hooks : 흑색 이벤트를 제외한 이벤트들을 지정한다.

deploy.sh

#!/bin/bash
BUILD_JAR=$(ls /home/ec2-user/testboard/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" >> /home/ec2-user/deploy.log
  kill -15 $CURRENT_PID
  sleep 10
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 &

이 상태로 main 브렌치에 push하게 되면,
github webhook으로 인해 Jenkins가 빌드를 감지하게 된다.


오류

Jenkins에서는 통과했지만, CodeDeploy에서 S3EC2로 이동하는 과정에서 오류가 발생했다.

내용은 대충 인스턴스 개수에 관한 문제였다.
그래서 설정을 그냥 모두로 바꿔서 해결했다.

참고로 CodeDeploy에서 오류가 발생하면 배포 구성을 지우고 다시 만들어야 새로운 설정이 적용된다.

참고 글
Jenkins + CodeDeploy를 활용한 EC2에 스프링 부트 프로젝트 배포 자동화

0개의 댓글