O-stock 서비스의 빌드/배포 파이프라인을 구현하는 데 사용할 다양한 기술을 먼저 그림으로 살펴보자
깃허브 : 소스 코드에 대한 소스 제어 저장소다 깃허브를 빌드 프로세스에 통합하는 다양한 웹훅과 강력한 REST 기반 API를 제공하기 때문에 깃허브를 소스 제어 저장소로 선택했다.
젠킨스 : O-stock 마이크로서비스를 구축 및 배포하고 도커 이미지를 프로비저닝하는 데 사용되는 지속적 통합 엔진이다. 젠킨스는 웹 인터페이스로 쉽게 구성할 수 있으며, 작업을 더 쉽게 만들어 주는 몇 가지 내장 플러그인이 포함되어 있다.
메이븐/스포티파이 도커 플러그인 또는 스프링 부트 도커 : 자바 코드를 컴파일, 테스트, 패키징하는 데 바닐라 메이븐을 사용했지만, 이러한 필수 메이븐 플러그인을 사용하면 도커 빌드를 메이븐 내에서 시작할 수 있다.
Docker : 도커는 여러 클라우드 공급자에 이식이 가능하다. 동일한 컨테이너를 가져와 최소의 작업으로 AWS, 애저, 클라우드 파운드리에 배포할 수 있다. 또 도커는 가볍다.
후반부에는 데이터베이스 서버, 메시징 플랫폼, 서치 엔진 등 대략 열 개의 도커 컨테이너를 구축하고 배포한다.
아마존 ECR : 서비스를 빌드하고 도커 이미지를 생성한 후 고유 식별자로 태그를 지정하고 중앙 저장소로 푸시한다. 이 도커 이미지 리포지토리로 ECR를 선택했다
아마존 EKS 컨테이너 서비스 : 아마존 클라우드 공급자로 가장 성숙하고 도커 서비스를 쉽게 배포할 수 있도록 하기 때문에 클라우드 플랫폼으로 아마존을 선택했다.
이번 예제에서는 깃허브를 소스 제어 저장소로 선택하고 젠킨스를 빌드 엔진으로 선택했다.
깃 소스 제어 저장소는 매우 인기 있고 깃허브는 가장 많이 사용하는 클라우드 기반의 소스 제어 저장소 중 하나이다. 젠킨스는 깃허브와 긴밀하게 통합되는 빌드 엔진이며 사용법도 간단하다.
예제를 완벽히 따르기 위해 깃허브, 젠킨스, AWS 계정을 설정을 설정해야 한다.
미리 EC2 인스턴스에 젠킨스 환경 설정 방법을 처음부터 단계별로 안내하는 가이드를 한번 읽어보고 설정을 하자.
필자는 아래와 같이 설정했다.
// 인스턴스 접속 명령어
ssh -i <key_pem> ec2-user@<EC2_INSTANCE_IPV4>
// EC2 접속
ssh -i elk-service.pem ec2-user@13.209.97.168
// jdk 11 설치
sudo amazon-linux-extras install java-openjdk11
// 버전 확인
java -version
sudo su -
cd ~
// 자바 설치된 경로확인
file /etc/alternatives/java
// bash profile에 JAVA_HOME 설정
vi .bash_profile
------------------------------------------------------------------------
export JAVA_HOME="/usr/lib/jvm/java-11-openjdk-11.0.7.10-4.amzn2.0.1.x86_64"
PATH=$PATH:$HOME/bin:$JAVA_HOME
------------------------------------------------------------------------
// 업데이트(리프레시)
source .bash_profile
// $JAVA_HOME 확인
echo $JAVA_HOME
sudo wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat-stable/jenkins.repo
sudo rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io.key
sudo yum install jenkins
service jenkins start
service jenkins status
// Jenkins web : http://13.209.97.168:8080/ 에 로그인
// 아래 명령어로 생성된 비밀번호를 사용하여 로그인
// 접속하면 새로운 어드민 계정을 생성하고 플러그인을 설치해야한다
cat /var/lib/jenkins/secrets/initialAdminPassword
그런데 접속하면 Install plugin ~ 이라고 써있는 버튼이 있는데 누르면 아래와 같이 기본 항목들을 알아서 다운로드 해준다.
// 젠킨스 웹에서 JAVA_HOME 설정하기 위해 메뉴이동
Manage Jenkins -> Global Configuration -> JDK Installations
// 자동으로 설치 체크 해제
Name: JAVA_HOME
JAVA_HOME: <Result_ECHO_JAVA_HOME> for example: /usr/lib/jvm/java-11-openjdk-11.0.7.10-4.amzn2.0.1.x86_64
Install Automatically -> Unchecked
// 적용 및 저장
Apply -> Save
hostname jenkins
sudo su -
yum install git -y
// 젠킨스 웹에서 깃 플러그인 설치
// 설치가능 목록에 검색해서 있으면 항목 체크하고 Install without restart 누른다.
// 설치가능 목록에 없으면 '설치된 플러그인 목록'에 있을수 있으니 확인하자.
Manage Jenkins -> Manage Plugins -> Available -> Github
Manage Jenkins -> Manage Plugins -> Available -> Github Integration
// 전역 구성 도구에서 git 설정
Global Tools Configuration -> GiT Installations
Name: git
Path to Git Executable: /usr/bin/git
Install Automatically -> Unchecked
// 적용 및 저장
Apply -> Save
// 메이븐 다운로드
cd /opt
wget https://mirrors.ucr.ac.cr/apache/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.tar.gz
// 목록 조회
[root@jenkins opt]# ls -l
total 9284
-rw-r--r-- 1 root root 9506321 Nov 19 2019 apache-maven-3.6.3-bin.tar.gz
drwxr-xr-x 4 root root 33 May 27 00:47 aws
drwxr-xr-x 2 root root 6 Aug 16 2018 rh
// 압축풀기
tar -xvzf apache-maven-3.6.3-bin.tar.gz
// 목록조회
[root@jenkins opt]# ls -l
total 9284
drwxr-xr-x 6 root root 99 Jun 22 03:09 apache-maven-3.6.3
-rw-r--r-- 1 root root 9506321 Nov 19 2019 apache-maven-3.6.3-bin.tar.gz
drwxr-xr-x 4 root root 33 May 27 00:47 aws
drwxr-xr-x 2 root root 6 Aug 16 2018 rh
// 파일 이동
mv apache-maven-3.6.3 maven
// 프로필 설정
vi ~/.bash_profile
------------------------------------------------------------------------
# User specific environment and startup programs
export JAVA_HOME="/usr/lib/jvm/java-11-openjdk-11.0.7.10-4.amzn2.0.1.x86_64"
M2_HOME=/opt/maven
M2=/opt/maven/bin
PATH=$PATH:$HOME/bin:$JAVA_HOME:$M2:$M2_HOME
export PATH
------------------------------------------------------------------------
// 파일 업데이트(리프레시)
source ~/.bash_profile
// 버전 확인
mvn --version
sudo amazon-linux-extras install docker
sudo service docker start
sudo systemctl enable docker
sudo usermod -a -G docker jenkins
sudo usermod -a -G docker ec2-user
// 젠킨스 웹 에서 도커 플러그인 설치한다
Manage Jenkins -> Manage Plugins -> Available -> Docker Pipeline
// 젠킨스 웹 에서 ECR 플러그인 설치
Manage Jenkins -> Manage Credentials -> Jenkins -> Global Credentials -> Add credential
// ecr-user로 된 IAM 사용자를 생성하고 권한은 AmazonEC2ContainerRegistryFullAccess 를 사용
// 자격증명이 포함된 CSV를 다운로드 해놓는다.
// IAM의 ID와 key 기준으로 젠킨스 자격증명 등록
ID: ecr-user
Description: ecr-user
Access Key ID: <KEY_DOWNLOADED_IN_STEP_14>
Secret Access Key: <KEY_DOWNLOADED_IN_STEP_14>
// Kubectl 설치
sudo su -
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
chmod +x ./kubectl
sudo mv ./kubectl /usr/local/bin/kubectl
// 버전확인
kubectl version --short --client
// ecr-user로 된 IAM 사용자를 생성하고 권한은 AmazonEC2ContainerRegistryFullAccess 를 사용
// 자격증명이 포함된 CSV를 다운로드 해놓는다.
// IAM의 ID와 key 기준으로 젠킨스 자격증명 등록
aws configure
// 클러스터 컨피그 생성
aws eks --region ap-northeast-2 update-kubeconfig --name ostock-dev-cluster
// 성공시 내용
Added new context arn:aws:eks:ap-northeast-2:8XXXXXXXXXXX3:cluster/ostock-dev-cluster to /root/kubeconfig
// 서비스 리스트 확인
kubectl get svc
cat > ~/.kube/config-ostock-dev-cluster
export KUBECONFIG=$KUBECONFIG:~/.kube/config-ostock-dev-cluster
echo $KUBECONFIG
kubectl get svc
플러그인 설치 및 설정을 완료했다
파이프라인을 구축하려면 깃허브 웹훅을 생성해야 한다.
웹훅은 웹 HTTP 콜백이라고도 한다.
이러한 HTTP 콜백은 실시간 정보를 다른 애플리케이션에 제공한다.
일반적으로 콜백은 웹훅이 포함된 애플리케이션에서 프로세스나 작업이 실행될 때 트리거 된다.
깃허브에서 웹훅을 생성하면 코드가 푸시될 때 젠킨스가 알림을 받을 수 있다.
이 알림을 받고 젠킨스는 특정 빌드 프로세스를 시작한다.
깃허브에서 다음과 같이 웹훅을 생성한다
1. 파이프라인 프로젝트가 포함된 리포지터리로 이동한다.
2. 설정 메뉴에 들어간다.
3. 웹훅을 선택한다.
4. 웹훅 추가를 누른다
5. 특정 페이로드 URL을 제공한다.
6. 단순 푸시 이벤트 옵션을 클릭한다.
7. 웹훅 추가 버튼을 누른다.
페이로드 URL은 젠킨스 IP 주소를 사용하여 설정한다는 것을 기억하자.
이 방법으로 리포지터리에 푸시할 때 마다 젠킨스를 호출할 수 있다.
지금껏 서비스 컴파일은 다음과 같았다.
로컬 머신에서 명령줄 프로그램을 실행한다(wsl)
메이븐 스크립트를 실행한다. 이 스크립트로 모든 서비스를 빌드 한 후 도커 이미지로 패키징 하여 로컬에서 실행되는 도커 리포지터리에 푸시했다(mvn clean package dokcerfile:build)
로컬 도커 리포지터리에서 새로 생성된 도커 이미지를 시작한다.(docker-compose up 을 통해 모든 서비스를 시작했다)
젠킨스에서 이 프로세스를 어떻게 반복할 것인가?
모든 것은 Jenkinsfile 이라는 하나의 파일에서 시작한다.
Jenkinsfile은 젠킨스가 빌드를 실행할 때 작업을 기술한 스크립트다.
이 파일은 마이크로서비스의 깃허브 리포지터리의 루트 디렉터리에 저장된다.
깃허브 리포지터리에 커밋이 발생하면 웹훅은 페이로드 URL을 사용하여 젠킨스를 호출한다.
젠킨스 잡은 Jenkinsfile을 찾아 빌드 프로세스를 시작한다.
다음은 젠킨스를 사용한 빌드/배포 프로세스와 관련된 일반적인 단계를 살펴보자
1. 개발자는 깃허브 리포지터리의 마이크로서비스 중 하나를 변경한다.
2. 젠킨스는 깃허브에서 푸시 발생에 대한 알림을 받는다. 이 알림은 깃허브 웹훅에서 작성되었다.
젠킨스는 빌드를 실행할 프로세스를 시작한다. 젠킨스는 깃허브에서 소스 코드를 확인하고 jenkinsfile을
사용하여 전체 빌드 및 배포 프로세스를 시작한다.
3. 젠킨스는 빌드에 대한 기본 구성을 설정하고 의존성들을 설치한다.
4. 젠킨스는 단위 및 통합 테스트를 실행하며, 프로젝트를 빌드하고 애플리케이션에 대한 JAR 파일을 생성한다.
5. 젠킨스는 메이븐 Dockerfile 플러그인을 실행하여 새 도커 이미지를 생성한다.
6. 그런 다음 젠킨스는 ECR 리포지터리 데이터로 새 이미지에 태그를 지정한다.
7. 빌드 프로세스는 지정한 태그 이름으로 이미지를 ECR로 푸시한다.
8. 빌드 프로세스는 EKS 클러스터에 연결하고 service.yaml, deployment.yaml 파일을 사용하여 서비스를 배포한다.
앞서, 모든 플러그인을 설치 했다면 쿠버네티스와 ECR 자격 증명을 생성해야 한다.
Manage jenkins - Manage Credentials - jenkins - Global Credentials 으로 이동 후
Add Credentials files를 누른다.
kubeconfig 를 선택하고 쿠버네티스 클러스터 정보로 양식을 작성한다.
클러스터 정보를 조회하려면 다음 명령을 실행한다.(클러스터에 연결되어 있어야한다)
kubectl config view --raw
해당 명령어로 나온 내용을 젠킨스 내용 텍스트 상자에 붙여놓는다.
이 작업을 수행하려면 먼저 AWS 콘솔의 'IAM' 페이지로 이동해야 한다.
왼쪽 메뉴의 - Users - Add User 를 누른다.
Add User 페이지에서 사용자 이름, 액세스 유형, 정책을 지정해야 한다.
그런 다음 사용자 자격 증명이 기록된 .CSV 파일을 내려받고 사용자를 저장하여 마친다.
이제 단계별로 자격증명을 만드는 과정을 진행해본다.
'IAM' 페이지에서 다음 데이터를 추가한다.
User name : ecr-user
Access type : Programmatic access
두 번째 페이지는, Permission - Attach Existing Policies Directly 옵션을 클릭한 후
AmazonEC2ContainerRegistryFullAccess를 검색해서 선택한다.
모든 단계를 마치고 마지막 페이지에서 .CSV 파일을 내려받는다.
이 자격 증명을 나중에 사용해야 하기 때문에 자격 증명 파일을 꼭 내려받아야 한다.
먼저 ECR 플러그인이 젠킨스에 설치되었는지 확인해야한다.
설치되었다면
Manage jenkins - Manage Credentials - jenkins - Global Credentials 으로 이동한 후
Add Credentials - Kind(AWS Credentials) 옵션을 선택하고 다음 데이터를 추가한다.
ID: ecr-user
Description: ECR User
Access Key ID: <Access_key_id_from_csv>
Secret Access Key: <Secret_Access_key_from_csv>
자격 증명이 생성되었다면, 이어서 파이프라인 구성을 진행하자
젠킨스 대시보드로 이동하여 화면 왼쪽 위의 새로운 Item을 클릭한다.
구성 서버를 빌드하는 젠킨스 파이프라인을 생성한다.
항목이름은 configserver으로 지정하고, 2번째 항목인 파이프라인 옵션을 선택한다
깃허브 리포지터리 URL을 추가하고 GitHub hook trigger for GITScm polling 옵션을 체크한다
이 옵션은 이전 절에서 구성 설정한 웹훅 페이로드를 활성화한다.
마지막으로 Pipeline - Definition 드롭다운 메뉴에서 Pipeline script from SCM 을 선택하는 것이다.
이 단계에서는 애플리케이션의 소스 코드 리포지터리에서 Jenkinsfile을 검색한다.
Jenkinsfile은 빌드에 대한 핵심 런타임 구성을 다룬다. 일반적으로 이 파일은 여러 섹션으로 나뉘어 있고 필요한 만큼 섹션이나 스테이지를 추가할 수 있다.
다음 구성 서버의 Jenkinsfile 파일을 살펴보자
node {
def mvnHome
stage('Preparation') { // preparation 스테이지를 정의한다.
// 깃 리포지터리를 지정한다.
git 'https://github.com/klimtever/smia2-configserver-jenkins.git'
// 젠킨스 서버에서 메이븐 구성을 노출한다.
mvnHome = tool 'M2_HOME'
}
stage('Build') { // 빌드 스테이지를 정의한다
// 메이븐 빌드를 실행한다
withEnv(["MVN_HOME=$mvnHome"]) {
if (isUnix()) {
// 메이븐 clean package 명령을 실행한다
sh "'${mvnHome}/bin/mvn' -Dmaven.test.failure.ignore clean package"
} else {
bat(/"%MVN_HOME%\bin\mvn" -Dmaven.test.failure.ignore clean package/)
}
}
}
stage('Results') { // JUnit 결과를 가져온다. 그리고 도커 이미지 생성에 필요한 애플리케이션 jar 파일을 생성한다.
junit '**/target/surefire-reports/TEST-*.xml'
archiveArtifacts 'configserver/target/*.jar'
}
stage('Build image') { // Build image 스테이지를 정의한다
// 메이븐 docker:build 명령을 실행한다 이 명령으로 새 도커 이미지를 생성하고, ECR 리포지터리 정보로 태그를 지정한다.
sh "'${mvnHome}/bin/mvn' -Ddocker.image.prefix=758417428849.dkr.ecr.ap-northeast-2.amazonaws.com/ostock -Dproject.artifactId=configserver -Ddocker.image.version=chapter12 dockerfile:build"
}
stage('Push image') { // Push image 스테이지를 정의한다.
docker.withRegistry('https://758417428849.dkr.ecr.ap-northeast-2.amazonaws.com', 'ecr:ap-northeast-2:ecr-user') {
// ECR 저장소에 이미지를 푸시한다.
sh "docker push 758417428849.dkr.ecr.ap-northeast-2.amazonaws.com/ostock/configserver:chapter12"
}
}
stage('Kubernetes deploy') { // Kubernetes deploy 스테이지를 정의한다.
kubernetesDeploy configs: 'configserver-deployment.yaml', kubeConfig: [path: ''], kubeconfigId: 'kubeconfig', secretName: '', ssh: [sshCredentialsId: '*', sshServer: ''], textCredentials: [certificateAuthorityData: '', clientCertificateData: '', clientKeyData: '', serverUrl: 'https://']
}
}
첫 스테이지에서는 깃 구성을 추가한다. 이렇게 하면 빌드 섹션에서 깃허브 URL에 정의하는 단계를 생략할 수 있다.
두번째 스테이지에 두 번째 명령줄은 Jenkinsfile 전체에서 메이븐 명령을 사용할 수 있도록 메이븐 설치 경로를 표시한다.
세번째 스테이지에서는 애플리케이션을 패키지하는데 사용할 명령을 정의한다. 애플리케이션을 패키징하기 위해 메이븐 루트 디렉터리를 정의하는 메이븐 환경 변수를 사용한다.
네번째 스테이지에서는 새 도커 이미지 생성을 담당하는 dockerfile:build 명령어를 실행한다.(마이크로서비스 pom.xml 파일에서 메이븐 sporify-dockerfile 플러그인을 정의했었다)
이 명령어에서는 도커 이미지 시작어, 이미지 버전, 산출물 ID를 전달하는데, 원하는 만큼 매개변수를 설정할 수 있는 좋은 위치이기도 하다. 또한 이 스테이지에서는 ECR 리포지터리 데이터가 포함된 특정 태그를 생성하고 새 이미지에 지정할 수 있다. 다른 변수를 지정해서 다른 버전의 도커 이미지를 만들 수도 있다.
다섯번째 스테이지에서는 이미지를 ECR 리포지터리에 푸시한다. 이제 방금 생성한 구성 서버를 리포지토리에 추가했다.
마지막 스테이지인 Kubernetes deploy 스테이지에서는 EKS 클러스터에 배포한다.
젠킨스는 Jenkinsfile에서 사용할 수 있는 다양한 파이프라인 부분을 자동으로 생성할 수 있는 파이프라인 구문 옵션을 제공한다.
1. 젠킨스 대시보드 페이지로 이동하여 파이프라인을 선택한다
2. 대시보드 왼쪽 열에 표시된 파이프라인 구문(Pipeline Syntax) 옵션을 클릭한다.
3. 스니펫 생성기에서 Sample Step 드롭다운 메뉴를 클릭하고 kubernetesDeploy: Deploy to kubernetes를 선택한다.
4. Kubeconfig 드롭다운 메뉴에서는 앞 정에서 생성한 Kubernetes credentials 를 선택한다.
5. Config Files 옵션에서 configserver-deployment.yaml 파일을 선택한다. 이 파일은 깃허브 프로젝트의 루트 디렉터리에 있다.
6. 다른 값들은 기본값을 사용한다.
7. 파이프라인 스크립트 생성 버튼을 누른다.
설정을 완료했다면 이제 코드를 변경할 수 있다. 젠킨스 파이프 라인은 자동으로 트리거된다.
🧨 젠킨스를 이용한 자동 빌드/배포 설정도 했다. 다음 챕터는 프로메테우스를 이용한 모니터링을 구축해보자.