안녕!
우아한테크코스 5기 [스탬프크러쉬]팀 깃짱이라고 합니다.
이번 포스팅 주제는 스탬프크러쉬의 스프링부트 애플리케이션 배포 자동화 과정이다.
포스팅에서 잘못된 내용이 있다면 댓글로 언제든 알려주세요
💋 배포 자동화의 필요성
대체 배포 자동화는 왜 해야 하는걸까?
우리 서비스는 단지 코드를 썼다고 작동하는게 아니다.
우리 팀은 GitHub 저장소의 develop 브랜치를 개발 서버에서 배포할 브랜치로 정했다.
즉, develop 브랜치에 변화가 있으면 = push되는 commit이 있으면, 이 코드는 개발 서버에서 그대로 배포하게 된다.
배포는 언제 해야할까? 주기적으로 월요일에 하면 되나?
배포 수동화는 지난 레벨에서도 실컷 했지만, 조금 힘들다.
새로운 commit이 push될 때마다, 동작하지 않는 테스트 코드가 있는데 그대로 코드가 병합된 건 아닌지 살펴야 하고, 코드가 build되는지 확인해야 한다. 이 확인 작업을 마치면, 실제로 개발한 애플리케이션을 띄울 서버(주로 클라우드를 사용하겠쬬)에 접속해서 직접 배포 명령어를 입력해야 한다. 이 작업이 귀찮아서 스크립트에 묶어서 배포할 명령어들을 저장해 놓기도 하는데, 이 스크립트를 실행하는 명령어는 그럼에도 입력해야 한다.
(그래도 자동화하기 싫은 사람을 위해)
부지런한 사람이 할 수도 있지 않나?
하지만 개발 서버에는 아무나 접속하는게 아니다.
기본적으로 클라우드에 있는 개발 서버(EC2)에 접속하려면 pem-key가 필요하다.
키 갖고 있는 사람이 들어가서 배포하면 되지 않나?
하지만 개발 서버는 아무나 접속하면 안되기 때문에, 주로 보안이 철저하다.
방화벽이 존재하는 경우도 있어서, 특정 IP 대역에서만 접속할 수 있는 경우도 굉장히 많다.
그러면, 내가 로컬에서 작업한 코드를 공통 개발 브랜치에 병합한 뒤에는 회사로 달려가서 회사 IP를 사용해 개발 서버에 들어간 뒤에 배포 스크립트를 작동하면 된다. (그냥 자동화 하자)
💋 스탬프크러쉬가 선택한 툴
✔ Jenkins 도입 이유
CI, CD 툴은 젠킨스 외에도 Buildkite, Github Actions, GitLab CI/CD, Bitbucket Pipelines, Circleci 등 정말 많다.
우리팀은 아래와 같은 이유로 젠킨스를 도입했다.
1. 사용자가 많아 레퍼런스가 정말 많은 툴이기 때문이다.
2. 플러그인이 많아서, 깃허브와 연동, 다른 클라우드 서버와의 통신 등등 편리한 기능이 많다.
✔ Docker 도입 이유
젠킨스를 설치하는 데 있어서, 필요한 환경을 단지 컨테이너만을 받아와서 사용하면 된다는 점이 매력적이었다.
(물론 이 생각은 도커 컨테이너를 사용한 젠킨스 설정이 복잡해서 중간에 이게 맞나... 하긴 했었다.)
이걸 미리 생각하는건 웃기지만, 서비스 사용자가 많아졌을 때, 도커가 좋은 이유에 대한 포스팅도 읽었는데 좋다고 생각했다.
💋 배포 자동화의 과정
✔ 전체적인 플로우부터 설명하겠습니다!
자동 배포 과정을 크게 보면,
1. 깃허브에서 우리가 개발 서버의 소스 코드로 사용할 develop 브랜치에 변화가 생긴다. (push 감지)
2. 깃허브에서 push를 감지하고, 젠킨스로 webHook을 보낸다.
3. 젠킨스는 깃허브 코드를 pull 받아, 빌드하고 테스트 코드를 실행한다.
4. 위 과정이 모두 성공한다면, 빌드한 파일을 개발 서버로 전송하고, 개발 서버 내의 배포 스크립트를 실행한다.
5. 배포 스크립트가 실행되면, 개발 서버에 우리 애플리케이션이 실행된다.
이중에, 1번은 깃허브에서 설정해야 할 것이고,
2~4는 젠킨스 내에서 구성으로 설정해야 한다.
5번에서 사용할 배포 스크립트는 먼저 배포 서버에 넣어놔야 한다.
✔ EC2 생성 및 Swap Memory 할당
AWS EC2 인스턴스를 생성했다. 총 3대의 인스턴스를 생성했고, 이중 한 대가 젠킨스를 통한 배포 자동화를 위한 서버다.
EC2 3대의 서버 역할 분담과 Swap Memory 할당은 지난 포스팅에 자세히 설명해 놓았다!
✔ infra 서버에 접속
infra 서버에 접속한다.
ssh -i {key.pem 이름} ubuntu@{public 아이피}
이때 key의 권한이 너무 public하거나 private하면 접속이 안될 수 있다.
key의 권한은 400으로 준다.
chmod 400 {key.pem 이름}
✔ GitHub WebHook 설정
깃허브 web hook을 설정해서 우리가 설정한 이벤트에 대해서 인프라 서버에 요청이 가도록 하자!
Payload에는 우리 인프라 서버의 IP로 요청을 보내고 뒤에 /github-webhook을 써놓으면, 이후에 인프라 서버 쪽에서 깃허브 웹훅을 트리거로 받겠다고 설정하면 인식할 수 있음!
✔ Docker 컨테이너를 통해 Jenkins 설치
설치 과정은 EC2 환경에서 도커를 활용한 젠킨스 설치하기라는 포스팅을 보면서 진행했다.
위 포스팅이 진짜진짜 설명이 잘 되어있으니, 들어가서 따라하면 될듯!
다만 우리 팀은 스프링부트 애플리케이션에서 Java 17 버전을 사용했기 때문에 젠킨스 이미지로, jenkins:lts 컨테이너가 아닌, jenkins:jdk17 컨테이너를 다운로드 받았다.
docker pull jenkins/jenkins:jdk17
2023년 7월 기준, 현재 jenkins:lts 컨테이너는 기본적으로 Java 11 버전만을 지원한다.
자바 버전 관련 문제 에러 로그에 대하여 열어보기!
빌드가 실패해서 아래와 같은 에러가 났었다.
이유는, 우리 프로젝트는 자바 17로 작성했는데, 젠킨스가 자바 11로 빌드하려고 했기 때문이다.
한번도 자바 11을 다운로드 받은 적이 없었는데, 알고보니 무심코 다운로드 받은 젠킨스 lts 이미지가 기본적으로 자바 11을 사용하고 있기 때문이었다.
![](https://blog.kakaocdn.net/dn/Fo0yD/btsoyVnBn0F/MJRZTkJjRCCsGmqwj0AiGk/img.png)
잘못된 자바 버전의 젠킨스 이미지를 다운로드 받았다면, 두 가지 방법이 있는데
1. 도커를 지워버린다. (비추)
2. 젠킨스 이미지를 지우고, 도커를 비워준 후에 다시 원하는 버전(jdk17)의 이미지로 다운로드 받는다.
도커를 비워주는 명령어다.
sudo docker container prune
[개인적 궁금증]
제나랑 jenkins/jenkins:lts를 지워주는 docker rm 명령어를 이전에 했었는데, 그렇게 하니 젠킨스 실행 시에 플러그인들이 거의 다운로드되지 않았다.....
![](https://blog.kakaocdn.net/dn/lr16H/btsou1I66CR/zhRb3bsiJSqPRLn7kBsb90/img.png)
![](https://blog.kakaocdn.net/dn/mOVso/btsozSYtAyl/h2hMq6EOiDlM1GYOTuTvH1/img.png)
한참 헤매다가 레오가 아래의 명령어를 작성하니 성공했다.
prune이 따로 어떤 의미가 더 있는지.. 궁금함!
프룬이 쾌변에 그렇게 좋다던데 장청소하는거처럼 도커를 청소하는건가?? (제나&깃짱 뇌피셜)
암튼 두 가지를 잘 설치하고, 나면 이제 젠킨스에 들어갈 수 있다.
비밀번호를 찾는 내용도 링크 걸어둔 포스팅에 있으니, 다 뚫고 들어가면!
젠킨스에 들어갈 수 있다.
(기뻐서 제나랑 같이 기념사진 찍음)
✔ Jenkins 구성 설정
구성에 대해 설정한다.
깃허브 코드 저장소 등록하면, 여기서 소스 코드를 불러오겠다고 설정함.
메모리 공간을 생각해서 최대 5개까지의 빌드 파일을 저장하기로 설정하고,
빌드가 일어나는 트리거를 깃허브 훅으로 설정한다. (앞에서 깃허브로 push가 일어나면 webHook을 보내기로 설정한 것과 관련있음!)
마지막으로 파이프라인 스크립트를 작성한다.
트리거가 감지되면 이 스크립트가 실행된다.
우리가 작성한 스크립트 내용이다.
4가지 단계로 구분해서 Stage를 지정해줬다.
pipeline {
agent any
stages {
stage('Github') {
steps {
git branch: 'develop', url: 'https://github.com/woowacourse-teams/2023-stamp-crush.git'
}
}
stage('Build') {
steps {
dir('backend') {
sh 'pwd'
sh "./gradlew bootJar"
}
}
}
stage('Test') {
steps {
dir('backend') {
sh "./gradlew test"
}
}
}
stage('Deploy') {
steps {
dir('backend/build/libs') {
sshagent(credentials: ['key-stamp-crush']) {
sh 'scp -o StrictHostKeyChecking=no backend-0.0.1-SNAPSHOT.jar ubuntu@192.168.1.193:/home/ubuntu'
sh 'ssh ubuntu@192.XXX.XX.XX "sh run.sh" &'
}
}
}
}
}
}
각 스테이지에 대해서 간략히 설명하자면,
1. GitHub 스테이지
깃허브 브랜치로부터 최근 소스코드를 pull 받아서, 인프라 서버로 가져옴.
2. Build 스테이지
받아온 소스 코드의 backend 패키지를 빌드한다.
3. Test 스테이지
소스 코드의 테스트 코드를 돌려본다.
4. Deploy 스테이지
Jenkins에 등록해둔 credentials를 사용해서 개발 서버에 빌드한 파일을 전송한다.
(credentials 등록은 다음 단계에서 할 거임! 여기 [] 안에 들어갈 말과 credentials의 id를 똑같게 하는게 중요함)
이때 sshagent 플러그인은 젠킨스 설정에서 미리 다운로드 받아놔야 하고,
개발 서버에 들어있는 run.sh 배포 스크립트 파일을 실행한다.
그리고, 하나 더 세팅이 남아있다.
마지막에 build된 파일을 개발 서버로 전송해야 하는데, 이때 pem key를 먼저 젠킨스에 넘겨줘야 젠킨스가 전송을 할 수 있다.
다음 단계에서 설정!
✔ Jenkins에 개발 서버로 접근할 수 있는 보안 키 등록
ssh 명령어로 다른 서버로 접근하기 위해서는 pem key가 필요하다.
따라서 이걸 그냥 스크립트에 넣어버릴 순 없으니깐 젠킨스에서 제공하는 credentials에 등록해서, 좀 더 안전하게 보관한다.
id로는 위에 스크립트에서 한 단어랑 반드시 똑같이 해야 한다.
✔ 개발 서버에 배포 스크립트 등록
이제 그러면 개발 서버로 들어가서 run.sh라는 이름으로 배포 스크립트를 등록해야 한다.
우리팀은 아래와 같이 작성했다.
#! /bin/bash
PROJECT_NAME=backend
CURRENT_PID=$(pgrep -f ${PROJECT_NAME}-.*.jar | head -n 1)
if [ -z "$CURRENT_PID" ]; then
echo " 실행중인 애플리케이션이 없으므로 종료하지 않습니다."
else
echo " 실행중인 애플리케이션을 종료했습니다. (pid : $CURRENT_PID)"
kill -9 $CURRENT_PID
fi
echo "\n SpringBoot 애플리케이션을 실행합니다.\n"
JAR_NAME=$(ls | grep .jar | head -n 1)
sudo -E nohup java -jar /home/ubuntu/$JAR_NAME &
이렇게 해놓으면 이제 배포 자동화가 완료되었다!
💋 배포 자동화 완료!
develop 브랜치에 push가 되면, 이제는 자동으로 모든 단계가 진행된다. ㅎㅎㅎㅎㅎ
💋 배포 자동화로 이젠 개발자를 집에서도 일 시킬 수 있다!
배포 자동화하고 크게 달라진건,
이제 개발자를 집에서도 일을 시킬 수 있다는 것이다.
ㅋㅋㅋㅋㅋㅋ이제 그냥 푸시만 하면 되는거니깐~
언제 어디서나 일을 시킬 수 있다.
아
💋 참고자료
'PROJECT > Stamp Crush' 카테고리의 다른 글
[우테코] 스탬프크러쉬 서비스 API 설계 (복잡한 요청은 여러 개의 요청으로 나눠서, 조회 API 예외 상황에 대한 정의, API의 재사용성을 통해 10시간을 절약했다) (0) | 2023.08.01 |
---|---|
[우테코] 스탬프크러쉬 팀의 서비스 기능 목록을 공유합니다! (0) | 2023.07.24 |
[우테코] 스탬프크러쉬 팀의 클라우드 서버 역할 분담: 개발 서버, 데이터베이스 서버, 인프라 서버로 분리한 이유 (6) | 2023.07.20 |
[우테코] 스탬프크러쉬 서비스 페르소나와 유저 시나리오 (feat. 페르소나 자판기 깃짱) (0) | 2023.07.20 |
[우테코] 스탬프크러쉬 서비스 개발 일정 추정: 1차 데모데이 피드백 검토, 나의 피드백 등등 (2) | 2023.07.20 |