HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
♥️
2기 최종 프로젝트 팀별 공간
/
[팀 BackFro💯] ArtZip: 세상 모든 전시회를 한 번에
[팀 BackFro💯] ArtZip: 세상 모든 전시회를 한 번에
/
☠️
백엔드 기술 문서
/
♾️
CI/CD 무중단 배포 with Jenkins
♾️

CI/CD 무중단 배포 with Jenkins

JEKINS EC2 Docker Nginx Spring Boot
 
아래 블로그를 따라 실습해본 CI/CD와 무중단 배포에 대하여 제 삽질을 섞어 정리합니다. 무중단 배포 방식은 Blue/Green 방식을 이용합니다. 잘못된 내용 또는 오타가 있을 수도 있습니다. 혹시 그런게 있다면 코멘트 남겨 주세요!
코프링 CI/CD 무중단 배포 (with jenkins,docker,nginx)
우클릭 후 새 탭에서 이미지 열기 클릭하면 큰 이미지로 볼수 있습니다. 기존의 서버는 살려두면서 Blue/Green 배포전략을 사용해 무중단 배포를 구현했습니다. 원래 쿠버네티스를 통해 구현할까 했었는데 관리형 쿠버네티스를 사용하는게 아닌 이상 신경써야 할게 너무도 많은 쿠버네티스의 압도적인 러닝커브에 일단은 추후로 미루어 두었습니다. 현재는 DB는 연결하지 않았지만 다음 글에서는 RDS를 연결하는 것까지 해볼 예정입니다.
코프링 CI/CD 무중단 배포 (with jenkins,docker,nginx)
https://velog.io/@roo333/%EC%BD%94%ED%94%84%EB%A7%81-CICD-%EB%AC%B4%EC%A4%91%EB%8B%A8-%EB%B0%B0%ED%8F%AC-with-jenkinsdocker
코프링 CI/CD 무중단 배포 (with jenkins,docker,nginx)
 

필요한 것들

  • 배포에 사용할 백엔드 어플리케이션
    • CI/CD와 무중단 배포에 사용할 백엔드 어플리케이션이 필요합니다. 백엔드 어플리케이션은 Spring Boot를 이용하여 개발 되었으며 java 버전은 17을 사용하고 빌드툴로는 Gradle 7.4.1 을 사용하였습니다.
  • EC2
    • jenkins용 EC2와 백엔드 어플리케이션이 배포될 EC2가 필요합니다. 즉, 총 2개의 EC2가 필요합니다.
       

백엔드 어플리케이션 작성

Spring Boot 2.6.9 Java 17 Gradle 7.4.1 actuator
 
무중단 배포를 위해 아래와 같이 application.yml과 ProfileController를 작성해줍니다. ProfileController는 현재 어떤 어플리케이션이 사용되고 있는지 알려주는 역할을 합니다.
 
application.yml
spring: config: activate: on-profile: set1 server: port: 8081 --- spring: config: activate: on-profile: set2 server: port: 8082
 
ProfileController.java
@RestController @RequiredArgsConstructor public class ProfileController { private final Environment environment; @GetMapping("/profile") public String getProfile() { return Arrays.stream(environment.getActiveProfiles()).findFirst().orElse(""); } }
 
무중단 배포시 서버의 상태를 확인하기 위해 아래와 같이 actuator를 추가 합니다.
implementation 'org.springframework.boot:spring-boot-starter-actuator'
 
 

EC2 설정

Jenkins용 EC2 백엔드 어플리케이션용 EC2를 준비합니다.
  • EC2 for Jenkins
    • ubuntu 22.04
    • 인바운드 규칙
      • 유형
        프로토콜
        포트 범위
        소스
        SSH
        TCP
        22
        내 IP
        사용자 지정 TCP
        TCP
        9000
        Anywhere-IPv4, Anywhere-IPv6
    • 탄력적 IP 할당
      •  
  • EC2 for Backend Application
    • ubuntu 18.04
      • 백엔드 어플리케이션용 EC2를 ubuntu 22.04 로 사용하였을 때 Jenkins에서 연동이 안되어 ubuntu 18.04 로 사용하게 되었다.
        젠킨스 ssh로 ec2 연결중 BapPublisherException 예외..
        프로젝트 배포 자동화를 구현하면서 오랜만에 젠킨스를 사용하게 되었습니다. 예전에도 사용해봐서 그렇게 무리 없을거라.....고 생각했는데...... 빌드후 jar파일을 ec2에 던져야 하는데 젠킨스 시스템 설정후 pubilsh over ssh 설정후 'test configuration' 을해보면... jenkins.plugins.publish_over.BapPublisherException: Failed to connect and initialize SSH connection. Message: [Failed to connect session for config [server__name]. Message [Auth fail]] 이런 에러가 나왔다.
        젠킨스 ssh로 ec2 연결중 BapPublisherException 예외..
        https://velog.io/@mins1031/%EC%A0%A0%ED%82%A8%EC%8A%A4-ssh%EB%A1%9C-ec2-%EC%97%B0%EA%B2%B0%EC%A4%91-BapPublisherException-%EC%98%88%EC%99%B8
        젠킨스 ssh로 ec2 연결중 BapPublisherException 예외..
    • 인바운드 규칙
      • 유형
        프로토콜
        포트 범위
        소스
        SSH
        TCP
        22
        내 IP
        SSH
        TCP
        22
        EC2 for Jenkins 의 탄력적 IP
        HTTP
        TCP
        80
        Anywhere-IPv4, Anywhere-IPv6
        HTTPS
        TCP
        443
        Anywhere-IPv4, Anywhere-IPv6
    • 탄력적 IP 할당
    •  
EC2 인스턴스가 생성이 완료되면 ssh 접속을 통해 EC2 인스턴스에 초기 설정을 해준다. (해당 내용은 optional한 내용이니 하기 싫으면 안해도 된다.)
 
  • SSH 접속
    • pem key는 ~/.ssh 디렉토리에 저장되어있다고 가정하겠다. 우선 발급 받은 pem key의 권한을 변경한다.
      chmod 600 ~/.ssh/{pem key 이름}
      지금 상태에서는 굉장히 긴 명령어를 치고 EC2 인스턴스에 접근해야하 한다. 이는 귀찮으니 좀 더 편하게 접근할 수 있도록 설정하자. pem키가 있는 디렉토리에 config 파일을 생성하고 아래와 같은 내용을 채우고 저장한다 .
      Host {원하는 이름} HostName {인스턴스 탄력적 IP} User {username} IdentityFile ~/.ssh/{pem key}
      그후 config 파일에 소유자가 rwx 권한을 부여한다.
      chmod 700 ~/.ssh/config
      이제ssh {원하는 이름}을 입력하면 ec2 인스턴스에 접근할 수 있다.
       
  • 인스턴스 초기 설정
    • Hostname 변경
      • 현재 Hostname이 IP로 주어져 있어 이게 Jenkins용 EC2인지 어플리케이션용 EC2인지 구분이 안가는 경우가 있다. Hostname을 알기 쉽게 변경하도록 하자.
        sudo vi /etc/hosts → 127.0.0.1:localhost를 127.0.0.1:{원하는 이름}으로 변경 → 저장 sudo vi /etc/hostname → ip-~~~를 앞에서 설정한 {원하는 이름}으로 변경 → 저장 sudo reboot를 이용해 재부팅
    • 서버 타임존을 UTC에서 KST로 변경
      • sudo rm /etc/localtime sudo ln -s /usr/share/zoneinfo/Asia/Seoul /etc/localtime
        이후 EC2에 date라고 입력해보면 변경된 타임존을 확인할 수 있다.
    • EC2에 인스턴스에 docker 설치
      • sudo apt update sudo apt install apt-transport-https ca-certificates curl software-properties-common curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable" sudo apt update apt-cache policy docker-ce sudo apt install docker-ce
        우분투 18.04 도커(Docker) 설치 방법 - 코스모스팜 블로그
        안녕하세요 코스모스팜 입니다. 도커(Docker)는 응용 프로그램들을 소프트웨어 컨테이너 안에 배치시키는 일을 자동화하는 오픈 소스 프로젝트입니다. 가상머신(Virtual machine)과 비슷하지만 도커의 컨테이너는 더 이식성이 뛰어나고 리소스 친화적이며 호스트(Host) 운영 체제에 더 많이 의존합니다. 가상머신 환경에서는 게스트(Guest) 운영 체제가 존재하지만 도커의 컨테이너에는 게스트 운영 체제가 없으며 호스트 운영 체제 위에 도커 엔진이 동작됩니다.
        우분투 18.04 도커(Docker) 설치 방법 - 코스모스팜 블로그
        https://blog.cosmosfarm.com/archives/248/%EC%9A%B0%EB%B6%84%ED%88%AC-18-04-%EB%8F%84%EC%BB%A4-docker-%EC%84%A4%EC%B9%98-%EB%B0%A9%EB%B2%95/
        우분투 18.04 도커(Docker) 설치 방법 - 코스모스팜 블로그
        Install Docker Engine on Ubuntu
        Estimated reading time: 10 minutes Docker Desktop for Linux Docker Desktop helps you build, share, and run containers easily on Mac and Windows as you do on Linux. We are excited to share that Docker Desktop for Linux is now GA. For more information, see Docker Desktop for Linux.
        Install Docker Engine on Ubuntu
        https://docs.docker.com/engine/install/ubuntu/
        Install Docker Engine on Ubuntu
         
    • sudo 명령어 없이 docker 사용
      • sudo groupadd docker sudo usermod -aG docker $USER newgrp docker
        만약 이렇게 하였는데 도커 명령어를 sudo 키워드 없이 사용하였을 때 아래와 같은 warning을 본다면
        WARNING: Error loading config file: /home/user/.docker/config.json - stat /home/user/.docker/config.json: permission denied
        다음을 추가적으로 입력해주자.
        sudo chown "$USER":"$USER" /home/"$USER"/.docker -R sudo chmod g+rwx "$HOME/.docker" -R
        Post-installation steps for Linux
        This section contains optional procedures for configuring Linux hosts to work better with Docker. The Docker daemon binds to a Unix socket instead of a TCP port. By default that Unix socket is owned by the user root and other users can only access it using sudo.
        Post-installation steps for Linux
        https://docs.docker.com/engine/install/linux-postinstall/#manage-docker-as-a-non-root-user
        Post-installation steps for Linux
       
    • Jenkins용 EC2 메모리 스왑
      • 현재 EC2는 모두 프리티어를 사용하고 있다. 직접 문제를 겪지는 않았지만 공부하면서 찾아보았을 때 프리티어는 기본 메모리가 1GB밖에 되지 않으므로 Jenkins가 빌드 도중 죽어버리는 문제가 있다고 한다. 이러한 문제를 사전에 방지하기 위해서는 swap 메모리를 할당해야 한다.
        sudo dd if=/dev/zero of=/swapfile bs=128M count=16 sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile sudo swapon -s sudo vi /etc/fstab /swapfile swap swap defaults 0 0
        EC2 프리티어에서 Jenkins가 돌아가지 않는 문제 해결하기
        프리티어 계정은 램이 1GB입니다. jenkins를 돌리기엔 매우 나약나약한.....나약한.....그래서 처음에 jenkins 설정을 세팅하고 빌드를 했는데 ec2 터미널이 먹통이 되더니 아무것도 되지 않았습니다. ec2를 껐다 켜니까 되길래 다시 빌드했더니 다시 먹통이었고, 처음에는 인바운드 규칙때문인가 해서 위치 무관으로도 바꿔봤는데 해결되지 않았습니다. 그러다가 우연히 cpu 사용량을 보게 되었는데 그래프가 날뛰고 있어서 이슈에 남겨두었습니다.
        EC2 프리티어에서 Jenkins가 돌아가지 않는 문제 해결하기
        https://tape22.tistory.com/22
        EC2 프리티어에서 Jenkins가 돌아가지 않는 문제 해결하기
       
       

Jenkins

  • Jenkins 설치
    • Jenkins용 EC2에 도커를 이용하여 Jenkins를 설치한다.
      sudo docker run -itd --name jenkins -p 9000:8080 jenkins/jenkins:lts
 
  • Jenkins 접속
    • Jenkins용 EC2의 탄력적 IP:9000로 접속하여 초기 비밀번호를 입력한다.
    • 초기 비밀번호 확인
      • 참고하고 있는 블로그에서는 docker exec jenkins cat /var/lib/jenkins/secrets/initialAdminPassword 라고 하는데 docker exec jekins cat /var/jenkins_home/secrets/initialAdminPassword 가 맞는거 같다.
    • 이후 admin(아이디, 비밀번호 등)을 등록하게 되는데 여기서 입력한 것들은 나중에 접속할 때 사용해야 하니 항상 따로 저장해두자.
    •  
  • Jenkins와 github 연동
    • github의 main 브랜치에 변화(push or merge)가 있으면 자동을 pull 받아와 build를 할 수 있도록 설정해야한다.
       
      Github 프로필 클릭 → Settings 클릭 → Developer Settings 클릭 → Personal access tokens 클릭
      notion image
      notion image
      notion image
       
      아래와 같이 설정하고 토큰을 생성한다. 토큰은 반드시 기억해두자.
      notion image
       
      이후 깃허브 레파지토리의 Settings의 Webhook에서 Add Wehook을 클릭한다. 그리고 Payload URL에 Jekins용 EC2의 IP/github-webhook/ 또는 Jekins용 EC2의 도메인이름/github-webhook/ 을 입력하고 Webhook을 추가한다.
      notion image
       
      다시 Jenkins로 돌아와 새로운 item 클릭하고 Freestyle project를 생성한다.
      notion image
       
      아이템이 만들어지면 구성을 클릭하고 소스 코드 관리 섹션에가서 깃허브 레파지토리의 URL, 아까 받아놓은 Personal access token 그리고 대상 브랜치를 입력한다.
      notion image
      notion image
      Personal access token은 Credentials에 Add를 클릭하여 Kind를 Secret text로 설정하고 Secret에 입력한다.
      notion image
       
      마지막으로 빌드 유발 섹션에서 GitHub hook trigger for GITScm polling (Github에서 push에 의한 hook 이벤트가 발생할 경우 저장소를 polling해서 빌드를 유발)을 선택하고 저장한다.
      notion image
       
  • Jenkins JDK 설정
    • 현재 프로젝트는 Java 17로 작성되었고 이에 맞는 JDK를 Jenkins에 설정 해주어야 한다.
       
      Jekins 관리 클릭하고 Global Tool Configuration 클릭한다.
      notion image
       
      아래와 같이 JDK 17 설치를 설정하고 저장해주자.
      notion image
       
      마지막으로 Jekins 관리에서 시스템 설정에 들어가 환경변수를 설정해주어야 한다. JAVA_HOME이라는 변수에 Jenkins내에 앞에서 설정한 JDK가 설치된 경로를 입력해주어야 한다.
      notion image
       
  • Jenkins Gradle 설정
    • 현재 프로젝트의 Build Tool은 Gradle이므로 Jenkins에서도 이에 따른 설정을 해주어야 한다. 우선 Jenkins에 Gradle 플러그인이 설치 되었는지 확인하고 그렇지 않다면 설치해준다. 이는 Jenkins 관리에서 플러그인 관리를 통해 할 수 있다.
      notion image
       
      이후 Global Tool Configuration 의 Gradle 섹션에서 자신의 프로젝트와 맞는 Gradle을 추가하고 이를 저장한다.
      notion image
       
      마지막으로 아이템의 구성에 들어가 Add Build step 을 통해 Invoke Gradle Script를 선택하고 Gradle의 버전을 선택하고 Tasks에 Gradle 작업을 명시하고 저장한다.(당연한 이야기이지만 tasks를 명시하지 않는다면 아무일도 일어나지 않는다.)
      notion image
 
  • Jekins와 백엔드 어플리케이션 서버 연동
    • Jekins에서 빌드가 성공적으로 완료된다면 그 결과물(jar 파일)을 백엔드 어플리케이션 서버에 전달해주어야한다.
       
    • Publish Over SSH
      • 위에서 말한 빌드 결과물을 다른 서버로 보내기 위해서는 Publish Over SSH라는 플러그인을 Jenkins에 설치해주어야 한다. 해당 플러그인을 설치한 후에는 Jekins 관리의 시스템 설정에서 Publish Over SSH 항목을 작성해주어야 한다.
        notion image
      • Name : 서버 이름을 입력한다.
      • Key : EC2에 접속하기 위해 사용하는 pem 파일의 내용을 입력하면된다.
      • Hostname : 연결할 서버의 IP를 입력한다.
      • Username : 서버의 Username을 입력한다. EC2에 직접 접속하면 확인할 수 있다.
      • Remote Directory : 배포할 서버의 기본 workspace(EC2에 접속했을 때의 기본 데렉토리)를 입력한다.
      • Publish Over SSH 항목의 작성을 완료하였다면 Test Configuration을 클릭하여 성공하는지 확인한다. (실패했다면 무언가 잘못 입력한 것이다.)
         
        Publish Over SSH 항목의 작성을 완료하고 Test Configuration까지 성공하였다면 아이템의 구성으로 돌아가 빌드 후 조치 에서 Send build artifacts over SSH를 누르고 아래 사진과 같이 입력을 해줍니다.
        notion image
      • Name : 앞에서 설정한 서버 이름
      • Source files : 전송할 파일
      • Remove prefix : Source files에서 지정한 경로의 하위 폴더를 지우는 기능이다. 위의 예시같이 입력한다면 폴더를 제외하고 jar 파일만 전송하게 된다.
      • Remote directory : 백엔드 어플리케이션 서버에서 파일이 전송될 디렉토리
      • Exec command : 파일 전송이 끝난 후에 백엔드 어플리케이션 서버에서 실행될 명령어
      위의 입력 내용들은 자신이 사용하고 있는 환경에 따라 달라질 수 있다. 예시와 동일하게 작성하려 하지 말고 자신이 사용하고 있는 환경을 고려하여 입력하자.
       
      [Jenkins] [ec2] Jenkins 원격 서버 배포(Publish Over SSH)
      안녕하세요. 갓대희 입니다. 이번 포스팅은 [ Jenkins와 ec2 연결하여 배포 하기 - Jenkins - Publish Over SSH ] 입니다. : ) Jenkins와 배포서버 구성을 한 서버안에서 한다면, 이전 포스팅에서 젠킨스와 Github만 연동하여 배포, 실행하면 가능할 것이다. (참고 - 2020/06/18 - [6.
      https://goddaehee.tistory.com/259
      [Jenkins] [ec2] Jenkins 원격 서버 배포(Publish Over SSH)
 
  • .gitignore된 파일들은 어떻게 해야하나?
    • 현재 Jenkins는 main에 push 또는 merge가 되는 경우 github 레파지토리에서 코드를 가져와 빌드를 한다. 당연히 .gitignore된 파일에 대해서는 알지 못하기 때문에 빌드를 실패하게 된다. 이 문제에 대한 해결방법은 생각보다 간단하다. jekins 내부의 workspace에 .gitignore된 파일을 직접 추가해주면 된다. 현재 Jenkins는 EC2에서 Docker로 실행되고 있다. Docker 내부에 vi를 설치하기 귀찮고 힘드니 로컬의 파일을 도커 내부 지정된 위치로 복사하자.
       
      docker cp “로컬 파일” “컨테이너 이름:복사할 위치”
       
      깃허브에 없는 파일을 젠킨스에 수동으로 파일 업로드 하는방법
      젠킨스 서버 접속 후 원하는 파일 업로드 아래 경로로 가면 Item종류가 있다. 원하는 Item이름에 들어가서 경로를 확인해준다. /var/lib/jenkins/workspace/{Item이름}/{업로드한 파일을 놓을 경로..} 필자는 aws-..
      깃허브에 없는 파일을 젠킨스에 수동으로 파일 업로드 하는방법
      https://dncjf64.tistory.com/351
      깃허브에 없는 파일을 젠킨스에 수동으로 파일 업로드 하는방법
      OKKY | jenkins에서 Spring을 빌드했을경우 application.yml..
      jenkins로 github에 있는 프로젝트를 CI/CD하는데 github에는 application.yml을 gitignore설정해놔서 없습니다 jenkins를 통해 `clean build`할 경우 실패가 떠서 jenkins가 빌드할경우 생기는 폴더 /var/jenkins_home/workspace/[아이템명]/src/main/resources/ 에서 application.yml을 넣어주니까 다시 빌드하니 성공했습니다. 여기서 궁금한점이 jenkins가 빌드할 경우 github에 있는 소스코드를 다운받아서 clean build 하는데 이때 다운받은 소스코드를 /var/jenkins_home/workspace/[아이템명] 위에 완전히 덮어쓰기하는게 아닌가요?
      OKKY | jenkins에서 Spring을 빌드했을경우 application.yml..
      https://okky.kr/article/1242707
      OKKY | jenkins에서 Spring을 빌드했을경우 application.yml..
       
  • 테스트할 때 Redis가 필요하면 어떻게 해야하는가?
    • 테스트할 때 Redis가 필요하다면 Jenkins 내부에서 Redis를 따로 실행시킬 수 없기 때문에 build가 실패하게 될 것으로 생각된다. 하지만 찾아보니 embedded h2와 같이 embedded Redis도 존재하는거 같다. 이걸 사용하면 해당 문제를 해결할 수 있지 않을까?
      [Redis] SpringBoot Data Redis 로컬/통합 테스트 환경 구축하기
      안녕하세요? 이번 시간엔 SpringBoot Data Redis 로컬 테스트 예제를 진행해보려고 합니다. 모든 코드는 Github에 있기 때문에 함께 보시면 더 이해하기 쉬우실 것 같습니다. (공부한 내용을 정리하는 Github와 세미나+책 후기를 정리하는 Github, 이 모든 내용을 담고 있는 블로그가 있습니다. ) 회사 신규 프로젝트로 Redis 를 사용하게 되었습니다. 로컬에서 개발하고 테스트 할 수 있는 환경구성이 필요했는데요.
      [Redis] SpringBoot Data Redis 로컬/통합 테스트 환경 구축하기
      https://jojoldu.tistory.com/297
      [Redis] SpringBoot Data Redis 로컬/통합 테스트 환경 구축하기
      내장 Redis 설정기
      안녕하세요 :) 마크입니다! 토큰과 캐싱 개발 초기엔 내장 Redis가 존재하는지 모르고, RedisRepository 역할을 하는 객체를 직접 자바 코드로 구현하여 테스트를 진행했다. 즉, Fake 객체를 만들어서 테스트하는 방법을 택했다. 이렇게 테스트 하는 것의 가장 큰 문제는 실제 Redis 환경이 아니란 점이다..
      내장 Redis 설정기
      http://tech.pick-git.com/embedded-redis-server/
      내장 Redis 설정기
       
  • Slack alarm 설정
    • 아래 글을 참고하여 설정하자
      Jenkins 빌드 실행 결과를 Slack 알림으로 받기
      많은 개발자 분들이 개발하는 과정에서 테스트, 빌드, 배포를 자동화하는데 Jenkins를 사용하고 있습니다. 저는 개발자는 아니지만, RestAssured, Selenide 등의 도구로 테스트 코드를 작성하고 Jenkins를 통해 테스트가 자동으로 실행되도록 하고 있습니다. 그러다보니 가끔 Jenkins에 접속해서 테스트가 성공했는지 실패했는지 확인해왔습니다. 하지만, 이 글에서는 매번 Jenkins에 접속해야만 테스트 결과를 확인할 수 있었던 것을 Slack 알림으로 대체한 과정을 정리했습니다.
      https://phoby.github.io/slack-jenkins-notification/
      Jenkins 빌드 실행 결과를 Slack 알림으로 받기
 
 

무중단 배포 설정 및 스크립트

 
  • Nginx
    • Nginx 설치
      • sudo apt-get install nginx sudo service nginx start sudo service nginx status
 
  • Nginx 설정
    • sudo vim /etc/nginx/nginx.conf 를 입력하여 설정 파일을 열고 http 블록내에 아래 server 블록을 추가시켜 주자.
      server { listen 80; fastcgi_buffers 8 16k; fastcgi_buffer_size 32k; fastcgi_connect_timeout 300; fastcgi_send_timeout 300; fastcgi_read_timeout 300; include /etc/nginx/conf.d/service-url.inc; location / { proxy_pass $service_url; } }
       
      sudo vim /etc/nginx/conf.d/service-url.inc 를 입력하고 아래 내용을 작성한 후 저장한다.
      set $service_url http://127.0.0.1:8081;
       
      마지막으로 sudo service nginx restart 를 입력하여 Nginx를 재시작 해준다.
    • 주의
      • http 블록내 아래 부분을 지워주도록 하자. 안지워주면 계속 Nginx에서 기본적으로 제공하는 페이지만 보여준다.
        include /etc/nginx/sites-enabled/*;
       
  • Dockerfile 및 쉘 스크립트 작성
    • Dockerfile과 쉘 스크립트들은 블로그에 있는 것들을 카피하고 필요한 부분만 변경하였다.
       
    • Dockerfile
      • FROM openjdk:17-jdk-alpine ARG IDLE_PROFILE ARG JAR_FILE=*SNAPSHOT.jar ENV ENV_IDLE_PROFILE=$IDLE_PROFILE COPY ${JAR_FILE} /app.jar RUN echo $ENV_IDLE_PROFILE ENTRYPOINT ["java","-jar","/app.jar","--spring.profiles.active=${ENV_IDLE_PROFILE}"]
       
    • deploy.sh
      • #!/bin/bash echo "> 현재 구동중인 profile 확인" CURRENT_PROFILE=$(curl -s http://localhost/profile) echo "> $CURRENT_PROFILE" if [ $CURRENT_PROFILE == set1 ] then IDLE_PROFILE=set2 IDLE_PORT=8082 elif [ $CURRENT_PROFILE == set2 ] then IDLE_PROFILE=set1 IDLE_PORT=8081 else echo "> 일치하는 Profile이 없습니다. Profile: $CURRENT_PROFILE" echo "> set1을 할당합니다. IDLE_PROFILE: set1" IDLE_PROFILE=set1 IDLE_PORT=8081 fi CONTAINER_ID=$(docker container ls -f "name=${IDLE_PROFILE}" -q) sudo docker stop ${IDLE_PROFILE} sudo docker rm ${IDLE_PROFILE} TAG_ID=$(docker images dockerhys/practice | sort -r -k2 -h | awk 'NR > 0 {if ($1 == "dockerhys/practice") {print $2 += .01; exit} else {print 0.01; exit}}') echo "> 태그 아이디 ${TAG_ID}" echo "> 도커 build 실행 : docker build --build-arg DEPENDENCY=build/dependency --build-arg IDLE_PROFILE=${IDLE_PROFILE} -t dockerhys/practice:${TAG_ID} ." sudo docker build --build-arg DEPENDENCY=build/dependency --build-arg IDLE_PROFILE=${IDLE_PROFILE} -t dockerhys/practice:${TAG_ID} . echo "> $IDLE_PROFILE 배포" sudo docker login -u 아이디 -p 비밀번호 sudo docker push dockerhys/practice:${TAG_ID} #tag가 latest인 image를 최신 버전을 통해 생성 sudo docker tag dockerhys/practice:${TAG_ID} dockerhys/practice:latest #latest를 docker hub에 push sudo docker push dockerhys/practice:latest echo "> 도커 run 실행 : sudo docker run --name $IDLE_PROFILE -d --rm -p $IDLE_PORT:${IDLE_PORT} dockerhys/practice " sudo docker run --name $IDLE_PROFILE -d --rm -p $IDLE_PORT:${IDLE_PORT} dockerhys/practice #버전 관리에 문제가 있어 latest를 삭제 sudo docker rmi dockerhys/practice:latest echo "> $IDLE_PROFILE 10초 후 Health check 시작" echo "> curl -s http://localhost:$IDLE_PORT/actuator/health " sleep 10 for retry_count in {1..10} do response=$(curl -s http://localhost:$IDLE_PORT/actuator/health) up_count=$(echo $response | grep 'UP' | wc -l) if [ $up_count -ge 1 ] then echo "> Health check 성공" break else echo "> Health check의 응답을 알 수 없거나 혹은 status가 UP이 아닙니다." echo "> Health check: ${response}" fi if [ $retry_count -eq 10 ] then echo "> Health check 실패. " echo "> Nginx에 연결하지 않고 배포를 종료합니다." exit 1 fi echo "> Health check 연결 실패. 재시도..." sleep 10 done echo "> 스위칭을 시도합니다..." sleep 10 sudo /home/ubuntu/switch.sh
       
    • switch.sh
      • #!/bin/bash echo "> 현재 구동중인 Port 확인" CURRENT_PROFILE=$(curl -s http://localhost/profile) if [ $CURRENT_PROFILE == set1 ] then IDLE_PORT=8082 elif [ $CURRENT_PROFILE == set2 ] then IDLE_PORT=8081 else echo "> 일치하는 Profile이 없습니다. Profile:$CURRENT_PROFILE" echo "> 8081을 할당합니다." IDLE_PORT=8081 fi PROXY_PORT=$(curl -s http://localhost/profile) echo "> 현재 구동중인 Port: $PROXY_PORT" echo "> 전환할 Port : $IDLE_PORT" echo "> Port 전환" echo "set \$service_url http://127.0.0.1:${IDLE_PORT};" | sudo tee /etc/nginx/conf.d/service-url.inc echo "> Nginx Reload" sudo service nginx reload