MSA 서비스 만들기 1
개요
지난 1주 동안 부트캠프에서 미니 프로젝트를 진행하였다. 매일 10시까지 있었던건 안비밀
본인 조는 일종의 게시판 서비스를 만들었는데… 본인은 게이트웨이와 사용자(user) 마이크로서비스를 담당하였다.
구성도는 위와 같다.
각 마이크로서비스(gateway, user, post, leaderboard)가 서로의 db를 가지고,
kafka를 통해 통신하는 구조였다. 당연히 각각은 docker로 컨테이너 구현되어 있고.
발표 때는 시간과 여백이 부족하여 로컬 환경에서 구동했는데, 프로젝트가 끝났지만 뭔가 오기? 가 생겨 주말 동안 젠킨스 배포 시스템과 쿠버네티스 구현을 해보기로 했다.
젠킨스 만들기
젠킨스 초기설정
우선 젠킨스를 설치해야 하니 컨테이너로 만들고…
1
2
3
4
5
6
7
8
9
10
11
12
13
14
version: "3"
services:
jenkins:
image: jenkins/jenkins:lts
container_name: jenkins
restart: always
user: root
volumes:
- ./jenkins_home:/var/jenkins_home
- /var/run/docker.sock:/var/run/docker.sock
ports:
- 8000:8080
environment:
- DOCKER_HOST=unix:///var/run/docker.sock
docker-compose up -d
로 실행시켜줬다. 포트는 8000 포트를 사용할 예정~
(ports: -8000:8080
의 의미는 컨테이너 안에는 8080 포트로 실행하는데 밖에서는 8000으로 접속한다는 것을 의미한다. 즉 일종의 프록싱)
젠킨스를 처음 들어가면 초기 비밀번호가 필요할건데, 화면에도 나오지만
/var/jenkins_home/secrets/initialAdminPassword
여기 있다고 한다.
컨테이너에 직접 접속해서 찾으면 된다.
1
2
docker exec -it (내 젠킨스 컨테이너이름) /bin/bash
cat /var/jenkins_home/secrets/initialAdminPassword
여차저차 초기셋팅을 끝내고, 플러그인을 설치해야 한다.
사진에 동그라미 친 것처럼 설정→Plugins→Available plugins에 들어가서
- Authentication Tokens API
- Docker
- Docker Pipeline
- Generic Webhook Trigger
- Git Parameter
- Stage View
이렇게 6개를 설치하자.
그 다음에는 다시 설정→Tools에 들어가서 빌드 설정을 해줘야 하는데,
본 프로젝트는 spring boot, 즉 자바 Gradle로 마이크로서비스를 개발하기 때문에
JDK, Gradle 설정을 넣어줘야 한다. 추가로 Docker 이미지로 배포할 것이기 때문에 Docker 설정도~
토큰 발급
젠킨스에서 해주는 빌드 구조가 github에서 파일을 받아, docker image로 만드는 것이기 때문에, 깃허브와 독커허브 양쪽에서 토큰을 발급받아야 한다.
각 싸이트에서 토큰 받는 방법은 생략하고~(다들 아시겠죠?)
위 사진처럼 프로필→Credentials→Stores from parent의 global 도메인을 클릭한 뒤
New credentials 버턴을 누르고, 위 사진처럼 입력해서 깃허브/도커 이렇게 2개를 만들어 준다.
Username은 내 실제 깃허브/도커 아이디이고, ID는 여기서 구분할 아이디이다.
본인은 ID를 github-token, dockerhub-token 이렇게 했다.
젠킨스파일 만들기
각 서비스별로 젠킨스파일을 만들어 준다. 젠킨스파일은 이왕이면 소스코드 루트(최상위)에 위치해 있는 것이 좋다.
이 젠킨스 파일은 실제로 깃허브에서 소스 코드를 가져와 독커 이미지를 만드는 프로세스이다.
아래는 예시 파일~
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#!/usr/bin/env groovy
def APP_NAME
def APP_VERSION
def DOCKER_IMAGE_NAME
def PROD_BUILD = false
def TAG_BUILD = false
pipeline {
agent {
node {
label 'master'
}
}
parameters {
gitParameter branch: '',
branchFilter: '.*',
defaultValue: 'origin/(메인브랜취 이름)',
description: '', listSize: '0',
name: 'TAG',
quickFilterEnabled: false,
selectedValue: 'DEFAULT',
sortMode: 'DESCENDING_SMART',
tagFilter: '*',
type: 'PT_BRANCH_TAG'
booleanParam defaultValue: false, description: '', name: 'RELEASE'
}
environment {
GIT_URL = "(서비스 깃허브 주소)"
GITHUB_CREDENTIAL = "github-token"
ARTIFACTS = "build/libs/**"
DOCKER_REGISTRY = "(내 이름)"
DOCKERHUB_CREDENTIAL = 'dockerhub-token'
}
options {
disableConcurrentBuilds()
buildDiscarder(logRotator(numToKeepStr: "30", artifactNumToKeepStr: "30"))
timeout(time: 120, unit: 'MINUTES')
}
tools {
gradle 'Gradle 8.14.2'
jdk 'OpenJDK 17'
dockerTool 'Docker'
}
stages {
stage('Set Version') {
steps {
script {
APP_NAME = sh (
script: "gradle -q getAppName",
returnStdout: true
).trim()
APP_VERSION = sh (
script: "gradle -q getAppVersion",
returnStdout: true
).trim()
DOCKER_IMAGE_NAME = "${DOCKER_REGISTRY}/${APP_NAME}:${APP_VERSION}"
sh "echo IMAGE_NAME is ${APP_NAME}"
sh "echo IMAGE_VERSION is ${APP_VERSION}"
sh "echo DOCKER_IMAGE_NAME is ${DOCKER_IMAGE_NAME}"
sh "echo TAG is ${params.TAG}"
if( params.TAG.startsWith('origin') == false && params.TAG.endsWith('/master') == false ) {
if( params.RELEASE == true ) {
DOCKER_IMAGE_NAME += '-RELEASE'
PROD_BUILD = true
} else {
DOCKER_IMAGE_NAME += '-TAG'
TAG_BUILD = true
}
}
}
}
}
stage('Build & Test Application') {
steps {
sh "gradle clean build"
}
}
stage('Build Docker Image') {
// when {
// expression { PROD_BUILD == true || TAG_BUILD == true }
// }
steps {
script {
docker.build "${DOCKER_IMAGE_NAME}"
}
}
}
stage('Push Docker Image') {
// when {
// expression { PROD_BUILD == true || TAG_BUILD == true }
// }
steps {
script {
docker.withRegistry("", DOCKERHUB_CREDENTIAL) {
docker.image("${DOCKER_IMAGE_NAME}").push()
}
sh "docker rmi ${DOCKER_IMAGE_NAME}"
}
}
}
}
}
보면 알겠지만, environment 측의
1
2
3
4
5
6
7
environment {
GIT_URL = "(서비스 깃허브 주소)"
GITHUB_CREDENTIAL = "github-token"
ARTIFACTS = "build/libs/**"
DOCKER_REGISTRY = "(내 이름)"
DOCKERHUB_CREDENTIAL = 'dockerhub-token'
}
여기가 중요한데,
GITHUB_CREDENTIAL와 DOCKERHUB_CREDENTIAL에 아까 만들었던
credentials ID를 입력해주는 것이다.
tools 측도
1
2
3
4
5
tools {
gradle 'Gradle 8.14.2'
jdk 'OpenJDK 17'
dockerTool 'Docker'
}
아까 설정의 Tools에서 입력한 버젼 그대로 입력해주면 된다.
폴더, 파이프라인 만들기
우선 프로젝트 빌드를 모아 줄 폴더가 필요하다.
왼쪽의 New Item을 클릭해서 Select an item type에 Folder를 선택하고 확인을 누른다. 이후 나오는 config는 폴더니까 패쓰
이제 폴더에 들어가서 다시 New Item을 클릭하고 Pipeline을 선택해서 확인을 누른다.
여기도 마찬가지로 설정페이지가 나오는데, 여기는 설정 해줘야 한다.
pipeline 항목이 중요한데,
- Definition에 Pipeline script from SCM을 선택하고,
- SCM에 Git을 선택하고,
- Repository URL에 서비스 깃허브 레포주소를 입력하고,
- Credentials에 내 깃허브 아이디로 되어 있는 것을 선택하고,
- Branch specifier에 내 마스터 브랜취 이름을 입력하면 된다.
이러면 젠킨스가 알아서 마스터 브랜취를 선택하여 빌드한다.
추가로 브랜취를 선택하고 싶으면, 이 빌드는 매개변수가 있습니다를 선택하여
- Parameter Type에 Branch or Tag
- Default Value에 origin/master 또는 main을 입력해 주면 된다.
이 매개변수 이름 TAG는 Jenkinsfile의
1
2
3
4
5
6
7
8
9
10
11
12
13
14
parameters {
gitParameter branch: '',
branchFilter: '.*',
defaultValue: 'origin/(메인브랜취 이름)',
description: '', listSize: '0',
name: 'TAG',
quickFilterEnabled: false,
selectedValue: 'DEFAULT',
sortMode: 'DESCENDING_SMART',
tagFilter: '*',
type: 'PT_BRANCH_TAG'
booleanParam defaultValue: false, description: '', name: 'RELEASE'
}
여기 parameter 부문에 위치해 있어 연계되는 것을 확인할 수 있다.
빌드
설정을 끝내고 왼쪽의 파라메타와 함께 빌드를 클릭한 뒤
TAG를 선택하고 빌드를 하면 된다!
이렇게 파이프라인 메인 페이지에 빌드 현황을 확인할 수 있다!!
빌드가 성공적으로 끝나면, docker hub에서 올라간 이미지를 확인할 수 있다..
끝마치며
다음 시간에는 이렇게 빌드한 이미지를 가지고 쿠버네티스에 올리는 방법을 알아보겠다!