인프라 구축 환경
- AWS EC2 인스턴스 2개 활용 예정
- 구축용(Jenkins) 서버 : Jenkins, Git, Gradle, Docker, Jdk8
- 배포용 서버 : bash, Spring boot
- Git Repository : Github
인프라 구축을 하기 위해 배포할 서버가 필요하다.
여기서 나는 AWS 프리티어를 사용하고 있고 제일 보편적으로 AWS EC2를 많이 사용하기 때문에
EC2 인스턴스 t2.micro 리전을 생성하여 인프라 구축 환경을 만들려고 한다.
목표
다음과 같은 그림 구조로 CI/CD 파이프라인을 구축하여 자동배포가 가능하도록 할 예정이다.
EC2 Jenkins 서버 구축
1. 스왑 메모리
프리티어 기준 EC2 메모리는 1GB이며,
젠킨스는 스프링 프레임워크 프로젝트 빌드시 약 2.n GB의 메인 메모리를 사용한다.
그렇기 때문에 아주 적절한 스왑 메모리를 할당해야 한다.
적게 할당하면 메인 메모리가 부족해서 빌드할 때 서버가 터지고,
너무 많이 할당하면 디스크가 부족해서 서버가 터진다.
그렇기 때문에 Swap 메모리를 확보해 총 3GB로 사용하는 방법을 많이 사용한다.
/스왑 파일 생성하기
sudo dd if=/dev/zero of=/swapfile bs=128M count=16
//스왑 파일에 대한 읽기 쓰기 권한 업데이트하기
sudo chmod 600 /swapfile
//Linux 스왑 영역 설정하기
sudo mkswap /swapfile
//스왑 공간에 스왑 파일을 추가하여 스왑 파일을 즉시 사용할 수 있도록 하기
sudo swapon /swapfile
//확인하기
sudo swapon -s
// /etc/fstab 파일을 편집하여 부팅 시 스왑 파일을 활성화하기
sudo vi /etc/fstab
//파일 가장 마지막에 다음을 추가하고 :wq로 저장하고 종료
/swapfile swap swap defaults 0 0
//메모리 확인하기
free
메모리를 확인하면 swap 2.n GB의 가상메모리를 확인할 수 있다.
2. Docker 설치
도커 설치법은 도커 공식 홈페이지에서 자세히 알려준다.(ubuntu 기준)
도커를 설치했으면 docker --version 명령어로 잘 받아졌는지 확인해 보자.
3. Jenkins 설치
$ sudo docker run -d --name jenkins -p 9090:8080 jenkins/jenkins:jdk11
- -d : 컨테이너를 백그라운드로 실행한다.
- --name : 컨테이너에 이름을 부여한다. 컨테이너 실행과 같은 명령어에서 컨테이너 ID 대신 이름을 사용해 편리하게 사용할 수 있다.
- -p 9090:8080 : 컨테이너 외부와 통신할 port(9090)와 내부적으로 사용할 port(8080)를 지정해 포워딩할 수 있다. 9090 port로 접속하기 위해 설정했다.
8080 포트는 다른 프로그램에서 기본 포트로 사용하는 경우가 많기 때문에
포트 충돌을 방지하기위해 9090으로 포트를 생성하였다.
이후부터는
$ sudo docker start jenkins
생성된 컨테이너를 바로 실행시키면 된다.
4. Jenkins 플러그인 설치
자 이제 자신의 젠킨스에 접속할 수 있게 되었다.
젠킨스 접속은 {자신의 도메인}:{할당한 포트}로 접근하면 된다.
http://{ec2 jenkins 서버 인스턴스 ip}:9090/
이렇게 접근하면 처음에는 위와 같은 화면이 나올 것이다.
/var/jenkins_home/secrets/~~~ 이런 경로에서 확인하라는데,
인스턴스에서 sudo docker logs {컨테이너 이름} 명령어를 입력하면 아래와 같이 나온다.
*************************************************************
*************************************************************
*************************************************************
Jenkins initial setup is required. An admin user has been created and a password generated.
Please use the following password to proceed to installation:
{여기 나오는게 Jenkins 패스워드}
This may also be found at: /var/jenkins_home/secrets/initialAdminPassword
*************************************************************
*************************************************************
*************************************************************
이후 Install suggested plugins 선택하여 플러그인 설치해 주시고,
계정 생성화면이 나타나면 젠킨스에서 사용할 계정을 생성하면 메인 대시보드가 나올 것이다.
5. CI 구축하기
5.1 Github Web Hook
레파지토리의 설정으로 들어가서 Webhooks 설정으로 들어가 Add webhook을 클릭한다.
다음은 Payload URL을 설정해줘야 한다.
아래의 그림과 같이, 도메인:도커로 띄운 젠킨스 포트/github-webhook/ 으로 설정해 주면 된다.
Content Type은 application/json으로 바꾸고
웹 훅이 트리거를 발생시킬 주기를 해당 레파지토리에 push 했을 때로 설정한다. (Just the push event)
그리고 Add webhook을 눌러 추가하면 된다.
5.2 액세스 토큰 발급
setting -> Developer settings -> Personal access token(Tokens)
-> Generate new Token (classic)으로 액세스 토큰을 발급받아보자. (jenkins의 자격증명으로 사용된다)
repo와 admin:repo_hook를 셀렉트 해주고 생성하면 된다.
액세스 토큰 이름은 상관없다. 기간은 해당 액세스 토큰을 자신이 사용할 기간까지만 할당하는 게 좋다.
생성하고 나면 아래의 키를 볼 수 있는데 페이지를 떠나는 순간 토큰의 정보를 볼 수 없게 된다.
단 한 번밖에 볼 수 없는 키이므로 즉시 어딘가에 복사해 놓자.
5.3 Credentials 만들기
CI를 Github Webhook으로 구축한다는 많은 포스트들을 보면
Github API Usage, JDK 설정 등을 따로 해주는데, 딱히 그렇지는 않다고 한다.
Credentails 등록만으로도 Github Webhook 연동이 가능하다.
그러므로 Credentials를 등록하여 github 정보를 넣고 생성해 보자
- 대시보드 -> 젠킨스 관리 -> Credentials
5.4 Gradle 설정
그리고 Gradle 버전을 설정해줘야 한다.
- 대시보드 -> 젠킨스 관리 -> Tools
Gradle Installations 섹션이 있는데,
Gradle Installations를 눌러서 안정된 버전을 선택해 주자.
5.5 CI 스크립트 작성
이제 직접 파이프라인을 구축해 보자.
- 대시보드 -> New Item -> Pipeline 선택 후 OK -> Github hook trigger for GITScm polling을 선택
아래의 Pipeline Syntax를 눌러서 자신의 설정에 맞는 스크립트 한 줄을 git 정보를 기입하여 뽑아보자.
이후 파이프라인 스크립트 창으로 돌아와서 아래와 같은 파이프라인 스크립트에 붙여 넣기 하면 된다.
pipeline {
agent any
tools {
gradle 'gradle'
}
stages {
stage('Git Clone') {
steps {
{복사한 내용}
}
}
stage('build project') {
steps {
sh "./gradlew clean build"
}
}
}
}
추가로 application-secret과 같은 파일을 github에 업로드하지 않고
local 환경에서 다루고 있다면, 파이프라인 설정을 추가로 작성하여 build 전 파일을 다운로드할 수 있다.
5.5.1 추가 파이프라인 작성
+Add Credentials 클릭
Credentials 생성
- Kind : Secret file
- File : application-{secret}.yml 파일 등록
- ID : 해당 credentials을 사용할 ID 지정
- Creat!
추가 파이프라인 작성
pipeline {
agent any
tools {
gradle 'gradle'
}
stages {
//..
stage('Delete Files') {
steps {
script {
def filesToDelete = ['src/main/resources/application-secret.properties', 'src/main/resources/application-prod.properties']
for (String file : filesToDelete) {
if (fileExists(file)) {
sh "rm $file"
}
}
}
}
}
stage('secret.properties download') {
steps {
withCredentials([file(credentialsId: 'secret-credentials', variable: 'secretConfigFile'),
file(credentialsId: 'prod-credentials', variable: 'prodConfigFile')]) {
script {
sh 'cp $secretConfigFile src/main/resources/application-secret.properties'
sh 'cp $prodConfigFile src/main/resources/application-prod.properties'
}
}
}
}
//..
}
}
6. CD 구축하기
6.1 SSH 플러그인 설치
원래 SSH 플러그인은 Publish Over SSH를 많이 사용하는데, 접속 불가 이슈가 있다고 한다.
또한 jenkins SSH 플러그인의 SSH Agent가 더 간편한 것 같아서 이를 사용해보려고 한다.
- 대시보드 -> 젠킨스 관리 -> 플러그인
검색에서 SSH Agent를 검색한 후 설치한다.
6.2 EC2 개발 환경 정보 추가 설정
jenkins의 접속할 때 인스턴스 sshkey를 활용해서 접속한 것처럼
개발환경의 sshkey를 활용하여 접속하여야 한다. sshkey를 넣어서 연결해 보자.
- 대시보드 -> 젠킨스 관리 -> Credentials -> Add credentials
id는 마음대로 설정하고
username은 인스턴스 os의 이름,
private key의 Key는 자신의 pem키 내용을 복사하면 된다.
기존에 저장해 놓은 sshkey 파일을 열어서 확인할 수 있고,
로컬에서 자신의 pem키 경로로 이동해서 cat {~~. pem} 명령어로 확인할 수 있다.
BEGIN RSA PRIVATE KEY부터 END RSA PRIVATE KEY까지 모두 복사해서 붙여 넣자.
6.3 CD 스크립트 작성
마지막으로 다시 파이프라인 스크립트로 돌아와서
stage('Deploy') 부분을 자신의 설정에 맞게 추가해 주면 된다.
pipeline {
agent any
tools {
gradle 'gradle'
}
stages {
//.. build project
stage('Deploy') {
steps {
sshagent(credentials: ['instance-key']) {
sh '''
ssh -o StrictHostKeyChecking=no ubuntu@172.31.38.22 uptime
scp build/libs/always-0.0.1-SNAPSHOT.jar ubuntu@172.31.38.22:/home/ubuntu
ssh -t ubuntu@172.31.38.22 "chmod +x deploy.sh && ./deploy.sh"
'''
}
}
}
}
}
cd 스크립트를 설명하면,
젠킨스 서버에서 운영 서버에 접근할 수 있도록 StrictHostKeyChecking를 비활성화시켜준다.
그 후 scp를 통해 빌드된 jar파일을 운영 서버로 전송시킨 후,
운영 서버에 미리 작성한 deploy.sh 파일을 실행하여 빌드된 파일을 실행시켜 준다.
deploy.sh파일의 내용은 아래와 같다.
#!/bin/bash
pid=$(pgrep -f always)
if [ -n "${pid}" ]
then
kill -15 ${pid}
echo kill process ${pid}
else
echo no process
fi
chmod +x ./always-0.0.1-SNAPSHOT.jar
nohup java -jar ./always-0.0.1-SNAPSHOT.jar >> application.log 2> /dev/null &
추가로 window환경에서 하시는 분들은 Unix/Linux 환경으로 스크립트를 전송할 때,
줄 바꿈 문자 문제가 발생한다면 배포 서버에 dos2unix deploy.sh를 사용하여
스크립트 파일을 Unix 형식으로 변환하여 빌드하면 성공한다.
이제 모든 CI/CD 파이프라인이 완성되어, 목표에 맞는 인프라 파이프 구조가 다음 그림과 같이 만들어졌다.
다시 배포할 일이 생긴다면 docker hub를 사용하고,
무중단 배포와 같은 추가 설정을 도입해 보면 좋을 것 같다.
reference
https://seongwon.dev/DevOps/20220717-CICD%EA%B5%AC%EC%B6%95%EA%B8%B02/
https://velog.io/@bagt/Jenkins%EC%99%80-Docker%EB%A1%9C-CICD-%EA%B5%AC%EC%B6%95%ED%95%98%EA%B8%B0
'Project > 협업프로젝트' 카테고리의 다른 글
[협업프로젝트] Spring Data Elastic Search 설정 및 구현 회고 (1) (0) | 2024.10.13 |
---|---|
[협업프로젝트] Jenkins와 Docker로 CI/CD pipeline 구축하기 (1) (0) | 2023.10.30 |
[협업프로젝트] SpringBoot 프로젝트 EC2, RDS 적용 (0) | 2023.10.30 |
[협업프로젝트] SpringBoot 프로젝트 EC2 배포하기 (1) | 2023.10.29 |
[협업프로젝트] SwaggerUI + Spring RestDocs 로 API 문서화하기 (2) | 2023.10.14 |