본문 바로가기

Infra

[Jenkins] NCP, Github, Docker, Spring Boot, Slack로 CI/CD 구축하기

728x90
반응형
이번에 젠킨스를 이용하여 Spring Boot를 CI/CD 파이프라인 구축하는 것에 대해 글을 작성해보려 합니다. 많은 오류와 시행착오 속에서 어떻게 해결했는지 알아보겠습니다.

30트 이상만에 오류를 해결하고 성공한 Jenkins 모습.

🔥빌드 순서

  • Code push to Github
  • Build By Jenkins
  • Push to Docker hub
  • Docker run

🔥기술 스택

  • Spring Boot / Gradle
  • Docker
  • Github
  • Jenkins
  • NCP - Server
  • Slack
spring 서버와 jenkins 서버를 따로 두었다.
compact 서버는 월 4~5만원 정도

  • 신규 가입하면 10만 크레딧을 지원해줘서 micro는 너무 답답하여 compact를 사용했습니다.
  • 공인 IP를 연결하고, ACG를 설정해줍니다.
  • 포트 포워딩을 해줍니다.
  • 작은 프로젝트라 VPC를 사용 안하고 Classic 사용
## ubuntu server jdk-11 -> jdk-17 변경하기

sudo apt update
sudo apt install openjdk-17-jdk
java -version
sudo vi /etc/environment
source /etc/environment -> JAVA_HOME="/usr/lib/jvm/java-17-openjdk-amd64" 하단에 넣기
echo $JAVA_HOME

# 아래와 같이 나오면 성공
/usr/lib/jvm/java-17-openjdk-amd64​

🖥️서버가 자꾸 터질 때

서버 내에 스왑 파일을 생성하고, 가상 메모리 기법을 활성화 하여 가상 메모리 공간을 마련해 안정적으로 동작할 수 있게
$ sudo dd if=/dev/zero of=/swapfile bs=128M count=16
$ sudo chmod 600 /swapfile
$ sudo mkswap /swapfile
$ sudo swapon /swapfile
$ sudo swapon -s
$ sudo vi /etc/fstab
/swapfile swap swap defaults 0 0
#안에 데이터가 있을 경우 맨 아래에 추가해주면 되요

🐬도커 설치하기

https://docs.docker.com/engine/install/ubuntu/

sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo apt-key fingerprint 0EBFCD88
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
sudo apt-get update
sudo apt-get install -y docker-ce
sudo usermod -aG docker root(ubuntu)
sudo curl -L "https://github.com/docker/compose/releases/download/1.23.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose

#도커 권한
sudo chmod 006 /var/run/docker.sock

#도커 버전
docker -v

🐬저는 스프링 부트와 젠킨스 서버를 따로 두었기 때문에 스프링 부트 서버에도 도커를 설치해줍니다.

sudo apt update
sudo apt install apt-transport-https ca-certificates curl software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
sudo apt update
sudo apt install docker-ce
sudo systemctl start docker
sudo systemctl enable docker

👴🏼Jenkins 설치 및 빌드

docker run -d -p 8080:8080 -p 50000:50000 -v /jenkins:/var/jenkins -v /root/.ssh:/root/.ssh -v /var/run/docker.sock:/var/run/docker.sock --name jenkins -u root jenkins/jenkins:jdk17

# 조심) 계정이 root면 위 것으로 사용하고, ubuntu면 -v /home/ubuntu/.ssh:/root/.ssh
# 볼륨은 꼭 생성합시다!
이미지를 pull 받고 run을 돌려도 되지만, docker는 이미지가 없는 경우 docker hub에서 공식 이미지를 다운받아서 run 시켜주기 때문에 편한 방법 사용하면 되요.

Jenkins Container 조회

docker ps
docker ps -a

Jenkins 접속

#url로 접속
공인 IP:8080

비밀번호

#아래 코드를 입력하면 로그와 비밀번호가 뜹니다.
docker logs jenkins

설치
순서대로 진행하고 계정을 생성합니다.

 


🐬Dockerfile 작성

 

FROM openjdk:17-alpine
ARG JAR_FILE=build/libs/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]

#왼쪽과 같이 도커 파일을 생성하고 플러그인을 설치해줍니다.
#이후에 깃허브에 push
git add Dockerfile
git commit -m 'Docs : add Dockerfile'
git push

 


👴🏼🐱Jenkins, Github 연동

  •  공개키, 비밀키 생성(Jenkins Server)
    Jenkins Container를 생성할 때 "/root/.ssh:/root/.ssh"로 .ssh 디렉토리를 마운트 해놓았기 때문에
    Container 밖에서 ssh 키를 생성하면 Jenkins Container와 연결된다.
# 그냥 전부 enter를 입력해 default로 만든다.
ssh-keygen

# /root/.ssh에 id_rsa와 id_rsa.pub이 생성된다.
ls /root/.ssh
id_rsa  id_rsa.pub  known_hosts

#id_rsa : prvate key
#id_rsa.pub : public key -> 깃허브
  • Github Deploy Key 등록
    Github Repository > Setting > Deploy Keys > Add deploy key 선택
    title은 아무거나 입력
# 공개키 복붙하고 key에 아래 내용을 넣어주면 된다.
# ssh-rsa 이렇게 시작할텐데 처음부터 끝까지 전부 붙여주면 된다.
cat /root/.ssh/id_rsa.pub
  • Jenkins Credentials 등록
    - Jenkins 대시보드 > Jenkins 관리 > Security > Credentials
# Stores scoped to Jenkins에 Domain이 (global)인 text 클릭
# Global credentials (unrestricted)로 이동한다. 
# 왼쪽 메뉴의 Add credentials를 눌러 credentials를 추가

#KindSSH
	Username with private key
#ID
	github
#Username
	root (default)
#Private Key
	Enter directly 체크 -> private key 입력

	여기서 private key는 Jenkins Server에서 생성한 id_rsa이다. 아래 명령어로 확인 가능하다.
    
    cat /root/.ssh/id_rsa
    # 이것도 -----BEGIN RSA PRIVATE KEY----- 시작할텐데 전부 붙여 넣기.
  • Git clone을 위한 권한 설정
    - Jenkins 대시보드 > System > Github

Add 누른다
Secret text 선택후 secret에 access token 등록(id는 구분할 수 있는 이름)
token 생성
위 두가지를 전부 선택하여 생성

token을 복사하고 secret에 넣어준 후에 test connection을 해줍니다.
그리고 git clone 파이프 라인 생성을 위해 Add로 하나 더 생성해 줍니다.

Username -> github 아이디
Password -> access token
ID -> 구분 가능한 이름

👴🏼🐬Jenkins, Docker hub 연결

Docker Plugin 설치
- Jenkins 대시보드 > Jenkins 관리 > plugins > Available plugins
Docker, Docker Pipeline 검색 후 설치 및 재실행
== docker restart 컨테이너ID(젠킨스 서버에서 docker ps -a로 검색가능)

  • Docker Hub Credencials 등록
    - Jenkins 대시보드 > Jenkins 관리 > Security > Credentials
# Kind
	Username with password
# Username
	본인의 Docker Hub ID
# Password
	본인의 Docker Hub Password
# ID
	docker-hub
  • Jenkins 내부에 Docker 설치
docker exec -u root -it jenkins /bin/bash
# 리눅스 버전
cat /etc/issu

# Docker 설치
## - Old Version Remove
apt-get remove docker docker-engine docker.io containerd runc

## - Setup Repo
apt-get update -y
apt-get install -y\
    ca-certificates \
    curl \
    gnupg \
    lsb-release
mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
  $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
  
## - Install Docker Engine
apt-get update -y
apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin -y

👴🏼🖥️Jenkins, Spring Boot Server SSH 연결

Jenkins Server == 유저 == 비밀키
Spring Server == 서버 == 공개키
Jenkins 대시보드 > Jenkins 관리 > 플러그인 관리 > 설치 가능 > SSH Agent
플러그인을 검색하고 설치 및 재실행

Spring Server에 공개키 설정(.ssh/authorized_keys -> 공개키 추가)

# jenkins server에서
cat /root/.ssh/id_rsa.pub

# Spring server에 pub키 추가 데이터가 있다면 맨 아래에 추가
vi /root/.ssh/authorized_keys

 

Jenkins Credentials 등록

Jenkins 대시보드 > Jenkins 관리 > Security > Credentials
# Stores scoped to Jenkins에 Domain이 (global)인 text 클릭
# Global credentials (unrestricted)로 이동한다.
# 왼쪽 메뉴의 Add credentials를 눌러 credentials를 추가

# Kind
	SSH Username with private key
# ID
	ssh
# Username
	root (default)
# Private Key
	Enter directly 체크 -> jenkins server의 private key 입력
    
    cat /root/.ssh/id_rsa
	#이것도 전부다 입력

👴🏼🐱Jenkins, Github Webhook 설정

push가 발생했을 때 자동으로 jenkins 빌드가 실행되게 

  • Github Integration Plugin 설치
    - Jenkins 대시보드 > Jenkins 관리 > plugins > Available plugins
    Github Integration Plugin 설치 및 재실행

Jenkins Pipeline 설정

- Jenkins Pipeline 구성 > General > Github project 깃 레포 입력 > 훅 체크

프로젝트 이름 적고 Pipeline 선택 후 OK
git repo 적고 훅 선택


🐱Github Webhook 추가

Github Repository에서 Settings > Webhooks > Add Webhook 눌러 추가한다.
# Payload URL
	Jenkins Server URL:Jenkins Server 포트/github-webhook/
# Content
	application/x-www-form-urlencoded
#나머지는 모두 default 설정 유지
	Add webhook 버튼을 눌러 Webhook을 추가 -> 목록에서 녹색 체크 아이콘이 생성되면 성공(새로고침 해주기)

🔗Pipeline Script 생성하기

위에서 깃헙 credential 두번째 생성한걸 여기서 사용한다. Pipeline Syntax를 클릭
깃 클릭

 

레포 주소와 브렌치 설정하고 Credentials 선택해주고 script 누르고 결과를 steps에 붙여주자!

pipeline {
    agent any
    
    environment {
        imagename = "kwondh/ssda"	<-도커 허브 이미지명
        registryCredential = 'docker-hub'
        dockerImage = ''
        SLACK_CHANNEL = "#jenkins"
        SLACK_SUCCESS_COLOR = "#2C953C";
        SLACK_FAIL_COLOR = "#FF3232";
    }
    
    stages {
        stage('Git Clone') {
            steps {
                git branch: 'main', credentialsId: 'gitgit', url: 'Github Repository SSH Url([git@github.com 으로 시작하는 깃허브 주소])'
            }
            post {
                success {
                    slackSend (
                        channel: SLACK_CHANNEL,
                        color: SLACK_SUCCESS_COLOR,
                        message: "===================================\n배포 파이프라인 시작되었습니다."
                        )
                }
            }
        }
        
        stage('Build Gradle') {
            steps {
                echo 'Build Gradle'
                dir('.') {
                    sh './gradlew build -x test'
                    sh './gradlew clean build'
                }
            }
            post {
                success {
                    slackSend (
                        channel: SLACK_CHANNEL,
                        color: SLACK_SUCCESS_COLOR,
                        message: "Build Gradle 성공함ㅋㅋ"
                        )
                }
            }
        }
        
        stage('Build Docker') {
            steps {
                echo 'Build Docker'
                script {
                    dockerImage = docker.build imagename
                }
            }
            post {
                success {
                    slackSend (
                        channel: SLACK_CHANNEL,
                        color: SLACK_SUCCESS_COLOR,
                        message: "Build Docker 성공함ㅋㅋ"
                        )
                }
            }
        }
        
        stage('Push Docker') {
            steps {
                echo 'Push Docker'
                script {
                    docker.withRegistry( '', registryCredential) {
                        dockerImage.push()
                    }
                }
            }
            post {
                success {
                    slackSend (
                        channel: SLACK_CHANNEL,
                        color: SLACK_SUCCESS_COLOR,
                        message: "Push Docker 성공함ㅋㅋㅋ"
                        )
                }
            }
        }
        
        stage('Docker Run') {
            steps {
                echo 'Pull Docker Image & Docker Image Run'
                sshagent(credentials: ['ssh']) {
                    sh "ssh -o StrictHostKeyChecking=no -p 1025 root@공인IP(spring server 아래와 같음 접속이 잘 안되면 jenkins서버에서 스프링 서버로 접속해보기) 'docker pull kwondh/ssda'" <- 도커 허브 이미지명
                    sh "ssh -o StrictHostKeyChecking=no -p 1025 root@106.10.32.11 'docker ps -q --filter name=ssda | grep -q . && docker rm -f \$(docker ps -aq --filter name=ssda); docker run -d --name ssda -p 8080:8080 kwondh/ssda'"
                }
            }
            post {
                success {
                    slackSend (
                        channel: SLACK_CHANNEL,
                        color: SLACK_SUCCESS_COLOR,
                        message: "배포 완료^3^\n=============================="
                        )
                }
            }
        }
    }
   
}

 

너무 어려웠지만 포기하지 않고 해결해 나갔다. 수정해야 할 부분이 있다면 알려주세요!! 감사합니다.

 


참고 블로그
https://velog.io/@jongminshin373/Jenkins-NCP-Github-Docker-Spring-Boot-Discord-%EB%A1%9C-CICD-%EA%B5%AC%EC%B6%95%ED%95%98%EA%B8%B0#1%EF%B8%8F%E2%83%A3-%EB%B9%8C%EB%93%9C-%EC%88%9C%EC%84%9C

https://velog.io/@sihyung92/%EC%9A%B0%EC%A0%A0%EA%B5%AC2%ED%8E%B8-%EC%A0%A0%ED%82%A8%EC%8A%A4-%ED%8C%8C%EC%9D%B4%ED%94%84%EB%9D%BC%EC%9D%B8%EC%9D%84-%ED%99%9C%EC%9A%A9%ED%95%9C-%EB%B0%B0%ED%8F%AC-%EC%9E%90%EB%8F%99%ED%99%94

 

728x90
반응형