이번 포스팅에서는 Statefulset 형태로 구현이 가능한 대표적인 클러스터인 Galera Cluster를 다루어 볼 것이다. 그 중에서도 Galera Cluster의 각 노드(Pod)의 상태를 etcd 데이터 스토어에 기록하고 사용할 수 있도록 etcd cluster를 동시에 활용하는 방식을 적용해 보려 한다. 주요 참조 기술 및 블로그는 글 말미의 Reference 를 참조하기 바란다.  앞서의 포스팅들과는 다르게 여기서는 Kubernetes 의 현 시점의 최신 버전인 1.11.3 을 활용하였다.



Mariadb Galera Cluster 구현을 위한 준비와 개념도


[Prerequisites]


  • Running k8s cluster with persistent storage(glusterfs or nfs storageclass, etc.)
  • Tested kubernetes version: 1.9.x, 1.11.x


Kubernetes 상에서 동작하는 Galera Cluster Application의 구조는 다음의 그림에 나타나 있다


 


  • galera-cluster-etcd-k8s-mod 프로젝트 clone
먼저 프로젝트의 manifest 를 clone 또는 다운로드해 둔다. 아래 github 프로젝트를 브라우저로 열고 내용을 확인하면서 개별 작업해도 무방
 

# git clone https://github.com/DragOnMe/galera-cluster-etcd-k8s-mod.git

# cd galera-cluster-etcd-k8s-mod.git


  • Container image re-building

docker.io/severalnines/mariadb 이미지도 역시 훌륭하게 동작하지만, 한글 데이터, 소문자 테이블명 등의 처리가 가능하도록 하기 위해서,  해당 이미지의 빌드 소스 위치인 github.com/severalnines/galera-docker-mariadb 레포지터리의 my.cnf 설정 파일을 변경하여 새로운 이미지를 빌드 & 푸쉬해서 사용하도록 한다.


여기서는 drlee001 대신에 github.com 사이트에 본인 각자의 account 를 발급 닫아 사용하면 된다


# cd galera-docker-mariadb

# docker build -t  drlee001/mariadb:10.1-modcnf .

# docker login -u drlee001

# docker push  drlee001/mariadb:10.1-modcnf



ETCD와 Galera Cluster 구축


  • etcd cluster 생성 및 점검

Galera Cluster 의 각 Mariadb node 상태 정보가 etcd store에 실시간 저장하고 관리되므로 가장 먼저 etcd 저장소를 구축해야 한다. 해당 아키텍처는 위 그림에 표현되어 있으니 참고하자.


실제로는 모든 galera 노드들이 자신의 상태 값을 주기적으로 etcd에 저장하며, 이 값들은 일정 시간이 지나면(TTL: 10초) 자동으로 expire 되는 식으로 동작한다.


# cd ..

# kubectl config set-context $(kubectl config current-context) --namespace=ns-galera-etcd

Context "kubernetes-admin@kubernetes" modified.


# kubectl create -f 00-etcd-cluster.yaml 

namespace/ns-galera-etcd created

service/etcd-client created

pod/etcd0 created

service/etcd0 created

pod/etcd1 created

service/etcd1 created

pod/etcd2 created

service/etcd2 created


# kubectl get pod,svc

NAME        READY     STATUS    RESTARTS   AGE

pod/etcd0   1/1       Running   0          4m

pod/etcd1   1/1       Running   0          4m

pod/etcd2   1/1       Running   0          4m


NAME                  TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)             AGE

service/etcd-client   ClusterIP   10.134.158.165   <none>        2379/TCP            4m

service/etcd0         ClusterIP   10.142.79.41     <none>        2379/TCP,2380/TCP   4m

service/etcd1         ClusterIP   10.136.241.253   <none>        2379/TCP,2380/TCP   4m

service/etcd2         ClusterIP   10.128.106.181   <none>        2379/TCP,2380/TCP   4m


# curl -L http://10.134.158.165:2379/version

{"etcdserver":"3.3.8","etcdcluster":"3.3.0"}


# kubectl exec -it etcd0 -- etcdctl cluster-health

member ade526d28b1f92f7 is healthy: got healthy result from http://etcd1:2379

member cf1d15c5d194b5c9 is healthy: got healthy result from http://etcd0:2379

member d282ac2ce600c1ce is healthy: got healthy result from http://etcd2:2379

cluster is healthy


# kubectl exec -it etcd0 -- etcdctl --version

etcdctl version: 3.3.8

API version: 2

* ETCD의 API 서버로 쿼리를 보내는 방법은 위에 나온 것 처럼 etcdclient 서비스로 curl 명령을 통해서 API 호툴을 하거나 또는 각 etcd pod 중 하나로 직접 접속해서 etcdctl 명령을 보내는 2가지 방법이 있다 



  • Galera Cluster 의 구축 및 etcd 데이터 확인

# kubectl create -f 01-galera-mariadb-ss.yaml 

service/galera-hs created

statefulset.apps/galera-ss created


# kubectl get pods -w

NAME          READY     STATUS    RESTARTS   AGE

etcd0         1/1       Running   0          20m

etcd1         1/1       Running   0          20m

etcd2         1/1       Running   0          20m

galera-ss-0   0/1       Running   0          38s

galera-ss-0   1/1       Running   0         2m

galera-ss-1   0/1       Pending   0         0s

galera-ss-1   0/1       Pending   0         0s

galera-ss-1   0/1       Pending   0         8s

galera-ss-1   0/1       ContainerCreating   0         8s

galera-ss-1   0/1       Running   0         11s

galera-ss-0   0/1       Running   0         3m

galera-ss-0   1/1       Running   0         3m

galera-ss-1   1/1       Running   0         2m

galera-ss-2   0/1       Pending   0         0s

galera-ss-2   0/1       Pending   0         0s

galera-ss-2   0/1       Pending   0         19s

galera-ss-2   0/1       ContainerCreating   0         19s

galera-ss-2   0/1       Running   0         24s

galera-ss-0   0/1       Running   0         6m

galera-ss-0   1/1       Running   0         6m

galera-ss-2   0/1       Running   1         2m

galera-ss-2   1/1       Running   1         4m


# kubectl get pod,svc

NAME              READY     STATUS    RESTARTS   AGE

pod/etcd0         1/1       Running   0          32m

pod/etcd1         1/1       Running   0          32m

pod/etcd2         1/1       Running   0          32m

pod/galera-ss-0   1/1       Running   0          12m

pod/galera-ss-1   1/1       Running   0          10m

pod/galera-ss-2   1/1       Running   1          8m


NAME                                                  TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)             AGE

service/etcd-client                                   ClusterIP   10.134.158.165   <none>        2379/TCP            32m

service/etcd0                                         ClusterIP   10.142.79.41     <none>        2379/TCP,2380/TCP   32m

service/etcd1                                         ClusterIP   10.136.241.253   <none>        2379/TCP,2380/TCP   32m

service/etcd2                                         ClusterIP   10.128.106.181   <none>        2379/TCP,2380/TCP   32m

service/galera-hs                                     ClusterIP   None             <none>        3306/TCP            12m

service/glusterfs-dynamic-mysql-datadir-galera-ss-0   ClusterIP   10.139.193.16    <none>        1/TCP               12m

service/glusterfs-dynamic-mysql-datadir-galera-ss-1   ClusterIP   10.136.64.128    <none>        1/TCP               10m

service/glusterfs-dynamic-mysql-datadir-galera-ss-2   ClusterIP   10.138.84.181    <none>        1/TCP               7m


# curl -L http://10.134.158.165:2379/v2/keys

{"action":"get","node":{"dir":true,"nodes":[{"key":"/galera","dir":true,"modifiedIndex":8,"createdIndex":8}]}}


# curl -L http://10.134.158.165:2379/v2/keys/galera/mariadb_galera_ss

{"action":"get","node":{"key":"/galera/mariadb_galera_ss","dir":true,"nodes":[{"key":"/galera/mariadb_galera_ss/10.40.0.3","dir":true,"modifiedIndex":8,"createdIndex":8},{"key":"/galera/mariadb_galera_ss/10.44.0.5","dir":true,"modifiedIndex":49,"createdIndex":49},{"key":"/galera/mariadb_galera_ss/10.32.0.6","dir":true,"modifiedIndex":129,"createdIndex":129}],"modifiedIndex":8,"createdIndex":8}}


# kubectl exec -it etcd0 -- etcdctl ls /galera/mariadb_galera_ss

/galera/mariadb_galera_ss/10.40.0.3

/galera/mariadb_galera_ss/10.44.0.5

/galera/mariadb_galera_ss/10.32.0.6

* 각 데이터 노드(pod)는 0번 부터 하나씩 순차적으로 만들어지며, 클러스터 내의 각 노드들은 자동으로 discover 된다



Galera Cluster의 데이터 동기화 점검


Galera Cluster 각 노드의 주요 상태를 조회해 보면 다음과 같다

 

# ./88-galera-test.sh 

+---------------------------+----------------+

| VARIABLE_NAME             | VARIABLE_VALUE |

+---------------------------+----------------+

| WSREP_CLUSTER_SIZE        | 3              |

| WSREP_CLUSTER_STATUS      | Primary        |

| WSREP_CONNECTED           | ON             |

| WSREP_LOCAL_INDEX         | 1              |

| WSREP_LOCAL_STATE_COMMENT | Synced         |

| WSREP_READY               | ON             |

+---------------------------+----------------+

+---------------------------+----------------+

| VARIABLE_NAME             | VARIABLE_VALUE |

+---------------------------+----------------+

| WSREP_CLUSTER_SIZE        | 3              |

| WSREP_CLUSTER_STATUS      | Primary        |

| WSREP_CONNECTED           | ON             |

| WSREP_LOCAL_INDEX         | 2              |

| WSREP_LOCAL_STATE_COMMENT | Synced         |

| WSREP_READY               | ON             |

+---------------------------+----------------+

+---------------------------+----------------+

| VARIABLE_NAME             | VARIABLE_VALUE |

+---------------------------+----------------+

| WSREP_CLUSTER_SIZE        | 3              |

| WSREP_CLUSTER_STATUS      | Primary        |

| WSREP_CONNECTED           | ON             |

| WSREP_LOCAL_INDEX         | 0              |

| WSREP_LOCAL_STATE_COMMENT | Synced         |

| WSREP_READY               | ON             |

+---------------------------+----------------+



데이터 동기화를 위해 각 데이터베이스 노드에서 데이터를 Insert, Select 및 삭제가 정상적으로 동작하고 동기화 되는지 점검한다


# ./89-galera-sync-test.sh 

1. Create database & table(node 0):

2. Insert 2 records into table(node 0):

+-------------------+----------------+

| VARIABLE_NAME     | VARIABLE_VALUE |

+-------------------+----------------+

| WSREP_LOCAL_INDEX | 1              |

+-------------------+----------------+

+------+-----------------+

| id   | name            |

+------+-----------------+

| aaa  | xxx             |

| id   | this is my name |

+------+-----------------+

3. Show data(node 1):

+-------------------+----------------+

| VARIABLE_NAME     | VARIABLE_VALUE |

+-------------------+----------------+

| WSREP_LOCAL_INDEX | 2              |

+-------------------+----------------+

+------+-----------------+

| id   | name            |

+------+-----------------+

| aaa  | xxx             |

| id   | this is my name |

+------+-----------------+

4. Show data(node 2):

+-------------------+----------------+

| VARIABLE_NAME     | VARIABLE_VALUE |

+-------------------+----------------+

| WSREP_LOCAL_INDEX | 0              |

+-------------------+----------------+

+------+-----------------+

| id   | name            |

+------+-----------------+

| aaa  | xxx             |

| id   | this is my name |

+------+-----------------+

5. Delete data(node 2):

6. Show data(node 0):

+-------------------+----------------+

| VARIABLE_NAME     | VARIABLE_VALUE |

+-------------------+----------------+

| WSREP_LOCAL_INDEX | 1              |

+-------------------+----------------+

+------+-----------------+

| id   | name            |

+------+-----------------+

| id   | this is my name |

+------+-----------------+

7. Show data(node 1):

+-------------------+----------------+

| VARIABLE_NAME     | VARIABLE_VALUE |

+-------------------+----------------+

| WSREP_LOCAL_INDEX | 2              |

+-------------------+----------------+

+------+-----------------+

| id   | name            |

+------+-----------------+

| id   | this is my name |

+------+-----------------+

8. Delete database & table(node 1):

+--------------------+

| Database           |

+--------------------+

| information_schema |

| mydatabase         |

| mysql              |

| performance_schema |

+--------------------+



Galera Cluster 의 리셋, 삭제


Galera Cluster에서 사용하는 etcd 데이터 영역을 Reset 하려면, 먼저 Galera Cluster 를 먼저 삭제한 후,


# curl http://10.134.158.165:2379:2379/v2/keys/galera/mariadb_galera_ss?recursive=true -XDELETE 


또는


# kubectl exec -it etcd0 -- etcdctl rm /galera/mariadb_galera_ss --recursive


을 수행한다


만약 전체 영역을 모두 삭제하고 싶다면 아래 script 를 수행하면 된다.


# ./99-teardown.sh 

service "galera-hs" deleted

statefulset.apps "galera-ss" deleted

persistentvolumeclaim "mysql-datadir-galera-ss-0" deleted

persistentvolumeclaim "mysql-datadir-galera-ss-1" deleted

persistentvolumeclaim "mysql-datadir-galera-ss-2" deleted

namespace "ns-galera-etcd" deleted

service "etcd-client" deleted

pod "etcd0" deleted

service "etcd0" deleted

pod "etcd1" deleted

service "etcd1" deleted

pod "etcd2" deleted

service "etcd2" deleted

No resources found.

Id:6d779dbd1e08b7ff7348360190091632    Cluster:60147830250310129f7b11084613a204    Name:heketidbstorage



# kubectl config set-context $(kubectl config current-context) --namespace=default

Context "kubernetes-admin@kubernetes" modified.



Reference


  • https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/
  • https://severalnines.com/blog/mysql-docker-deploy-homogeneous-galera-cluster-etcd
  • https://github.com/severalnines/galera-docker-mariadb



- Barracuda -



블로그 이미지

Barracuda

Bryan의 MemoLog. 쉽게 익혀 보는 IT 실습과 개념원리, 코딩 세계의 얕은 맛보기들, 평범한 삶 주변의 현상 그리고 進上, 眞想, 진상들


Mongodb Replicaset을 구현하는 방법은 여러 가지(sidecar, init-container 방식 등)이 있지만, 여기서는 docker.io의 mongo 3.4 ~ mongo:3.7 까지의 범용 이미지를 사용한 Replicaset 구현 방법을 다루어 보고자 한다.


Mongodb Replicaset 구현 & 기능 검증


[Prerequisites]


  • Running k8s cluster with persistent storage(glusterfs class, etc.)
  • Tested kubernetes version: 1.9.x, 1.11.x


[Deployment resources - mongodb-service.yaml]


# Service/endpoint for load balancing the client connection from outside
# By NodePort
apiVersion: v1
kind: Service
metadata:
  namespace: ns-mongo
  name: mongodb-svc
  labels:
    role: mongo
spec:
  type: NodePort
  ports:
    - port: 27017
      name: client
      nodePort: 30017
  selector:
    role: mongors
---
# A headless service to create DNS records
apiVersion: v1
kind: Service
metadata:
  annotations:
    service.alpha.kubernetes.io/tolerate-unready-endpoints: "true"
  namespace: ns-mongo
  name: mongodb-hs
  labels:
    name: mongo
spec:
  # the list of ports that are exposed by this service
  ports:
    - port: 27017
      name: mongodb
      targetPort: 27017
  clusterIP: None
  selector:
    role: mongors
---
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
  namespace: ns-mongo
  name: mongod-ss
spec:
  serviceName: mongodb-hs
  replicas: 3
  template:
    metadata:
      labels:
        role: mongors
        environment: test
        replicaset: MainRepSet
    spec:
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: replicaset
                  operator: In
                  values:
                  - MainRepSet
              topologyKey: kubernetes.io/hostname
      terminationGracePeriodSeconds: 10
      volumes:
        - name: secrets-volume
          secret:
            secretName: shared-bootstrap-data
            defaultMode: 256
      containers:
        - name: mongod-container
          # Notice
          # Tested on mongo:3.4, 3.6, 3.7
          # as to mongo:3.2, an error happens like below:
          # Error parsing option "wiredTigerCacheSizeGB" as int: Bad digit "." while parsing 0.25
          image: mongo:3.4
          command:
            - "numactl"
            - "--interleave=all"
            - "mongod"
            - "--wiredTigerCacheSizeGB"
            - "0.25"
            - "--bind_ip"
            - "0.0.0.0"
            - "--replSet"
            - "MainRepSet"
            - "--auth"
            - "--clusterAuthMode"
            - "keyFile"
            - "--keyFile"
            - "/etc/secrets-volume/internal-auth-mongodb-keyfile"
            - "--setParameter"
            - "authenticationMechanisms=SCRAM-SHA-1"
          resources:
            requests:
              cpu: 0.3
              memory: 128Mi
          ports:
            - containerPort: 27017
          volumeMounts:
            - name: secrets-volume
              readOnly: true
              mountPath: /etc/secrets-volume
            - name: mongodb-pv-claim
              mountPath: /data/db
  volumeClaimTemplates:
    - metadata:
        namespace: ns-mongo
        name: mongodb-pv-claim
        annotations:
          volume.beta.kubernetes.io/storage-class: glusterfs-storage
      spec:
        accessModes: [ "ReadWriteOnce" ]
        resources:
          requests:
            storage: 400Mi

* Service(NodePort), headless service, statefulset 으로 구성



[Deployment steps]


  • Statefulset deployment

# git clone https://github.com/DragOnMe/mongo-statefulset-glusterfs.git

# cd mongo-statefulset-gluster-pv

# ./01-generate_mongo_ss.sh

namespace "ns-mongo" created

secret "shared-bootstrap-data" created

service "mongodb-svc" created

service "mongodb-hs" created

statefulset "mongod-ss" created


Waiting for the 3 containers to come up (2018. 09. 16. (일) 17:19:37 KST)...

 (IGNORE any reported not found & connection errors)

  Error from server (NotFound): pods "mongod-ss-2" not found

  ...

  Error from server (NotFound): pods "mongod-ss-2" not found

  error: unable to upgrade connection: container not found ("mongod-container")

  ...

  error: unable to upgrade connection: container not found ("mongod-container")

  connection to 127.0.0.1:27017

...mongod containers are now running (TIMESTAMP)


deployment "mongo-client" created

NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS    CLAIM                                   STORAGECLASS        REASON    AGE

pvc-17853524-b98a-11e8-8c49-080027f6d038   1G         RWO            Delete           Bound     ns-mongo/mongodb-pv-claim-mongod-ss-1   glusterfs-storage             3m

pvc-1cea12e2-b98a-11e8-8c49-080027f6d038   1G         RWO            Delete           Bound     ns-mongo/mongodb-pv-claim-mongod-ss-2   glusterfs-storage             3m

pvc-407bdb23-b989-11e8-8c49-080027f6d038   1G         RWO            Delete           Bound     ns-mongo/mongodb-pv-claim-mongod-ss-0   glusterfs-storage             9m


NAME                                                 TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)           AGE

svc/glusterfs-dynamic-mongodb-pv-claim-mongod-ss-0   ClusterIP   10.140.100.198   <none>        1/TCP             9m

svc/glusterfs-dynamic-mongodb-pv-claim-mongod-ss-1   ClusterIP   10.136.50.38     <none>        1/TCP             3m

svc/glusterfs-dynamic-mongodb-pv-claim-mongod-ss-2   ClusterIP   10.135.150.63    <none>        1/TCP             3m

svc/mongodb-hs                                       ClusterIP   None             <none>        27017/TCP         9m

svc/mongodb-svc                                      NodePort    10.138.204.207   <none>        27017:30017/TCP   9m


NAME                     DESIRED   CURRENT   AGE

statefulsets/mongod-ss   3         3         9m


NAME                               STATUS    VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS        AGE

pvc/mongodb-pv-claim-mongod-ss-0   Bound     pvc-407bdb23-b989-11e8-8c49-080027f6d038   1G         RWO            glusterfs-storage   9m

pvc/mongodb-pv-claim-mongod-ss-1   Bound     pvc-17853524-b98a-11e8-8c49-080027f6d038   1G         RWO            glusterfs-storage   3m

pvc/mongodb-pv-claim-mongod-ss-2   Bound     pvc-1cea12e2-b98a-11e8-8c49-080027f6d038   1G         RWO            glusterfs-storage   3m

Waiting for rollout to finish: 0 of 1 updated replicas are available...

deployment "mongo-client" successfully rolled out

* 3개의 mongod pod가 순차적으로 만들어지며, 마지막 2 번 pod가만들어지면 결과를 보여줌

* 생성이 진행되는 동안 Error from server, ... unable to upgrade connection 과 같은 오류가 발생하지만 종료될 때까지 무시


# kubectl get pods -n ns-mongo 

NAME                           READY     STATUS              RESTARTS   AGE

mongo-client-799dc789b-p8kgv   1/1       Running             0          10m

mongod-ss-0                    1/1       Running             0          36m

mongod-ss-1                    1/1       Running             0          30m

mongod-ss-2                    0/1       ContainerCreating   0          4s


# kubectl logs -f -n ns-mongo mongod-ss-0

2018-09-16T09:11:09.843+0000 I CONTROL  [initandlisten] MongoDB starting : pid=1 port=27017 dbpath=/data/db 64-bit host=mongod-ss-0

2018-09-16T09:11:09.844+0000 I CONTROL  [initandlisten] db version v3.4.17

...

2018-09-16T09:11:11.409+0000 I CONTROL  [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/defrag is 'always'.

2018-09-16T09:11:11.409+0000 I CONTROL  [initandlisten] **        We suggest setting it to 'never'

2018-09-16T09:11:11.834+0000 I REPL     [initandlisten] Did not find local replica set configuration document at startup;  NoMatchingDocument: Did not find replica set configuration document in local.system.replset

2018-09-16T09:11:11.838+0000 I NETWORK  [thread1] waiting for connections on port 27017


# kubectl logs -f -n ns-mongo mongod-ss-1

2018-09-16T09:11:18.847+0000 I CONTROL  [initandlisten] MongoDB starting : pid=1 port=27017 dbpath=/data/db 64-bit host=mongod-ss-1

...

2018-09-16T09:11:20.808+0000 I NETWORK  [thread1] waiting for connections on port 27017


# kubectl logs -f -n ns-mongo mongod-ss-2

2018-09-16T09:11:25.977+0000 I CONTROL  [initandlisten] MongoDB starting : pid=1 port=27017 dbpath=/data/db 64-bit host=mongod-ss-2

...

2018-09-16T09:11:27.538+0000 I CONTROL  [initandlisten] ** WARNING: You are running this process as the root user, which is not recommended.

2018-09-16T09:11:27.539+0000 I CONTROL  [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/defrag is 'always'.

...

2018-09-16T09:11:27.878+0000 I FTDC     [initandlisten] Initializing full-time diagnostic data capture with directory '/data/db/diagnostic.data'

2018-09-16T09:11:28.224+0000 I REPL     [initandlisten] Did not find local voted for document at startup.

2018-09-16T09:11:28.224+0000 I REPL     [initandlisten] Did not find local replica set configuration document at startup;  NoMatchingDocument: Did not find replica set configuration document in local.system.replset

2018-09-16T09:11:28.226+0000 I NETWORK  [thread1] waiting for connections on port 27017

...

2018-09-16T09:11:32.214+0000 I -        [conn1] end connection 127.0.0.1:53452 (1 connection now open)

* Replica set 의 구성 대상인 3개의 mongod pod가 위와 같은 대기상태의 메시지 log(...waiting for connection..) 를 보일 때까지 대기


  • Replicaset 초기화 및 mongod admin 계정 생성

# ./02-configure_repset_auth.sh abc123

Configuring the MongoDB Replica Set

MongoDB shell version v3.4.17

connecting to: mongodb://127.0.0.1:27017

MongoDB server version: 3.4.17

{ "ok" : 1 }


Waiting for the MongoDB Replica Set to initialise...

MongoDB shell version v3.4.17

connecting to: mongodb://127.0.0.1:27017

MongoDB server version: 3.4.17

.

.

...initialisation of MongoDB Replica Set completed


Creating user: 'main_admin'

MongoDB shell version v3.4.17

connecting to: mongodb://127.0.0.1:27017

MongoDB server version: 3.4.17

Successfully added user: {

"user" : "main_admin",

"roles" : [

{

"role" : "root",

"db" : "admin"

}

]

}

* Replicset 구성을 수행하도록 하고, 데이터베이스 암호는 abc123 으로 설정

* Mongodb Replicaset 의 구현이 완료되었다. 이제 Replicaset 을 인식하는 클러스터 내의 다른 앱에서 각 mongod pod에 아래와 같은 URI 로 접속이 가능하다. 예를 들어 pymongo 의 경우 mongodb://mongod-ss-0.mongodb-hs.ns-mongo.svc.cluster.local:27017,mongod-ss-1.mongodb-hs.ns-mongo.svc.cluster.local:27017,mongod-ss-2.mongodb-hs.ns-mongo.svc.cluster.local:27017/?replicaSet=test 와 같은 형식으로 접속 가능


  - mongod-ss-0.mongodb-hs.ns-mongo.svc.cluster.local:27017

  - mongod-ss-1.mongodb-hs.ns-mongo.svc.cluster.local:27017

  - mongod-ss-2.mongodb-hs.ns-mongo.svc.cluster.local:27017



[How to check if things are working properly]


  • Replicaset member, mongod 간 데이터 동기화

# export MONGOD_NAMESPACE="ns-mongo"

# export MONGO_CLIENT=`kubectl get pods -n $MONGOD_NAMESPACE | grep mongo-client | awk '{print $1}'`

# kubectl exec -it -n $MONGOD_NAMESPACE $MONGO_CLIENT -- mongo mongodb://mongod-ss-0.mongodb-hs.ns-mongo.svc.cluster.local:27017

MongoDB shell version v3.4.2

connecting to: mongodb://mongod-ss-0.mongodb-hs.ns-mongo.svc.cluster.local:27017

MongoDB server version: 3.4.17

MainRepSet:PRIMARY> db.getSiblingDB('admin').auth("main_admin", "abc123");

1

MainRepSet:PRIMARY> use test;

switched to db test

MainRepSet:PRIMARY> db.testcoll.insert({a:1});

WriteResult({ "nInserted" : 1 })

MainRepSet:PRIMARY> db.testcoll.insert({b:2});

WriteResult({ "nInserted" : 1 })

MainRepSet:PRIMARY> db.testcoll.find();

{ "_id" : ObjectId("5b9fd8f0bc9812b50016a157"), "a" : 1 }

{ "_id" : ObjectId("5b9fd8f8bc9812b50016a158"), "b" : 2 }

* Primary(0 번)에 접속하여 데이터 입력, 저장


# kubectl exec -it -n $MONGOD_NAMESPACE $MONGO_CLIENT -- mongo mongodb://mongod-ss-1.mongodb-hs.ns-mongo.svc.cluster.local:27017

MongoDB shell version v3.4.2

connecting to: mongodb://mongod-ss-1.mongodb-hs.ns-mongo.svc.cluster.local:27017

MongoDB server version: 3.4.17

MainRepSet:SECONDARY> db.getSiblingDB('admin').auth("main_admin", "abc123");

1

MainRepSet:SECONDARY> use test;

switched to db test

MainRepSet:SECONDARY> db.setSlaveOk(1);

MainRepSet:SECONDARY> db.testcoll.find();

{ "_id" : ObjectId("5b9fd8f0bc9812b50016a157"), "a" : 1 }

{ "_id" : ObjectId("5b9fd8f8bc9812b50016a158"), "b" : 2 }

* Secondary(1번과 2번)에 접속하여  데이터 동기화 확인



  • Primary Pod 삭제 후, ReplicaSet 및 데이터 유지 확인
# kubectl get pod -n ns-mongo -o wide
NAME                           READY     STATUS    RESTARTS   AGE       IP          NODE
mongo-client-799dc789b-6rgvv   1/1       Running   0          1d        10.38.0.8   kubenode3
mongod-ss-0                    1/1       Running   6          1d        10.40.0.5   kubenode2
mongod-ss-1                    1/1       Running   6          1d        10.38.0.2   kubenode3
mongod-ss-2                    1/1       Running   0          1d        10.38.0.7   kubenode3

# kubectl delete pod -n ns-mongo mongod-ss-0
pod "mongod-ss-0" deleted

# kubectl get pod -n ns-mongo -o wide
NAME                           READY     STATUS    RESTARTS   AGE       IP          NODE
mongo-client-799dc789b-6rgvv   1/1       Running   0          1d        10.38.0.8   kubenode3
mongod-ss-0                    1/1       Running   0          4s        10.40.0.5   kubenode2
mongod-ss-1                    1/1       Running   6          1d        10.38.0.2   kubenode3
mongod-ss-2                    1/1       Running   0          1d        10.38.0.7   kubenode3

# kubectl exec -it -n $MONGOD_NAMESPACE $MONGO_CLIENT -- mongo mongodb://mongod-ss-0.mongodb-hs.ns-mongo.svc.cluster.local:27017
MongoDB shell version v3.4.2
connecting to: mongodb://mongod-ss-0.mongodb-hs.ns-mongo.svc.cluster.local:27017
MongoDB server version: 3.4.17
MainRepSet:SECONDARY> db.getSiblingDB('admin').auth("main_admin", "abc123");
1
MainRepSet:SECONDARY> use test;
switched to db test
MainRepSet:SECONDARY> db.setSlaveOk(1);
MainRepSet:SECONDARY> db.testcoll.find();
{ "_id" : ObjectId("5b9fd8f0bc9812b50016a157"), "a" : 1 }
{ "_id" : ObjectId("5b9fd8f8bc9812b50016a158"), "b" : 2 }

# kubectl exec -it -n $MONGOD_NAMESPACE $MONGO_CLIENT -- mongo mongodb://mongod-ss-2.mongodb-hs.ns-mongo.svc.cluster.local:27017
MongoDB shell version v3.4.2
connecting to: mongodb://mongod-ss-2.mongodb-hs.ns-mongo.svc.cluster.local:27017
MongoDB server version: 3.4.17
MainRepSet:PRIMARY>
* mongod-ss-0 을 삭제한 후 mongod-ss-0은 다시 되살아 났으며(데이터는 유지), mongod-ss-2가 Primary로 승격되었다. 결과적으로 Replicaset은 계속 유지

  • 서비스 삭제 후 재생성, DB 데이터 유지 확인

# ./03-delete_service.sh 

statefulset "mongod-ss" deleted

service "mongodb-hs" deleted

NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS    CLAIM                                   STORAGECLASS        REASON    AGE

pvc-6eb5c4f7-b990-11e8-8c49-080027f6d038   1G         RWO            Delete           Bound     ns-mongo/mongodb-pv-claim-mongod-ss-0   glusterfs-storage             1d

pvc-740db9df-b990-11e8-8c49-080027f6d038   1G         RWO            Delete           Bound     ns-mongo/mongodb-pv-claim-mongod-ss-1   glusterfs-storage             1d

pvc-78ccd2ce-b990-11e8-8c49-080027f6d038   1G         RWO            Delete           Bound     ns-mongo/mongodb-pv-claim-mongod-ss-2   glusterfs-storage             1d

# kubectl get all -n ns-mongo -l role=mongors

No resources found.

* Service(headless)와 Statefulset을 삭제


# ./04-recreate_service.sh 

NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS    CLAIM                                   STORAGECLASS        REASON    AGE

pvc-6eb5c4f7-b990-11e8-8c49-080027f6d038   1G         RWO            Delete           Bound     ns-mongo/mongodb-pv-claim-mongod-ss-0   glusterfs-storage             1d

pvc-740db9df-b990-11e8-8c49-080027f6d038   1G         RWO            Delete           Bound     ns-mongo/mongodb-pv-claim-mongod-ss-1   glusterfs-storage             1d

pvc-78ccd2ce-b990-11e8-8c49-080027f6d038   1G         RWO            Delete           Bound     ns-mongo/mongodb-pv-claim-mongod-ss-2   glusterfs-storage             1d

service "mongodb-svc" unchanged

service "mongodb-hs" created

statefulset "mongod-ss" created

NAME                                                 TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)           AGE

svc/glusterfs-dynamic-mongodb-pv-claim-mongod-ss-0   ClusterIP   10.134.165.156   <none>        1/TCP             1d

svc/glusterfs-dynamic-mongodb-pv-claim-mongod-ss-1   ClusterIP   10.131.121.182   <none>        1/TCP             1d

svc/glusterfs-dynamic-mongodb-pv-claim-mongod-ss-2   ClusterIP   10.138.205.244   <none>        1/TCP             1d

svc/mongodb-hs                                       ClusterIP   None             <none>        27017/TCP         6s

svc/mongodb-svc                                      NodePort    10.129.188.234   <none>        27017:30017/TCP   1d


NAME                     DESIRED   CURRENT   AGE

statefulsets/mongod-ss   3         3         6s


NAME                              READY     STATUS              RESTARTS   AGE

po/mongo-client-799dc789b-6rgvv   1/1       Running             0          1d

po/mongod-ss-0                    1/1       Running             0          6s

po/mongod-ss-1                    1/1       Running             0          3s

po/mongod-ss-2                    0/1       ContainerCreating   0          1s

NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS    CLAIM                                   STORAGECLASS        REASON    AGE

pvc-6eb5c4f7-b990-11e8-8c49-080027f6d038   1G         RWO            Delete           Bound     ns-mongo/mongodb-pv-claim-mongod-ss-0   glusterfs-storage             1d

pvc-740db9df-b990-11e8-8c49-080027f6d038   1G         RWO            Delete           Bound     ns-mongo/mongodb-pv-claim-mongod-ss-1   glusterfs-storage             1d

pvc-78ccd2ce-b990-11e8-8c49-080027f6d038   1G         RWO            Delete           Bound     ns-mongo/mongodb-pv-claim-mongod-ss-2   glusterfs-storage             1d


Keep running the following command until all 'mongod-ss-n' pods are shown as running:  kubectl get svc,sts,pods -n ns-mongo

# kubectl get all -n ns-mongo -l role=mongors

NAME                     DESIRED   CURRENT   AGE

statefulsets/mongod-ss   3         3         3m


NAME             READY     STATUS    RESTARTS   AGE

po/mongod-ss-0   1/1       Running   0          3m

po/mongod-ss-1   1/1       Running   0          3m

po/mongod-ss-2   1/1       Running   0          3m

* Service와 Replicaset 재생성. 새로운 mongod pod가 만들어지면서 기존 pv를 binding



# kubectl exec -it -n $MONGOD_NAMESPACE $MONGO_CLIENT -- mongo mongodb://mongod-ss-0.mongodb-hs.ns-mongo.svc.cluster.local:27017

MongoDB shell version v3.4.2

connecting to: mongodb://mongod-ss-0.mongodb-hs.ns-mongo.svc.cluster.local:27017

MongoDB server version: 3.4.17

MainRepSet:PRIMARY> db.getSiblingDB('admin').auth("main_admin", "abc123");

1

MainRepSet:PRIMARY> use test;

switched to db test

MainRepSet:PRIMARY> db.testcoll.find();

{ "_id" : ObjectId("5b9fd8f0bc9812b50016a157"), "a" : 1 }

{ "_id" : ObjectId("5b9fd8f8bc9812b50016a158"), "b" : 2 }

* 기존 PV의 데이터가 그대로 유지되면서 Replicaset은 초기 상태로 복구(mongod-ss-0이 primary), db 데이터도 그대로 유지



- Barracuda -


블로그 이미지

Barracuda

Bryan의 MemoLog. 쉽게 익혀 보는 IT 실습과 개념원리, 코딩 세계의 얕은 맛보기들, 평범한 삶 주변의 현상 그리고 進上, 眞想, 진상들

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 구현

주로 Kubernetes 공식 문서 내용을 기준으로 하여, StatefulSet의 주요 특징들을 확인하는 내용 위주로 정리한다

필요한 사항은 다음과 같다.
  • Running Kubernetes Cluster - v1.9 이상
  • Persistent Storage - GlusterFS(Hyper-converged 또는 External)

다음의 YAML 파일을 이용하여 ns-statefulset 네임스페이스 내에 Nginx 컨테이너 이미지로 StatefulSet 을 생성한다.

# kubectl create namespace ns-statefulset
namespace "ns-statefulset" created

# vi nginx-statefulset-test.yaml
# 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

# kubectl create -f nginx-statefulset-test.yaml
service "nginx-svc" created
service "nginx-hs" created
statefulset "nginx-ss" created


# kubectl get pods -n ns-statefulset -w
NAME         READY     STATUS              RESTARTS   AGE
nginx-ss-0   0/1       ContainerCreating   0          39s
nginx-ss-0   1/1       Running   0         1m
nginx-ss-1   0/1       Pending   0         0s
nginx-ss-1   0/1       Pending   0         0s
nginx-ss-1   0/1       ContainerCreating   0         0s
nginx-ss-1   1/1       Running   0         1m
nginx-ss-2   0/1       Pending   0         0s
nginx-ss-2   0/1       Pending   0         0s
nginx-ss-2   0/1       ContainerCreating   0         0s
nginx-ss-2   1/1       Running   0         1m
* 별도 설정을 하지 않으면 각 Pod는 순번(Ordinal Index)에 따라 하나씩 순차적으로 생성됨 

# kubectl get pods -n ns-statefulset 
NAME         READY     STATUS    RESTARTS   AGE
nginx-ss-0   1/1       Running   0          5m
nginx-ss-1   1/1       Running   0          4m
nginx-ss-2   1/1       Running   0          2m

# kubectl get service -n ns-statefulset
NAME                                   TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
glusterfs-dynamic-www-pvc-nginx-ss-0   ClusterIP   10.131.7.158     <none>        1/TCP          10d
glusterfs-dynamic-www-pvc-nginx-ss-1   ClusterIP   10.128.134.234   <none>        1/TCP          10d
glusterfs-dynamic-www-pvc-nginx-ss-2   ClusterIP   10.141.206.45    <none>        1/TCP          10d
nginx-hs                               ClusterIP   None             <none>        80/TCP         10d
nginx-svc                              NodePort    10.137.146.250   <none>        80:30080/TCP   10d

# kubectl get pvc,pv -n ns-statefulset 
NAME                     STATUS    VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS        AGE
pvc/www-pvc-nginx-ss-0   Bound     pvc-a107f13f-57ed-11e8-8c49-080027f6d038   1G         RWO            glusterfs-storage   10d
pvc/www-pvc-nginx-ss-1   Bound     pvc-a5f52c7d-57ed-11e8-8c49-080027f6d038   1G         RWO            glusterfs-storage   10d
pvc/www-pvc-nginx-ss-2   Bound     pvc-aa78d9ba-57ed-11e8-8c49-080027f6d038   1G         RWO            glusterfs-storage   10d

NAME                                          CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS    CLAIM                               STORAGECLASS        REASON    AGE
pv/pvc-a107f13f-57ed-11e8-8c49-080027f6d038   1G         RWO            Delete           Bound     ns-statefulset/www-pvc-nginx-ss-0   glusterfs-storage             10d
pv/pvc-a5f52c7d-57ed-11e8-8c49-080027f6d038   1G         RWO            Delete           Bound     ns-statefulset/www-pvc-nginx-ss-1   glusterfs-storage             10d
pv/pvc-aa78d9ba-57ed-11e8-8c49-080027f6d038   1G         RWO            Delete           Bound     ns-statefulset/www-pvc-nginx-ss-2   glusterfs-storage             10d



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


# kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS    CLAIM                               STORAGECLASS        REASON    AGE
pvc-978bac5f-ae99-11e8-8c49-080027f6d038   1G         RWO            Delete           Bound     ns-statefulset/www-pvc-nginx-ss-0   glusterfs-storage             7h
pvc-9c62652a-ae99-11e8-8c49-080027f6d038   1G         RWO            Delete           Bound     ns-statefulset/www-pvc-nginx-ss-1   glusterfs-storage             7h
pvc-a0b1695a-ae99-11e8-8c49-080027f6d038   1G         RWO            Delete           Bound     ns-statefulset/www-pvc-nginx-ss-2   glusterfs-storage             7h
pvc-cef812d4-aed3-11e8-8c49-080027f6d038   1G         RWO            Delete           Bound     ns-statefulset/www-pvc-nginx-ss-3   glusterfs-storage             50m

# for i in $(seq 0 3); do kubectl delete pvc -n ns-statefulset www-pvc-nginx-ss-$i; done
persistentvolumeclaim "www-pvc-nginx-ss-0" deleted
persistentvolumeclaim "www-pvc-nginx-ss-1" deleted
persistentvolumeclaim "www-pvc-nginx-ss-2" deleted
persistentvolumeclaim "www-pvc-nginx-ss-3" 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 -

 

블로그 이미지

Barracuda

Bryan의 MemoLog. 쉽게 익혀 보는 IT 실습과 개념원리, 코딩 세계의 얕은 맛보기들, 평범한 삶 주변의 현상 그리고 進上, 眞想, 진상들