해당 내용은 Class101의 현직 대기업 개발자 푸와 함께하는 진짜 백엔드 시스템 실무! 강의를 기반으로 작성했습니다.
😀 목표
- 배포를 자동화 하는 과정 이해하기
- Github Webhook과 jenkins로 배포 자동화 세팅하기
참고로 이번에 자동화 하는 과정에서 Docker는 사용하지 않는다.
1. 전체적인 과정 이해하기
-
먼저 Github Webhook 이란?
- 특정 이벤트가 발생 시 다른 URL로 API 호출을 할 수 있게 해주는 역할
-
자동화 적용 후 예상 과정
- CPU 바운드 애플리케이션을 로컬에서 수정한 후 Github에 push한다.
- Github Webhook이 동작해 jenkins에게 API 요청을 날린다.
- jenkins는 Github로부터 온 API 요청을 받아서 저장소의 소스코드를 다운받고 스프링 부트
프로젝트를 빌드하여 JAR파일로 만든다.
- jenkins가 JAR파일을 CPU 워커 인스턴스들에 배포하고 실행시킨다.
-
자동화 적용을 위한 작업 과정
- Github 에서 jenkins로 API요청이 오면 해당 리포지토리로 접근해 소스를 다운받고 JAR파일로 만들고 배포하도록 설정한다.
- Github Webhook 기능을 활성화 시킨다.
- 애플리케이션의 포트를 8080포트로 변경시킨다.
- 테스트해보면서 삽질한다.
- 자동화 성공 이후 무중단 배포를 위해 추가 설정을 한다.
2. jenkins에 Github Webhook 빌드 유발 설정
-
빌드에서 해야하는 일은 소스코드를 저장소에서 pull 받고 해당 소스코드의 의존성을 다운로드 받은 후, 애플리케이션으로 바로 실행할 수 있도록 jar파일로 묶는 행위가 포함된다.
-
위 과정을 빌드에서 수행해주면 배포될 인스턴스가 여러개 있어도 소스코드와 의존성을 다운로드 받는 과정은 오직 한 번만 이루어 지면 된다.(각 인스턴스마다 소스코드, 의존성을 다운로드 받게되면 배포시간이 늘어날 것 이다.)
2-1. 리포지토리 fork
- 해당 링크의 리포지토리를 fork한다. 내 리포지토리에 추가된다.
2-2. 리포지토리 등록
- 젠킨스가 리포지토리에 접근해서 소스를 다운받기위해 등록하는 과정이다.
- 지난번에 생성해둔 deploy → 구성 으로 들어간다.
- 소스코드 관리에서 git으로 선택하고 url에 fork한 리포지토리의 주소를 넣어주면된다.
- 이 때 그대로 리포지토리의 url이 아닌, code 버튼을 클릭해서 나오는 url을 넣어야 한다.
2-3. 빌드 유발 체크
2-4. 빌드 설정
- 젠킨스가 리포지토리에서 소스코드를 받아온 후 실행할 명령어를 입력하는 과정이다.(jar파일을 만드는 과정)
- Execute shell을 클릭하면 위와 같이 명령어를 입력할 수 있는 공간이 생긴다.
- 해당 빌드는 Github에서 받아온 소스코드를 Maven으로 jar파일을 생성해 Deploy(배포)할 준비를 해야한다.
- 그 전에 어떤 명령어를 입력해야 jar파일이 생성되는지 알아보자.
2-5. jar파일 생성 과정 살펴보기
- 빌드할 때 jar파일이 어떻게 생성되는지 살펴보기 위한 과정이다. 넘어가도 좋다.
과정 살펴보기
- 이전에 만든 CPU 바운드 애플리케이션으로 확인해보자
- 먼저 배포 시 빌드를 하기 위해 꼭 해야하는 작업은 clean과 package 작업이다.
- clean 시 target폴더 부분이 어떻게 변하는지 확인해보자.
- target 폴더가 사라진 걸 확인할 수 있다.
- package를 하니 다시 target 폴더가 생겼고 안에 jar파일도 존재한다.
그냥 간단히 생각하면
원래 있던 jar파일은 수정된 소스코드가 반영되기 전 jar파일이므로 지워주고
새로 패키징하여 jar파일을 만드는 과정이다.
이 과정을 Execute shell에다 실행해주면 되는데 mvnw라는 실행파일을 이용하면 된다.
2-6. 빌드 명령어 입력 후, 빌드
- 간단하다 위에서 확인한 것 처럼 클린과 패키징 해주는 명령어만 입력하면 된다.
- 저장을 누르고 빌드를 해보면 에러가 나온다. 콘솔 로그를 확인해보자.
- mvnw 명령어를 사용할 때 Permission denied가 뜬걸 볼 수 있다.
- 이유는 우리가 만든 CPU 바운드 애플리케이션은 윈도우에서 생성되었고
윈도우에서는 mvnw에 실행권한을 주지 못하게 때문에 애플리케이션이 리눅스 환경에 옮겨왔을 때는 실행 권한이 없다는 에러가 나온다.
2-7. 권한 추가후 다시 빌드
- 권한이 없다면 권한을 추가해주자. ./mvnw 명령어에 544로 실행권한을 준다.
- 강의는 정상적으로 빌드가 됬는데 나는 빌드가 되지 않는다.
- 심지어 빌드 취소버튼을 눌러도 동작하지않는다. 서버가 죽어버렸다.. ssh로 접속도 안된다.
- 인스턴스를 몇번 재실행하면서 해보니 그냥 maven repository에서 의존성을 다운받느라 시간이 조금 걸리는거였다... 빨간색이 뜬다고 겁먹지말고 기다리자..
2-8. jar파일로 배포
- 처음에 말했듯이 docker를 사용하지않고 인스턴스에 jar파일을 실행시켜서 애플리케이션을 띄울거다.
- 근데 현재는 docker run 명령어를 사용해서 배포중이다. 이걸 수정해주자.
- target~~~.jar 부분 즉 jar파일의 경로를 복사한다.
- 다시 구성으로 가서 Source files를 추가하고 prefix를 제거해준다.
- 실행 명령어는 jar파일을 실행하도록 입력해준다.
- 1,2,3 인스턴스 모두 똑같이 설정해준 후 빌드해보자.
2-9. 삽질과정
-
java 명령어를 실행할 수 없다는 로그가 찍혔다.
즉 워커 인스턴스에 java가 설치가 안 되어 있다. 각 워커 인스턴스에 자바를 설치해주자.
sudo yum install -y java
-
다시 빌드해보면 지난번과 같이 빌드가 완료되지 않는다.
각 워커 인스턴스 Exec command를 아래와 같이 수정한다.
sudo java -jar cpu-0.0.1-SNAPSHOT.jar > nohup.out 2>&1 &
-
이유는 이전 글 에서 확인하자.
3. Github Webhook 설정
-
이제 우리가 코드를 수정 후 push하면 github가 젠킨스에게 API 요청을 날려야한다.
github에게 젠킨스의 ip를 알려주자.
-
깃허브 리포지토리로 돌아와서 Settings → webhooks로 들어간다.
-
Payload URL에 젠킨스의 ip와 /github-webhook/ 을 입력해준다.
-
Content type을 json으로 지정하고 Just the push event를 클릭해주면
psuh 이벤트가 발생했을 때만 웹훅이 동작한다.
4. 포트 변경
-
이전에는 도커 컨테이너를 띄우면서 8080 포트로 띄웠는데, 지금은 docker를 이용하지않고
jar파일을 실행해서 애플리케이션을 실행시키기 때문에 http 기본 포트인 80포트로 연결이 된다.
-
그런데 Nginx를 8080포트로 연결했기 때문에 애플리케이션의 포트를 8080으로 변경하고
다시 배포해야 한다.
ps -aux | grep java // 프로세스 정보 확인
sudo kill -9 [PID] // 프로세스 kill
- webhook 이벤트 설정 후 해당 리포지토리를 sourcetree를 이용해 clone 받아오자
5. 자동화 결과 확인
- 이제 github에 push하면 젠킨스가 자동으로 빌드 후 배포해줄 것이다.
- 젠킨스로 돌아와서 확인해보면 빌드를 누르지 않았는데 새로운 빌드가 생긴걸 볼 수 있다.
- 워커 인스턴스에 요청을 보내면 정상적으로 응답이 오는 걸 볼 수 있다.
- 그런데 이거는 이전에 실행된 애플리케이션 아닐까? 라는 생각이 들 수 있다.
- 테스트해보자.
6. 한번 더 자동화 확인
- 현재는 위처럼 /hello url로 요청하면 hello 메시지가 응답이 온다. 이걸 변경해보자.
- hello → hello deply로 변경 후 push해보자.
6-1. lsof 설치 후 실행 명령어 추가
- 젠킨스 설정에 와서 8080포트를 사용중인 프로세스를 죽이는 명령어를 추가해 준다.
6-2. push
- 다시 push를 해야 하기 때문에 응답 문자열을 수정해주고 다시 push 하자
- push 후 젠킨스 빌드 콘솔 로그를 확인해보면 성공적으로 빌드가 되었는데 url입력해보니
응답이 오지않는다.
- 워커 인스턴스에서 확인해보니 애플리케이션이 실행되지 않았다.
- 그래서 젠킨스에서 따로 빌드해봤는데 되지 않았고 결국 젠킨스 서버가 또 죽어버렸다.
- 젠킨스 인스턴스를 중지 후 실행시켰고 빌드해보니 다시 정상적으로 실행됬다.
- 이젠 애플리케이션에서 코드 수정 후 push 했더니 젠킨스에서 빌드를 하지 않는다.
- 확인해보니 젠킨스를 껐다가 키는 과정에서 젠킨스의 ip가 변경되어 깃허브 webhook 이벤트 설정이 동작하지 않았다. 다시 웹훅 설정에서 Payload URL을 변경해주자.
6-3. 다시 push
- push후 젠킨스에서 자동으로 빌드가 되긴 했는데 또 애플리케이션에서 응답이없다.
- 로그를 확인해보니 nohup, java 등등 프로세스를 찾을 수 없단다.
- 프로세스 죽이는 명령어랑 jar파일 실행시키는 명령어는 별도인데 한줄로 처리되는것 같다.
- 그렇다 명령어 실행부분에 한줄로 입력해놨다.
프로세스 죽이는 명령이 이후에 엔터키를 누르자..
- 이후 push하면 젠킨스에서 자동으로 빌드 후 배포한다.
애플리케이션에서 성공적으로 응답이 온다.
문제가 생긴 이유는 명령어를 한줄로 입력해서 애플리케이션이 실행되지 않았고,
그 과정에서 젠킨스 서버가 죽어버려서 재실행 하는 바람에 젠킨스 인스턴스의
ip가 변경되었고 깃헙이 젠킨스에게 API 요청을 날리지 못했다..
7. 무중단 배포 테스트
- 현재는 3개의 인스턴스가 한번에 배포되고 있어서 무중단 배포가 되지 않는다.
- 실제로 airtillery로 스크립트를 실행시키고 push해서 배포하면 502에러가 나는 요청이 존재한다.
- 여러 방법이 있지만 간단하게 배포되는동안 인스턴스에 딜레이를 주면 된다.
- 예로 sleep 5 명령어를 주게되면 5 초이후에 쉘이 명령을 입력받는다.
- 인스턴스 2,3번 실행 명령어에 sleep 30 을 추가해주자.
- 이후 테스트해보면 에러나는 요청없이 모두 처리된다.
해당 과정은 생략했다..
8. 만약 도커로 배포한다면
-
기존
-
docker 추가
-
깃허브와 젠킨스사이에 도커허브가 끼면 된다.
-
그리고 이미지에 대한 빌드를 도커허브에서 automated build 기능을 이용해서 진행한다.
-
이전에는 젠킨스가 빌드했지만 도커허브가 빌드를 한다.
-
그리고 인스턴스에서는 java -jar 명령어가 아닌 docker run 명령어로 실행하도록 변경한다.
9. 마치며
-
거의 반나절이 걸렸다.. 강의를 구매하면서 가장 궁금했던 과정 중 하나였고 내 프로젝트에 적용시켜보고자 하는 부분이였다.
-
그런데 나는 docker를 이용해서 애플리케이션을 띄었기 떄문에 이거보다 더 복잡하고 엄청난 삽질이 예상된다. 사실 할 수 없을지도 모른다..
-
그래서 일단은 docker를 이용하지않고 위 과정과 똑같이 먼저 내 프로젝트에 적용해보고
성공하면 이후에 docker를 이용해서 자동화 해볼 생각이다.