이 글에서 다룰 전체 프로세스이다.
0. 프로젝트를 github
로 push
한다. (main
브렌치)
1. github webhook
을 통해 Jenkins
가 호출된다.
2. Jenkins
에서 빌드를 진행한다.
3. Jenkins
가 빌드한 파일을 s3
에 업로드한다.
4. Jenkins
가 CodeDeploy
로 배포를 요청한다.
5. CodeDeploy
는 s3
에서 업로드된 빌드 파일을 가져온다.
6. CodeDeploy
가 EC2
에 배포를 진행한다.
선택에는 두 가지 방법이 있는데,
Jenkins
를 로컬에서 실행 시킨 후에, ssh
로 ec2
를 연결하는 방식Jenkins
설치 후, ssh
연결만 하면 됨.Jenkins
를 계속 켜야함.ssh
를 연결할 수 있으므로, 관리가 편함.ec2
내부에 Jenkins
를 설치하여 모든 것을 ec2
에 맡기는 방식ec2
에 모든것을 위임하므로 ec2
를 여러개 사용할 경우, 모든 서버에 Jenkins
를 설치해야함.ec2
에서 알아서 맡아서 해줌.이러한 이유로 두 번째 방법으로 하기로 하였다. 설치방법과 실행은 더 복잡하지만, 자동화를 해준다는 큰 장점이 있다.
CodeDeploy
는 AWS
에서 운영환경에 자동 배포하는 역할을 수행하는 AWS Service
이다. 즉, CD
지속적 배포 서비스이다.
먼저 CodeDeploy
를 이용하기 위해 IAM
에서 권한을 줘야한다.
IAM
- 역할
- 역할 만들기
정책 중에
AmazonS3FullAccess
와
AWSCodeDeployFullAccess
를 찾아 추가한다.
정책 이름 확인 후에 생성한다.
이렇게 EC2
에 대한 역할이 생성되었다.
이번에는 CodeDeploy
역할을 생성할 것이다.
똑같이 역할 만들기
를 누른다.
이전과 다르게 사용 사례에 CodeDeploy
를 선택한다.
정책은 이렇게 자동으로 선택되어있다.
최종으로 이렇게 2개의 역할을 생성하였다.
S3
- 버킷
- 버킷 만들기
AmazonS3FullAccess
권한이 이미 EC2
에 부여되었기 때문에 엑세스 차단을 해도 된다.
생성하는 과정은 생략하겠다.
인스턴스를 선택하고,
작업
- 보안
- IAM 역할 수정
이전에 생성했던 역할을 선택한다.
그리고 인스턴스를 재부팅 한다.
그리고 보안 그룹에서 사용자 TCP
로 9000
과 8080
을 열어준다.(Jenkins
, Spring boot
)
CodeDeploy
- 배포
- 애플리케이션
- 애플리케이션 생성
생성 후에 배포 그룹에서 배포 그룹 생성을 누른다.
혹시나 나가졌다면
CodeDeploy
- 배포
- 애플리케이션
- 생성된 애플리케이션 선택
- 세부 정보 보기
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
# 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
EC2
를 프리티어로 사용하고 있다면, 1GB
로 Jenkins
와 함께 어플리케이션을 실행하기에는 부족한 메모리입니다.
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
를 이용하기 위해서는 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
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
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
그리고 저장
Jenkins와 연동한 깃허브 리포지토리
-> Settings
-> Webhooks
URL
: Pulic IP:9000/github-webhook/
마지막에 /
를 붙이지 않으면 302 Redirect
가 발생함
파일 생성
이 내용은 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
: EC2
가 window
가 아니라면 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
에서 S3
를 EC2
로 이동하는 과정에서 오류가 발생했다.
내용은 대충 인스턴스 개수에 관한 문제였다.
그래서 설정을 그냥 모두로 바꿔서 해결했다.
참고로 CodeDeploy
에서 오류가 발생하면 배포 구성을 지우고 다시 만들어야 새로운 설정이 적용된다.