Nginx & WSGI pod를 service로 노출하기
Last updated
Was this helpful?
Last updated
Was this helpful?
최초작성일 [2020.03.18]
아래와 같은 구조로 쿠버네티스의 service를 생성하려고 한다. (replicaset 또는 deployment를 미리 생성해야 한다.)
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
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에 접근하기 위한 용도로 쓰인다.
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.
참고
외부로 노출시키려는 pod의 라벨을 식별한다. ( 참고.)