Kubernetes의 컨테이너 오케스트레이션을 이용한 어플리케이션의 구현 방식 또는 기술에서 중요하게 다뤄야 하는 것 중 하나가 StatefulSet 이다. 개념을 명확히 해야 하는 점에서, 아래의 두 가지 개념을 염두에 두고 상황에 따라 잘 활용해야 할 필요가 있어서 본 시리즈를 기획하였다.
Stateless Application
- Web front-end 와 같이 디스크에 중요한 데이터가 없는 것들
- 필요한 만큼의 여러 개의 똑같은 컨테이너를 시작/종료할 수 있는 것들
- Ephemeral 특성 - 컨테이너가 죽으면 내부에 보관중인 데이터는 사라짐
- Instance 별의 특별한 데이터가 없을 것
Stateful Application
- Container-specific 특성(주로 호스트/도메인명, 드물게는 IP 주소)
- 암호, 인증키, 설정값 등의 Instance 개별 할당
- 적용가능 Application(Clustered) 들은 다음과 같음
: MySQL(Galera Cluster) Mongodb(Replicaset), Zookeeper ensemble, PostgreSQL cluster, Redis, ElasticSearch, etc.
Kubernetes 에서는 Stateful Application의 오케스트레이션을 위해서 StatefulSet(workload API Object, Kubernetes 1.9 버전부터 정식 지원) 형태로 구현되어 있는데, 본 5편으로 이루어진 시리즈에서는 다음의 내용들을 직접 구현하는 방법들을 정리해 두기로 한다.
여기서 보여지거나 언급되는 각 솔루션들의 구현 형태는 여러 다양한 변형이 존재할 수 있으며, Kubernetes 1.9.x 버전에서 정상 작동하는 실제적 내용으로 수정/검증, 편집된 것이며, 레퍼런스가 있을 경우 아래에 별도 명시한다.
- Nginx Web Cluster(본 편 ... 1/5)
- Mongodb Replicaset by StatefulSet(2/5)
- Mariadb Galera Cluster by StatefulSet and etcd(3/5)
- Mariadb pxc-cluster(4/5)
- Zookeeper Ensemble by StatefulSet(5/5)
Nginx Web Cluster 구현
- Running Kubernetes Cluster - v1.9 이상
- Persistent Storage - GlusterFS(Hyper-converged 또는 External)
# Service/endpoint for load balancing the client connection from outside
# By NodePort
---
apiVersion: v1
kind: Service
metadata:
namespace: ns-statefulset
name: nginx-svc
labels:
role: nginx
spec:
type: NodePort
ports:
- port: 80
name: client
nodePort: 30080
selector:
role: nginxrs
# A headless service to create DNS records
---
apiVersion: v1
kind: Service
metadata:
namespace: ns-statefulset
name: nginx-hs
labels:
app: nginx
spec:
ports:
- port: 80
name: web
targetPort: 80
clusterIP: None
selector:
role: nginxrs
# StatefulSet for nginx cluster
---
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
namespace: ns-statefulset
name: nginx-ss
spec:
serviceName: nginx-hs
replicas: 3
template:
metadata:
labels:
role: nginxrs
environment: test
spec:
containers:
- name: nginx
image: gcr.io/google_containers/nginx-slim:0.8
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www-pvc
mountPath: /usr/share/nginx/html
terminationGracePeriodSeconds: 10
volumeClaimTemplates:
- metadata:
name: www-pvc
annotations:
volume.beta.kubernetes.io/storage-class: glusterfs-storage
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 100Mi
StatefulSet 만의 특징적인 사항들의 확인
[Service와 Pod의 네트워크 ID 확인]
Busybox pod 를 통해 StatefulSet의 Headless Service(nginx-hs)와 Pod의 DNS 정보를 확인
# kubectl run -n ns-statefulset -it busybox --image=busybox
/ # nslookup -type=a nginx-hs.ns-statefulset.svc.cluster.local
Server: 10.128.0.10
Address: 10.128.0.10:53
Name: nginx-hs.ns-statefulset.svc.cluster.local
Address: 10.40.0.4
Name: nginx-hs.ns-statefulset.svc.cluster.local
Address: 10.32.0.12
Name: nginx-hs.ns-statefulset.svc.cluster.local
Address: 10.38.0.4
/ # nslookup -type=a nginx-ss-0.nginx-hs.ns-statefulset.svc.cluster.local
Server: 10.128.0.10
Address: 10.128.0.10:53
Name: nginx-ss-0.nginx-hs.ns-statefulset.svc.cluster.local
Address: 10.40.0.4
* Headless service는 StatefulSet의 도메인을 구성하는 단위이며, ${서비스명}.${네임스페이스}.svc.cluster.local 형식의 도메인이 만들어 짐
* 위의 yaml 파일 내용을 보면 headless service의 spec: 에서 clusterIp: None 으로 지정되어 있는 것이, 일반적인 kubernetes service와 극명하게 차이가 나는 부분이며, 이를 통해 headless service와 연결되는 특정한 Pod에 직접 access 가 가능하게 됨
* 각 Pod의 이름은 ${StatefulSet 이름}-${순번} 형식으로 결정되며,Pod의 도메인 형식은 ${StatefulSet 이름}-${순번}.${서비스명}.${네임스페이스}.svc.cluster.local 이 됨
[각 Pod의 고유 정보를 설정하고 Scale-out, Self-healing 확인]
# for i in $(seq 0 2); \
do kubectl exec nginx-ss-$i -n ns-statefulset \
-- sh -c 'echo $(hostname -f) > /usr/share/nginx/html/index.html'; \
done
# for i in $(seq 0 2); \
do kubectl exec nginx-ss-$i -n ns-statefulset \
-- sh -c 'curl -s localhost'; \
done
nginx-ss-0.nginx-hs.ns-statefulset.svc.cluster.local
nginx-ss-1.nginx-hs.ns-statefulset.svc.cluster.local
nginx-ss-2.nginx-hs.ns-statefulset.svc.cluster.local
# for i in $(seq 0 2); \
do kubectl exec nginx-ss-$i -n ns-statefulset \
-- sh -c 'cat /usr/share/nginx/html/index.html'; \
done
nginx-ss-0.nginx-hs.ns-statefulset.svc.cluster.local
nginx-ss-1.nginx-hs.ns-statefulset.svc.cluster.local
nginx-ss-2.nginx-hs.ns-statefulset.svc.cluster.local
# kubectl scale -n ns-statefulset statefulset nginx-ss --replicas=4
statefulset "nginx-ss" scaled
# kubectl get pods -n ns-statefulset -w
NAME READY STATUS RESTARTS AGE
busybox-5f9469d8dc-cwjhf 1/1 Running 1 7h
nginx-ss-0 1/1 Running 0 7h
nginx-ss-1 1/1 Running 0 7h
nginx-ss-2 1/1 Running 0 7h
nginx-ss-3 1/1 Running 0 8m
# kubectl exec nginx-ss-3 -n ns-statefulset \
-- sh -c 'echo $(hostname -f) > /usr/share/nginx/html/index.html'
* StatefulSet 의 replicas 를 4로 증가하고 nginx 의 index.html 생성
# curl -s http://10.255.10.170:30080
nginx-ss-3.nginx-hs.ns-statefulset.svc.cluster.local
# curl -s http://10.255.10.170:30080
nginx-ss-2.nginx-hs.ns-statefulset.svc.cluster.local
...
# curl -s http://10.255.10.170:30080
nginx-ss-1.nginx-hs.ns-statefulset.svc.cluster.local
...
# curl -s http://10.255.10.170:30080
nginx-ss-0.nginx-hs.ns-statefulset.svc.cluster.local
* 일반 service인 Nginx-svc 서비스(NodePort 30080으로 expose 됨)로 curl 접속, 각 Pod로 접속이 분배(로드밸런싱) 됨을 확인
# kubectl delete -n ns-statefulset pod nginx-ss-1
pod "nginx-ss-1" deleted
# kubectl get pods -n ns-statefulset -wNAME READY STATUS RESTARTS AGE
busybox-5f9469d8dc-cwjhf 1/1 Running 1 7h
nginx-ss-0 1/1 Running 0 7h
nginx-ss-1 1/1 Running 0 5s
nginx-ss-2 1/1 Running 0 7h
nginx-ss-3 1/1 Running 0 16m
# kubectl exec -it -n ns-statefulset \
busybox-5f9469d8dc-fv4jw \
-- sh -c 'wget -qO- nginx-ss-1.nginx-hs.ns-statefulset.svc.cluster.local'
nginx-ss-1.nginx-hs.ns-statefulset.svc.cluster.local
* Pod nginx-ss-1를 삭제하였으나 self-healing이 동작하여 StatefulSet 의 향상은 유지되어, pod nginx-ss-1 에 원래의 Persistent Volume이 연결됨(해당 Pod 고유의 기존 데이터도 그대로 유지)
* Busybox 에서 pod nginx-ss-1의 웹서버에 wget으로 접속, 웹서비스가 정상 동작됨을 확인
[StatefulSet과 관여되는 서비스 Clear, Persistent Volume Clear]
# kubectl delete service -n ns-statefulset nginx-svc
service "nginx-svc" deleted
# kubectl delete service -n ns-statefulset nginx-hs
service "nginx-hs" deleted
# kubectl delete statefulset -n ns-statefulset nginx-ss
statefulset "nginx-ss" deleted
* StatefulSet에 연결된 Persistent Volume이 삭제되지 않을 경우, 확인 후 명시적으로 Clear 해 주어야 함. 이는 scale-in을 하여 Pod가 삭제되는 경우에도 동일하게 발생할 수 있으며, 글을 쓰기 시작한 시점에는 이러한 문제를 해결하고자 별도의 노력이 필요한 상황이며, 아래 2번째 레퍼런스를 참고해 볼 필요가 있음.
[References]
- https://kubernetes.io/docs/tutorials/stateful-application/basic-stateful-set/
- https://medium.com/@marko.luksa/graceful-scaledown-of-stateful-apps-in-kubernetes-2205fc556ba9
- Barracuda -
'Technical > Cloud, Virtualization, Containers' 카테고리의 다른 글
[Kubernetes StatefulSet] Mariadb Galera Cluster with etcd(3/5) (0) | 2018.10.14 |
---|---|
[Kubernetes StatefulSet] Mongodb Replicaset by StatefulSet(2/5) (2) | 2018.09.16 |
[Kubernetes - CI/CD] Customized Jenkins 제작과 활용 - 2/2 (0) | 2018.04.03 |
[Kubernetes - CI/CD] Customized Jenkins 제작과 활용 - 1/2 (0) | 2018.03.20 |
[Kubernetes Cluster 관리] 클러스터 컨텍스트 변경과 kubectl을 통한 multi-cluster 접속 (0) | 2017.12.20 |