CS/데이터베이스
Cloud - 운영 전략 2
RangA
2023. 6. 21. 18:34
웹 서버
TOMCAT
Tomcat이란?
- Apache사에서 개발한 서블릿 컨테이너만 있는 오픈소스 웹 애플리케이션 서버
- Spring Boot의 내장 서버이기 때문에 별도의 설치 과정 없이 자연스럽게 Tomcat을 사용함
- Tomcat의 특징
- 자바 애플리케이션을 위한 대표적인 오픈소스 WAS(Web Application Server)
- 오픈소스이기 때문에 라이선스 비용 부담 없이 사용할 수 있음
- 독립적으로도 사용 가능하며 Apache 같은 다른 웹 서버와 연동하여 함께 사용할 수 있음
- Tomcat은 자바 서블릿 컨테이너에 대한 공식 구현체로, Spring Boot에 내장되어 있어 별도의 설치 과정이 필요하지 않음
Tomcat 실행 및 의존성 확인하기
- IntelliJ 상단 메뉴바의 View > Tool Windows > Gradle을 클릭함
- Gradle 탭에선 프로젝트에서 추가한 의존성 모듈을 모두 확인할 수 있음
- spring-boot-starter-web 모듈의 토글을 열어보면, 해당 모듈이 포함하고 있는 다른 모듈을 확인할 수 있음
- 웹 서버를 구성하는 모듈 속엔 spring-boot-starter-tomcat 모듈도 포함하고 있음
Jetty
Jetty란?
- 이클립스 재단의 HTTP 서버이자 자바 서블릿 컨테이너
- Jetty도 Tomcat과 같이 자바 서블릿 컨테이너이자 서버로 사용할 수 있기 때문에 개발자는 원하는 서버를 선택하여 프로젝트를 구성할 수 있음
- Jetty의 특징
- 2009년 이클립스 재단으로 이전하며 오픈소스 프로젝트로 개발됨
- Jetty는 타 웹 애플리케이션 대비 적은 메모리를 사용하여 가볍고 빠름
- 애플리케이션에 내장 가능함
- 경량 웹 애플리케이션으로 소형 장비, 소규모 프로그램에 더 적합함
Spring Boot 서버 Jetty로 변경하기
- 아무런 설정을 해주지 않는다면 Spring Boot의 기본 내장 서버인 Tomcat으로 실행됨
- build.gradle 파일에서 spring-boot-starter-web 의존성이 추가되어 있는 부분을 확인하여, 이 의존성 모듈 내에 포함되어 있는 Tomcat을 제외시킴
- 제외시킨 후 프로젝트를 재 빌드하면 의존성이 제거되었음을 확인할 수 있음
- 제외시킨 후 프로젝트를 재 빌드하면 의존성이 제거되었음을 확인할 수 있음
- Tomcat을 제외했다면 대체할 서버로 Jetty 의존성을 추가함
- 추가한 후 프로젝트를 재 빌드하면 Jetty에 대한 의존성이 추가되었음을 확인할 수 있음
- 추가한 후 프로젝트를 재 빌드하면 Jetty에 대한 의존성이 추가되었음을 확인할 수 있음
implementation ('org.springframework.boot:spring-boot-starter-web') {
exclude module: 'spring-boot-starter-tomcat'
}
implementation ('org.springframework.boot:spring-boot-starter-jetty')
NginX - Proxy Server
NginX란?
- Nginx는 가볍고 높은 성능을 보이는 오픈소스 웹 서버 소프트웨어
- Tomcat과 Jetty는 자바 서블릿 컨테이너 혹은 웹 애플리케이션 서버였다면, Nginx는 웹 서버로 클라이언트에게 정적 리소스를 빠르게 응답하기 위한 웹 서버로 사용할 수 있음
- Nginx의 특징
- Nginx는 트래픽이 많은 웹 사이트의 확장성을 위해 개발된 고성능 웹 서버
- 비동기 이벤트 기반으로 적은 자원으로 높은 성능과, 높은 동시성을 위해 개발됨
- 다수의 클라이언트 연결을 효율적으로 처리할 수 있음
- 클라이언트와 서버 사이에 존재하는 리버스 프록시 서버로 사용할 수 있음
- Nginx를 클라이언트와 서버 사이에 배치하여 무중단 배포를 할 수 있음
Spring Boot와 Nginx 연동하기
- 지금까지 클라이언트는 8080번 포트를 사용하는 스프링부트로 요청을 보내고 응답을 받았으나, 이 구조에서 스프링부트 앞에 Nginx로 리버스 프록시 서버를 구축하여, 클라이언트와 서버가 Nginx를 통해서 소통할 수 있도록 함
1. NginX 설치
- Mac OS 사용자
- 터미널에 명령어를 입력함
- 설치 진행이 되지 않는다면 brew update를 진행함
brew install nginx
- Windows 사용자
- Nginx 다운로드 사이트에서 Stable 버전을 다운로드함
- 다운로드한 압축 폴더를 원하는 경로로 이동한 후 압축을 해제하며, 폴더 내에 Nginx의 실행파일과 Nginx 설정 폴더가 있으니 경로를 기억해야 함
2. NginX 실행
- Mac OS
- 설치가 완료되었다면 다음 명령어를 통해 Nginx를 실행함
- 설치가 완료되었다면 다음 명령어를 통해 Nginx를 실행함
brew services start nginx
- Windows
- 압축을 해제한 폴더의 nginx.exe를 실행함
- 실행 시 방화벽 창이 뜬다면 추가 정보 버튼을 클릭해 실행버튼을 활성화함
실행 확인
- 실행 후 localhost에 접근하여 연결이 잘 되는지 확인함
- MacOS는 8080번 포트(localhost:8080), Windows는 80번 포트(localhost:80)가 기본 포트로 설정되어 있음
3. NginX 설정 파일 수정
연결이 원활하게 되었다면 Nginx의 설정파일을 수정해야 하며, 설정파일 수정 내용은 모든 OS 동일함
Mac OS
- 설정파일은 brew 버전에 따라 위치가 다를 수 있음
- Nginx의 설정파일 위치는 아래 명령어로 확인할 수 있음
- nano 에디터를 이용해 설정파일을 수정함
$ nginx -t
$ nano /opt/homebrew/etc/nginx/nginx.conf
- Windows
- Nginx 실행파일이 있던 폴더(압축 해제한 폴더)에 설정파일이 모여있는 conf 폴더가 있음
- conf 폴더 내의 nginx.conf 파일을 수정하며, 우클릭 후 IntelliJ에서 수정하거나 터미널에서 nano 에디터로 수정할 수 있음
설정 파일 수정
- 설정파일에는 Nginx의 다양한 설정값이 있음
- 설정에서 포트 번호를 80으로 변경하고 리버스 프록시 서버로서 Spring Boot 프로젝트에 연동함
server {
listen 80; # (Mac OS) 8080 포트에서 80번 포트로 변경함
...
location / {
...
proxy_pass http://localhost:8080; # 요청을 8080 포트로 넘김
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;
}
}
4. NginX 재시작
설정파일을 저장한 후 Nginx를 재시작함
Mac OS
$ brew services restart nginx
- Windows
- 명령 프롬프트를 실행함
- Nginx 실행 파일이 있는 폴더(압축 해제한 폴더)로 이동하여 다음 명령어를 실행함
$ nginx -s reload
- Nginx 재시작 후 localhost (80번 포트는 생략 가능)에 접속하면, 80번 포트로 수정한 Nginx에는 접속이 되지만, 아직 8080번 포트를 사용하지 않기 때문에 오류가 발생함
- Spring Boot(8080번 포트)를 실행해야 하며, Spring Boot가 8080번 포트에서 정상적으로 실행이 되었다면 브라우저를 새로고침함
NginX 종료
- Mac OS
$ brew services stop nginx
- Windows 명령 프롬프트
$ nginx -s stop
NginX - Load Balancer
- NGINX를 이용하여 로컬 환경에서 로드밸런싱을 구성함
- 클라이언트 - NGINX - Spring Boot로 이전의 프록시 서버와 비슷한 구조
- NGINX는 스프링부트 서버 앞에 위치하여 클라이언트와 서버가 NGINX를 통해 소통하도록 되어있음
1. 두 개의 스프링부트 서버 실행
NGINX를 이용한 로드밸런싱을 구현하기 전, 두 개의 스프링부트 서버를 각각 실행함
하나는 8080번 포트, 다른 하나는 8081번 포트를 사용해서 실행함
- 포트 번호는 동일하지 않아도 상관 없음
- 포트 번호는 동일하지 않아도 상관 없음
프로젝트를 빌드함
./gradlew build
- 빌드 파일을 실행함 (포트를 변경하지 않은 경우 8080번 포트에서 실행됨)
java -jar sample-0.0.1-SNAPSHOT.jar
- 빌드 파일을 이용하여 새 터미널에 다른 포트(8081번 포트)에서 실행함
java -Dserver.port=8081 -jar sample-0.0.1-SNAPSHOT.jar
- 8080번 포트로 실행한 프로젝트의 PID와 8081번 포트로 실행한 프로젝트의 PID가 서로 다른 PID를 통해 실행됨
- 두 프로젝트는 서로 별개의 프로세스를 가지며 각각 실행되며, 어느 하나를 멈춘다고 해도 다른 포트로 열린 프로젝트에 영향이 가지 않음
2. NginX 설정파일 수정
- NGINX 설정파일을 수정함
http {
upstream backend {
server localhost:8080;
server localhost:8081;
}
location / {
proxy_pass http://backend;
}
}
- backend라는 서버 그룹을 만든 뒤 그룹 자체로 전달을 하는 구조
- 서버 그룹의 이름은 다른 이름으로 변경 가능함
- 그룹에 속한 각 서버의 값은 실행한 두 개의 스프링부트 프로젝트 접속 URL을 작성함
- 로컬환경에서 8080번 포트와 8081번 포트로 실행했기 때문에 각각 포트 번호까지 함께 작성함
- 서버 그룹을 모두 작성했다면 location의 proxy_pass 값으로 해당 서버 그룹을 설정함
- NGINX의 포트는 80번으로 설정되어 있기 때문에 포트를 생략한 localhost로 접속 시 8080번 포트와 8081번 포트가 번갈아 연결됨
3. 로드밸런싱 결과
- NGINX를 실행하며, NGINX는 localhost(80번 포트 생략가능)로 실행됨
- 새로고침을 하면 두 프로세스가 번갈아 나오게 됨
VPC
VPC 관련 개념
VPC
- VPC는 Virtual Private Cloud 서비스로, 클라우드 내 프라이빗 공간을 제공함으로써, 클라우드를 퍼블릭과 프라이빗 영역으로 논리적으로 분리할 수 있게 함
- 이전에 VPC가 없었을 때는 클라우드에 있는 리소스를 격리할 수 있는 방법이 없었고, 따라서 인스턴스들이 서로 거미줄처럼 연결되고, 인터넷과 연결되어 시스템의 복잡도를 엄청나게 끌어올릴 뿐만 아니라, 의존도를 높였음
- 따라서 유지 및 관리에 많은 비용과 노력을 투입해야 하는 단점이 있었음
- VPC를 분리함으로써 확장성을 가질 수 있고, 네트워크에 대한 완전한 통제권을 가질 수 있음
VPC 이해를 위한 구성 요소와 주요 용어
IP Address
- IP는 컴퓨터 네트워크에서 장치들이 서로를 인식하고 통신을 하기 위해서 사용하는 특수한 번호로, IPv4, IPv6로 나뉘어 있으며 혼용하여 사용하고 있음
- IPv4를 기준으로 예를 들면, 아래와 같은 형식인 172.16.0.0의 모습으로 이루어져 있음
172. | 16. | 0. | 0 |
---|---|---|---|
10101100. | 00010000. | 00000000. | 00000000 |
- 표에서 보이는 십진수의 형태는 보기 편하도록 변형한 것이고, 실제의 형태는 2진수 8자리의 형태, 즉 각 8bit(비트)씩 총 32bit로 구성되어 있음
- 8bit를 Octet(옥텟)이라고 부르며, '.' 으로 구분함
- IPv4는 4개의 Octet(옥텟)으로 이루어져 있다고 할 수 있음
IP Address Class
- 이전에는 IPv4 주소에서 호스트가 연결되어 있는 특정 네트워크를 가리키는 8비트의 네트워크 영역(Network Address)과 해당 네트워크 내에서 호스트의 주소(Host Address)를 가리키는 나머지 영역을 구분하기 위해서 클래스(Class)를 사용했음
- 클래스는 총 5가지(A, B, C, D, E) 클래스로 나누어져 있음
- D와 E 클래스는 멀티캐스트용, 연구 개발을 위한 예약 IP이므로 보통 사용되지 않음
- A 클래스
- 0.0.0.0의 경우는 자체 네트워크를 의미하기 때문에 제외되고, 127.0.0.0 ~ 127.255.255.255는 자기 자신을 가리키기 위한 목적으로 예약된 IP주소이기 때문에 사용할 수 없음
- 0.0.0.0의 경우는 자체 네트워크를 의미하기 때문에 제외되고, 127.0.0.0 ~ 127.255.255.255는 자기 자신을 가리키기 위한 목적으로 예약된 IP주소이기 때문에 사용할 수 없음
Network Address | Host Address | Host Address | Host Address |
---|---|---|---|
0-127 | 0-255 | 0-255 | 0-255 |
- B 클래스
Network Address | Host Address | Host Address | Host Address |
---|---|---|---|
128-191 | 0-255 | 0-255 | 0-255 |
- C 클래스
Network Address | Host Address | Host Address | Host Address |
---|---|---|---|
192-223 | 0-255 | 0-255 | 0-255 |
CIDR(Classless inter-domain routing)
- CIDR는 사이더라고 불리며, 클래스 없는 도메인 간 라우팅 기법으로 1993년 도입되기 시작한 국제 표준의 IP주소 할당 방법이며, 앞서 설명한 IP 클래스 방식을 대체한 방식
- 기존에는 클래스에 따라 정해진 Network Address와 Host Address를 사용해야 했다면, CIDR은 원하는 블록만큼 Network Address를 지정하여 운용할 수 있음
- /16은 첫 16bit를 Network Address로 사용한다는 의미로, 총 2^16인 65,536개의 IP주소를 사용할 수 있는 커다란 네트워크 블록을 이러한 방식으로 표시함
CIDR 블록 | IP 주소의 수 |
---|---|
/28 | 16 |
/24 | 254 |
/20 | 4,094 |
/18 | 16,382 |
/16 | 65,536 |
서브넷(Subnet)
- 서브넷은 서브네트워크(Subnetwork)의 줄임말로 IP 네트워크의 논리적인 하위 부분을 가리킴
- 서브넷을 통해 하나의 네트워크를 여러 개로 나눌 수 있음
- VPC를 사용하면 퍼블릭 서브넷, 프라이빗 서브넷, VPN only 서브넷 등, 필요에 따라 다양한 서브넷을 생성할 수 있음
- 퍼블릭 서브넷 : 인터넷을 통해 연결할 수 있는 서브넷
- 프라이빗 서브넷 : 인터넷을 연결하지 않고, 보안을 유지하는 배타적인 서브넷
- VPN only 서브넷 : 기업 데이터 센터와 VPC를 연결하는 서브넷
- 서브넷은 VPC의 CIDR 블록을 이용해 정의되며, 최소 크기의 서브넷은 /28
- 이때 주의 할 점은 서브넷은 AZ당 최소 하나를 사용할 수 있고, 여러 개의 AZ에 연결되는 서브넷은 만들 수 없음
- AWS가 확보한 서브넷 중 처음 네 개의 IP주소와 마지막 IP주소는 인터넷 네트워킹을 위해 예약되어 있음
- 서브넷에서 가용 IP주소를 계산할 때는 항상 이 부분을 기억하고 있어야 함
- 예를 들어, 10.0.0.0/24 체계의 CIDR 블록이 있는 서브넷에서 10.0.0.0, 10.0.0.1, 10.0.02, 10.0.0.3, 10.0.0.255 등 5개의 IP주소는 예약되어 있음
라우팅 테이블(Routing Table)
- 라우팅 테이블은 트래픽의 전송 방향을 결정하는 라우트와 관련된 규칙을 담은 테이블로 목적지를 향한 최적의 경로로 데이터 패킷을 전송하기 위한 모든 정보를 담고 있음
- 라우팅 테이블은 하나의 지점에서 또 다른 지점으로 가기 위한 모든 정보를 제공하기 위한 테이블
- 모든 서브넷은 라우팅 테이블을 지님
- 특정 VPC의 서브넷이 라우팅 테이블에 인터넷 게이트웨이(VPC와 인터넷 간 통신을 가능하게 하는 구성요소)를 포함하고 있다면, 해당 서브넷은 인터넷 액세스 권한 및 정보를 가짐
- 각각의 서브넷은 항상 라우팅 테이블을 가지고 있어야 하며, 하나의 라우팅 테이블 규칙을 여러 개의 서브넷에 연결하는 것도 가능함
- 서브넷을 생성하고 별도의 라우팅 테이블을 생성하지 않으면 클라우드가 자동으로 VPC의 메인 라우팅 테이블을 연결함