Jenkins CI/CD 원격서버(Kubernetes) SpringBoot 배포 [Freestyle Job 구성]



  • Category : DEVOPS
  • Tag : Jenkins


목차

  1. Infra 환경 구성
  2. SpringBoot Project Local Test
  3. Remote Server 구성
  4. Jenkins Remote Server 등록
  5. Jenkins Repository 연동
  6. Jenkins 배포 Pipeline 구성
  7. Jenkins Build
  8. SpringBoot 서버 종료(Docker)




1. Infra 환경 구성

img





2. SpringBoot Project Local Test

Maven Project

  • 프로젝트 빌드 : 프로젝트의 pom.xml 파일을 설정하고 Maven을 사용하여 프로젝트를 빌드합니다.
  • JAR,WAR 파일 생성 : mvn package 명령어로 Spring 프로젝트를 빌드하여 JAR 파일을 생성합니다.

Gradle Project

1). 프로젝트 빌드

프로젝트 내에 gradlew파일이 있는 디렉토리에서 gradlew build 명령어를 실행하여 jar,war파일을 생성합니다.

img

# 명령어
gradlew build

Starting a Gradle Daemon, 5 incompatible and 1 stopped Daemons could not be reused, use --status for details

> Task :test
OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended

BUILD SUCCESSFUL in 1m 21s
7 actionable tasks: 7 executed

2). jar,war파일 생성 확인

위 과정을 거치면 /build/libs 폴더 내에 war 혹은 jar파일이 생성됩니다. img

3). 프로젝트 실행

/build/libs디렉토리로 이동하여 아래 명령어를 통해 로컬에서 프로젝트 구동을 확인합니다. 이클립스및 다른 툴을 이용하여 구동하는것도 좋습니다.

# 명령어
java -jar <project file name>.war
java -jar <project file name>.jar

# 8080외의 포트 지정 예) 6060포트
java -jar -Dserver.port=6060 demo-war-0.0.1-SNAPSHOT.war




3. Remote Server 구성

sudo apt update
sudo apt install openjdk-17-jdk -y
sudo apt install maven -y
sudo apt install gradle




4. Jenkins Remote Server 등록

1. Publish Over SSH Plugin 설치

1). Dashboard > Jenkins 관리로 이동 후 Plugins를 클릭한다.

img

2). Available plugins를 선택하고 Publish over ssh를 검색하여 설치한다.

img

3). 설치가 끝나고 실행중인 작업이 없으면 Jenkins를 재시작한다.

img

2. 배포대상 원격서버 등록

아래 이미지와 같이 SSH Server를 등록하지 않은 경우 ssh서버등록을 해야한다. img

1). Dashboard > Jenkins 관리 > System(시스템 설정)메뉴로 진입

img

2). SSH Servers에서 추가를 눌러 SSH Server를 추가

img

3). 다음과 같이 배포대상 VM정보를 입력하여 추가

img

  • Name : 서버를 구분하기 위한 명칭
  • Hostname : 서버 주소
  • Username : 배포자명
  • Remote Directory : 배포 원격 디렉토리[중요]
    • 원격 디렉토리에서 배포할 경로를 설정해준다.
    • home/master/was/SpringBoot

4). 고급을 눌러 설정한 VM환경에 맞게 세팅해준다.

나같은 경우 Azure VM에 ID/Password방식으로 구성했기 때문에 Passphrase / Password에서 해당 VM의 비밀번호만 넣어주면 된다. 토큰 인증방식으로 구성한 경우 별도의 인증키를 넣어주어야 한다. img

5). 위 사항을 정확히 입력 후 Test Configuration을 클릭하면 왼쪽에 Success라고 뜬다. 확인 후 저장을 누른다.

img





5. Jenkins Repository 연동(배포 job 생성)

1. 새로운 item 생성

img

2. 새로운 Job 생성: Jenkins 대시보드에서 새로운 Freestyle 프로젝트를 생성합니다.

img

3. 소스 코드 관리 > Subversion을 선택합니다.

Modules

  1. Repository URL : SVN repository주소를 입력합니다. img

  2. Credentials

    Jenkins 에서 빌드, 배포를 수행하려면 기본적으로 2가지 Credential 정보가 필요합니다. 소스를 Checkout 할 Git Repository 의 접속 계정 정보와 Docker Image를 Push 하기 위한 Registry 접속 계정 정보입니다. 여기서는 SVN에 접속할 SVN 계정정보를 등록합니다.

  3. Add를 클릭 후 Jenkins를 눌러줍니다. img

  4. SVN관련 계정정보를 입력 후 Add로 추가합니다. img

  • 세팅 참고 예) img 작성 완료 후 저장을 눌러 완료합니다.




6. Jenkins 배포 Pipeline 구성

1. Dashboard 에서 작업할 job을 선택합니다.

img

본 설명에서 Springboot-Demo-war 선택

2. 구성을 선택합니다.

img

3. Build Steps 구성

build를 하기위한 방식은 여러방식이 있는듯 하다. 각자 환경에 맞게 선택하면 된다.

1). script 명령어를 통해 build

# gradlew 파일의 위치로 이동
cd demo-war

ls -l

chmod +x gradlew
./gradlew clean build --info

img

2). [작성 예정]

4. 빌드 후 조치

빌드 후 조치 추가 > Send build artifacts over SSH 선택 img

SSH Server

  • Name : 등록한 원격 서버를 선택한다.
  • 고급을 눌러 Verbose output in console에 체크해준다.

    배포단계에서 상세로그를 확인할 수 있다.

    img

Transfers

  • Source files :
    • <프로젝트명>/<파일경로>/<.war or .jar> 파일형식으로 build된 파일경로를 입력한다.
    • 파일이 한개인 경우 */.war 와 같은 형식으로 입력하면 된다.
    • SpringBoot build시 plain을 생성하게 되므로 확인필요.
  • Remove prefix :
    • <프로젝트명>/<파일경로>/
    • 비워두면 쓸대없는 디렉토리가 생성된다고 한다. (직접 해보진 않음)
  • Remote directory :
    • 원격 서버에서 배포할 디렉토리를 입력한다.
    • 단, 경로가 맞지않으면 자동으로 생성하지 않아 실패하게됨
  • Exec command :
    • war나 jar파일을 원격서버로 전달하고 해당 경로에서 진행할 작업 script를 작성한다.

Exec command에 들어갈 script 구성

# java -jar -Dserver.port=6060 demo-war-0.0.1-SNAPSHOT.war

echo "현재 디렉토리 출력"
pwd
cd was/SpringBoot

whoami

echo "현재 날짜와 시간으로 태그 생성"
TIMESTAMP=$(date +"%Y%m%d%H%M%S")
DOCKER_IMAGE="iiblackcode/springboot-6060"
TAG="$DOCKER_IMAGE:$TIMESTAMP"

echo "Docker 이미지 강제 삭제 (기존 이미지 태그가 있는 경우)"
# sudo docker rmi -f $TAG || true
sudo docker rmi $(sudo docker images -q)

echo "Docker 이미지 빌드"
sudo docker build -t $TAG .

echo "생성된 Docker image 확인"
sudo docker images

echo "Docker hub login or ACR 등록"
sudo docker login

echo "Docker 이미지 푸시"
sudo docker push $TAG


# sudo docker run -it -d -p 6060:8080 springboot-6060
# sudo docker ps -a

echo "yaml파일 경로로 이동"
cd ../../web/
ls

echo "deployment.yaml 파일 업데이트"
# sed -i "s|image: iiblackcode/springboot-6060:.*|image: \$TAG|" deployment.yaml
sed -i "s|image: iiblackcode/springboot-6060:.*|image: $TAG|" deployment.yaml

echo "업데이트된 deployment.yaml 파일 내용 확인"
cat deployment.yaml

echo "Deployment.yaml 재실행"
kubectl apply -f deployment.yaml

여기서 개인적으로 Remote Server내에서 war/jar파일이 전송될 디렉토리와 yaml파일을 별도로 관리하기 위해 분리함

# build되는 war/jar파일 위치
master@master:~/was/SpringBoot$ ll
total 31764
drwxrwxr-x 2 master master     4096 Jul 23 06:23 ./
drwxrwxr-x 4 master master     4096 Jul 12 04:53 ../
-rw-rw-r-- 1 master master      149 Jul 23 07:09 Dockerfile
-rw-rw-r-- 1 master master      837 Jul 23 06:23 Jenkinsfile
-rw-rw-r-- 1 master master 32506960 Jul 24 05:55 demo-war-0.0.1-SNAPSHOT.war

# yaml파일 디렉토리
master@master:~/web$ ls
deployment.yaml  metallb-config.yaml  service.yaml
  • service.yaml 파일
apiVersion: v1
kind: Service
metadata:
  name: springboot-service
spec:
  selector:
    app: springboot
  ports:
  - protocol: TCP
    port: 8080          # 외부에서 접근할 포트
    targetPort: 8080    # Pod 내 컨테이너의 포트
    nodePort: 30061     # NodePort를 유효 범위 내로 설정
  type: LoadBalancer  
  # type: NodePort
  • deployment.yaml 파일
apiVersion: apps/v1
kind: Deployment
metadata:
  name: springboot-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: springboot
  template:
    metadata:
      labels:
        app: springboot
    spec:
      containers:
      - name: springboot
        image: iiblackcode/springboot-6060:latest
        ports:
        - containerPort: 8080

작성 참고

img 작성 완료 후 저장버튼을 눌러 저장을 완료합니다.





7. Jenkins Build

이후 전체적인 흐름으로

  1. SVN으로 SpringBoot Sourcecode commit&push 진행
  2. SVN에서 Jenkins로 build(Gradle/Meaven)
  3. Jenkins에서 원격서버(kubernetes)에 war/jar파일 ssh전송
  4. Docker Container image build
    • build 빌드전 기존 이미지 삭제
  5. Docker hub로 image push
  6. deployment 재배포를 통해 pod생성

이런 흐름으로 진행되지만 실제로 운영환경에서 개발자는 Code Commit&Push만 하고 운영환경에서 Jenkins Build now 버튼 한번의 클릭으로 이 모든 과정이 이뤄지게 된다.






Share this post