티스토리 뷰

목차

개요
사전 준비
Github
Jenkins Pipeline
Configure Project

 

개요

지난 포스팅에서 Kubernetes에 Jenkins를 세팅했습니다.

이 포스팅에서는 Sample Project가 github의 master branch에 push될 때 Jenkins Pipeline을 통해 빌드 및 배포되도록 합니다. 순서는 다음과 같습니다.

 

1. github 저장소를 하나 생성한 뒤 webhook을 정의합니다.
2. 샘플 프로젝트에 Dockerfile과 Kubernetes object yaml 파일을 만들고 Kubernetes에 수동으로 파드를 생성합니다.
3. 샘플 프로젝트에 Jenkinsfile을 만들어 pipeline을 정의합니다.
4. jenkins에 pipeline project를 생성합니다.
5. 프로젝트 소스를 github에 push하고 배포가 정상적으로 이루어지는지 확인합니다.

 

사전 준비

Git이 설치되어 있어야합니다.

 

1) Github

먼저 github에 sample용 저장소를 하나 생성합니다.
그 후 setting -> Webhooks으로 가서 Webhook을 다음과 같이 추가합니다. 가린 부분은 Jenkins의 URL입니다.

 

생성한 뒤 잠시 후 다음과 같이 표시됩니다.
만약 에러가 발생한다면 포트포워딩 등 외부에서 접근이 가능하게 설정되어 있는지 확인합니다.

 

2) Configure Project

이전 포스팅에서 create-react-app으로 생성했던 샘플 프로젝트에 배포 설정을 진행합니다.

먼저 앞서 생성한 github를 등록합니다.

$ git remote add origin <github repository url>

 

package.json의 scripts.test를 아래와 같이 변경합니다.

"test": "react-scripts test --watchAll=false",

 

그 후 다음과 같이 설정 파일들을 생성합니다.

 

config/nginx/nginx.conf

server {

    listen      3000;
    server_name sample

    location / {
        root   /usr/share/nginx/html;
        index  index.html;
        try_files $uri $uri/ /index.html;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

}

 

Dockerfile

FROM node:10.20.1 as builder

WORKDIR /usr/src/app  
COPY ./package.json ./yarn.lock ./  
RUN yarn install

COPY . .  
RUN yarn build

FROM nginx:stable-alpine
COPY --from=builder /usr/src/app/config/nginx/nginx.conf /etc/nginx/conf.d/nginx.conf  
COPY --from=builder /usr/src/app/build /usr/share/nginx/html

EXPOSE 3000  
CMD ["nginx", "-g", "daemon off;"]

 

.dockerignore

.git/
node_modules/
build/
sample.yaml

 

이제 docker image로 빌드한 뒤 dockerhub에 푸쉬합니다.

$ docker build -t <dockerhub-repository> . # 마지막에 . << 빼먹지 않도록 주의.
$ docker push <dockerhub-repository>

 

config/k8s/sample.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: sample
spec:
  selector:
    matchLabels:
      run: sample
  replicas: 1
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  template:
    metadata:
      labels:
        run: sample
    spec:
      containers:
      - name: sample
        image: <dockerhub-repository>
        ports:
        - containerPort: 80
---    
apiVersion: v1    
kind: Service    
metadata:    
  name: sample
  labels:    
    run: sample
spec:    
  selector:    
    run: sample
  ports:    
  - port: 3000    
    targetPort: 3000    
    protocol: TCP    
  type: LoadBalancer 

 

이제 수동으로 파드를 생성합니다.

$ kubectl apply -f ./config/k8s/sample.yaml -n dev
$ kubectl get pods -n dev # 파드가 정상적으로 생성되었는지 확인합니다.

여기까지 문제없이 진행되었다면 브라우저에서 localhost:3000로 접속했을 때 샘플 프로젝트가 정상적으로 나타납니다.

 

 

Jenkinsfile - jenkins pipeline을 정의합니다.

// scripted 문법으로 작성하며 podTemplate의 사용법은 https://github.com/jenkinsci/kubernetes-plugin를 참고합니다.
podTemplate(containers: [
    containerTemplate(name: 'node', image:'node:10.20.1', command: 'cat', ttyEnabled: true),
    containerTemplate(name: 'docker', image: 'docker', command: 'cat', ttyEnabled: true),
    containerTemplate(name: 'kubectl', image: 'lachlanevenson/k8s-kubectl:v1.18.3', command: 'cat', ttyEnabled: true),
],
volumes: [
  hostPathVolume(mountPath: '/var/run/docker.sock', hostPath: '/var/run/docker.sock')
]) {
    node(POD_LABEL) {
        def uuid = UUID.randomUUID().toString()
        def repo = "<dockerhub-repository>-${uuid}"

        stage('Checkout github branch') {
            // checkout code from a git repository
            checkout scm
        }

        stage('Run test') {
            container('node') {
                sh "npm install"
                sh "npm run test"
            }
        }

        stage('Build and Push docker image') {
            container('docker') {
                withCredentials([[
                    $class: 'UsernamePasswordMultiBinding',
                    credentialsId: 'dockerhub',
                    usernameVariable: 'DOCKER_HUB_USER',
                    passwordVariable: 'DOCKER_HUB_PASSWORD'
                ]])  {
                    sh """
                        docker login -u ${DOCKER_HUB_USER} -p ${DOCKER_HUB_PASSWORD}
                        docker build -t ${repo} .
                        docker push ${repo}
                    """
                }
            }
        }
        stage('Apply kubernetes') {
            container('kubectl') {
                sh """
                     kubectl set image deployment sample sample=${image}
                """
            }
        }
    }
}

 

프로젝트 소스를 github에 push한 뒤 github의 master branch에 제대로 올라왔는지 확인합니다.

$ git add .
$ git commit -m check remote repository
$ git push origin master

 

3) Jenkins Pipeline

마지막으로 Jenkins에서 파이프라인을 생성합니다.

- Credentials 생성

먼저 Pipeline을 구성하는데 필요한 Github와 Dockerhub의 Credentials을 등록합니다.

 

- Pipeline 생성

이전 포스팅에서 설정한 Jenkins에서 new Item -> Pipeline을 다음과 같이 생성합니다.
만약 목록에 Pipeline이 없다면 Jenkins 관리 -> 플러그인 관리에서 설치합니다.

 

생성된 Pipeline의 Build Now를 클릭하고 아래 명령어를 통해 파드를 확인합니다.

$ kubectl get pods -n dev --watch

위에서 deployment를 생성할 때 spec.strategy.type을 RollingUpdate로 지정해 놓았기 때문에 새로운 파드가 정상적으로 생성될 때까지 기존에 있던 파드가 계속 살아있는 걸 확인할 수 있습니다.
이 때 localhost:3000 접속해보면 트래픽이 기존에 있던 파드로 전달되는 걸 볼 수 있습니다.
이후 새로운 파드가 정상적으로 생성되면 기존에 있던 파드는 삭제되고 트래픽이 새로운 파드로 전달되게 됩니다.

 

 

이제 브라우저에서 localhost:3000로 접속하면 아래와 같이 배포된 프로젝트가 나타나게 됩니다.

 

이제 master branch에 push할 때마다 프로젝트가 배포되며 이상으로 Jenkins & kubernetes를 통한 간단한 CI/CD 구성을 마칩니다.

'Docker' 카테고리의 다른 글

CI/CD with Jenkins & Docker & Kubernetes on Windows [1/2]  (0) 2020.05.30
댓글