Nginx & WSGI pod를 service로 노출하기
최초작성일 [2020.03.18]
아래와 같은 구조로 쿠버네티스의 service를 생성하려고 한다. (replicaset 또는 deployment를 미리 생성해야 한다.)

1. WSGI pod의 service 생성하기
WSGI 프로세스는 아래의 configuration으로 작동한다. 포트번호 9090을 통해 트래픽을 받아 flask 애플리케이션으로 전달한다.
[uwsgi]
wsgi-file=app/app.py
# flask app's name
callable=flask_app
# bind to the specified UNIX/TCP socket using default protocol
socket=:9090
# set internal http socket timeout
http-timeout=5
# enable master process
master = 1
# spawn the specified number of workers/processes
processes = 4
enable-threads=true
# serialize accept(), AKA Thundering Herd
# https://uwsgi-docs.readthedocs.io/en/latest/articles/SerializingAccept.html
thunder-lock=true
WSGI는 nginx를 통해 들어오는 트래픽만을 허용하므로 service 타입은 ClusterIP
로 선택한다. ClusterIP
타입은 pod를 클러스터 내부에 한정하여 노출하려고 할 때 사용한다.
apiVersion: v1
kind: Service
metadata:
name: service-flask-wsgi
spec:
type: ClusterIP
selector:
app: flask-wsgi
ports:
- name: port-flask-wsgi
port: 9090
targetPort: 9090
attribute
usage
selector
외부로 노출시키려는 pod의 라벨을 식별한다. (label selector 참고.)
ports.port
서비스가 생성되면 서비스는 클러스터 내부에서만 사용할 수 있는 고유한 IP를 가지게 된다. 서비스의 IP에 접근할 때 ports.port
에 해당하는 값을 포트번호로 쓴다.
ports.targetPort
selector에 정의된 라벨에 해당하는 pod들이 사용하는 포트번호. replicaset 템플릿에서 지정한containerPort
의 값과 같아야 한다.
위에서 작성한 템플릿 service-app.yml
을 클러스터에 적용한다.
$ kubectl apply -f service-app.yml
service/service-flask-wsgi created
$ kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 100.64.0.1 <none> 443/TCP 4d23h
service-flask-wsgi ClusterIP 100.66.110.185 <none> 9090/TCP 121m
metadata.name
의 값에 맞게 service-flask-wsgi
라는 서비스가 생성되었다. CLUSTER-IP
필드의 IP주소는 클러스터 내부에서 해당 서비스에 접근하는 용도로 쓰인다. 즉, 클러스터 외부에서는 CLUSTER-IP
필드의 주소로 접근할 수 없다.
kubernetes
라는 서비스가 이미 있는 것을 볼 수 있다. kubernetes
서비스는 pod 내부에서 쿠버네티스의 API에 접근하기 위한 용도로 쓰인다.
2. Nginx pod의 service 생성하기
nginx.conf
는 아래와 같다. Nginx가 업스트리밍하는 서버의 주소가 위에서 생성한 서비스의 이름에 해당하 service-flask-wsgi
인 것을 알 수 있다. 쿠버네티스 애플리케이션에는 service나 pod와 같은 리소스를 쉽게 찾을 수 있도록 리소스의 이름을 레코드로 관리하는 내부 DNS가 있다. 그리고 pod들은 이 DNS에 주소를 질의하기 때문에 service의 이름을 주소로 사용할 수 있다.
user nginx;
worker_processes auto;
...
http {
...
upstream flask_server {
server service-flask-wsgi:9090;
keepalive 512;
keepalive_timeout 5;
}
server {
listen 80;
server_name service-flask-wsgi;
location / {
include /etc/nginx/uwsgi_params;
uwsgi_pass flask_server;
}
}
}
Nginx pod를 클러스터 외부에 노출하기 위해 아래와 같은 템플릿을 작성한다. NodePort
타입은 모든 노드의 특정 포트를 개방하여 외부에서 서비스에 접근하도록 허용한다. 아래의 service는 모든 노드에 포트번호 80번을 개방한다.
apiVersion: v1
kind: Service
metadata:
name: service-my-nginx
spec:
type: NodePort
selector:
app: my-nginx
ports:
- name: port-my-nginx
port: 8080
targetPort: 80
위에서 작성한 템플릿 service-nginx.yml
을 클러스터에 생성한다.
$ kubectl apply -f service-nginx.yml
service/service-my-nginx created
$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 100.64.0.1 <none> 443/TCP 4d22h
service-flask-wsgi ClusterIP 100.66.110.185 <none> 9090/TCP 60m
service-my-nginx NodePort 100.68.131.17 <none> 8080:31085/TCP 4s
service-my-nginx
라는 이름으로 service가 생성된 것을 확인할 수 있다. service 타입이 NodePort
였음에도 CLUSTER-IP
가 만들어진 것을 볼 수 있는데, NodePort
타입의 service가 ClusterIP
타입의 기능을 포함하기 때문이다. 따라서 NodePort
타입으로 생성한 서비스는
클러스터 내부에서
CLUSTER-IP
또는 service 이름을 통해 접근할 수 있고클러스터 외부에서 노드의 IP를 통해 접근할 수 있다.
PORT(S)
의 값은 <클러스터 내부에서 접근할 때 쓰는 포트번호>:<클러스터 외부에서 접근할 때 쓰는 포트번호>
로 되어있다.
클러스터 내부에서 service-my-nginx
에 접근해보자. 클러스터 내부의 워커 노드 중 하나에 접속하여 curl
을 실행했다. IP주소는 CLUSTER-IP
에 해당하는 100.68.131.17
이고 포트번호 8080
으로 접근한다.
admin@ip-172-20-40-1:~$ curl 100.68.131.17:8080
Hello, This is DaEun Kim.
이번에는 클러스터 외부에서 service-my-nginx
에 접근한다. 워커 노드의 퍼블릭IP주소와 함께 포트번호는 31085
으로 접근한다. 내/외부 IP주소를 포함한 노드의 정보를 조회하고 싶다면 아래의 커맨드를 실행한다.
$ kubectl get nodes -o wide
위 커맨드에서 조회한 노드의 퍼블릭 IP주소로 curl을 실행한다.
$ curl 13.125.164.232:31085
Hello, This is DaEun Kim.
참고
Last updated
Was this helpful?