[Jenkins] K8s에 jenkins 설치하는 방법

Joseph's Engineering Blog·2023년 9월 5일
0

Jenkins

목록 보기
1/2
post-thumbnail

포스팅 이유

Jenkins를 K8s위에서 설치하며 Jenkins에 대해 공부하기 위함



1. Jenkins 설치 준비

구성 환경 정보

  • Jenkins
  • Harbor (내부 사설 이미지 저장소)
  • Gitlab (내부 소스 저장소)
  • ArgoCD (CD용으로 사용)

Jenkins를 설치하여 총 네개의 모듈을 사용하여 CI/CD를 진행할 예정입니다.

Harbor, Gitlab, ArgoCD는 이미 설치되어 Tekton을 사용하여 CI/CD를 진행하고 있는 환경이고 추가적으로 Jenkins를 구축하여 Jenkins 파이프라인을 구성할 계획입니다.
(해당 내용에 대해서는 별도 포스팅에서 구체적으로 다룰 예정입니다.)

kubernetes 환경에 jenkins를 설치하기 위해 아래와 같은 내용이 필요합니다.

  • Jenkins 설치 yaml
  • Jenkins Image
  • Docker Image

구체적으로 알아보겠습니다.



2. Jenkins 설치

다음 yaml들을 사용해 Jenkins를 설치합니다.

## Jenkins Namespace, ConfigMap, Seceret
apiVersion: v1
kind: Namespace
metadata:
  name: jenkins-namespace
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: docker-config
  namespace: jenkins-namespace
data:
  daemon.json: |
    {
      "insecure-registries": ["harbor.test.ehddhks.com"] ## 공인인증서 적용안된 내부 구축 하버
    }

docker-config ConfigMap을 사용하는 이유

내부 사설 이미지 저장소(Harbor)를 사용하기 위해 해당 ConfigMap이 필요합니다.
insecure-registries에 사용할 Harbor 주소를 넣어주면 됩니다.
해당 내용이 없으면 docker command를 통해 build된 image를 해당 저장소에 push 할 때 tls 인증 에러가 발생합니다.

## Jenkins PVC yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  labels:
    app: jenkins
  name: jenkins-pvc
  namespace: jenkins-namespace
spec:
  accessModes:
  - ReadWriteMany
  resources:
    requests:
      storage: 30Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  labels:
    app: jenkins
  name: jenkins-log-pvc
  namespace: jenkins-namespace
spec:
  accessModes:
  - ReadWriteMany
  resources:
    requests:
      storage: 1Gi
## Jenkins Service Yaml

apiVersion: v1
kind: Service
metadata:
  name: jenkins-service
  namespace: jenkins-namespace
  labels:
    app: jenkins
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 8080
    name: http
  - port: 443
    protocol: TCP
    targetPort: 8080
    name: https
  selector:
    app: jenkins
    
---
apiVersion: v1
kind: Service
metadata:
  name: jenkins-service-jnlp
  namespace: jenkins-namespace
  labels:
    app: jenkins
spec:
  ports:
  - port: 50000
    protocol: TCP
    targetPort: 50000
    name: jnlp
  selector:
    app: jenkins         
## Jenkins Deployment Yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: jenkins-deployment
  namespace: jenkins-namespace
spec:
  progressDeadlineSeconds: 600
  replicas: 1
  selector:
    matchLabels:
      app: jenkins
  revisionHistoryLimit: 10
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: jenkins
    spec:
      containers:
      - image: 192.168.178.11:5000/jenkins/jenkins:lts-docker
        imagePullPolicy: IfNotPresent
        name: jenkins
        ports:
        - containerPort: 8080
          name: http
          protocol: TCP
        - containerPort: 50000
          name: jnlp
          protocol: TCP
        resources: {}
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
        volumeMounts:
        - mountPath: /var/jenkins_home
          name: jenkins-vol
        - mountPath: /var/run
          name: shared
        - mountPath: /var/logs
          name: jenkins-log
      - image: docker:dind
        imagePullPolicy: IfNotPresent
        name: docker
        securityContext:
          privileged: true
        volumeMounts:
        - mountPath: /var/run
          name: shared
        - mountPath: /etc/docker
          name: docker-config
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext:
        runAsUser: 0
      terminationGracePeriodSeconds: 30
      volumes:
      - name: jenkins-vol
        persistentVolumeClaim:
          claimName: jenkins-pvc
      - hostPath:
          path: /usr/share/zoneinfo/Asia/Seoul
          type: ""
        name: timezone-seoul
      - name: jenkins-log
        persistentVolumeClaim:
          claimName: jenkins-log-pvc
      - name: shared
        emptyDir: {}
      - name: docker-config
        configMap:
          name: docker-config

Deployment yaml에서의 살펴 볼 부분은 크게 세 개입니다.

  1. Jenkins Image
  2. Docker Sidecar
  3. Shared Volume

이 세 가지는 Jenkins 파이프라인에서 image build를 하기 위해 추가되고 수정 된 부분들입니다.

Jenkins에서는 Image를 build할 때 docker를 사용하여 진행합니다. Docker Plugin을 Jenkins에서 제공하지만 Pod 형태로 뜨는 Jenkins 내부에 Docker Server를 설치하기는 쉽지 않습니다.

따라서 Docker 이미지 중 dind(docker in docker) 이미지를 이용해 docker를 sidecar 형태로 띄워 docker server로 활용하고, Jenkins에서 docker 컨테이너의 docker.sock 파일에 접근할 수 있게 /var/run directory를 두 컨테이너의 Shared Volume으로 설정했습니다.

마지막으로 docker command를 사용하기 위해 기존 jenkins:lts 이미지에 docker command binary 파일을 추가한 Custom Image를 만들었습니다.

Custom Image 만드는 방법

## jenkins container 생성
podman run -it -d --name jenkins --privileged jenkins/jenkins:lts

## docker binary copy
podman cp /usr/bin/docker jenkins:/usr/bin/docker

## commit 후 image push
podman commit jenkins
podman tag d864c93e011ce4760837a4ae22de76e7b0888ac1f451e784a90229091a1c00bc 192.168.178.11:5000/jenkins/jenkins:lts-docker
podman push 192.168.178.11:5000/jenkins/jenkins:lts-docker

다음과 같은 과정을 통해 docker command binary가 포함된 jenkins 이미지를 생성하여 local image registry에 push합니다.



3. Jenkins 접속

yaml들의 배포가 끝나면 Ingress를 통해 외부에 서비스를 노출시킵니다.

Ingress를 통해 접속해보면

잠시 기다리면

다음과 같은 창이 뜹니다.

초기 비밀번호는 jenkins pod의 로그를 보면 확인할 수 있습니다.

$ kubectl  logs jenkins-deployment-6c6c8c5896-hjcg5  -c jenkins 

2023-09-05 08:04:22.069+0000 [id=59]	INFO	jenkins.install.SetupWizard#init: 

*************************************************************
*************************************************************
*************************************************************

Jenkins initial setup is required. An admin user has been created and a password generated.
Please use the following password to proceed to installation:

49516f1247a4469b800a8e93eb8c842c  <= 초기 비밀번호

This may also be found at: /var/jenkins_home/secrets/initialAdminPassword

*************************************************************
*************************************************************
*************************************************************

2023-09-05 08:04:38.538+0000 [id=59]	INFO	jenkins.InitReactorRunner$1#onAttained: Completed initialization
2023-09-05 08:04:38.555+0000 [id=32]	INFO	hudson.lifecycle.Lifecycle#onReady: Jenkins is fully up and running

비밀번호를 사용해 로그인하면

다음과 같은 창이 뜹니다. 필요한 plugin들은 접속 후에 별도로 추가 설치 가능하기 때문에 Install suggested plugins를 눌러 추천된 plugin들만 설치합니다.

Tip

폐쇄망 환경에서는 어떻게 해야할까??
이때는 외부망 통신이 가능한 환경에서 Jenkins를 설치하고 plugin들을 설치합니다. 이후 /var/jenkins_home/plugins 디렉토리 안의 plugin들을 추출하여 폐쇄망 환경에 구성된 jenkins의 동일 directory에 넣어주고 해당 directory를 pvc를 통해 mount 시켜주면 됩니다.

설치가 끝나면 Admin 생성 화면이 나옵니다. 항목들을 작성하여 Admin 계정을 생성합니다.

Jenkins url을 확인하고

Welcome to Jenkins!!!

profile
Kubernetes / DevOps / Git / Network / AWS / Terraform / Opensource / Java / Springboot

0개의 댓글