Kubernetes Cluster 에 Jenkins 설치하기(Deployment, Local Persistent Volume)
목차
- Virtual Box 에 Ubuntu 20.04 LTS 설치하기
- VirtualBox VM 에 고정 IP 설정하기(IPTIME 공유기의 DHCP 설정 기반)
- VirtualBox VM 외부에서 접속하기(IPTIME 공유기의 DDNS, Port-Fowarding 설정 기반)
- Virtualbox VM(Ubuntu 20.04 LTS)에 Kubernetes cluster 설치하기
- Raspberry pi 4B 에 Ubuntu 20.04 LTS 설치하기
- Raspberry pi 4B 에 Kubernetes Cluster 설치하기
- Kubernetes Cluster 에 MySQL 설치하기(Deployment, Local Persistent Volume)
- Scrapy 기반 Daum News Crawler 구현하기
- Kubernetes Cluster 에 Docker Private Registry 설치하기(TLS, Self Signed Certificate)
- Kubernetes Cluster 에 Web Crawler 배포하기(CronJob)
서버 소프트웨어를 개발 후 배포하는 방법은 여러가지가 있습니다. 단순히 로컬에서 빌드 후 결과파일을 직접 서버에 copy 하는 방법에서 시작해서 CI/CD 기반의 툴(Jenkins, CircleCI 등)을 활용해 그 과정을 자동화하는 방법까지 다양합니다. 이번 글에서는 많이 쓰이는 CI/CD 툴인 Jenkins 를 Kubernetes Cluster 상에 설치하는 과정을 진행해보겠습니다.
Helm 차트를 활용해 좀 더 손쉽게 Jenkins 를 Kubernetes Cluster 상에 설치하는 방법도 있으나, Kubernetes 에 익숙해지는 과정에 있는 만큼, kubectl 과 yaml 파일 기반으로 직접 설치해 보도록 하겠습니다.
- Jenkins Docker Image 생성
Raspberry pi 는 arm 기반 아키텍쳐인데 공식적인 jenkins docker image 는 아직 arm 을 지원하지 않는 듯 합니다. 따라서 이미지를 직접 만들도록 하겠습니다. 먼저 Dockerfile 을 작성합니다.
FROM ubuntu:20.04
RUN apt-get update && apt-get install -y \
gnupg \
wget \
&& rm -rf /var/lib/apt/lists/*
RUN wget -q -O - https://pkg.jenkins.io/debian-stable/jenkins.io.key | apt-key add - \
&& sh -c 'echo deb https://pkg.jenkins.io/debian-stable binary/ > /etc/apt/sources.list.d/jenkins.list'
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y \
jenkins \
openjdk-8-jdk \
&& rm -rf /var/lib/apt/lists/*
ENTRYPOINT service jenkins start && tail -f /var/log/jenkins/jenkins.log
ubuntu 20.04 LTS 를 기반으로 jenkins 를 설치하는 간단한 내용입니다.
$ sudo docker build -t truelifer-registry.com:8090/jenkins_for_raspberry_pi_4:$(git log -1 --format=%h) .
$ sudo docker build -t truelifer-registry.com:8090/jenkins_for_raspberry_pi_4:latest .
위에서 작성한 Dockerfile 을 가지고 Image 를 빌드합니다. 태그는 최신 git commit 의 축약된 hash 값 및 latest 로 지정해줍니다.
$ sudo docker push truelifer-registry.com:8090/jenkins_for_raspberry_pi_4:$(git log -1 — format=%h)
sudo docker push truelifer-registry.com:8090/jenkins_for_raspberry_pi_4:latest
위에서 build 한 최신버전의 image 를 Registry 에 push해줍니다.
$ sudo docker build -t truelifer-registry.com:8090/daum_news_crawler:$(git log -1 --format=%h) .$ sudo docker build -t truelifer-registry.com:8090/daum_news_crawler:latest .
- Namespace 생성
$ kubectl create namespace jenkins
먼저 jenkins 를 위한 별도의 namespace 를 생성해줍니다.
namespace/jenkins created
정상적으로 생성이 되었다면 위와 같은 메세지가 출력됩니다.
- StorageClass 생성
이전 글에서 이미 만들어 놓은 StorageClass 를 사용합니다.
- Persistent Volume 생성
$ sudo mkdir -p /workspace/data/kubernetes/pv/jenkins
$ sudo chmod 777 /workspace/data/kubernetes/pv/jenkins
우선 worker1, worker2 각각 위의 명령을 통해 jenkins의 데이터가 저장될 폴더를 생성하고 적절한 권한을 부여합니다. 우선은 777으로 권한을 설정했으나 향후 RBAC 기반으로 전체적인 권한체계를 구성할 예정입니다.
$ vi pv-jenkins.yaml
vi 편집기로 pv 생성을 위한 yaml 파일을 생성합니다.
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-jenkins
spec:
capacity:
storage: 4Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: local-storage
local:
path: /workspace/data/kubernetes/pv/jenkins
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- worker2
4GB 의 용량으로 설정하고 하나의 pod 만 접근하기 때문에 ReadWriteOnce, pod 가 삭제되더라도 데이터 보존을 위해 Retain 전략으로 설정합니다. NodeAffinity 설정을 통해 worker2 에 pv 를 생성하도록 합니다. 즉, Jenkins pv 는 worker2 노드에 만들어지고 Jenkins pod 역시 worker2 노드에 생성되게 됩니다.
$ kubectl apply -f ./pv-jenkins.yaml -n jenkins
kubectl 명령을 통해 pv 를 생성해 줍니다.
persistentvolume/pv-jenkins created
정상적으로 생성이 되었다면 위와 같은 메세지가 출력됩니다.
- Persistnet Volume Claim 생성
$ vi pvc-jenkins.yaml
vi 편집기로 pvc 생성을 위한 yaml 파일을 생성합니다.
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: pvc-jenkins
spec:
accessModes:
- ReadWriteOnce
storageClassName: local-storage
resources:
requests:
storage: 4Gi
위에서 생성한 local-storage 타입으로 4GB 의 용량의 pvc 를 생성합니다.
$ kubectl apply -f ./pvc-jenkins.yaml -n jenkins
kubectl 명령을 통해 pv 를 생성해 줍니다.
persistentvolumeclaim/pvc-jenkins created
정상적으로 생성이 되었다면 위와 같은 메세지가 출력됩니다.
$ kubectl get pvc pvc-jenkins -n jenkins
생성된 pvc 의 상태를 조회해봅니다.
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
pvc-jenkins Pending local-storage 4m10s$ kubectl get pv pv-jenkins -n jenkins
생성된 pv 의 상태도 조회해봅니다.
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv-jenkins 4Gi RWO Retain Available local-storage 6m59s
VolumeBindingMode 를 WaitForFirstConsumer로 설정했기 때문에 Status 가 아직 Available 인 점을 확인할 수 있습니다.
- Deployment 생성
$ vi deployment-jenkins.yaml
vi 편집기로 deployment 생성을 위한 yaml 파일을 생성합니다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: jenkins
spec:
replicas: 1
selector:
matchLabels:
app: jenkins
template:
metadata:
labels:
app: jenkins
spec:
containers:
- name: jenkins
image: truelifer-registry.com:8090/jenkins_for_raspberry_pi_4:latest
ports:
- containerPort: 8080
volumeMounts:
- name: jenkins-home
mountPath: /var/jenkins_home
- name: docker-socket
mountPath: /var/run/docker.sock
- name: docker-binary
mountPath: /usr/bin/docker
volumes:
- name: jenkins-home
persistentVolumeClaim:
claimName: pvc-jenkins
- name: docker-socket
hostPath:
path: /var/run/docker.sock
- name: docker-binary
hostPath:
path: /usr/bin/docker
위에서 생성한 pv, pvc 을 기반으로 deployment yaml 파일을 작성합니다.
$ kubectl apply -f ./deployment-jenkins.yaml -n jenkins
kubectl 명령을 통해 deployment 를 생성해 줍니다.
deployment.apps/jenkins created
정상적으로 생성이 되었다면 위와 같은 메세지가 출력됩니다.
$ kubectl get pods -n jenkins
생성된 pod 를 조회해봅니다.
NAME READY STATUS RESTARTS AGE
jenkins-64c46866bb-5xwsk 1/1 Running 0 1m10
Status 가 Running 상태로 정상적으로 배포되었음을 확인할 수 있습니다.
- Service 생성
$ vi service-jenkins.yaml
vi 편집기로 service 생성을 위한 yaml 파일을 생성합니다.
apiVersion: v1
kind: Service
metadata:
name: jenkins
spec:
type: NodePort
ports:
- port: 8080
nodePort: 30001
targetPort: 8080
selector:
app: jenkins
Jenkins 를 외부에서 웹브라우저를 통해 접속하기 위해 NodePort 타입으로 설정하도록 합니다. Node 의 Port 기본 범위는 30000 ~ 32767로 정해져있습니다. 저는 30001 포트를 사용하도록 하겠습니다.
$ kubectl apply -f ./service-jenkins.yaml
kubectl 명령을 통해 service 를 생성해 줍니다.
service/service-jenkins created
정상적으로 생성이 되었다면 위와 같은 메세지가 출력됩니다.
$ kubectl get services -n jenkins
생성된 service를 조회해봅니다.
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
jenkins NodePort 10.108.24.158 <none> 8080:30001/TCP 12s
NodePort 타입으로 service 가 정상적으로 생성되었음을 확인할 수 있습니다.
- IPTIME Port Fowarding 설정
위 과정을 통해 Kubernetes Cluster 상에 Jenkins 를 배포하는 과정은 완료가 되었습니다. 외부에서 접속하기 위해서는 추가적으로 한 가지 작업이 더 남아있습니다. 공유기의 Port Fowarding 설정입니다. Chrome 브라우저를 통해 IPTIME 관리자페이지(192.168.0.1) 로 접속한 후 로그인을 합니다.
jenkins-rasp-worker2 라는 이름으로 port fowarding rule 을 추가합니다. 외부에서 {도메인이름}:8080 으로 오는 접속을 내부의 Node(worker2 의 30001번 포트)로 연결해 주는 작업입니다.
- 외부접속 테스트 및 로그인
이제 모든 설정이 완료되었습니다. Chrome 웹 브라우저를 통해 정상적으로 접속이 되는지 확인해보도록 하겠습니다.
Jenkins 화면이 정상적으로 출력되었습니다. 최초에 Jenkins 에 접속하기 위해서는 Admin Password 를 입력해야 합니다. kubectl logs 명령어를 통해 Jenkins 컨테이너의 로그를 확인하거나 Jenkins 컨테이너 내부에 들어가서 cat /var/jenkins_home/secrets/initialAdminPassword 명령어를 통해 비밀번호를 확인할 수 있습니다. 확인한 비밀번호를 입력 후 하단의 Continue 버튼을 클릭합니다.
Jenkins 의 플러그인을 설치하는 화면입니다. 필요한 플러그인만 골라서 설치하려면 우측의 “Select Plugins to install” 을 클릭합니다.
적당히 필요한 플러그인을 선택 후 “Install” 버튼을 클릭합니다.
선택한 플러그인의 설치가 진행됩니다.
플러그인 설치가 완료되면 계정생성 폼이 뜹니다. 적당한 id/pw 를 입력 후 우측 하단의 “Save and Continue” 를 클릭합니다.
Jenkins URL 을 설정 후 우측 하단의 “Save and Finish”를 클릭합니다.
모든 구성이 완료되었습니다. “Start using Jenkins” 버튼을 클릭합니다.
구성이 완료된 Jenkins 의 기본 화면입니다. 이제 이 페이지에서 Build & Deploy Pipeline 을 만들어 CI/CD 를 구현하면 됩니다.
- 마무리
이번 글에서는 Jenkins 를 Kubernetes Cluster 상에 배포/설치해 보았습니다. 이전 글에서 구현했던 daum news crawler의 소스코드에 변경사항이 생기면 그것을 반영하기 위해 수동으로 Docker 이미지를 빌드하고 Registry 에 push 한 후에 Kubernetes Cronjob 을 재생성해주어야 합니다. 이전 글에서 CI/CD 툴은 Jenkins를 설치한 이유는 이런 일련의 과정(pipeline)을 자동화하기 위함이었습니다. 다음 시간에는 수동으로 해야 했던 이 작업들을 Jenkins를 통해 자동화해보도록 하겠습니다.