Infra/CI, CD

[Jenkins] 젠킨스 빌드 후 EC2 배포 하기 - Publish Over SSH

민돌v 2023. 4. 11. 21:27

===== Jenkins 간단 CI/CD 구축해보기 Series.  =====

 

 

 

이제 Jenkins 에서 빌드가 완료되면, EC2  ubuntu 서버에 .jar 파일이 자동으로 배포되어 기존의 실행중이던 프로세스를 종료하고

새롭게 빌드되어 생성된 따끈따끈한 .jar 파일을 실행하고자 합니다.

 

[목차]

  1. jenkins ssh 플러그인 설치
  2. jenkins ssh 연결 시스템 설정
    • 리눅스 계정 생성
    • SSH SHA1 방식 접속 허용
  3. Jenkins Job 빌드 완료후 배포

 


 

1. Publish Over SSH 플러그인 설치

.jar 파일의 송신을 Jenkins "Publish Over SSH" 플러그인을 사용하여 SSH 통신으로 넘기고자 합니다.

  • [Jenkins 관리] → [플러그인 관리] → [설치가능 플러그인] → Publish Over SSH 검색

 


 

2. Jenkins 시스템 설정

1) 이제 플러그인을 사용하기 전에, Jenkins 서버에서 EC2 서버에 연결할 수 있도록 설정합니다.

  • [젠킨스 관리] → [시스템 설정] → 하단에 [Publish over SSH]
  • Key에는 AWS EC2 인스턴스 생성 시 발급받은 RSA 키가 필요합니다. EC2 생성할 때 받은 ssh 접속 키인 pem 파일내용을 붙여넣기를 하면 됩니다.

 

2) 그 후, 하단에 SSH Servers 를 추가합니다.

  • Name: 본인이 사용할 임의의 SSH Server의 Name을 입력하면 됩니다. (자유롭게 지정)
  • Hostname: 실제로 접속할 원격 서버 ip, 접속 경로를 입력합니다. ex) 퍼블릭 IPv4 주소: 3.37.87.X
  • Username: 접속할 원격 서버의 user 이름입니다. ex) ec2-user입니다. (💡ssh 접속 계정 ID)
  • Remote Directory: 원격서버에서 접속하여 작업을 하게 되는 디렉토리 입니다.

👏🏻 근데 임의로 Name 과 Username 을 작성하니 [jenkins.plugins.publish_over.BapPublisherException: Auth Fail] 이 떴습니다

  • 접속하려는 username 이 접속하려는 서버의 ssh username 이 아니기 때문입니다.

📌 EC2 Ubuntu 에서 SSH 접속 계정 만들기 → 여기까지 하면 터미널에서 ssh 생성한_id@공개 ipv4 주소 접속까지는 되실 겁니다

ubuntu 계정 생성하기 👇

더보기

1. adduser 로 아이디를 만들어줍니다.

2. new_user 홈 디렉토리에 .ssh 폴더 생성

  • sudo mkdir /home/new_user/.ssh

3. authorized_key 파일 복사

  •  sudo cp /home/ubuntu/.ssh/authorized_keys /home/new_user/.ssh   (ubuntu)

4. 권한 변경

  • sudo chown -R new_user:new_user /home/new_user/.ssh

5. sudo 권한 주기

  • sudo usermod -aG sudo new_user (ubuntu)

6. sudoers 파일 등록

  • sudo chmod 640 /etc/sudoers
  • sudo vi /etc/sudoers
    • root    ALL=(ALL:ALL) ALL
      new_user   ALL=(ALL:ALL) ALL

7. openssh-server 패키지 설치

  • sudo apt update
  • sudo apt install openssh-server

8. 만약 ufw사용중이라면 ssh를 허용

  • sudo ufw allow ssh

9. ssh 로그인 접속 허용

  • sudo vi /etc/ssh/sshd_config
    • PermitRootLogin yes
    • PasswordAuthentication yes

10. SSH 재시작

  • sudo systemctl restart ssh 혹은 sudo systemctl restart sshd

 

📌 SSH 터미널 접속은 되지만 여전히 젠킨스 pubilc over ssh 플러그인 접속은 Auth Fail : permission denied 일 때 문제해결 방법

  • ubilc over ssh플러그인이 SHA2 방식으로 접속을 안하고 SHA1 방식으로 접속시켜서 그런 것 같다고 합니다.
  • 높은 버전의 Ubuntu(혹은 OpenSSH)는 SHA1 방식을 허용하지 않아서 접속이 안되는 것이라는 추측입니다.
  • ubuntu 버전을 18.0.4 로 낮췄을 때는 접속이 되는 경우도 있다고 하네요

Jenkins Auth Fail 해결하기👇

더보기
우분투 기준 /etc/ssh/sshd_config 에 다음 두줄을 추가하고

PubkeyAuthentication yes
PubkeyAcceptedKeyTypes +ssh-rsa

sshd 서비스 재시작 하니까 문제가 해결되었습니다

sudo service sshd restart

 

성공!

 


 

3. Jenkins 빌드 안료 후 EC2 에 배포하기

자! 그러면 이제 빌드 완료시 연결한 SSH 방식으로 jar 파일을 전송하고 실행해봅시다!

  • [Jenkins job] 클릭 - [구성] - 쭈욱 내려서 [빌드 후 조치] 탭
  • 빌드 후 조치 추가를 누르면 Send build artifacts over SSH가 추가되어 있습니다.

 

선택하면 SSH 정보와 전송할 파일, 전송 이후 작업 등을 추가해야 합니다. SSH Server 정보는 위에서 추가한 "api-server" 가 기본적으로 세팅되어 있습니다.

  • Source files -  젠킨스 프로젝트 이름까지의 경로가 기본으로 잡혀있다. ( $JENKINS_HOME/workspace/$JOB_NAME/ 이하 경로) 이후 build/libs 아래 생성되는 jar파일을 지정해줍니다. 와일드카드를 활용할 수 도 있습니다..(*.jar)
  • Remove prefix -  SSH 로 접속/파일 전송 시 source files 에서 제거할 prefix
  • Remote directory - 젠킨스에서 SSH로 접속한 이후 소스 파일을 업로드할 경로를 지정합니다. 기본으로 ssh 계정의 home 디렉토리를 본다. 아래 /deploy는 /home/jenkins-ssh/deploy와 같습니다.
  • Exec command - Remote directory로 이동 후 여기에 입력되어있는 명령어를 실행한다. 입력창이 textarea로 되어있어 대각선 아래를 드래그하면 입력 창을 늘릴 수 있습니다.

 

start_server.sh

  • 쉘 스크립트 실행 파일은 미리 ec2 에 만들어 놓았습니다.
  • 기존에 실행인 프로세스가 있다면 순차적으로 종료하고 ( kill -15) 배포된 jar 파일을 실행합니다.
    • nohup : jar 파일을 백그라운드로 실행시킵니다.
    • >> ~/~_api.log : 출력되는 로그들을 특정 경로의 특정 파일의 이름으로 보관합니다. (저는 배포 날짜마다 로그 파일을 만들어주길 선택했습니다.)
    • 2>$1 
      • 이걸 하지 않으면 jenkins 의 쉘스크립트가 계속 실행되다가 unstable 로 끝납니다.
      • > (redirect) , 2 (표준 에러 출력), & (출력), 1(표준 출력) : 표준에러는 표춘 출력에 표시해라
      • 즉 표출출력과, 표준 에러 출력까지 전부 ~~_api.log 파일에 전부 리다이렉트되어 출력시켜 다시 젠킨스 프롬프트로 돌아가 작업을 맞치도록 합니다.
#! /bin/sh

echo "Java Version"
java -version

echo "Start Spring Boot Application!"
CURRENT_PID=$(ps -ef | grep api-0.0.1-SNAPSHOT.jar | grep java | awk '{print $2}')

echo $CURRENT_PID

if [ -z $CURRENT_PID ]; then
        echo ">현재 구동중인 어플리케이션이 없으므로 종료하지 않습니다."

else
        echo "> kill -15 $CURRENT_PID"
        kill -15 $CURRENT_PID
        sleep 10
fi

echo ">어플리케이션 배포 진행!"

nohup java -jar ~/deploy/api-0.0.1-SNAPSHOT.jar >> ~/deploy/logs/$(date '+%Y-%m-%d')_api.log 2>&1 &

 

 

성공...!!! 이렇게 젠킨스로 CI/CD 구축 끝..!!!

 

비록 무중단 배포는 아니지만 일단 개발을 하면서 필요한 부분까지 인프라 구축을 전부 손수 직접했다는게 너무 기분이 좋네요!!

 

+ 🚨 마주친 에러

  • jenkins 에서 ssh 로 실행되어질 때, 터미널에서 접근한 것과 다르게 java version 이 sdk man 으로 설정한 버전과 다르게 11 이 나와 jenkins sh 실행이 되지 않는 버그가 있었습니다.
  • 이렇게 된 이유도 잘 모르겠고, jenkins ssh 로 접근했을 때 출력되는 java home 도 jenkins 의 java home 이 출력되는거로 보아 젠킨 별도의 설정이 있나 봅니다.. 자포자기로 sdkman 설정 그대로 두고 openjdk-17 을 ssh 로 연결하려는 ec2 에 설치했더니 해결되었습니다..
  • error code : Error: LinkageError occurred while loading main class org.springframework.boot.loader.JarLauncher
    java.lang.UnsupportedClassVersionError: org/springframework/boot/loader/JarLauncher has been compiled by a more recent version of the Java Runtime (class file version 61.0), this version of the Java Runtime only recognizes class file versions up to 55.0

참고