Devops

SpringBoot Jenkins 배포 자동화 1

heekng 2022. 3. 23. 00:33
반응형

SpringBoot Jenkins 배포 자동화 1

Spring 프로젝트를 만들고, 배포를 하면서 기존 Build된 WAR 파일을 원격 서버에 전송하고, 원격 서버에서 직접 배포하는 과정이 불편하게 느껴졌다.
때문에 EC2환경에서 docker와 Jenkins를 사용하여 Github의 소스를 빌드하고, 배포하는 작업을 자동화 하려 한다.

환경
SpringBoot, jar, gradle
AWS EC2
Jenkins
Docker
Github

Jenkins 배포 과정

Jenkins를 이용한 배포 과정은 다음과 같다.

  1. SpringBoot 프로젝트 개발
  2. Github에 push
  3. Jenkins에서 build
  4. build한 결과 jar파일을 web server에 SSH 송신
  5. web server에서 jar파일 실행(배포)

Jenkins Docker 환경 설정

환경은 AWS EC2이며, 도커가 설치되어 있다고 가정합니다.

  1. 먼저 EC2 서버에서 Jenkins image를 다운로드 받는다.
# jenkins 이미지 다운로드
docker pull jenkins/jenkins:lts
  1. Jenkins를 컨테이너에 올려 Run한다.
# jenkins 컨테이너 활성화
docker run -d -p 9090:8080 --name [Jenkins container name] -u root jenkins/jenkins:lts
  • [Jenkins container name]: Jenkins 컨테이너의 이름을 입력
  • -d: detached mode, 백그라운드에서 컨테이너가 실행되게 한다.
  • -p: 서버의 9090포트와 컨테이너 내부 8080포트를 연결한다.
  • -v: 서버의 /home/jenkins경로와 컨테이너 내부 /var/jenkins_home경로를 마운트한다.
  • --name: 실행될 컨테이너의 이름을 jenkins-docker으로 설정한다.
  • -u: 실행할 사용자를 root으로 설정한다.

Jenkins 기본 설정

Jenkins 환경을 사용하기 위한 기본 설정을 한다.

Jenkins initialAdminPassword 확인

Jenkins의 설정 페이지에 접속하기 위한 기본 패스워드를 확인한다.

# jenkins 컨테이너 접속
docker exec -it jenkins-docker /bin/bash

# 패스워드 확인
cat /var/jenkins_home/secret.key
# 출력되는 키 복사

Admin 계정 설정

  1. 서버IP:9090 포트로 접속
    • docker가 실행되는 서버 주소와 Jenkins docker를 실행할 떄 연결해둔 9090포트로 접속한다.
    • 9090포트를 열어두어야 한다.
  2. initalAdminPassword 입력하여 인증
    • 위에서 복사해둔 secret.key를 입력한다.
  3. Install suggested plugins 선택
    • customizejenkinsImage
  4. Admin 계정 생성
    • 계정명: Jenkins에 접속할 때 사용할 계정
    • 나머지 모두 입력 후 Save and Continue

SSH 설정

  1. Jenkins 접속 -> Jenkins 관리 -> 플러그인 관리
    • jenkins1
  2. Publish Over SSH 설치 후 재시작

SpringBoot web server 설정

springboot 프로젝트를 서버에 띄우기 위해 설정한다.

Dockerfile 작성

FROM ubuntu:20.04

# user setting
ENV USER [username]

# packages install
RUN apt-get update && apt-get upgrade -y
RUn apt-get install -y sudo vim net-tools ssh openssh-server openjdk-11-jdk-headless

# root ssh login enable
RUN sed -i 's/PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config
# /etc/pam.d/sshd disable
RUN sed -i 's/UsePAM yes/#UserPAM yes/g' /etc/ssh/sshd_config

# 999 groupadd groupname:username
RUN groupadd -g 999 $USER
# user add in group
RUN useradd -m -r -u 999 -g $USER $USER

# user can sudo setting
RUN sed -ri '20a'$USER' ALL=(ALL) NOPASSWD:ALL' /etc/sudoers

# password setting
RUN echo 'root:root' | chpasswd
RUN echo $USER':[userpassword]' | chpasswd

# JAVA_HOME setting
ENV JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64

# run container with ssh restart setting
ENTRYPOINT sudo service ssh restart && bash

USER $USER
  • [username]: 도커 컨테이너에 띄우는 ubuntu 서버 아이디
  • [userpassword]: 도커 컨테이너에 띄우는 ubuntu 서버 비밀번호

도커 이미지 생성

# Dockerfile의 경로
docker build -t [imageName] .
  • 작성한 Dockerfile을 기반으로 이미지를 만든다.

Docker run

docker run --name [web server container Name] -itd -p [웹서버포트]:8080 -p [ssh포트]:22 [imageName]
  • [web server container Name]: 웹 서버 컨테이너의 이름을 입력한다.
  • [웹서버포트]: 도커 컨테이너 내부 8080포트와 연결할 외부 포트를 설정한다.
  • [ssh포트]: ssh연결을 위한 포트를 설정한다.

Jenkins와 github SSH 통신 설정

Jenkins는 내부에서 빌드, 배포를 모두 해준다.
github repository의 springboot project를 Jenkins 안에서 빌드하기 위해 소스코드를 자동으로 받아올 수 있어야 하는데, SSH를 이용해 인증을 해준다.

Jenkins server ssh 생성

# jenkins 컨테이너 접속
docker exec -it [jenkins container name] /bin/bash

# .ssh 키 디렉토리 생성
mkdir /.ssh

# .ssh 디렉토리 권한 부여
chmod 700 /.ssh

# 키 생성
ssh-keygen -t rsa

# public key 확인, 출력되는 public key 복사
cat /.ssh/id_rsa.pub
  • 현재 실행되고 있는 Jenkins docker container에 직접 접속하여 ssh 키를 생성하고, public key를 복사한다.

Github에 public key 추가

  1. github 로그인
  2. 우측상단 내 프로필 - settings
  3. 좌측 탭 - SSH and GPG keys
  4. new SSH key 버튼 클릭
  5. 복사한 Jenkins 서버의 public key 입력, 저장

Jenkins와 SpringBoot web server 통신 설정

Jenkins와 Github을 연결했으니, 이제 Jenkins에서 Spring Boot으로 빌드한 jar파일을 넘겨줄 수 있도록 SSH 연결을 한다.

web server에 Jenkins publickey 등록

# 웹 서버 컨테이너 접속
docker exec -it [web server container Name] /bin/bash

# 키 등록
vi ~/.ssh/authorized_keys
# jenkins server public key 입력 후 저장
  • 웹 서버에 컨테이너에 직접 접속하여 Jenkins server의 public key를 등록한다.
  • A 서버의 public key가 B 서버에 등록되어 있다면 A 서버에서 B 서버로의 ssh 접속을 승인받을 수 있다.
  • ~/.ssh 디렉토리가 없다면 해당 디렉토리를 생성해준다.
    • mkdir ~/.ssh

Jenkins에 web server 접근 설정

  1. Jenkins 접속
  2. Jenkins 관리 -> 시스템 설정
    • jenkins2
  3. 최 하단의 Publish over SSH 설정
    • Name: Jenkins에서 식별할 서버 이름
    • Hostname: 서버주소
      • EC2의 접속 주소를 뜻한다.
    • Username: 웹 서버 계정
      • 웹 서버 Dockerfile을 생성할 때 지정한 접속 계정
    • Remote Directory: /home/[username]
      • 위 웹 서버 Dockerfile을 생성할 때 지정한 접속 계정과 동일한 이름의 경로가 /home 디렉토리 아래에 자동으로 생긴다.
    • Passphrase / Password: [userPassword]
      • 웹 서버 컨테이너를 생성할 때 지정한 접속 계정의 패스워드
    • Port: 웹 서버 컨테이너를 생성할 때 컨테이너 내부 22번 포트와 연결한 외부 포트 번호 입력
  4. Test Configuration
    • EC2의 경우 보안 그룹 설정을 통해 컨테이너 내부 22번 포트와 연결된 외부 포트를 개방하여아 한다.
  5. 저장

Github 연결

  1. Jenkins 접속
  2. 새로운 Item
  3. Item name입력, Freestyle project 선택 후 ok
    • Item name은 Jenkins에서 관리할 프로젝트 이름이다.
    • 꼭 레포지토리 이름과 동일할 필요는 없다.
  4. 소스코드 관리 -> Git 선택
  5. Repository URL 입력
    • jenkins3
    • 위 이미지와 같이 Code - SSH를 선택해 나오는 URL을 넣는다.
  6. Credential Add
    • kind: SSH Username with private key
    • ID: jenkins
      • 도커 이미지에서 자동 설정된 id이다.
    • Username: 저장할 key의 식별 이름
    • private key: jenkins private SSH key
      • jenkins 컨테이너에 접속 후 cat /.ssh/id_rsa.pub 하여 출력되는 내용 복사, 붙여넣기
      • 또는 vi /.ssh/id_rsa.pub하여 조회되는 키 복사하여 붙여넣기
  7. Name, Refspec: 미지정하여도 무관
  8. Branch Specifier: github의 branch
    • main branch라면 */main과 같이 입력한다.
    • jenkins에서 github repository를 clone할 떄 기준으로 삼는 branch를 설정하는 것이다.

Build, Deploy 설정

이제 git, Jenkins, web server간의 연결이 끝났다.
Jenkins 내부의 build 설정과 빌드가 끝난 이후 jar파일을 웹 서버에 넘기고, 배포하는 과정을 설정한다.

build 설정

  1. Jenkins item 진입 -> 구성
  2. Build 탭 선택
    • User Gradle Wrapper 선택
    • Make gradlew executable 체크
  3. Tasks: clean build 입력
    • build 하기 위한 gradle 명령어를 입력하는 것이다.

deploy 설정

  1. Jenkins item 진입 -> 구성
  2. 빌드 후 조치 탭 선택
  3. SSH Sever 선택
    • 위에서 생성한 서버를 선택한다.
  4. Transfers 빌드 후 배포과정 설정
    • Sourcefile: build/libs/*.jar
      • 빌드 후 jar 파일이 존재하는 경로는 build/libs이며, 해당 경로 내에 있는 jar 파일을 모두 선택한다.
    • Remove prefix: build/libs
      • Jenkins의 파일 경로를 제외하기 위해 작성
    • Remote directory: web server에 저장될 경로
      • 편한 경로에 지정하면 된다.
      • 이 예제에서는 /프로젝트명/target 경로로 설정했다.
    • Exec command: sh /home/heekng/[프로젝트명]/target/run.sh
      • Exec command에서는 jar 파일 이동이 끝난 후 web server에서 실행할 shellscript를 작성한다.
      • 이번 예제에서는 jar파일을 실행하는 스크립트를 /home/heekng/[프로젝트명]/target/run.sh 경로에 저장해 두었기 때문에 위 경로에 있는 shellscript를 실행하도록 명령어를 작성했다.
      • 개개인의 서버마다 경로는 다르다. 꼭 확인하고 본인에게 맞는 경로를 작성하자.
  5. 저장

Shellscript 작성

echo "GET PID"

FIND_PID=$(ps -ef | grep java | grep [프로젝트명] | awk '{print $2}')

echo "FIND_PID: {$FIND_PID}"

sudo kill -9 $FIND_PID
sleep 10

echo "Deploy Project"

nohup java -jar /home/heekng/[프로젝트명]/target/[build된 jar 파일].jar >> /home/heekng/[프로젝트명]/logs/serverlog.log 2>&1 &

echo "deploy End"
  • 이미 프로세스가 실행중일 경우 서버를 내리고 다시 실행해야 한다.
  • 이미 실행중인 프로세스 중에 [프로젝트명]이 적혀있는 PID를 찾는다.
  • 해당 PID 프로세스를 죽인다.
  • 백그라운드에서 jar파일을 실행하고, 서버에서 출력되는 로그는 /home/heekng/[프로젝트명]/logs/serverlog.log에 저장되도록 설정한다.
    • nohup명령어는 로그아웃하여 세션이 끊기더라도 프로세스는 죽지 않도록 설정하는 것이다.
    • 마지막 & 는 백그라운드에서 실행함을 뜻한다.

Build & Deploy Test

이제 설정이 끝났으니 테스트를 해보자.

  1. Jenkins 내부 프로젝트를 선택하고
  2. 좌측의 Build Now를 클릭한다.
    • jenkins4

좌측 하단의 Build History를 통해 빌드 및 배포가 성공적으로 진행되었는지 확인 가능하다.
초록색 체크표시와 함께 Success가 확인되면 서버IP:web서버port로 접속을 테스트한다.

jenkins5

나의 경우 9000포트를 열어두었다.
비어있는 프로젝트를 배포한 상태이므로 whitelabel error page가 정상적으로 확인된다.

github, jenkins, docker를 이용하여 springboot 프로젝트를 빌드, 배포하는 과정을 진행했다.
이제 다음 포스팅에서 완전 자동화 배포를 구현해보자.

반응형