05. Week5 Jenkins on Kubernetes 아키텍처 (부록) - chuirang/DevOps GitHub Wiki

참고. Jenkins on Kubernetes 아키텍처 이해

목차

  1. Jenkins 아키텍처
  2. Jenkins on Kubernetes 아키텍처

Jenkins 아키텍처

img

출처: https://www.deftboxsolutions.com/blog/advantages-of-hosting-jenkins-on-cloudaws-over-on-premise-chapter-2/

VM기반의 Jenkins는 아래와 같은 문제점이 있다.

  • Job이 수행되지 않을 때도 Slave에 대한 비용 발생
  • 다수 Slave (노드) 별로 빌드, 배포 환경을 관리
  • 특정 빌드 Job으로 Slave 리소스 과부하 발생

Jenkins on Kubernetes 아키텍처

Kubernetes 환경의 jenkins는 아래와 같은 장점이 있다.

  • Job이 실행되지 않을 때는 Slave 를 유지할 필요가 없음
  • 컨테이너 이미지를 사용해 일관된 환경에서 빌드, 배포를 수행
  • 컨테이너 자원 제한을 이용한 리소스 관리

Jenkins를 Kubernetes 환경에서 사용한다는 것은 두 가지 의미가 있다.

  1. Jenkins (Master) 를 Pod 형태로 실행시킨다. Pipeline 을 실행하면 Jenkins Agent 가 Pod 형태로 실행된다.

  2. Jenkins 의 Pipeline 에서 Kubernetes 에 애플리케이션을 배포(갱신)한다.

Pipeline 을 생성하고 빌드를 실행하면 아래와 같이 실행된다.

그러하므로 Kubernetes 환경에서 Jenkins 를 사용하기 위해서는 아래와 같은 사항이 필요하다.

  1. Jenkins Server (Master Pod) 가 API Server로 Pod 실행을 요청하기 위해서 적절한 인증과 허가가 필요하다. 이를 위해서 Service Account 와 RBAC 을 설정해줘야 한다.

  2. Jenkins Slave (Job Pod) 가 Pipeline을 실행하기 위한 명령어가 충분히 갖춰진 컨테이너 이미지를 선택해야 한다.

  • Docker build 과정을 위해서 docker 명령어가 설치된 컨테이너가 필요
  • Deploly 과정을 위해서 kubectl 명령어가 설치된 컨테이너가 필요

이러한 과정을 효과적으로 관리하기 위해서는 Pod template에서 참조하는 이미지를 별도로 관리해야할 필요가 있다. (다만 본 실습의 목적은 Jenkins를 최적화하는 것이 아니므로 명령어가 설치된 임의의 container를 사용함)

참고로 Jenkins 의 Job Pod에 여러 개의 컨테이너 실행하는 경우 동일한 작업공간을 사용하므로, 서로의 결과(각 pipleline의 수행결과)를 참조할 수 있다.

Jenkins on Kubernetes 관련 이슈

  • PV IO 성능으로 인한 이슈
  • Agent Pod 의 스케쥴링 이슈

Jenkins on Kubernetes 를 위한 설정

Jenkins Agent를 Kubernetes Pod로 사용하기 위해서 아래와 같은 설정이 필요하다.

  1. Master 에 할당된 기본 Build Executor 를 0으로 수정한다. Jenkins Dashboard > Manage Jenkins > Manage Nodes and Clouds > 우측화면의 master 에서 톱니모양(configure)

    • Number of excutor: 0

    해당 설정으로 좌측 바에서 Build Executor Status 의 Idle excutor가 사라진다.

  2. Kubernetes 관련 Plugin 을 설치한다. (pipeline에서 kubectl을 사용하기 위해 kubectl CLI 플러그인을 설치하는 것은 별도이다.) Jenkins Dashboard > Manage Jenkins > Manage Plugins

    • kubernetes 를 검색하여 체크하고 [Download now and install after restart] 를 수행한다.
  3. Jenkins 가 Kubernetes 연동을 위해 사용할 Service Account와 RBAC을 생성한다.

    ## Service Account 생성 > Token 값 복사
    $ kubectl create serviceaccount jenkins -n jenkins
    $ kubectl describe secret $(kubectl describe serviceaccount jenkins -n jenkins |grep Token | awk '{print $2}') -n jenkins
    
    $ kubectl create rolebinding jenkins-admin-binding --clusterrole=admin --serviceaccount=jenkins:jenkins -n jenkins
    
  4. Jenkins 가 연동할 Kubernetes 를 등록해 준다.

    1. Jenkins Dashboard > Manage Jenkins > Manage Nodes and Clouds > 좌측 바의 Configure Clouds 선택
    2. Add a new cloud 를 눌러 kubernetes 를 선택하고 아래를 입력 한다.
    • Name: kubernets (default) *다른이름으로 지정하면 job에서 변경된 이름으로 정의해줘야 한다.

    • kubernetes Cloud details.. 클릭

      • Kubernetes URL: Kubernets API Server 입력

      • Kuberntes Namespace: jenkins (jenkins 를 설치한 네임스페이스 입력)

      • Credentials: [Add] 를 누른다.

        • Kind: Secret text
        • Scope: Global
        • Secret: 위에서 생성한 Service Account의 Token을 넣는다
        • ID: jenkins_on_kubernetes
      • 상기의 설정이 정상이라면 [Test Connection] 이 정상적으로 성공되야한다.

      • Jenkins URL: http://jenkins.jenkins.svc.cluster.local

        Jenkins Agent Pod 가 실행되면 Jenkins master로 연결이 되야하는데(jnlp container), 이를 위한 주소를 입력한다. (동일한 Kuberntes 환경에서 Pod-to-Svc 통신이므로 도메인을 입력하면 된다)

    • [Save] 를 눌러 저장한다.

  5. Test Job 을 생성한다.

    1. New Item > 이름 작성 > pipeline 선택 > [Save]

    2. Pipeline 에서 [try sample pipeline] 을 누르고 'Declarative (Kubernetes)'를 선택하면 아래와 같은 샘플 파이프라인이 확인된다.

    • agent 가 kuberntes 이고, inline pod yaml이 보인다. 이 pod yaml을 통해 Agent Pod가 실행되어 pipeline에 정의한 stages 가 실행된다.
    // Uses Declarative syntax to run commands inside a container.
    pipeline {
        agent {
            kubernetes {
                // Rather than inline YAML, in a multibranch Pipeline you could use: yamlFile 'jenkins-pod.yaml'
                // Or, to avoid YAML:
                // containerTemplate {
                //     name 'shell'
                //     image 'ubuntu'
                //     command 'sleep'
                //     args 'infinity'
                // }
                yaml '''
    apiVersion: v1
    kind: Pod
    spec:
      containers:
      - name: shell
        image: ubuntu
        command:
        - sleep
        args:
        - infinity
    '''
                // Can also wrap individual steps:
                // container('shell') {
                //     sh 'hostname'
                // }
                defaultContainer 'shell'
            }
        }
        stages {
            stage('Main') {
                steps {
                    sh 'hostname'
                }
            }
        }
    }
    
    
    1. Build Now 를 누른다.