MSA Deploy (3) - CI/CD & Harbor, Jenkins
5. CI/CD 환경
virtualbox에 vagrant로 프로비저닝한 환경에 harbor와 jenkins를 구성하기엔 리소스가 모자랄 것으로 예상해 로컬 PC 기반 CI/CD + k8s 배포 파이프라인 구축
1
2
3
4
5
6
7
8
9
[개발 코드]
↓
[Jenkins (빌드)]
↓
[Docker 이미지 생성]
↓
[Harbor (이미지 저장소)]
↓
[Kubernetes (이미지 pull → 배포)]
5-1. 작업 순서
- Harbor 구축 (이미지 저장소)
- Docker Registry 역할
- k8s가 여기서 이미지 pull
- Jenkins 구축 (CI/CD 서버)
- 코드 빌드
- Docker 이미지 생성
- Harbor로 push
- Docker ↔ Harbor 연결
- docker login
- 이미지 push 테스트
- Kubernetes ↔ Harbor 연결
- imagePullSecret 설정
- Pod에서 Harbor 이미지 pull 가능하게
- Jenkins Pipeline 구성 (Jenkinsfile)
- git pull
- build
- docker build
- docker push
- kubectl apply
5-2. harbor
5-2-1. 설치
harbor는 nginx(gateway), harbor-core(API), harbor-db(postgres), redis, registry로 구성된 마이크로 서비스 구조
여러 컨테이너를 묶어서 실행하기 위해 docker compose로 설치
1
wsl --install -d Ubuntu
Docker Desktop WSL integration 기능이 Ubuntu를 Docker CLI를 사용 가능한 상태로 연결해 Ubuntu WSL에서 작업한 내용이 docker-desktop에 전달됨
1
2
3
4
5
6
7
[Ubuntu WSL] ← 작업하는 환경
↓
[docker CLI]
↓
[docker-desktop WSL (Docker Engine)]
↓
[컨테이너 실행]
docker-desktop WLS 특징
- 도커를 돌리기 위한 내부 OS
- 실제 Docker 서버(엔진)
- Docker 엔진 전용 내부 환경
- 최소 구성 (busybox 수준)
- 패키지 설치 거의 불가
- sudo, apt, systemctl 없음
- Harbor 같은 복잡한 서비스 설치 불가
Ubuntu WSL이 필요한 이유
- 실제 서버처럼 사용하는 리눅스
- 완전한 리눅스 환경
- apt 사용 가능
- sudo 가능
- 패키지 설치 가능
- Harbor / Jenkins 설치 가능
Ubuntu WSL 초기설정
wsl.exe -d Ubuntu
1
2
3
4
5
6
7
8
9
# harbor 다운로드
wget https://github.com/goharbor/harbor/releases/download/v2.15.0/harbor-online-installer-v2.15.0.tgz
# 압축 해제
tar xzvf harbor-online-installer-v2.15.0.tgz
# 설정 파일 생성
cd harbor
cp harbor.yml.tmpl harbor.yml
마스터, 워커 노드에서 접근할 수 있도록 harbor.yml에서 hostname을 수정하고 https를 비활성화
1
2
3
4
5
6
7
8
vim harbor.yml
hostname: localhost
...
# https:
# port: 443
# certificate: /your/cert/path
# private_key: /your/key/path
설치 후 harbor 위치 이동
1
mv /mnt/c/harbor ~/
설치 성공 확인
1
2
3
4
5
6
7
8
9
10
11
gram@DESKTOP-TQV062L:~/harbor$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
11379e03240b goharbor/harbor-jobservice:v2.15.0 "/harbor/entrypoint.…" 15 seconds ago Up 9 seconds (health: starting) harbor-jobservice
b2111739189c goharbor/nginx-photon:v2.15.0 "nginx -g 'daemon of…" 15 seconds ago Up 12 seconds (health: starting) 0.0.0.0:80->8080/tcp nginx
09257b053a54 goharbor/harbor-core:v2.15.0 "/harbor/entrypoint.…" 15 seconds ago Up 13 seconds (health: starting) harbor-core
b8a8112c071a goharbor/harbor-registryctl:v2.15.0 "/home/harbor/start.…" 15 seconds ago Up 13 seconds (health: starting) registryctl
82c7b42d56bd goharbor/registry-photon:v2.15.0 "/home/harbor/entryp…" 15 seconds ago Up 13 seconds (health: starting) registry
a8a3a86ebcab goharbor/harbor-portal:v2.15.0 "nginx -g 'daemon of…" 15 seconds ago Up 13 seconds (health: starting) harbor-portal
00a9c89521b9 goharbor/redis-photon:v2.15.0 "redis-server /etc/r…" 15 seconds ago Up 13 seconds (health: starting) redis
f048b958637b goharbor/harbor-db:v2.15.0 "/docker-entrypoint.…" 15 seconds ago Up 13 seconds (health: starting) harbor-db
1c504cd1c846 goharbor/harbor-log:v2.15.0 "/bin/sh -c /usr/loc…" 15 seconds ago Up 14 seconds (health: starting) 127.0.0.1:1514->10514/tcp harbor-log
로컬PC에서 harbor 접속 확인

harbor 접속
Harbor 설치 환경
- Windows + WSL2(Ubuntu)
- Docker Desktop
- Harbor v2.15.0
- Kubernetes v1.18.4
- Docker runtime 18.09.9
5-2-2. Member 서비스 이미지 Push/Pull
MSA 환경에서 Docker 이미지를 중앙 저장소로 관리하기 위해 Harbor를 구축하고,
Vagrant 기반 Kubernetes Cluster에서 Harbor 이미지를 Pull 하도록 구성했다.
구성 환경은 아래와 같다.
1
2
3
4
5
6
7
8
9
[ Windows PC ]
└─ Docker Desktop
└─ Harbor (192.168.56.1:8080)
[ Vagrant Kubernetes Cluster ]
├─ m-k8s
├─ w1-k8s
├─ w2-k8s
└─ w3-k8s
- Harbor API 확인
1 2 3
curl http://192.168.56.1:8080/api/v2.0/ping # 정상 응답: Pong - Harbor UI에 접속해 프로젝트 생성

프로젝트 생성
- Docker insecure registry 설정
Harbor를 HTTP로 구성했기 때문에 Docker에서 insecure registry 설정이 필요하다. 적용 후 Docker Desktop을 재시작 해야한다.

http 설정

docker 설정
- Docker 이미지 Push
- 로컬에서 member-service 이미지 확인

docker 이미지
- Harbor 용 태그 생성
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
PS C:\WINDOWS\system32> docker tag member-service:latest 192.168.56.1:8080/deploy-test-member/member-service:latest PS C:\WINDOWS\system32> docker images REPOSITORY TAG IMAGE ID CREATED SIZE product-service latest 0004eb27476e 3 weeks ago 433MB ordering-service latest 46f21531d0c3 3 weeks ago 434MB 192.168.56.1:8080/deploy-test-member/member-service latest fcaee27bcf5f 4 weeks ago 421MB member-service latest fcaee27bcf5f 4 weeks ago 421MB goharbor/redis-photon v2.15.0 4ed296911e8b 7 weeks ago 173MB goharbor/harbor-registryctl v2.15.0 4b2b3294a46c 7 weeks ago 166MB goharbor/registry-photon v2.15.0 5b02673a2fa2 7 weeks ago 87.7MB goharbor/harbor-log v2.15.0 9e71d0bc1e73 7 weeks ago 170MB goharbor/harbor-jobservice v2.15.0 2fe35692621f 7 weeks ago 185MB goharbor/harbor-core v2.15.0 87a862e24da8 7 weeks ago 210MB goharbor/harbor-portal v2.15.0 b3939ccdd07f 7 weeks ago 166MB goharbor/harbor-db v2.15.0 e66097841983 7 weeks ago 274MB goharbor/prepare v2.15.0 029f75920a4b 7 weeks ago 199MB goharbor/nginx-photon v2.15.0 77728976f2e8 7 weeks ago 158MB redis 7.4 65750d044ac8 16 months ago 117MB apache/kafka 3.8.0 b610bd8a193a 21 months ago 382MB mysql 8.0.38 6c54cbcf775a 22 months ago 572MB
- Harbor push
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
PS C:\WINDOWS\system32> docker login 192.168.56.1:8080 Username: admin i Info → A Personal Access Token (PAT) can be used instead. To create a PAT, visit https://app.docker.com/settings Password: Login Succeeded PS C:\WINDOWS\system32> docker push 192.168.56.1:8080/deploy-test-member/member-service:latest The push refers to repository [192.168.56.1:8080/deploy-test-member/member-service] d06ca5ee8d0b: Layer already exists d24210e52761: Layer already exists f7409d4c66cc: Layer already exists 08e98c779fb9: Layer already exists 0a828e8088fe: Layer already exists 344ae0b6479e: Layer already exists 989e799e6349: Layer already exists latest: digest: sha256:cf421bb1ce160dc0b08b5f24118c47e3e565b05dc22facb1c57b1471276c7b48 size: 1786
- 이미지 push 확인

docker 이미지
- Deployment에서 이미지 Pull
member 서비스의 Deployment, Service를 Harbor에서 이미지를 pull 하도록 아래와 같이 수정
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
# depl_svc.yaml apiVersion: apps/v1 kind: Deployment metadata: name: member-depl namespace: deploy-test spec: replicas: 1 selector: matchLabels: app: member template: metadata: labels: app: member spec: imagePullSecrets: - name: harbor-secret containers: - name: member-container image: 192.168.56.1:8080/deploy-test-member/member-service:latest imagePullPolicy: Always ports: - containerPort: 8080 resources: limits: cpu: "250m" memory: "500Mi" requests: cpu: "100m" memory: "250Mi" env: - name: DB_HOST value: "mysql-master-0.mysql-master.deploy-test-data.svc.cluster.local" - name: DB_PW value: "rootpass" readinessProbe: httpGet: path: /health port: 8080 initialDelaySeconds: 10 periodSeconds: 10 --- apiVersion: v1 kind: Service metadata: name: member-service namespace: deploy-test spec: type: ClusterIP ports: - port: 80 targetPort: 8080 selector: app: member
kubectl apply -f depl_svc.yaml로 적용 후 pod 배포 확인
이미지 Pull
5-2-3. ordering, product 서비스 이미지 Push/Pull
- ordering 서비스
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
PS C:\WINDOWS\system32> docker login 192.168.56.1:8080 Authenticating with existing credentials... [Username: admin] i Info → To login with a different account, run 'docker logout' followed by 'docker login' Login Succeeded PS C:\WINDOWS\system32> docker tag ordering-service:latest 192.168.56.1:8080/deploy-test-ordering/ordering-service:latest PS C:\WINDOWS\system32> docker push 192.168.56.1:8080/deploy-test-ordering/ordering-service:latest The push refers to repository [192.168.56.1:8080/deploy-test-ordering/ordering-service] 7fa3ab0f89c0: Pushed d24210e52761: Mounted from deploy-test-member/member-service f7409d4c66cc: Mounted from deploy-test-member/member-service 08e98c779fb9: Mounted from deploy-test-member/member-service 0a828e8088fe: Mounted from deploy-test-member/member-service 344ae0b6479e: Mounted from deploy-test-member/member-service 989e799e6349: Mounted from deploy-test-member/member-service latest: digest: sha256:7ce6d68cb67b39f8767632e569074d4161ddfcdb87b07eee59cbd4de1ba3366f size: 1786
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
# depl_svc.yaml apiVersion: apps/v1 kind: Deployment metadata: name: ordering-depl namespace: deploy-test spec: replicas: 1 selector: matchLabels: app: ordering template: metadata: labels: app: ordering spec: imagePullSecrets: - name: harbor-secret containers: - name: ordering-container image: 192.168.56.1:8080/deploy-test-ordering/ordering-service:latest imagePullPolicy: Always ports: - containerPort: 8080 resources: limits: cpu: "250m" memory: "500Mi" requests: cpu: "100m" memory: "250Mi" env: - name: DB_HOST value: "mysql-master-0.mysql-master.deploy-test-data.svc.cluster.local" - name: DB_PW value: "rootpass" readinessProbe: httpGet: path: /health port: 8080 initialDelaySeconds: 10 periodSeconds: 10 --- apiVersion: v1 kind: Service metadata: name: ordering-service namespace: deploy-test spec: type: ClusterIP ports: - port: 80 targetPort: 8080 selector: app: ordering
- product 서비스
1 2 3 4 5 6 7 8 9 10 11
PS C:\WINDOWS\system32> docker tag product-service:latest 192.168.56.1:8080/deploy-test-product/product-service:latest PS C:\WINDOWS\system32> docker push 192.168.56.1:8080/deploy-test-product/product-service:latest The push refers to repository [192.168.56.1:8080/deploy-test-product/product-service] b67528f7fc65: Pushed d24210e52761: Pushed f7409d4c66cc: Pushed 08e98c779fb9: Pushed 0a828e8088fe: Pushed 344ae0b6479e: Pushed 989e799e6349: Pushed latest: digest: sha256:9f8260d717ed01dd380bebe4d5e78b34ff0bb023c0aabb0a30c8754d8738cc60 size: 1786
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
# depl_svc.yaml apiVersion: apps/v1 kind: Deployment metadata: name: product-depl namespace: deploy-test spec: replicas: 1 selector: matchLabels: app: product template: metadata: labels: app: product spec: imagePullSecrets: - name: harbor-secret containers: - name: product-container image: 192.168.56.1:8080/deploy-test-product/product-service:latest imagePullPolicy: Always ports: - containerPort: 8080 resources: limits: cpu: "250m" memory: "500Mi" requests: cpu: "100m" memory: "250Mi" env: - name: DB_HOST value: "mysql-master-0.mysql-master.deploy-test-data.svc.cluster.local" - name: DB_PW value: "rootpass" readinessProbe: httpGet: path: /health port: 8080 initialDelaySeconds: 10 periodSeconds: 10 --- apiVersion: v1 kind: Service metadata: name: product-service namespace: deploy-test spec: type: ClusterIP ports: - port: 80 targetPort: 8080 selector: app: product
kubectl apply -f depl_svc.yaml로 적용 후 pod 배포 확인
이미지 Pull
5-3. jenkins
Harbor에 Jenkins를 추가해 CI/CD 환경을 구축한다.
1
2
3
4
5
Git Push
→ Jenkins Build
→ Docker Image Build
→ Harbor Push
→ Kubernetes Deployment
flowchart LR
A[Git Repository]
--> B[Jenkins]
B --> C[Gradle Build]
C --> D[Docker Build]
D --> E[Harbor Push]
E --> F[Kubernetes Pull]
F --> G[Deployment]
구성 환경은 아래와 같다.
1
2
3
4
5
6
7
8
9
10
11
12
[ Windows PC ]
├─ Docker Desktop
│ ├─ Harbor(:8080)
│ └─ Jenkins(:8081)
│
└─ WSL2 Ubuntu
[ Vagrant Kubernetes Cluster ]
├─ m-k8s
├─ w1-k8s
├─ w2-k8s
└─ w3-k8s
5-3-1. Jenkins 설치
- Jenkins Docker 실행
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
PS C:\WINDOWS\system32> docker run -d --name jenkins -p 8081:8080 -p 50000:50000 -v jenkins_home:/var/jenkins_home -v //var/run/docker.sock:/var/run/docker.sock jenkins/jenkins:lts Unable to find image 'jenkins/jenkins:lts' locally lts: Pulling from jenkins/jenkins a7730063fcfe: Pull complete beb35d8d9493: Pull complete a576649e9376: Pull complete 32ad68c1bba8: Pull complete 6e001067f512: Pull complete f015f18f3c7a: Pull complete 0454b3406328: Pull complete 6e428cebe944: Pull complete 1aac2fe67fcc: Pull complete b850d1c40542: Pull complete 32ebd389acde: Pull complete e714309bcf67: Pull complete Digest: sha256:7004d07dbcdc5439fdad8853acdb029c5e3ab7a3d8190184fbf89bec66786c02 Status: Downloaded newer image for jenkins/jenkins:lts aba5d2c3669bd8d6864452056d008a10e0e484ba8aae63adae4dc5cd7a0379cb PS C:\WINDOWS\system32> docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES aba5d2c3669b jenkins/jenkins:lts "/usr/bin/tini -- /u…" 33 seconds ago Up 33 seconds 0.0.0.0:50000->50000/tcp, 0.0.0.0:8081->8080/tcp jenkins 69f2b3db8863 goharbor/nginx-photon:v2.15.0 "nginx -g 'daemon of…" 19 hours ago Up 19 hours (healthy) 0.0.0.0:8080->8080/tcp nginx 7f2521b15b61 goharbor/harbor-jobservice:v2.15.0 "/harbor/entrypoint.…" 19 hours ago Up 19 hours (healthy) harbor-jobservice 98fd6931f30e goharbor/harbor-core:v2.15.0 "/harbor/entrypoint.…" 19 hours ago Up 19 hours (healthy) harbor-core 91f563ca1cdc goharbor/harbor-registryctl:v2.15.0 "/home/harbor/start.…" 19 hours ago Up 19 hours (healthy) registryctl 52c2e44c992d goharbor/harbor-portal:v2.15.0 "nginx -g 'daemon of…" 19 hours ago Up 19 hours (healthy) harbor-portal cea0f2cba842 goharbor/harbor-db:v2.15.0 "/docker-entrypoint.…" 19 hours ago Up 19 hours (healthy) harbor-db 334279cfc2fa goharbor/registry-photon:v2.15.0 "/home/harbor/entryp…" 19 hours ago Up 19 hours (healthy) registry d42af998eddd goharbor/redis-photon:v2.15.0 "redis-server /etc/r…" 19 hours ago Up 19 hours (healthy) redis 58db501b6900 goharbor/harbor-log:v2.15.0 "/bin/sh -c /usr/loc…" 19 hours ago Up 19 hours (healthy) 127.0.0.1:1514->10514/tcp harbor-log
- Jenkins 초기 비밀번호 확인, 브라우저 접속
1 2 3 4 5 6
PS C:\WINDOWS\system32> docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassworddocker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword cat: /var/jenkins_home/secrets/initialAdminPassworddocker: No such file or directory cat: exec: No such file or directory cat: jenkins: No such file or directory cat: cat: No such file or directory cf0980bdaca649828a67d6f4dcfabfbd

Jenkins 접속
- Jenkins 내부 Docker 설치
Jenkins에서 Docker 사용이 가능한지 확인한다.
1 2 3
gram@DESKTOP-TQV062L:~/harbor$ docker exec -it -u root jenkins bash root@aba5d2c3669b:/# docker version bash: docker: command not found
Jenkins container 안에 Docker CLI가 없어 기존 Jenkins를 삭제하고 jenkins + docker cli 커스텀 이미지를 만들어서 설치한다.
1 2 3 4
PS C:\WINDOWS\system32> docker stop jenkins jenkins PS C:\WINDOWS\system32> docker rm jenkins jenkins
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
gram@DESKTOP-TQV062L:~/harbor$ mkdir ~/jenkins-docker gram@DESKTOP-TQV062L:~/harbor$ cd ~/jenkins-docker/ gram@DESKTOP-TQV062L:~/jenkins-docker$ vim Dockerfile gram@DESKTOP-TQV062L:~/jenkins-docker$ docker build -t my-jenkins . [+] Building 17.3s (6/6) FINISHED docker:default => [internal] load build definition from Dockerfile 0.1s => => transferring dockerfile: 139B 0.0s => [internal] load metadata for docker.io/jenkins/jenkins:lts 0.0s => [internal] load .dockerignore 0.0s => => transferring context: 2B 0.0s => [1/2] FROM docker.io/jenkins/jenkins:lts 0.2s => [2/2] RUN apt-get update && apt-get install -y docker.io 16.2s => exporting to image 0.7s => => exporting layers 0.7s => => writing image sha256:2982b24efd31963c44816a3726c565131471a6b57118c08838fccc8e6329d07a 0.0s => => naming to docker.io/library/my-jenkins 0.0s gram@DESKTOP-TQV062L:~/jenkins-docker$ # Dockerfile FROM jenkins/jenkins:lts USER root RUN apt-get update && apt-get install -y docker.io USER jenkins
새 jenkins를 실행한다.
1 2
PS C:\WINDOWS\system32> docker run -d --name jenkins -p 8081:8080 -p 50000:50000 -v jenkins_home:/var/jenkins_home -v //var/run/docker.sock:/var/run/docker.sock my-jenkins 0fadb941d9dc79bc4f43aebac1d0d0d681a4f83f215bc447346a38afd65a6cf0
Jenkins에서 Docker가 정상적으로 실행된 것을 확인한다.
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
gram@DESKTOP-TQV062L:~/jenkins-docker$ docker exec -it -u root jenkins bash root@0fadb941d9dc:/# docker version Client: Version: 26.1.5+dfsg1 API version: 1.45 Go version: go1.24.4 Git commit: a72d7cd Built: Sun Mar 8 15:28:39 2026 OS/Arch: linux/amd64 Context: default Server: Docker Desktop 4.40.0 (187762) Engine: Version: 28.0.4 API version: 1.48 (minimum version 1.24) Go version: go1.23.7 Git commit: 6430e49 Built: Tue Mar 25 15:07:22 2025 OS/Arch: linux/amd64 Experimental: false containerd: Version: 1.7.26 GitCommit: 753481ec61c7c8955a23d6ff7bc8e4daed455734 runc: Version: 1.2.5 GitCommit: v1.2.5-0-g59923ef docker-init: Version: 0.19.0 GitCommit: de40ad0
- Harbor 테스트
Jenkins Container 안에서 Harbor 접속 테스트를 한다.
1 2 3 4 5 6 7 8 9 10
# docker exec -it -u root jenkins bash 로 Jenkins Container 접속 root@0fadb941d9dc:/# docker login 192.168.56.1:8080 Username: admin Password: WARNING! Your password will be stored unencrypted in /root/.docker/config.json. Configure a credential helper to remove this warning. See https://docs.docker.com/engine/reference/commandline/login/#credentials-store Login Succeeded
5-3-2. Github 연동
- Github SSH 연동
Jenkins에서 Git Clone을 하기 위해 Github SSH Key를 생성하고 Github Public key에 등록한다.
그리고 Jenkins 브라우저에서 Github SSH Key로 Credential 설정을 한다.1 2 3 4 5
# Jenkins 전용 SSH Key 생성 ssh-keygen -t ed25519 -C "jenkins" # 저장 위치 ~/.ssh/jenkins_key # 주의 사항: CI/CD 자동화를 위해 Passphrase 없이 생성함
- Gihub Clone 테스트
Freestype Project 생성 후 Git Clone 테스트를 수행한다.
Repository는https://github.com/5-SH/deploy-test-member.git로 설정함.
Jenkins 접속
5-3-3. Jenkins Pipeline 생성
Jenkins Pipeline을 사용해 Spring Boot 애플리케이션을 자동 빌드하고 Harbor Registry에 이미지를 Push한 뒤 Kubernetes에 자동 배포한다.
- Jenkins Pipeline 구성
1 2 3 4 5 6 7 8 9 10 11
Git Clone ↓ Gradle Build ↓ Docker Image Build ↓ Harbor Login ↓ Harbor Registry Push ↓ Kubernetes Deployment
- Jenkinsfile 구성
Harbor(192.168.56.1:8080)에서 이미지를 Pull 하고
k8s/depl_svc.yml을 사용해 k8s에 배포한다.
rollout restart명령으로 변경사항에 관계 없이 k8s에서 서비스를 재배포 한다.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
pipeline { agent any environment { IMAGE_NAME = "192.168.56.1:8080/deploy-test-member/member-service" IMAGE_TAG = "latest" } stages { stage('Git Clone') { steps { git branch: 'main', credentialsId: 'github-ssh', url: 'https://github.com/5-SH/deploy-test-member.git' } } stage('Gradle Build') { steps { sh ''' chmod +x gradlew ./gradlew clean build ''' } } stage('Docker Build') { steps { sh ''' docker build -t $IMAGE_NAME:$IMAGE_TAG . ''' } } stage('Harbor Login') { steps { withCredentials([ usernamePassword( credentialsId: 'harbor-account', usernameVariable: 'HARBOR_USER', passwordVariable: 'HARBOR_PASS' ) ]) { sh ''' docker login 192.168.56.1:8080 \ -u $HARBOR_USER \ -p $HARBOR_PASS ''' } } } stage('Harbor Push') { steps { sh ''' docker push $IMAGE_NAME:$IMAGE_TAG ''' } } stage('Kubernetes Deploy') { steps { withCredentials([ file( credentialsId: 'kubeconfig', variable: 'KUBECONFIG' ) ]) { sh ''' kubectl apply -f k8s/depl_svc.yml kubectl rollout restart deployment/member-depl -n deploy-test ''' } } } } }
- Jenkins Docker 이미지 커스터마이징
초기 Jenkins Container에 Docker CLI, kubectl, OpenJDK 17이 없어 빌드와 배포에 실패를 했다.
Jenkins Dockerfile을 아래와 같이 커스터마이징 해 도구들을 추가했다.
그리고 kubectl 설치, docker.sock 접근 권한, docker 명령 실행 실패로 root 유저를 사용했다.1 2 3 4 5 6 7 8 9
# Dockerfile FROM jenkins/jenkins:lts-jdk17 USER root RUN apt-get update && apt-get install -y docker.io curl RUN curl -LO "https://dl.k8s.io/release/v1.28.15/bin/linux/amd64/kubectl" && install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl && rm -f kubectl
Jenkins의 실행과 종료는 아래 명령어를 사용한다.
1 2 3 4 5
docker stop jenkins docker rm jenkins docker run -d --name jenkins -u root -p 8081:8080 -p 50000:50000 -v jenkins_home:/var/jenkins_home -v /var/run/docker.sock:/var/run/docker.sock my-jenkins
5-4. 최종 CI/CD 흐름
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Git Push
↓
Jenkins Trigger
↓
Gradle Build
↓
Docker Build
↓
Harbor Push
↓
kubectl Apply
↓
Kubernetes Rolling Update
↓
신규 Pod 생성
↓
서비스 반영

member 서비스 CI/CD 성공
5-5. ordering, product 서비스 CI/CD
- ordering 서비스
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
pipeline { agent any environment { IMAGE_NAME = "192.168.56.1:8080/deploy-test-ordering/ordering-service" IMAGE_TAG = "latest" } stages { stage('Git Clone') { steps { git branch: 'main', credentialsId: 'github-ssh', url: 'https://github.com/5-SH/deploy-test-ordering.git' } } stage('Gradle Build') { steps { sh ''' chmod +x gradlew ./gradlew clean build ''' } } stage('Docker Build') { steps { sh ''' docker build -t $IMAGE_NAME:$IMAGE_TAG . ''' } } stage('Harbor Login') { steps { withCredentials([ usernamePassword( credentialsId: 'harbor-account', usernameVariable: 'HARBOR_USER', passwordVariable: 'HARBOR_PASS' ) ]) { sh ''' docker login 192.168.56.1:8080 \ -u $HARBOR_USER \ -p $HARBOR_PASS ''' } } } stage('Harbor Push') { steps { sh ''' docker push $IMAGE_NAME:$IMAGE_TAG ''' } } stage('Kubernetes Deploy') { steps { withCredentials([ file( credentialsId: 'kubeconfig', variable: 'KUBECONFIG' ) ]) { sh ''' kubectl apply -f k8s/depl_svc.yml kubectl rollout restart deployment/ordering-depl -n deploy-test ''' } } } } }

ordering 서비스 CI/CD 성공
- product 서비스
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
pipeline { agent any environment { IMAGE_NAME = "192.168.56.1:8080/deploy-test-product/product-service" IMAGE_TAG = "latest" } stages { stage('Git Clone') { steps { git branch: 'main', credentialsId: 'github-ssh', url: 'https://github.com/5-SH/deploy-test-product.git' } } stage('Gradle Build') { steps { sh ''' chmod +x gradlew ./gradlew clean build ''' } } stage('Docker Build') { steps { sh ''' docker build -t $IMAGE_NAME:$IMAGE_TAG . ''' } } stage('Harbor Login') { steps { withCredentials([ usernamePassword( credentialsId: 'harbor-account', usernameVariable: 'HARBOR_USER', passwordVariable: 'HARBOR_PASS' ) ]) { sh ''' docker login 192.168.56.1:8080 \ -u $HARBOR_USER \ -p $HARBOR_PASS ''' } } } stage('Harbor Push') { steps { sh ''' docker push $IMAGE_NAME:$IMAGE_TAG ''' } } stage('Kubernetes Deploy') { steps { withCredentials([ file( credentialsId: 'kubeconfig', variable: 'KUBECONFIG' ) ]) { sh ''' kubectl apply -f k8s/depl_svc.yml kubectl rollout restart deployment/product-depl -n deploy-test ''' } } } } }

product 서비스 CI/CD 성공