Nginx로 무중단 배포하기 (Maven)
by 뚜부니무중단 배포 구조
무중단 배포는 여러 방법이 있는데, 그중 Nginx를 이용해 내부 포트를 바꿔 무중단 배포를 하는 방식에 대해 알아보았습니다.
테스트를 위해서는 1대의 Nginx와 2대의 Spring Boot jar이 필요합니다.
구조는 아래 그림과 같습니다.

사용자가 80번 포트로 접속하면 Nginx는 기존 버전의 서버 포트인 8081로 전달합니다.
8082 포트는 현재 연결된 상태가 아니므로 어떠한 요청도 받지 못하는 상태입니다.

신규 버전 배포가 필요하면 Nginx와 연결되지 않은 8082번 포트로 변경합니다.
이 과정에서 Nginx는 8081포트와 연결되어 있기 때문에 신규 배포가 아무런 영향을 끼치지 못합니다.
신규 배포가 정상적으로 완료되면 위 그림과 같이 Nginx에 연결된 포트를 8082로 변경하고 Nginx를 Reload 합니다.
Nginx Reload는 1초 이내에 실행이 완료됩니다.
Spring Boot 프로젝트 생성
start.spring.io 에서 신규 프로젝트를 하나 생성해줍니다.

해당 프로젝트를 intellij로 열어주고, 아래 API를 추가합니다.
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 WebRestController { private final Environment env; @GetMapping("/profile") public String getProfile() { return Arrays.stream(env.getActiveProfiles()) .findFirst() .orElse(""); } }
그다음 port 변경 시 사용할 properties를 생성해줍니다.
application-set1.properties
server.port=8081
application-set2.properties
server.port=8082
추가로 jar 파일 생성 시 날짜와 시간이 기록된 파일명으로 생성하기 위해 pom.xml에 아래 내용을 추가했습니다.
<build> <plugins> ... <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>build-helper-maven-plugin</artifactId> <version>1.11</version> <executions> <execution> <id>timestamp-property</id> <goals> <goal>timestamp-property</goal> </goals> <configuration> <name>build-time</name> <!-- Usage : ${build-time} --> <pattern>yyyyMMdd-HHmmss</pattern> <timeZone>Asia/Seoul</timeZone> </configuration> </execution> </executions> </plugin> </plugins> <!--suppress UnresolvedMavenProperty --> <finalName>build/${project.artifactId}-${project.version}-${build-time}</finalName> </build>
API 테스트
API가 정상 동작하는지 테스트를 하기 위해 사용할 properties 생성해줍니다.
application-local.properties
server.port=8080
그다음 local.properties를 활성 목록으로 설정해줍니다.
application.properties
# 프로파일 활성 목록 spring.profiles.active=local
그 다음 테스트 코드를 작성합니다.
import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.test.context.junit4.SpringRunner; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = RANDOM_PORT) public class WebRestControllerTest { @Autowired private TestRestTemplate restTemplate; @Test public void ProfileCheck () { //when String profile = this.restTemplate.getForObject("/profile", String.class); //then assertThat(profile).isEqualTo("local"); } }
테스트 실행 결과는 아래와 같습니다.

프로젝트 Build
build 방법은 2가지입니다.
첫 번째는 우측 Maven 버튼을 클릭한 후 아래와 같이 Lifecycle > package를 클릭하는 방법입니다.

두 번째 방법은 terminal에 아래 명령어를 입력하는 방법입니다.
./mvnw package
저는 두 번째 방법으로 build 했습니다.

Jar 업로드 및 실행
terminal에서 아래 명령어를 입력하여 서버로 파일을 업로드합니다.
scp -i {cer 위치} {업로드 하려는 파일명} {username}@{aws ip}:{파일 업로드 위치} # ex. scp -i /Users/subin/.ssh/nginx-blue-green.cer /Users/subin/WorkSpace/nginx-blue-green-deployment/target/build/demo-0.0.1-20220423-202310.jar ubuntu@13.125.245.196:/home/ubuntu/server/

파일 업로드가 완료되면 ec2 서버에서 jar를 실행합니다. 이때, properties는 set1으로 지정합니다.
nohup java -jar -Dspring.profiles.active=set1 *.jar &
그다음 netstat -tnlp
명령어를 통해 실행 중인 port를 확인해보면 java가 8081로 뜬 것을 확인할 수 있습니다.

실제로 적용이 되었는지 8081번 포트로 접속해서 확인해보겠습니다.
크롬 업데이트는 신경 쓰지 말아 주세요.. 실습 끝나고 업데이트할 예정이에요

Nginx 설정
이제 80번 포트로 접속했을 때 8081 포트에 대한 웹을 보여줄 수 있도록 Nginx를 설정하겠습니다.
먼저, Nginx를 설치해줍니다. (현재 실습 환경은 Ubuntu입니다.)
sudo apt update sudo apt install nginx
설치가 완료되면 아래와 같이 nginx의 상태를 확인해봅니다.
service nginx status

이제 8081 포트로 프락시 될 수 있게 conf 파일을 설정해야 합니다.
/etc/nginx/nginx.conf 파일을 열어서 확인해보면 아래와 같은 문구를 볼 수 있습니다.
## # Virtual Host Configs ## include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*;
해당 내용은 nginx는 /etc/nginx/conf.d/ 에 존재하는 모든. conf 파일과 /etc/nginx/sites-enabled/ 에 존재하는 모든 파일을 include 해온다는 뜻입니다.
여기서 우리가 건드릴 곳은 sites-enabled입니다. 정확히는 sites-available에 설정 파일을 생성하고 그에 대한 심볼릭 링크를 sites-enabled에 생성해야 합니다.
그다음 nginx를 restart 하거나 reload 하면 설정 파일의 내용들이 적용됩니다.

우선, /etc/nginx/sites-available 에 .conf 파일을 생성합니다. 여기서는 server.conf로 생성했습니다.
server { listen 80; listen [::]:80; server_name _; include /etc/nginx/conf.d/service-url.inc; location / { proxy_pass $service_url; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; } }

그리고 /etc/nginx/conf.d/service-url.inc를 아래와 같이 설정합니다.
set $service_url http://127.0.0.1:8081;

그 후 아래 명령어를 통해 /etc/nginx/sites-enabled에 심볼릭 링크를 생성해줍니다.
sudo ln -s /etc/nginx/sites-available/server.conf /etc/nginx/sites-enabled
sites-enabled에 연결된 심볼릭 링크는 server.conf 외에는 모두 지워줘야 nginx.conf에 server.conf가 적용됩니다.

그다음 nginx를 restart 하거나 reload 해줍니다.
sudo service nginx restart # 또는 sudo service nginx reload
이제 80번 포트로 접속하여 8081번 포트에 대한 내용을 불러오는지 확인해봅시다.

신규 버전으로 변경
신규 버전의 jar 파일을 nginx에서 사용하지 않은 set2로 백그라운드 실행합니다.
nohup java -jar -Dspring.profiles.active=set2 *.jar &
사실 전 아까와 같은 jar를 실행시켰어요...ㅎㅎ 아무튼 네트워크를 확인해보면 8082번 포트로 실행 중인 것을 확인할 수 있습니다.

그다음 service-url.inc를 8082번 포트로 변경하고 nginx를 reload 합니다.

다시 웹 페이지에 접속해보면 8082번 포트와 연결되어 set2를 보여주는 것을 확인할 수 있습니다.

정상 반영되면 8081번 포트에 대해서는 종료시킵니다.
# 8081번 포트 정보 확인 lsof -i:8081 # 정상 종료 kill -15 {PID 번호}

CentOS는 어떻게 작성해야 할까?!
사내 서버에 무중단 배포 환경을 구성하게 되어서 CentOS에 대해 알아본 내용도 추가로 정리합니다.
위의 내용을 기반으로 CentOS 관련 설정 일부만 추가한 내용이기 때문에, 위에 내용을 꼭 읽어주세요! 😄😄
CentOS의 경우, nginx 라이브러리가 yum 저장소에 없기 때문에 라이브러리를 먼저 추가해야 합니다.
sudo vi /etc/yum.repos.d/nginx.repo
/etc/yum.repos.d/nginx.repo 내용은 아래와 같이 작성합니다.
[nginx] name=nginx repo baseurl=http://nginx.org/packages/centos/7/$basearch/ gpgcheck=0 enabled=1
그 후 설치를 진행합니다.
sudo yum install -y nginx
설치가 완료되면 nginx 서비스를 등록하고 시작합니다.
sudo systemctl enable nginx sudo systemctl start nginx
CentOS는 리눅스와 다르게 바로 /etc/nginx/conf.d/default.conf 파일을 수정하면 됩니다.
server { listen 80; listen [::]:80; ... include /etc/nginx/conf.d/service-url.inc; location / { proxy_pass $service_url; } }
그리고 /etc/nginx/conf.d/service-url.inc를 아래와 같이 설정합니다.
set $service_url http://127.0.0.1:8081;
그 후 restart나 reload를 해줍니다.
sudo systemctl restart nginx # 또는 sudo systemctl reload nginx
글이 길어져서 배포 스크립트에 대한 내용은 다음 페이지에 작성하도록 하겠습니다!
배포 스크립트를 사용하면 사용하는 port 확인 후 사용하지 않은 포트로 jar 파일을 실행하고 nginx service-url.inc를 수정하고 nginx를 리로드 하는 귀찮은 과정들을 줄일 수 있어요.😎😎
Nginx로 무중단 배포하기 - Script 추가
이전 글을 아직 보시지 않았다면 읽고 와주세요. Nginx로 무중단 배포하기 무중단 배포 구조 무중단 배포는 여러 방법이 있는데, 그중 Nginx를 이용해 내부 포트를 바꿔 무중단 배포를 하는 방식에
subin-0320.tistory.com
🔗 참고
https://devlog-wjdrbs96.tistory.com/309
https://hgko1207.github.io/2020/11/16/linux-9/
https://kdkrkwhr.github.io/devops/2020/12/10/nginx-nonstop.html
블로그의 정보
개발하는 두부
뚜부니