Nginx 무중단 배포하기

SeonKyum·2021년 12월 22일
1

백엔드 개념

목록 보기
2/23

참고 : https://jojoldu.tistory.com/267?category=635883

https://velog.io/@swchoi0329/NGINX-무중단-배포

  1. 무중단 배포 구조
    1. 하나의 EC2서버에 하나의 NGINX와 2대의 스프링부트 서브를 이용하는 것
    2. 클라이언트의 요청을 NGINX가 받아서 8081port로 넘겨준다
    3. 신규 버전이 나오면 8082 포트로 배포한다. 정상 구동이 확인되면, NGINX를 reload한다음에 8082포트를 바라보게 만든다

      스프링부트 세팅

      무중단 배포 테스트용 Controller를 만들어준다
      import lombok.RequiredArgsConstructor;
      import org.springframework.core.env.Environment;
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.RestController;
      
      import java.util.Arrays;
      
      @RestController
      @RequiredArgsConstructor
      public class ProfileController {
          private final Environment env;
          
          //현재 어떤 포트로 돌아가는지 확인용. set1 = 8081, set2 = 8082
          @GetMapping("/profile")
          public String profile() {
              //현재 동작중인 프로파일의 이름을 반환
              return Arrays.stream(env.getActiveProfiles()).findFirst().orElse("");
          }
          
          //무중단배포 테스트를 위한 version 확인용. 새로고침하면 return 값이 자동으로 바뀌는지
          @GetMapping("/version")
          public String checkVersion() {
              return "ver2";
          }
      
      }
      application.properties에 profile 추가해보기
      spring.profiles.active=local
      localhost에서 구동 후, "/profile" API를 실행시키면 아래와 같이 나온다 WebSecurityConfig에 URI 권한 설정해주기
      //nginx관련
                      .antMatchers("/profile").permitAll()
                      .antMatchers("/actuator/**").permitAll()
                      .antMatchers("/health").permitAll()
                      .antMatchers("/version").permitAll()

      ec2 서버에 prod-application.yaml 만들어주기

      filezila에서 app폴더 만들어주기 app 폴더 안에 config폴더 만들어주기 config 폴더 안에 prod-application.yaml파일을 생성해준다. —-를 통해서 여러개의 profile을 만들어줄 수 있다. 8081로 동작하는 set1과 8082로 동작하는 set2를 만들어준다
      ---
      spring:
        config:
          activate:
            on-profile: set1
      
        datasource:
          url: jdbc:mysql://joopging-database-1.cjamvr086z6d.ap-northeast-2.rds.amazonaws.com:3306/Joopging_Database_1
          username: admin
          password: joopging1029
      
        jpa:
          hibernate:
            ddl-auto: update
      
        jackson:
          serialization:
            fail-on-empty-beans: false
      jwt:
        token:
          key: skldjficmnwl123kclknmcnfklsdkskmxxfofohue;
      
      server:
        port: 8081
      
      ---
      spring:
        config:
          activate:
            on-profile: set2
      
        datasource:
          url: jdbc:mysql://joopging-database-1.cjamvr086z6d.ap-northeast-2.rds.amazonaws.com:3306/Joopging_Database_1
          username: admin
          password: joopging1029
      
        jpa:
          hibernate:
            ddl-auto: update
      
        jackson:
          serialization:
            fail-on-empty-beans: false
      
      jwt:
        token:
          key: skldjficmnwl123kclknmcnfklsdkskmxxfofohue;
      
      server:
        port: 8082
      스프링 프로젝트의 Build파일을 app폴더에 옮겨주기 명령어를 통해 jar를 실행시켜준다. 이때 뒤에 특정 port로 실행시키기 위한 명령어가 따라 붙는다
      	nohup java -jar Joopging-0.0.1-SNAPSHOT.jar --spring.config.location=file:config/prod-application.yaml --spring.profiles.active=set1 &

      NGINX 설치 및 실행

      먼저 자바를 설치해준다
      # 업데이트 해주기
      sudo apt-get update 
      # 자바 설치
      sudo apt-get install openjdk-8-jdk 
      # 자바 버전 확인
      java -version
      그다음 nginx를 설치 및 실행한다
      sudo apt-get install nginx
      
      sudo service nginx start
      
      sudo service nginx status
      nginx는 80번 포트로 구동되기 때문에 ec2에서 80포트를 열어준다 ec2 서버에 접속시 아래처럼 뜨면 성공.

      Nginx가 받은 요청을 스프링서버가 열린 port로 보내주는 설정하기

      port 관련 설정이 담긴 파일을 열어준다
      sudo vim /etc/nginx/sites-enabled/default
      아래의 명령어 두개를 추가해주는데
      include /etc/nginx/conf.d/service-url.inc;
      proxy_pass $service_url;
      이 위치에 추가해준다 그리고 etc/nginx/conf.d 디렉터리로 이동해서 service-url.inc 파일을 생성해준다
      sudo vim service-url.inc 
      파일생성 후 내용을 아래처럼 입력 후 저장한다
      set $service_url http://127.0.0.1:8081;
      방금의 설정들이 바로 80포트로 온 요청들을 nginx가 8081포트로 보내주는 설정을 한것이다. 이제 nginx를 재시작해준 후, 다시 브라우저에서 ec2로 들어가서 profile uri 요청을 보내면 아래처럼 잘 나온다. (원래는 set1이 나와야함. 나중에 찍은거라 set2가 돌아가는중이다)

      무중단 배포 관련 설정해주기

      재시동 쉘 스크립트 만들어주기 처음에 만들어준 app 디렉토리 안에 deploy.sh 파일 만들어주기
      sudo vim 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
      
      echo "> $IDLE_PROFILE 배포"
      sudo fuser -k -n tcp $IDLE_PORT
      sudo nohup java -jar /home/ubuntu/app/Joopging-0.0.1-SNAPSHOT.jar --spring.config.location=file:/home/ubuntu/app/config/prod-application.yaml --spring.profiles.active=$IDLE_PROFILE &
      
      echo "> $IDLE_PROFILE 10초 후 Health check 시작"
      echo "> curl -s http://localhost:$IDLE_PORT/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
      
      /home/ubuntu/app/switch.sh
      현재 8081로 포트가 돌아간다면 8082포트를 IDLE_PORT로 설정 후, 기존 포트는 중단한다. 그리고 새로운 IDLE_PORT를 사용해서 jar를 배포해주겠다는 명령어들이다. 여기서 health check를 실행하는데 이를 위해서 인텔리제이 build.gradle에 다음 라이브러리를 추가해야 한다
      implementation 'org.springframework.boot:spring-boot-starter-actuator'
      전환 스크립트 만들어주기 전환 스크립트는 nginx가 기존에 구동되던 8081에서 8082를 가리키도록 바꿔주는 스크립트이다 위와 같이 app 디렉터리 안에 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
      쉘 권한 부여하기 방금 만든 2개의 쉘에 실행권한을 부여해준다
      sudo chmod +x deploy.sh
      sudo chmod +x switch.sh
      이제 deploy.sh 파일을 실행시키면 스크립트가 실행되면서 배포된 port가 바뀐 것을 알 수있다 이제 다시 브라우저에서 ip주소에 접근해보면, profile api의 결과가 바뀐 것을 알 수있다.
profile
차근차근,,

0개의 댓글