나는 CI/CD Manager 입니다.

Print

CI/CD Manager 는 소스 저장소(Gitea) 관리하고 빌드 및 배포를 위한 Pipeline(Jenkins)을 구성합니다.

네임스페이스에 Docker Secret 추가

Secret 은 비밀번호, OAuth 토큰 및 ssh 키와 같은 중요한 정보를 유지하기 위한 것입니다. 이 정보를 Secret 에 두는 것은 Pod 정의 또는 Docker Image에 그대로 넣는 것보다 안전하고 유연합니다. 

다음 절차에 따라서 위에서 생성한 Harbor 계정으로 Docker Secret을 추가하세요.

  1. Secret 탭을 클릭합니다.
  2. Secert 목록의 오른쪽 위에 있는 (Secret 추가) 버튼을 클릭합니다.
  3. Secret 추가 팝업이 뜨면 타입에 맞는 정보를 입력하고 등록 버튼을 클릭합니다.

    • Secret Name : my-docker-secret
    • Secret Type : Docker Registry
    • docker-server(필수) : Image Registry (Harbor) 주소. 
    • docker-username(필수) : Image Registry 로그인 사용자 아이디
    • docker-password(필수) : Image Registry 로그인 사용자 비밀번호
    • docker-email : Docker 로그인 사용자 이메일

소스 저장소 생성 및 권한 설정

계정 생성하기

사용자 계정은 ZCP에 등록되어 있는 사용자 계정과 자동으로 연계 되지 않습니다. 신규 가입의 경우 Gitea에 접속하면 아래와 같은 신규 가입 화면이 나타나고, 필요한 정보를 입력해 신규로 가입합니다.

(반드시 가입하기 하위에 사용자명과 이메일은 변경하지 않고, 비밀번호만 입력해 계정을 생성합니다.)

이후 ZCP Console을 통해서 소스 저장소에 접속하면 자동으로 로그인 됩니다.

저장소(Repository) 생성하기

저장소(Repository)는 git 원격 저장소(Remote Repository)입니다.

Gitea 초기 화면에서 우측 상단의 + 버튼을 누른 후 새 저장소를 클릭합니다.


저장소의 이름과 설명등을 입력하고 저장소 만들기 버튼을 클릭합니다.


저장소가 생성된 화면입니다. 


소스 코드 Push 하기

생성한 저장소에 소스 코드를 Push 합니다.

본 문서에서 사용한 샘플 소스 코드는  Hello ZCP (https://github.com/cnpst/hellozcp)에 있습니다.

# 샘플 소스 코드 가져오기
> git clone https://github.com/cnpst/hellozcp.git
Cloning into 'hellozcp'...
remote: Enumerating objects: 25, done.
remote: Counting objects: 100% (25/25), done.
remote: Compressing objects: 100% (18/18), done.
remote: Total 25 (delta 0), reused 25 (delta 0), pack-reused 0
Unpacking objects: 100% (25/25), done.

# 오리지널 저장소 연결 끊기
> cd hellozcp
> git remote remove origin

# ZCP git 저장소 연결 추가
> git remote add origin https://git.cloudzcp.io/earth1223/new-repository.git

# 소스 코드 Push
> git push -u origin master
Enumerating objects: 25, done.
Counting objects: 100% (25/25), done.
Delta compression using up to 8 threads
Compressing objects: 100% (18/18), done.
Writing objects: 100% (25/25), 46.95 KiB | 9.39 MiB/s, done.
Total 25 (delta 0), reused 0 (delta 0)
To https://git.cloudzcp.io/earth1223/new-repository.git
 * [new branch]      master -> master
Branch 'master' set up to track remote branch 'master' from 'origin'.


저장소에 소스 코드 Push 가 성공한 모습입니다.

빌드 및 배포 Pipeline 구성

ZCP 콘솔에서 DevOps 하위의 빌드 및 배포 메뉴를 클릭합니다.


자신의 Namespace 와 동일한 Folder 를 선택합니다.

Credentials 생성하기

Jenkins 가 Gitea 의 소스를 Checkout 받고, Docker registry 에 push 를 하려면 각 시스템에 로그인하기 위한 인증 정보가 필요합니다.

자신의 Folder 에 들어가서 좌측의 Credentials 메뉴를 클릭합니다.

Credentials 하위의 Folder 를 선택하고 Global credentials 를 클릭합니다.

좌측의 Add Credentials 메뉴를 선택하고, 위에서 생성한 Gitea 의 ID, Password 를 입력하여 Credential 정보를 생성합니다.

Credentials 의 ID 는 아래의 규칙으로 생성합니다.

ServiceCredentials ID
Gitea (GIT)GIT_CREDENTIALS
Harbor (Docker Registry)HARBOR_CREDENTIALS


Gitea, Harbor 두 Credentials 를 모두 생성한 화면입니다.

Jenkinsfile 생성하기

Jenkinsfile 은 Jenkins pipeline 에서 빌드 배포를 위한 일련의 동작(Workflow)을 정의하기 위한 파일입니다.

자세한 내용은 Jenkins 공식 문서를 참고하세요.


소스 코드의 Root 에 Jenkinsfile 이란 파일을 생성하고 아래의 내용을 붙여넣습니다.

@Library('retort-lib') _
def label = "jenkins-${UUID.randomUUID().toString()}"

def ZCP_USERID='zcpsample'
def DOCKER_IMAGE='zcpsample/sam-springboot'
def K8S_NAMESPACE='default'

timestamps {
    podTemplate(label:label,
        serviceAccount: "zcp-system-sa-${ZCP_USERID}",
        containers: [
            containerTemplate(name: 'maven', image: 'maven:3.5.2-jdk-8-alpine', ttyEnabled: true, command: 'cat'),
            containerTemplate(name: 'docker', image: 'docker:17-dind', ttyEnabled: true, command: 'dockerd-entrypoint.sh', privileged: true),
            containerTemplate(name: 'kubectl', image: 'lachlanevenson/k8s-kubectl', ttyEnabled: true, command: 'cat')
        ],
        volumes: [
            persistentVolumeClaim(mountPath: '/root/.m2', claimName: 'zcp-jenkins-mvn-repo')
        ]) {
    
        node(label) {
            stage('SOURCE CHECKOUT') {
                def repo = checkout scm
            }
    
            stage('BUILD') {
                container('maven') {
                    mavenBuild goal: 'clean package', systemProperties:['maven.repo.local':"/root/.m2/${JOB_NAME}"]
                }
            }
    
            stage('BUILD DOCKER IMAGE') {
                container('docker') {
                    dockerCmd.build tag: "${HARBOR_REGISTRY}/${DOCKER_IMAGE}:${BUILD_NUMBER}"
                    dockerCmd.push registry: HARBOR_REGISTRY, imageName: DOCKER_IMAGE, imageVersion: BUILD_NUMBER, credentialsId: "HARBOR_CREDENTIALS"
                }
            }
    
            stage('DEPLOY') {
                container('kubectl') {
                    kubeCmd.apply file: 'k8s/service.yaml', namespace: K8S_NAMESPACE
                    yaml.update file: 'k8s/deploy.yaml', update: ['.spec.template.spec.containers[0].image': "${HARBOR_REGISTRY}/${DOCKER_IMAGE}:${BUILD_NUMBER}"]
    
                    kubeCmd.apply file: 'k8s/deploy.yaml', wait: 300, recoverOnFail: false, namespace: K8S_NAMESPACE
                }
            }
        }
    }
}


Jenkinsfile 에서 4, 5, 6 번 라인의 내용을 자신의 설정에 맞게 수정하고 저장합니다.

4 : ZCP Console에 로그인할 때 사용하는 자신의 계정

5 : Docker Image 명. {프로젝트명}/{어플리케이션명} 으로 입력합니다. 프로젝트 명은 Harbor 에서 생성한 Private Project 이름입니다.

6 : ZCP Console에서 생성한 Namespace 명

Jenkinsfile Push 하기

생성한 Jenkinsfile 을 Git 저장소에 Push 합니다.


# Jenkinsfile을 Index에 추가
> git add Jenkinsfile

# Commit
> git commit -m "Add Jenkinsfile"
[master 4271304] Add Jenkinsfile
 1 file changed, 48 insertions(+)
 create mode 100644 Jenkinsfile

# Push
> git push -u zcp-origin master
Username for 'https://git.cloudzcp.io': earth1223
Password for 'https://earth1223@git.cloudzcp.io':
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 8 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 1.07 KiB | 1.07 MiB/s, done.
Total 3 (delta 1), reused 0 (delta 0)
To https://git.cloudzcp.io/earth1223/new-repository.git
   ca88947..4271304  master -> master
Branch 'master' set up to track remote branch 'master' from 'zcp-origin'.


저장소에 Jenkinsfile 이 추가된 모습입니다.