리버스 프록시 기반 분산 아키텍처 구축 - 1
AWS Lightsail
by HOON
1
Last updated on Jan. 31, 2025, 3:15 p.m.
안녕하세요, 오늘은 서비스 증가에 따라 서버 증축 및 분산 아키텍쳐를 구축하게 된 내용을 작성해보고자 합니다.
1. 아키텍쳐 개요
우선 저의 원래 서비스 환경에 대해서 말씀드리자면, AWS Lightsail의 가장 저렴한 버전을 사용중이였습니다.
사진과 같이 512MB 메모리, 2코어 cpu입니다. 가장 간단한 웹 구현에서는 문제가 없었으나
최근 Prometheus, Grafana, Jenkins를 추가하면서 최종적으로는 하나의 인스턴스에
docker, nginx, web(Django), postgresql, certbot, prometheus, nginx-exporter, postgres-exporter, jenkins
이렇게 9개의 컨테이너가 가동되고 있었습니다. 그에따라 당연히 서버가 down되는 상황이 자주 발생하게되었고
해당 플랜으로는 다소 무리가 있어 분산 아키텍쳐를 계획하게 되었습니다.
2. 아키텍쳐 설계
우선 분산하기전 제가 생각한 아키텍쳐를 그림으로 표현해보겠습니다.
분산을 위해 한가지 특징이 있다면, prometheus,grafana,jenkins 모두 nginx의 reverse proxy를 사용한다는 점입니다.
따라서 데이터가 쌓일 수 있는 web과 postgresql이 존재하는 인스턴스에 exporter를 배치하여 서빙하기 좋게 구현하겠습니다.
3. 아키텍쳐 구현
먼저, nginx reverse proxy를 사용한다했으니, nginx.conf 파일을 변경해보겠습니다.
ㄱ. 서버 A (메인 서버) - Nginx 설정
server {
listen 80;
server_name hongjunghoon.com;
location / {
return 301 https://$host$request_uri;
}
. . .
server {
listen 443 ssl;
server_name hongjunghoon.com;
. . .
# Jenkins 리버스 프록시
location /jenkins/ {
proxy_pass http://<sub-ip>:<port>/jenkins/; # sub 인스턴스의 ip와 통신할 port를 작성합니다.
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
# Prometheus 리버스 프록시
location /prometheus/ {
proxy_pass http://<sub-ip>:<port>/;
}
# Grafana 리버스 프록시
location /grafana/ {
proxy_pass http://<sub-ip>:<port>;
}
}
이렇게 작성해주면 각각의 요청을 sub 인스턴스의 매핑되어있는 주소:포트로 전달하여 데이터를 확인 할 수 있을 것 같습니다.
이번에는 sub 인스턴스를 수정해볼게요.
ㄴ. 서버 B (서브 서버) - Docker Compose 배포
#jenkins.yml
version: '3'
services:
jenkins:
image: jenkinsci/blueocean:latest
container_name: jenkins
user: root
ports:
- "<port>:<port>"
- "<port>:<port>"
prometheus:
image: prom/prometheus:latest
ports:
- "<port>:<port>"
grafana:
image: grafana/grafana:latest
ports:
- "<port>:<port>"
#monitoring.yml
version: '3'
services:
prometheus:
image: prom/prometheus:latest
container_name: new_godjango_prometheus
volumes:
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--web.route-prefix=/'
ports:
- "<port>:<port>" # 외부나 서버 A에서 접근할 수 있도록
# depends_on: [기타 exporter] (이제는 없음)
grafana:
image: grafana/grafana:latest
container_name: new_godjango_grafana
ports:
- "<port>:<port>"
environment:
- GF_SERVER_SERVE_FROM_SUB_PATH=true
depends_on:
- prometheus
networks:
godjango_custom:
external: true
순서대로 jenkins.yml 과 monitoring(prometheus,grafana).yml 입니다.
이 파일에서 port는 각자의 데이터를 전달받을 포트가 되어야하고 메인 인스턴스 및 서브 인스턴스에서 오픈 되어 있어야합니다!!
4. 문제 발생
네, 문제가 없으면 섭하죠.. 저는 jenkins 설정시에 문제가 좀 있었습니다.
우선, 제가 설정한 주소로 입력하면 504 Gateway time-out
에러가 발생했습니다.
일단 초기화 과정이 너무 길어서 아래와 같이 timeout 시간을 설정했습니다.
location /jenkins/ {
. . .
proxy_connect_timeout 300;
proxy_send_timeout 300;
proxy_read_timeout 300;
}
우선 Web 접속은 안되는걸 확인했습니다.
다음은 실제로 curl로 데이터를 가져와보겠습니다.
curl -v http://<sub_ip>:<port>/jenkins
* Trying <sub_ip>:<port>...
* TCP_NODELAY set
. . .
> GET /jenkins HTTP/1.1
> Host: <sub_ip>:<port>
> User-Agent: curl/7.68.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 302 Found
< Date: Wed, 29 Jan 2025 11:51:10 GMT
< Location: http://<sub_ip>:<port>/jenkins/
< Content-Length: 0
< Server: Jetty(9.4.45.v20220203)
<
이는 제가 메인서버에서 실행한 결과인데, 302 Found가 발생했네요??
302코드는 redirect가 된다는 뜻입니다. 따라서 저희가 nginx.conf파일에 정의해둔 redirect 경로로 따라가보면 정의가 되어야 합니다.
현상을 보니까 지금 curl은 잘 되는데, 웹 브라우저에서 504 → 흔히 Jenkins가 Location 헤더에 서버 B IP:Port을 반환해 버려서, 브라우저가 그쪽으로 직접 갔다가 안 열려 타임아웃 나는 경우같습니다.
따라서 저는 Jenkins가 공식 주소를 https://hongjunghoon.com/jenkins/
로 알고있도록 수정해주겠습니다.
우선 아까 작성한 jenkins.yml 파일 내 JENKINS_OPTS=--prefix=/jenkins
를 추가하여 /jenkins를 붙여주도록 수정합니다.
그리고 브라우저 캐시를 지우거나, 시크릿 모드로 접속하여 접속을 하면
성공입니다!
결과적으로 저는 메인과 서브 인스턴스를 나눠 인스턴스 2개로 부하를 줄이며 운영을 할 수 있습니다!!
Leave a Comment: