개발하는 두부

Nginx로 무중단 배포하기 (Maven)

by 뚜부니

무중단 배포 구조

무중단 배포는 여러 방법이 있는데, 그중 Nginx를 이용해 내부 포트를 바꿔 무중단 배포를 하는 방식에 대해 알아보았습니다.

테스트를 위해서는 1대의 Nginx와 2대의 Spring Boot jar이 필요합니다.

구조는 아래 그림과 같습니다.

8081 포트를 바라보는 nginx

사용자가 80번 포트로 접속하면 Nginx는 기존 버전의 서버 포트인 8081로 전달합니다.

8082 포트는 현재 연결된 상태가 아니므로 어떠한 요청도 받지 못하는 상태입니다.

8082 포트를 바라보는 nginx

신규 버전 배포가 필요하면 Nginx와 연결되지 않은 8082번 포트로 변경합니다.

이 과정에서 Nginx는 8081포트와 연결되어 있기 때문에 신규 배포가 아무런 영향을 끼치지 못합니다.

신규 배포가 정상적으로 완료되면 위 그림과 같이 Nginx에 연결된 포트를 8082로 변경하고 Nginx를 Reload 합니다.

Nginx Reload는 1초 이내에 실행이 완료됩니다.

 

Spring Boot 프로젝트 생성

start.spring.io 에서 신규 프로젝트를 하나 생성해줍니다.

Spring Boot Project 설정

해당 프로젝트를 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");
}
}

테스트 실행 결과는 아래와 같습니다.

profile check test code 실행 결과

프로젝트 Build

build 방법은 2가지입니다.

첫 번째는 우측 Maven 버튼을 클릭한 후 아래와 같이 Lifecycle > package를 클릭하는 방법입니다.

package 클릭으로 jar 생성

두 번째 방법은 terminal에 아래 명령어를 입력하는 방법입니다.

./mvnw package

저는 두 번째 방법으로 build 했습니다.

명령어 입력을 통해 jar 생성 결과

 

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 서버로 파일 업로드

파일 업로드가 완료되면 ec2 서버에서 jar를 실행합니다. 이때, properties는 set1으로 지정합니다.

nohup java -jar -Dspring.profiles.active=set1 *.jar &

그다음 netstat -tnlp 명령어를 통해 실행 중인 port를 확인해보면 java가 8081로 뜬 것을 확인할 수 있습니다.

8081번 포트로 실행된 jar

실제로 적용이 되었는지 8081번 포트로 접속해서 확인해보겠습니다.

크롬 업데이트는 신경 쓰지 말아 주세요.. 실습 끝나고 업데이트할 예정이에요

8081번 포트로 접속했을 때

 

Nginx 설정

이제 80번 포트로 접속했을 때 8081 포트에 대한 웹을 보여줄 수 있도록 Nginx를 설정하겠습니다.

먼저, Nginx를 설치해줍니다. (현재 실습 환경은 Ubuntu입니다.)

sudo apt update
sudo apt install nginx

설치가 완료되면 아래와 같이 nginx의 상태를 확인해봅니다.

service nginx status
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 하면 설정 파일의 내용들이 적용됩니다.

nginx 파일 설정에 대한 이미지

우선, /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;
}
}
server.conf 추가

그리고 /etc/nginx/conf.d/service-url.inc를 아래와 같이 설정합니다.

set $service_url http://127.0.0.1:8081;
service-url.inc 추가

그 후 아래 명령어를 통해 /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번 포트에 대한 내용을 불러오는지 확인해봅시다.

80번 포트로 접속했을 때 8081번 포트 접속 결과를 보여줌

 

신규 버전으로 변경

신규 버전의 jar 파일을 nginx에서 사용하지 않은 set2로 백그라운드 실행합니다.

nohup java -jar -Dspring.profiles.active=set2 *.jar &

사실 전 아까와 같은 jar를 실행시켰어요...ㅎㅎ 아무튼 네트워크를 확인해보면 8082번 포트로 실행 중인 것을 확인할 수 있습니다.

신규 jar 실행 후 추가된 8082번 포트

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

service-url.inc 변경 후 nginx reload

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

80번 포트로 접속했을 때 8082번 포트 접속 결과를 보여줌

정상 반영되면 8081번 포트에 대해서는 종료시킵니다.

# 8081번 포트 정보 확인
lsof -i:8081
# 정상 종료
kill -15 {PID 번호}
8081번 포트로 실행되는 jar 종료

 

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://velog.io/@damiano1027/Nginx-Nginx%EC%99%80-SpringBoot-%EB%82%B4%EC%9E%A5-Tomcat-%EC%97%B0%EB%8F%99

https://hgko1207.github.io/2020/11/16/linux-9/

https://kdkrkwhr.github.io/devops/2020/12/10/nginx-nonstop.html

블로그의 프로필 사진

블로그의 정보

개발하는 두부

뚜부니

활동하기