Beenslab Blog

쿠버네티스 Pod 외부접속 with nginx, websocket

beenchangseo·2024년 4월 3일Hits

이 포스팅은 아직 작성 중 입니다. (WIP)

쿠버네티스 Pod 외부접속 with nginx, websocket

로컬 개발 환경을 셋팅하다가, 쿠버네티스에 clusterIP로 설정한 웹 소켓 어플리케이션(pod)들과 host의 express 서버가 서로 통신이 필요한 상황이 왔다.

clusterIP로 설정한 pod는 쿠버네티스의 내부 사설 아이피를 할당 받게된다.

host에서 해당 pod로 접근하려면 NodePort로 변경해야하지만 ClusterIP를 유지하면서 Nginx로 proxy를 해보았다.

그림으로 표현하면 아래와 같다

kube_nginx_websocket_route1

Service 생성

서비스는 2개를 생성한다. (NodePort와 ClusterIP)

NodePort는 호스트와 통신하기위한 Nginx pod의 서비스, ClusterIP는 통신의 최종 도착지인 다른 pod 서비스이다.

# NodePort Service
apiVersion: v1
kind: Service
metadata:  
  name: nginx-service
spec:
  selector:    
    app: nginx
  type: NodePort
  ports:  
  - name: http
    port: 80
    targetPort: 80
    nodePort: 32088 # 호스트와 통신할 외부 포트
    protocol: TCP
# ClusterIP Service
kind: Service
apiVersion: v1
metadata:
  namespace: default
  name: my-application-service
spec:
  selector:
    app: my-application
  type: ClusterIP
  clusterIP: None
  ports:
  - port: 32088
    targetPort: 32088

Nginx 설정

nginx pod를 생성해보자

nginx의 설정 파일(sites.conf, nginx.conf. mime.types)들은 따로 생성하여 볼륨 마운트 시켰다

# Nginx Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80
        volumeMounts:
        - name: config
          mountPath: /etc/nginx
      volumes:
      - name: config
        hostPath:
            path: /Users/beenchangseo/deploy/k8s/nginx/config
            type: Directory

sites.conf

내가 테스트 할 호스트 어플리케이션은 http 서버이고 ClusterIP 서비스에 올려놓은 pod는 websocket 서버이다.

흐름은 아래 구조와 같다

http server -> nginx -> websocket server pod

nginx를 웹소켓 proxy로 사용할 수 있도록 아래와 같이 sites.conf를 설정 해준다.

# sites.conf
map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}

server {
	listen 80;
	server_name marketdata;

	location /my-application/ws {
        proxy_pass http://my-application.default.svc.cluster.local:32088;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
    }
}

nginx.conf

nginx.conf 설정은 log_format만 수정했다.

# nginx.conf
user nginx;
worker_processes auto;
worker_cpu_affinity auto;
worker_rlimit_nofile 65535;
pid /run/nginx.pid;

events {
    worker_connections 1024;
}

http {
    include /etc/nginx/mime.types;

    default_type application/octet-stream;

    log_format compression '$remote_addr - $remote_user [$time_local] '
                        '"$request" $status $body_bytes_sent '
                        '"$http_referer" "$http_user_agent" "$gzip_ratio"';

    access_log /var/log/nginx/access.log compression;
    
    error_log /var/log/nginx/error.log;

    include ./sites.conf;
}

mime.types

mime.types는 대충 인터넷에서 긁어왔다.

# mime.types
types {
    text/html                             html htm shtml;
    text/css                              css;
    text/xml                              xml;
    image/gif                             gif;
    image/jpeg                            jpeg jpg;
    application/javascript                js;
    ...
    ... 중략
    ...
    video/x-msvideo                       avi;
}

nginx pod에 올리기

쿠버네티스에 nginx pod를 생성한다.

kubectl apply -f nginx_service.yaml
kubectl apply -f nginx_deployment.yaml

로그가 잘 나오는지도 확인 해보자

kubectl get po | grep nginx
NAME                     READY     STATUS    RESTARTS   AGE       IP            NODE
nginx-3800858182-jr4a2   1/1       Running   0          13s       x.x.x.x



kubectl logs -f nginx-deployment-xxxxxxxx-xxxxx
[21/4/2024:02:54:45 +0000] - *.*.*.* | *.*.*.* - "GET / HTTP/1.1" 200 6180 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.182 Safari/537.36"

websocket server pod 올리기

실험용 테스트 웹 소켓 서버 pod를 생성해보자

아래 소스코드를 docker image로 build 후 pod에 올릴 생각이다.

import * as WebSocket from 'ws';
import * as express from 'express';

const app = express();

const server = app.listen(32088, () => {
    console.log('Server is listening on port 32088');
});

const wss = new WebSocket.Server({ server });

docker build 과정 생략...

이미지가 잘 만들어졌다면 이제 웹 소켓 서버를 pod에 올리자

# Websocket server deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: my-application
  name: my-application
spec:
  replicas: 1
  selector:
    matchLabels:
      app: my-application
  template:
    metadata:
      labels:
        app: my-application
    spec:
      containers:
      - image: my-application:latest
        imagePullPolicy: IfNotPresent
        name: my-application
        resources: {}
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
      dnsPolicy: ClusterFirst
status: {}

쿠버네티스에 아까 작성해놓은 ClusterIP Service와 websocket server pod를 생성한다.

kubectl apply -f clusterip_service.yaml
kubectl apply -f my_application_deployment.yaml

로그가 잘 나오는지도 확인 해보자

kubectl get po | grep my-application
NAME                            READY     STATUS    RESTARTS   AGE       IP            NODE
my-application-xxxxxxxx-xxxxx   1/1       Running   0          13s       x.x.x.x


kubectl logs -f my-application-xxxxxxxx-xxxxx
Server is listening on port 32088

Postman으로 websocket pod에 요청하기

nginx, websocket log 결과 확인