8 Oct 2020

[Project] DevSecOps 프로젝트 - CI 구성

목차

1. CI(Continuous Integration) 구성

   1.2. CI 란?

   1.2. GitLab - Jenkins 연동

   1.3. GitLab - Jenkins 웹훅 설정

2. Jenkins 파이프라인 설정

   2.1. 파이프라인 테스트

   2.2. Jenkins - Docker 연동 및 파이프라인 테스트


1. CI(Continuous Integration) 구성


1.1. CI 란?

CI란 팀의 구성원들이 작업한 내용을 정기적으로 통합하는 것을 의미한다.

개발자들은 소스 코드를 정기적으로 Git, SVN 과 같은 SCM(Source Code Management, 형상 관리 시스템)에 Push 하는데, 각각의 개발자들로부터 Push된 소스 코드들을 정기적으로 통합하는 것을 CI라고 한다.

CI를 구축하지 않은 경우 개발자들이 각자 개발한 소스 코드를 형상 관리 서버에 Commit 하면 별도의 품질관리를 거치지 않고 대부분 개발이 끝난 막바지에 통합을 하여 테스트를 진행하게 된다.

이럴경우, 개발 중 별도의 품질 관리를 수행하지 않았기 때문에 잘못된 소스 코드를 형상관리 시스템에 반영하였을 경우 발생되는 문제가 개발 후반에 모두 장애로 발견된다.

반면에 CI를 구축하게 되면 CI 서버는 형상 관리 서버에 Push 된 소스코드를 주기적으로 폴링하여 컴파일, 단위테스트, 코드 인스펙션 등의 과정을 수행하며 신규 또는 수정된 소스 코드에 결함이 있는지에 대한 여부를 지속적으로 검증하기 때문에 조기에 결함을 발견하여 해결할 수 있다.


1.2. GitLab - Jenkins 연동

먼저 SCM 툴인 Gitlab과 CI/CD Server 툴로 사용할 Jenkins를 연동하는 작업을 시작해보자.

[그림 1]과 같이 관리자 계정에서 Admin Area > Network 탭으로 들어와 아웃바운드를 설정한다.

gitlab_outbound
[그림 1] GitLab 네트워크 아웃바운드 설정


웹훅 및 서비스가 액세스 할 수 있는 IP, 즉 Jenkins 서버의 IP를 적어준다.

다음으로 GitLab 프로젝트를 생성하여 해당 프로젝트의 Settings > Access Tokens 탭에 들어온다.

gitlab_access_token
[그림 2] GitLab Access Token 생성


위의 [그림 2]와 같이 토큰 명과 만료일을 설정하고 액세스 토큰을 생성하면 토큰 값이 나온다.

토큰 값은 Jenkins에서 credentials를 생성할 때 필요하기 때문에 따로 기록해둔다.


다음으로 Jenkins의 설정의 Plugin Manager 탭으로 GitLab 관련한 플러그인을 모두 설치해준다.

GitLab 플러그인이 정상적으로 설치되면 시스템 설정으로 들어와서 [그림 3]과 같이 Gitlab을 연동하기 위한 설정을 해준다.

jenkins_gitlab_config
[그림 3] Jenkins에서 GitLab 설정


GitLab 호스트의 URL 및 포트를 적어주고 Credentials는 Add 버튼을 눌러 다음 [그림 4]와 같이 생성해준다.

jenkins_gitlab_credentials
[그림 4] Jenkins에서 GitLab Credentials 생성


Credentials 키를 정상적으로 생성 및 선택해주고 오른쪽 하단의 Test Connection 버튼을 눌러 Success 문구가 뜨는지 확인한다.


1.3. GitLab - Jenkins 웹훅 설정

Jenkins와 Gitlab을 성공적으로 연동시키고 나서 Jenkins 메인 화면에서 새로운 Item 탭을 눌러준다.

jenkins_new_item
[그림 5] Jenkins Item 생성


위의 [그림 5]와 같이 파이프라인을 선택하고 아이템의 이름을 명시하고 OK 버튼을 눌러 아이템을 만들어준다.

본 프로젝트에서는 devsecops-pipeline라는 이름의 아이템을 만들어주었다.


Jenkins에서 아이템을 정상적으로 만들어준 후에 Giblab의 Settings > Webhooks 탭으로 들어온다.

gitlab_webhook
[그림 6] GitLab 웹훅 설정


위의 [그림 6]와 같이 http://JenkinsID:JenkinsPassword@JenkinsIP:JenkinsPort/project/ProjectName의 형태로 URL을 작성해준다.

일단 설정은 푸시 이벤트에 대한 트리거만 걸어놓고 차후 멀티 브랜치에 대한 파이프라인 구성도 진행해볼 것이다.

웹훅 설정을 마치고 아래로 내리면 Test 버튼을 눌러 Push events에 대한 테스트를 진행해본다.

Hook executed successfully: HTTP 200 메시지가 뜨면 푸시 이벤트에 대한 웹훅도 정상적으로 설정되어 Jenkins를 통해 CI를 구성할 준비가 끝난 것이다.


2. Jenkins 파이프라인 설정


2.1. Pipeline 설정 및 테스트

[그림 5]에서 생성한 파이프라인의 구성 탭을 눌러서 다음 [그림 7]과 같이 Gitlab에 푸시되면 자동으로 파이프라인이 실행될 수 있도록 설정해준다.

gitlab_webhook
[그림 7] GitLab 웹훅 설정


아래로 쭉 내리면 [그림 8]과 같이 파이프라인 스크립트를 작성할 수 있는 공간이 있다.

echo_hello_world
[그림 8] Hello World 파이프라인 스크립트 작성


Gitlab에 푸시했을 때 정상적으로 파이프라인이 작동하는지만 확인해보기 위해 ‘Hello World’를 출력하는 간단한 스크립트를 작성하여 설정을 저장했다.


그러고나서 깃 푸시 이벤트를 보내면 다음 [그림 9]와 같이 자동으로 설정해둔 파이프라인이 정상적으로 실행되는 것을 확인할 수 있다.

pipeline_result
[그림 9] 파이프라인 실행 결과 확인


실행된 파이프라인에 대한 로그는 해당 빌드 넘버를 클릭하여 Console Output 탭을 눌러 확인할 수 있다.

build_console
[그림 10] 파이프라인 실행 콘솔 로그 확인


[그림 10]에서 볼 수 있듯이 정상적으로 파이프라인이 실행되어 콘솔에 ‘Hello World’ 문구가 출력된 것을 확인할 수 있다.


2.2. Jenkins - Docker 연동 및 파이프라인 테스트

Gitlab과 Jenkins가 정상적으로 연동되어 Git Push에 의해 자동으로 파이프라인이 실행되는 부분까지 진행하였고 다음으로 파이프라인에서 git clone하여 프로젝트 폴더의 Dockerfile을 통해 빌드하여 Docker hub에 푸시하는 부분까지 진행해보겠다.

우선 Jenkins가 설치되어 있는 노드에서 Git 혹은 Docker 관련 스크립트 실행시 커맨드 에러가 발생할 수 있으므로 servers 인스턴스에서 다음 명령어를 통해 파이프라인에서 Git과 Docker 명령을 사용할 수 있도록 해준다.

$ sudo yum -y update
$ sudo yum -y install docker docker-registry

docker 명령을 입력했을 때 권한 에러를 해결하기 위한 설정도 해주어야 한다.

$ sudo usermod -a -G docker $USER
$ sudo service docker restart
$ sudo chmod 777 /var/run/docker.sock


그리고 Jenkins에서 [그림 11]에 보이는 Docker 관련 플러그인을 설치해준다.

docker_plugin_installation
[그림 11] Jenkins에서 Docker 플러그인 설치


다음으로 Docker hub에 로그인 할 계정의 Credentials을 생성해야 한다.

추후 Harbor를 구축하여 연동해볼 예정

docker_hub_credentials
[그림 12] Docker hub credentials 생성


위의 Docker 관련 설정이 정상적으로 완료되면 파이프라인 스크립트를 다음과 같이 작성해준다.

pipeline {
    environment {
        registry = "crisis513/flask-app"
        registryCredential = 'crisis513'
        dockerImage = ''
        releaseName = "flask-app"
        release_version = 'latest'
    }
    agent any
    stages {
        stage('Cloning our Git') {
            steps {
                git 'http://GITLAB_SERVER_IP:8001/root/flask-app.git'
            }
        }
        stage('Building docker image') {
            steps {
                script {
                    dockerImage = docker.build registry + ":${release_version}"
                }
            }
        }
        stage('Deploy docker image') {
            steps {
                script {
                    docker.withRegistry( '', registryCredential ) {
                        dockerImage.push()
                    }
                }
            }
        }
        stage('Cleaning up') {
            steps {
                sh "docker rmi $registry:${release_version}"
            }
        }
    }
}

파이프라인 스크립트의 문법에 대해 알고싶다면 Jenkins Pipeline Syntax에서 확인

파이프라인은 다음과 같이 실행된다.

GitLab 서버에서 flask-app 프로젝트를 가져와서 프로젝트 내의 Dockerfile을 통해 빌드하고 ‘crisis513’ 이라는 ID를 가진 credentials를 통해 Docker hub에 로그인 하여 해당 도커 레포지토리(registry)에 release_version에 해당하는 태그를 붙여 푸시하고 로컬에 생성된 도커 이미지는 삭제된다.


Dockerfile의 내용은 다음과 같다.

FROM python:alpine

RUN apk add --no-cache linux-headers build-base

COPY requirements.txt /requirements.txt

RUN pip install -r /requirements.txt

COPY ./app /app
WORKDIR /app
RUN pip install flask

RUN touch database.db
RUN python ./setup.py

EXPOSE 8080
CMD ["uwsgi", "--ini", "conf.ini"]

해당 Dockerfile이 포함된 프로젝트는 git - crisis513/flask-app에서 확인 가능

위의 파이프라인이 정상적으로 실행된 결과는 다음 [그림 13]과 같다.

docker_push_pipeline_result
[그림 13] Docker 푸시까지의 파이프라인 실행 결과


Docker hub에 접속하면 도커 이미지도 정상적으로 푸시된 것을 확인할 수 있다.


여기까지 GitLab - Jenkins - Docker를 연동하여 Git 푸시 이벤트가 발생했을 때 Git 프로젝트를 clone하여 Dockerfile을 빌드하여 Docker hub에 푸시하기까지의 과정을 모두 살펴보았다.

다음 포스팅에서는 CD(Continuous Delivery/Continuous Deployment) 환경을 구성하는 방법에 대해 기술해보겠다!


Tags:
0 comments