5.1 CI/CD 와 Jenkins.


CI/CD 소개

CI/CD 는 지속적 통합(Continuous Integration)과 지속적 배포(Continuous Deployment)를 의미하는 용어로, 소프트웨어 개발 과정을 자동화하여 개발의 효율성과 배포의 안정성을 극대화하는 접근법입니다. 이 과정에서 개발자는 코드 변경사항을 자동으로 통합, 테스트, 배포함으로써 소프트웨어의 질을 지속적으로 개선하고, 사용자에게 빠르게 새로운 기능을 제공할 수 있습니다.

CI/CD의 이론적 개념

CI/CD는 두 가지 개념으로 구분됩니다:

  1. Continuous Integration (CI) : 지속적인 통합
    • 코드 변경사항을 주기적으로 리포지토리에 통합하는 과정입니다. 이 과정에 자동화된 테스트가 포함되어 있어 통합 과정에서 발생할 수 있는 문제를 즉시 발견하고 해결할 수 있습니다
    • 주요 목적은 코드의 품질을 지속적으로 유지하고, 배포 가능한 상태를 유지하는 것입니다.
  2. Continuous Deployment or Delivery (CD) : 지속적인 배포 : 통합된 코드를 배포하는 과정을 자동화
    • CI 과정을 통해 통합된 코드를 자동으로 스테이징 및 프로덕션 환경에 배포하는 단계입니다.
    • 주요 목적은 언제든지 최신 버전의 소프트웨어를 사용자에게 안정적으로 제공할 수 있는 상태를 유지하는 것 입니다.

Jenkins

Jenkins는 자바로 작성된 오픈 소스 자동화 서버로, CI/CD 파이프라인을 구축 및 관리하는 데 널리 사용됩니다. 확장 가능한 플러그인 생태계를 통해 다양한 개발, 테스팅, 배포 도구와 통합할 수 있으며, 사용자의 요구에 맞게 파이프라인을 맞춤 설정할 수 있습니다. Jenkins의 유연성은 높은 자유도를 제공하지만, 초기 설정과 관리에는 상대적으로 높은 러닝 커브가 존재합니다.

사전 준비사항

  • 기본적인 Git 지식 및 깃허브 계정
  • Docker 기초 지식 및 Docker 계정

Jenkins 설치가이드

Jenkins 설치 및 실행

Docker 이미지를 이용한 Jenkins 설치를 Docker 통해서 진행하겠습니다. Docker 를 사용하는 이유는 Jenkins 의 복잡한 설치 과정을 단순화하기 위함입니다.

docker run -d \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v jenkins_home:/var/jenkins_home \
  -p 8080:8080 \
  -p 50000:50000 \
  --name jenkins \
  -u root \
  jenkins/jenkins:lts
  • -v /var/run/docker.sock:/var/run/docker.sock : jenkins 컨테이너에서 host 머신의 docker socket 을 사용하기 위한 설정입니다. Docker 컨테이너 안에서 Docker 를 사용하는데 설정이 복잡하여 Host 의 Docker Socket 을 사용하도록 설정합니다.
  • -v jenkins_home:/var/jenkins_home : jenkins 컨테이너의 데이터를 저장하기 위한 설정입니다. jenkins 컨테이너가 삭제되거나 재시작해도 데이터가 유지되도록 설정합니다.
  • -u root : jenkins 컨테이너를 root 권한으로 실행하기 위한 설정입니다. jenkins 컨테이너에서 host 의 Docker socket 을 사용하기 위해서는 root 권한이 필요합니다. 프로덕션 환경에서 권장하는 방법은 아닙니다만 간단하게 테스트하기에는 용이한 설정입니다.

localhost:8080 으로 접속하여 Jenkins 가 정상적으로 실행되었는지 확인한 후 비밀번호 설정이나 권장 Plugin 설정과 같은 초기설정을 진행합니다.

Jenkins 컨테이너 안에서 Docker 설치

Jenkins 안에서 docker image 를 빌드하기 위해서는 컨테이너 안에서 docker 를 설치해야합니다. Jenkins 컨테이너에 접속하여 docker 를 설치합니다. jenkins/jenkins 이미지는 debian 기반의 os 이기 때문에 docker 설치시 debian os 설치 가이드를 따릅니다.

# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install sudo
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# Add the repository to Apt sources:
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update

sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

## Verify that the installation is successful by running the hello-world image
sudo docker run hello-world

Jenkins Pipeline

Jenkins 에서 Pipeline 이란 Jenkins 가 수행해야할 프로세스의 지침이라고 생각하면 됩니다. 프로세스 지침은 코드 컴파일, 테스트 실행, 소프트웨어 배포와 같이 단계별로 수행할 작업을 설정합니다.

Pipeline 예시 및 구성요소

pipeline {
    agent any
    stages {
        stage('Build') {
            steps {
                sh 'echo "Hello World"'
            }
        }
    }
}
  • pipeline : 파이프라인을 정의하는 블록입니다. 파이프라인의 전체 구조를 정의합니다.
  • agent : jenkins pipeline 이 실행될 에이전트를 지정할 수 있습니다. 에이전트는 머신 또는 컨테이너 등이 될 수 있습니다.
  • stages : 하나 이상의 stage 블록의 모음입니다. 각 stage는 파이프라인 프로세스의 구별되는 부분을 대표하며, 빌드, 테스트, 배포 등과 같은 작업을 의미합니다.
  • stage : 파이프라인의 일부로 특정 작업을 수행하는 하나의 단계 또는 여러 단계의 그룹입니다.
  • steps : 각 stage 내에는 실행할 실제 명령이나 스크립트를 정의하는 steps가 있습니다.

사전 준비

  • plugins : 기본적으로 Jenkins 에서 파이프라인을 실행하기 위해서는 Jenkins 에서 사용할 수 있는 플러그인을 설치해야합니다. 초기 admin 페이지에 접근시 권장하는 플러그인을 설치한 경우 추가작업은 필요없습니다.
    • Jenkins 어드민 페이지에 로그인 한 후 Manage Jenkins -> Plugins -> Available Plugins 에 접근하여 plugin 을 설치합니다.
    • 이 예제에서는 docker 를 사용해야하기 때문에 Docker Commons PluginDocker Pipeline 플러그인을 설치합니다.
  • docker hub credentials : docker hub 에 이미지를 푸시하기 위해서는 docker hub 에 로그인할 수 있는 credentials 가 필요합니다. Jenkins 에서 credentials 를 추가하는 방법은 다음과 같습니다.
    • 개인 docker hub 에 로그인 한 후 My Account -> Security -> New Access Token 을 클릭하여 새로운 토큰을 생성하고 이 토큰을 반드시 안전한 곳에 보관합니다.
    • Jenkins 에 로그인 후 Dashboard -> Credentials -> System -> Global credentials -> Add Credentials 를 클릭합니다.
    • KindUsername with password 로 선택하고, Username 에 docker hub 의 username 을 Password 에 위에서 발급한 access token 을 입력합니다. ID 는 이 token 의 접근하기위한 식별자이며 docker-hub-credentials 로 입력합니다.
  • docker hub repository : docker hub 에 이미지를 푸시하기 위해서는 docker hub 에 이미지를 푸시할 수 있는 repository 가 필요합니다. 예제를 위해 public 한 repository 를 생성합니다.

Jenkins Pipeline 작성

Jenkins 에 Dashboard 에서 New Item 을 클릭하고, Pipeline 을 선택합니다. Pipeline 의 이름을 입력하고, OK 를 클릭합니다.

Pipeline 설정에서 가장 아래 섹션에서 script 를 아래와 같이 작성합니다.

pipeline {
    agent any
    environment {
        IMAGE_NAME = '<docker-hub-username>/<docker-repository>'
        GIT_REPO_URL = '<github-repository-url>'
        DOCKER_REGISTRY = 'https://index.docker.io/v1/'
        DOCKER_CREDENTIALS_ID = 'docker-hub-credentials'
    }
    stages {
        stage('Clone repository') {
            steps {
                git url: GIT_REPO_URL
            }
        }
        stage('Build Docker image') {
            steps {
                script {
                    docker.build( "${IMAGE_NAME}:${env.BUILD_NUMBER}")
                }
            }
        }
        stage('Push Docker image') {
            steps {
                script {
                    docker.withRegistry(DOCKER_REGISTRY, DOCKER_CREDENTIALS_ID) {
                        def dockerImage = docker.image(env.IMAGE_TAG)
                        dockerImage.push("latest")
                        dockerImage.push("${env.BUILD_NUMBER}")
                    }
                }
            }
        }
    }
}

각 Stage 에서는 Git, Docker Pipeline plugin 을 사용하여 docker image 를 빌드하고, docker hub 에 푸시하는 작업을 수행합니다.

각 Stage 설명

  • Clone repository : Git plugin 을 사용하여 만들 이미지의 코드가 있는 repository 를 Clone 합니다.
  • Build Docker image : Docker Pipeline plugin 을 이용하여 docker image 를 빌드합니다. 이 때 build 의 옵션값들을 설정할 수 있습니다.
  • Push Docker image : Docker Pipeline plugin 을 이용하여 docker image 를 docker hub 에 푸시합니다. docker.withRegistry 의 블록 안에서는 로그인한 session 이 유지됩니다.

Pipeline 실행

Pipeline 을 실행하기 위해서는 Dashboard -> 정의한 pipe-line -> Build Now 를 클릭합니다. Pipeline 이 실행되면서 각 stage 들이 실행되는 것을 확인할 수 있습니다. 또한 각 스테이지별 진행 내역과 전체 pipeline log 또한 확인할 수 있습니다.

CI/CD 잘 구성하기

CI/CD 를 구현한다는 것은 단순히 Jenkins 를 설치하고 파이프라인을 작성하는 것이 아닙니다. CI/CD 를 잘 구성하기 위해서는 다음과 같은 사항을 고려해야합니다. CI/CD 는 개발팀의 문화와 프로세스를 지속적으로 발전시키는 변화이기 때문에, 이러한 변화를 잘 이끌어내기 위해서는 CI/CD 구성 목적과 평가를 잘 해야합니다.

명확한 목적을 설정하여 어떤 문제를 해결하고자 하는지, 어떤 결과를 얻고자 하는지를 명확히 설정해야합니다. 예를 들어 배포시간 단축, 버그 발생률 감소, 잦은 배포에도 안정적인 서비스 등을 목적으로 설정할 수 있습니다. 얻고자 하는 결과를 평가하기 위한 메트릭을 위해 KPIs 를 설정하여 목적을 달성했는지를 확인할 수 있어야합니다. 예를 들어 배포시간, 버그 발생률, 장애 복구시간, 배포 주기 등을 메트릭으로 설정할 수 있습니다.

결론

CI/CD 환경은 역동적으로 변화하고 있습니다. Jenkins 이외에도 GitHub Actions 과 같은 도구가 민첩하고 효율적으로 높은 품질의 소프트웨어 개발 관행을 촉진하는 데 앞장서고 있습니다. 전략적인 CI/CD 구현 사례를 채택하고 실제 구현 및 사례를 통해 개선시켜야할 뿐만 아니라 새로운 트렌드를 파악함으로써 CI/CD의 잠재력을 최대한 활용하여 더 고품질의 소프트웨어를 빠르게 제공할 수 있도록 해야합니다.