[DOCKER] 컨테이너 배포 자동화(CI/CD) 프로젝트-18

[실습] 컨테이너 배포 자동화를 위한 CI/CD(Jenkins) 구성

지속적 통합과 배포(CI/CD)

  • CI/CD는 애플리케이션 개발 단계를 자동화하여 보다 짧은 주기로 변경을 제공하여 전박적인 프로세스의 효율성과 지속성을 보장할 수 있다.
  • 지속적 통합(CI, Continuous Integration)
    • CI는 코드 변경 사항을 지정된 repository에 정기적으로 통합하고 자동화된 빌드와 테스트를 실행한다.
  • 지속적 전달과 배포(CD, Continuous Delivery & Deployment)
    • CD는 실제 운영에 배포하기 위해 코드 변경이 자동으로 빌드, 테스트, 준비되는 단계다.
    • 지속적 전달은 스테이징 환경에서 모든 코드 변경을 자동으로 배포하고 테스트하여 지속적 통합을 확장하고, 이후 운영에 배포하기 위한 수동 승인 단계를 거친다. 즉, 코드 베이스가 항상 배포 가능한 상태를 유지하는 단계다.
    • 지속적 배포는 수동 승인 단계를 배제한 전제 end to end 주기가 자동화되는 과정이다.
  • 지속적 통합과 배포(CI/CD) 파이프라인
    • CI/CD는 애플리케이션 개발 프로세스에서 자동화된 빌드, 테스트, 배포를 위해 사용되는 방법론으로 애플리케이션의 품질 향상 및 릴리스 주기를 단축 시키는데 도움이 되는 중요한 역활을 수행한다.

Jenkins

  • Java runtime 환경으로 구성된 소프트웨어 구축, 테스트, 전달 또는 배포와 관련된 모든 종류의 작업을 자동화를 목적으로 사용할 수 있는 독립형 오픈 소스 CI 서버이다.
  • Jemkins plugins(https://plugins.jenkins.io)
    • credentials plugin: 인증 관련으로 VM 환경에서는 ssh key, AWS/Git  등은 token을 활용
    • git plugin: GitHub source code 접근을 통해 빌드를 수행할 수 있도록 지원
    • docker plugin & pipline: docker agent를 통해 Jenkins가 docker를 사용하도록 지원
    • blue/ocean plugin: CD pipline의 자세한 시각화 지원으로 모든 상황에 대한 파악이 빠름
    • Amazon EC2 plugin: EC2 인스턴스 스케일링 가능한 빌드 클러스터 구성 가능
    • Metric plugin: 운영 환경의 중요 성능 metric(지표) 측정을 위한 java library 제공
  • Jenkins pipeline
    • jenkins의 pipeline은 용도에 맞게 plugin을 조합하여 원하는 Jenkins CI/CD 자동화를 구성하는 것이다.
    • Declarative(선언적) 방식과 scripted pipeline 구성 방식이 있다.
    • # Declarative (빠른 업데이트 및 가독성)
      pipeline {
          agent { docker 'node:6.3' }
          stages {
              stage('build') {
                  steps {
                      sh 'npm version'
                  }
              }
          }
      }
      # scripted pipeline
      node('docker') {
          checkout scm
          stage('Build') {
              docker.image('node:6.3').inside {
                  sh 'npm version'
              }
          }
      }
    • Jenkins pipeline section
      • Agent section
        • 여러 Slave node 사용할 경우, 어떤 노드에 일을 시킬 것인지 지정
        • 또는,  node 뿐만 아니라 Jenkins 내부 docker container에서 수행할 명령 지정도 가능
      • Stage section
        • 어떤 일들을 처리할 것인지 정의(category)
        • 예로, backend 배포를 위한 stage 정의
      • Steps section
        • 특정 stage 안에서의 작업 순서(단계, step)를 정의
        • plubin 설치 시 사용 가능한 step 생성
      • Post section
        • stage 종료 후 결과에 따른 후속 조치
        • 성공이면 Email 전송, 실패 시 중단 및 skip 등의 작업 결과에 따른 조치 지정
      • # GitHub에 등록한 access token을 Pipeline Project의 Script 적용
        pipeline {
        agent any
        stages {
            stage('Prepare') {
                agent any
                steps {
                    git branch: 'main',
                    credentialsId: 'github_access_token',
                    url: 'https://github.com/hylee-kevin/fastcampus.git'
                }
                post {
                    failure{
                        error "Fail Git Cloned Repository"
                    }
                }
            }
        }

         

[실습] Jenkins 환경 구성

docker run -itd --name=fc-jenkins -p 18080:8080 -p 50000:50000 --privileged=true -u root --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v /home/kevin/fastcampus/jenkins:/var/jenkins_home jenkins/jenkins:lts
sudo chown -R kevin.kevin /home/kevin/fastcampus/jenkins
sudo netstat -nltp | grep docker-proxy

port1 → (필수 ) 외부 연결을 위한 기본 port(8080)
port2 → 여러 노드에 Jenkins를 구성한 경우 Jenkins agent를 통해 노드간 통신을 위한 port(50000)
–privileged=true → 컨테이너 내부 시스템의 주요 자원에 접근할 가능하도록 권한 부여
-u root → 여러 권한 문제 및 명령어 수행을 위해 지정 . (일반 사용자 지정 시 권한 부여 후 사용 )
/var/run/docker.sock 공유 → Jenkins에서 docker build 사용을 위해 host에 설치된
docker.sock을 같이 사용하기 위해 볼륨을 구성해야 한다. 또는 docker in docker(dind) 사용.
Jenkins home과 애플리케이션 소스가 제공될 볼륨 설정.

 

18080으로 접근하면 비밀번호를 알아야한다.

docker exec fc-jenkins cat /var/jenkins_home/secrets/initialAdminPassword

비밀번호를 확인하고 복사하여 위의 화면에 입력한다.

위와 같이 선택하여 젠킨스 설치를 마무리하자.

docker logs fc-jenkins

위의 명령어를 실행하면 젠킨스의 로그를 확인 할수 있다.

 

젠킨스를 사용할 사용자를 만들어주자.

젠킨스 url을 확인후에 입력하자.

jenkins credential을 위해서 bash로 접근해서 ssh key를 생성합시다.

docker exec -it fc-jenkins bash
cd /var/jenkins_home/
mkdir .ssh && cd $_
ssh-keygen -t rsa -f /var/jenkins_home/.ssh/fc-jenkins


생성된 키는 /var/jenkins_home/.ssh 폴더 아래에 fc-jenkins fc-jenkins.pub란 이름으로 생선된다. pub키가 공개키로 깃허브나 도커에 제공해서 사용자 증명에 사용된다.

 

이제 도커에 fc-jenkins 이름의 private key를 등록하자. jenkins를 접속해서 jenkins 관리 > Credentials 이동하자.

global를 선택해서 Add credentials을 클릭한다.

Username: jenkins 생성시 만든 계정

private key: fc-jenkins private key를 복사해서 등록한다.

 

create를 클릭후 잘 생성된지 확인하자.

먼저 깃에서 web-count라는 저장소를 생성하자. Settings > Deploy keys > Add new를 선택해서 fc-jenkins라는 이름의 키를 만들자 key에는 fc-jenkins.pub 키를 복사해서 붙여넣기 하자.

 

 

 

다음으로 설정해야 할 것은 깃의 webhooks 설정이다.  우리는 깃에 main 브랜치에 소스가 커밋이 되었을때  젠킨스에 콜을 보내서 소스를 checkout 하고 docker image로 빌드 컨테이너를 생성하는 과정을 거쳐야 한다.
그러기 위해서는 젠킨스의 주소를 도메인 주소로 가지고 있어야 한다. 가비아와 같은 호스팅 사이트에서 등록해도 되지만 여기서는 실습을 위해서 ngrok을 사용해서 임시 도메인을 만들어서 진행하겠다.

mkdir ngrok && cd $_
wget -c https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip
unzip ngrok-stable-linux-amd64.zip
sudo snap install ngrok

위의 명령어를 실행시켜 설치해보자.

 

https://ngrok.com  회원 가입하여 개인 토큰을 발급 받자.

ngrok config add-authtoken 발급받은 토큰
ngrok http 18080

생성된 Forwarding에서 주소를 복사해서 git의 web-count 저장소의 webhooks의 payload url에 등록, content type은 application/json으로 설정하고 저장한다.

젠킨스에서 깃, 도커 등의 상용 프로그램을 사용 할려면 해당 플러그인을 설치해야 한다. jenkins 관리 > plugins를 클릭 하자.

 

ssh로 인증을 하기 위해서 Publish Over SSH  설치
도커을 위한 docker pipeline 설치
깃을 위해서 Generic Webhook Trigger, GitHub integration을 설치

모두 설치하고 젠킨스를 재부팅하자.

 

이제 dockerhub에서 설정을 해야한다. 젠킨스에서 사용할 도커 토큰을 발급하자. 우선 My Account로 이동하자.

Security탭을 선택하자.

 

New Access Token을 선택하자. 설명을 docker jenkins로 입력하고 권한을 Read, Write, Delete를 주고 생성하자.

생성된 키를 복사하자. 토큰은 한번만 노출이 되어서 잊어버리면 지우고 다시 생성해야 한다.

 

젠킨스로 이동해서 도커관련 credential 설정을 하자. jenkins 관리 > credential로 이동하자.

 

add credentials를 선택한다.

Username: docker id
Password: dockerhub에서 발급한 토큰
id: docker-access(젠킨스에서 사용할 이름)
Description: DOCKER-CREDENTIALS

docker-access가 생성됨을 확인한다.

도커와 마찬 가지로 깃도 토큰을 생성해야 한다. profile을 선택 해서 settings로 이동하자.  Personal access tokens를 선택 하고 classic을 선택했다.
이름: docker-jenkins
expiration: 30일로 선택했다.
권한: repo, workflow, gist, notifications, user, delete_repo 를 선택하고 생성하자.

 

마찬가지로 생성시에만 토큰을 노출해준다 복사하자.

Username: git id
Password: 발급받은 토큰
ID: github_access_token
생성하자

이제 세가지 credentials가 생성되었다. 첫번째가 jenkins, docker, git 정보이다.

 

https://github.com/hylee-kevin/fastcampus에서 10장의 web-count 소스를 가져온 다음 구런다음 도커 컴포즈로 컨테이너를 생성하자.

cp -r /home/kevin/fastcampus/ch10/web-count .
docker compose up -d
docker compose ps
docker ps

 

jenkins 내에서 도커를 실행시켜서 깃에서 다운로드 받은 소스를 이미지로 만들고 푸시 할수 있어야 한다. fc-jenkins컨테이너를 bash로 들어가서 도커를 설치 하자
처음에 강의 내용대로 설치를 했는데 docker-compose를 못찾는다는 오류가 발생해서 docker-compose는 따로 설치를 했다.

docker exec -it -u root fc-jenkins bash

sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

docker ps

위의 명령어로 실행하고 확인해보자.

 

 

이제 젠킨스는 깃과 도커를 사용할 준비가 거의 다 되었다. 젠킨스 아이템들을 만들어서 깃의 main 브랜치에 소스가 올라오면 작업할 pipline을 만들어보자.

스크린샷을 못찍어서 다른 사진을 이용하겠다. 위의 항목중에 Pipeline을 선택한다.

 

설명을 적고. project url에 web-count 주소를 적고 git-hub hook trigger를 선택하자.

 

파이프라인을 위와 같이 설정하고 저장을 하자.

jenkins/web-count 폴더에 Jenkinsfile을 만들자

vi Jenkinsfile
node {
    stage('Clone repository') {
        git credentialsId: 'github_access_token', url: 'https://github.com/hyleekevin/web-count.git'
    }
    stage('Build image') {
        dockerImage = docker.build("leecloudo/web_count:v1.0")
    }
    stage('Push image') {
        withDockerRegistry([ credentialsId: "docker-access", url: "" ]) {
            dockerImage.push()
        }
    }
}

Clone repository에서 깃을 체크아웃 받고 Build image 단계에서 이미지를 만들고 다음 단계에서 이미지를 도커에 푸시한다. credentialsId로는 위에서 설정한 credentials의 id를 선택한다. 여기까지가 CI과정이다.

 

이제 도커이미지를 다운로드 받아서 컨테이너를 빌드하는 과정을 하는 아이템을 만들어 보자. 여기 과정이 CD과정이다. freestyle project를 선택한다.

설명과 project url을 입력하자.

 

빌드 유발을 설정하자. 위에서 만든 web-count_pipeline을 선택하자.  git을 checkout하고 도커이미지를 빌드해서 푸시한후에 해당 아이템이 트리거 된다.

 

cd /var/jenkins_home/web-count # Jenkins container 
docker compose down
docker pull junseongday/web_count:v1.0
docker compose up -d

web-count 폴더로 이동후 도커컴포즈를 멈추고 이미지를 다시 받고 컴포즈를 올린다.

# 기존 docker-compose.yaml 코드 수정.
jenkins/web-count$ vi docker-compose.yml
version: '3.3' # 버전 에러가 발생해서 3.8 에서 3.3으로 수정
services:
webserver:
#build: . # jenkins 에서 이미 build가 되어 host에 pull되므로 build 생략
 image: junseongday/web_count:v1.0 # Jenkinsfile에서 작성한 docker image:tag 지정
 ports:
- "8899:8899"
depends_on:
- redis
redis:
image: redis:6.0

docker-compose.yaml의 내용이다. 포트는 8899이고 redis에 의존한다.

 

이제 해당 소스를 깃에 푸시해보자.

git init
git config --global user.email "junseongday@gmail.com"
git config --global user.name "junseongday"
git add .
git commit -m "web-count first commit"

git branch -M master
git remote add origin https:..github.com/junseongday/web-count.git
git remote -v
git push -u origin master

 

 

소스가 잘 올라간것을 확인해보자.

 

 

그리고 젠킨스에 정상적으로 item들이 잘 실행되었는지 확인해보자.

 

index.html을 수정해서 다시 푸시하고 배포까지 잘되는지 확인해보자.

소스를 커밋하니 배포까지 잘 되는 것을 확인했다. 젠킨스를 통한  CI/CD의 방법을 알아보았다.

 

Leave A Reply

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다