
아래의 사진은 65트만에 오류를 해결하고 성공한 Jenkins의 모습입니다.

저는 서버를 두 개로 준비해서 Jenkins가 돌아갈 서버,
Spring Boot가 돌아갈 서버 두개를 준비했습니다.

해당 코드는 서버 내의 스왑 파일을 생성하고, 가상 메모리 기법을 활성화 하는 코드입니다. 가상 메모리 공간을 마련하여 메모리 부족 상황에서 시스템이 더욱 안정적으로 동작할 수 있도록 도와줍니다.
$ 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
Jenkins 서버에서 Docker와 Jenkins 이미지를 설치하여 서버를 켜보겠습니다.
Install Docker Engine on Ubuntu
# 설치 및 버전 확인
docker -v
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:lts
# 조심) 계정이 root면 위 것으로 사용하고, ubuntu면 -v /home/ubuntu/.ssh:/root/.ssh
이미지를 pull 받고 run을 돌려도 되지만, docker는 이미지가 없는 경우 docker hub 에서 공식 이미지를 찾아서 다운받아서 run 시켜주기 때문에 편한 방법 사용하시면 됩니다.
docker ps
[공인 IP 주소]:8080
위 주소로 접속하면 Jenkins가 비밀번호를 입력하라는 내용이 나옵니다.
docker logs jenkins
당황하지 않고 Jenkins 서버로 와서 위 코드를 작성하여, Jenkins가 초기 실행될 때 발생한 코드를 복사해서 시작하면 됩니다.
이후 계정 생성은 본인이 기억할 수 있는 아이디와 비밀번호를 사용해줍니다.
Spring Project의 파일에 Dockerfile을 생성하고 아래 내용을 넣어줍니다.
FROM openjdk:17-alpine
ARG JAR_FILE=build/libs/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
git add Dockerfile
git commit -m 'Docs : add Dockerfile'
# 전 commit을 vi 편집기로 해서 아래 내용 작성했습니다.
git commit
Docs : add Dockerfile
This is a Dockerfile that uses Java 17 version and creates a .jar file.
git push
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
Github Repository > Settings > Deploy Keys > Add deploy key 선택
title은 아무거나 입력해도 상관없다. 본인은 jenkins 라고 입력했음
# 공개키 복붙하고 key에 아래 내용을 넣어주면 된다.
cat /root/.ssh/id_rsa.pub
**Stores scoped to Jenkins**에 Domain이 (global)인 text 클릭 Global credentials (unrestricted)로 이동한다. 왼쪽 메뉴의 Add credentials를 눌러 credentials를 추가
Enter directly 체크 -> private key 입력
여기서 private key는 Jenkins Server에서 생성한 id_rsa이다. 아래 명령어로 확인 가능하다.
cat /root/.ssh/id_rsa
Jenkins 대시보드 > Jenkins 관리 > 플러그인 관리 > 설치 가능 > Docker 검색 > Docker, Docker Pipeline 플러그인 설치 및 재실행
⚠️ 아마 곧 재시작 된다는 말이 나오게 되는데, 난 30분을 기다려도 재시작 되지 않았다. 그래서 수동으로 다시 시작하는 방법을 알려드리겠습니다.주의) 절대 컨테이너를 삭제하면 안됩니다.
Jenkins 컨테이너 재시작
docker ps -a
# 현재 잠시 Stop 상태의 Jenkins가 보인다면
docker start [Container ID]
이후 다시 시작하면 됩니다.
젠킨스가 빌드 되면서 docker와 관련된 명령어를 실행할 수 있도록 제작할 것인데, 중요한 것은 Jenkins 내부 컨테이너에 Docker가 설치되있지 않아서, 나중에 Docker 명령어 오류가 뜬다. 그것을 미연에 방지하기 위해 여러분들은 저처럼 삽질하지 마시고, 미리 설치하여 번거러움을 더시길 바랍니다 😊
# jenkins container 터미널 접속
docker exec -it jenkins /bin/bash
# linux 버전 확인
cat /etc/issue
# --------------- OS --------------------------------
# root@DESKTOP-R4P59B3:/home/opendocs# cat /etc/issue
# Ubuntu 20.04.4 LTS \n \l
# --------------- jenkins Container OS --------------------------------
# root@DESKTOP-R4P59B3:/home/opendocs# docker exec -it jenkins /bin/bash
# root@8fc963af71bb:/# cat /etc/issue
# Debian GNU/Linux 11 \n \l
# 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 서버로 SSH 연결을 할 때, 공개키, 비밀키를 사용하게 된다. SSH 접속 원리는 유저가 SSH 접속을 할 때, 유저한테 비밀키, 서버에 공개키를 저장해두고, ssh 키 인증을 하게된다.
그렇다면, Jenkins에서 Spring Server로 SSH 접속을 하게되면, Jenkins가 유저가 되고, Spring Server가 서버가 된다. 즉, 아까 ssh-keygen을 통해 생성된 공개키와 비공개 키 중 공개키를 Srping Server에 전달해야 한다.
Jenkins로 Spring Boot 코드를 빌드하고, 생성된 이미지를 Spring Boot 서버에서 구동시키기 위해서 ssh를 사용한다. 아래는 이후에 생성할 pipeline에서 사용하는 ssh 연결 후 명령어를 전달하는 코드이다.
stage('Docker Run') {
steps {
echo 'Pull Docker Image & Docker Image Run'
sshagent (credentials: ['SSH Credential ID -> ssh']) {
sh "ssh -o StrictHostKeyChecking=no root@[서버IP] 'docker pull [docker image]'"
sh "ssh -o StrictHostKeyChecking=no root@[서버IP] 'docker ps -q --filter name=carry | grep -q . && docker rm -f \$(docker ps -aq --filter name=[컨테이너 이름])'"
sh "ssh -o StrictHostKeyChecking=no root@[서버IP] 'docker run -d --name carry -p 8080:8080 [docker image]'"
}
}
}
Jenkins 대시보드 > Jenkins 관리 > 플러그인 관리 > 설치 가능 > SSH Agent 플러그인을 검색하고 설치 및 재실행
.ssh/authorized_keys 파일에 Jenkins Server의 public key를 추가
# jenkins server
cat /root/.ssh/id_rsa.pub
# Spring server에 pub키 추가
vi /root/.ssh/authorized_keys
Jenkins 대시보드 > Jenkins 관리 > Security > Credentials
**Stores scoped to Jenkins**에 Domain이 (global)인 text 클릭 Global credentials (unrestricted)로 이동한다. 왼쪽 메뉴의 Add credentials를 눌러 credentials를 추가
Enter directly 체크 -> jenkins server의 private key 입력
cat /root/.ssh/id_rsa
Discord > 서버 설정 > 연동 > 웹후크 > 새 웹후크

이름과 채널명은 자유롭게 작성하시면 됩니다. 웹후크 URL은 추후에 Pipeline에 넣을겁니다.
github에 push가 발생했을 때 자동으로 jenkins의 빌드가 실행될 수 있게 해줍니다. 하지만, 이것은 선택
Jenkins 대시보드 > Jenkins 관리 > 플러그인 관리 > 설치 가능 > Github Integration 플러그인을 검색하고 설치 및 재실행
Jenkins Pipeline 구성 > General > Github project에 repo URL을 입력해준다. 그리고 아래 GitHub hook trigger for GITScm polling 체크

Github Repository에서 Settings > Webhooks > Add Webhook 을 눌러 Webhook을 추가한다.
pipeline {
agent any
environment {
imagename = "[이미지 명]"
registryCredential = 'docker-hub'
dockerImage = ''
}
stages {
stage('Prepare') {
steps {
echo 'Clonning Repository'
git url: 'Github Repository SSH Url([git@github.com 으로 시작하는 깃허브 주소])',
branch: 'main',
credentialsId: 'github'
}
post {
success {
echo 'Successfully Cloned Repository'
}
failure {
error 'This pipeline stops here...'
}
}
}
stage('Bulid Gradle') {
steps {
echo 'Bulid Gradle'
dir('.'){
sh './gradlew build -x test'
sh './gradlew clean build'
}
}
post {
failure {
error 'This pipeline stops here...'
}
}
}
stage('Bulid Docker') {
steps {
echo 'Bulid Docker'
script {
dockerImage = docker.build imagename
}
}
post {
failure {
error 'This pipeline stops here...'
}
}
}
stage('Push Docker') {
steps {
echo 'Push Docker'
script {
docker.withRegistry( '', registryCredential) {
dockerImage.push()
}
}
}
post {
failure {
error 'This pipeline stops here...'
}
}
}
stage('Docker Run') {
steps {
echo 'Pull Docker Image & Docker Image Run'
sshagent (credentials: ['ssh']) {
sh "ssh -o StrictHostKeyChecking=no root@[공인 IP] 'docker pull jongdo737/carraway'"
sh "ssh -o StrictHostKeyChecking=no root@[공인 IP] 'docker ps -q --filter name=carry | grep -q . && docker rm -f \$(docker ps -aq --filter name=carry); docker run -d --name carry -p 8080:8080 jongdo737/carraway'"
}
}
}
}
post {
success {
discordSend description: "알림테스트",
footer: "테스트 빌드가 성공했습니다.",
link: env.BUILD_URL, result: currentBuild.currentResult,
title: "테스트 젠킨스 job",
webhookURL: "[DisCord Webhook 주소]"
}
failure {
discordSend description: "알림테스트",
footer: "테스트 빌드가 실패했습니다.",
link: env.BUILD_URL, result: currentBuild.currentResult,
title: "테스트 젠킨스 job",
webhookURL: "[DisCord Webhook 주소]"
}
}
}
아래 웹후크 주소를 추가해 줍니다. 그리고 Build를 누르게 되면 아까 설정한 Discord의 채널로 메시지가 전송되게 됩니다.
[Jenkins] NCP, Github, Docker, Spring Boot, Discord 로 CI/CD 구축하기 - 에러 해결 방법
https://hyeinisfree.tistory.com/23
https://malwareanalysis.tistory.com/353