[doik2] 1주차 - 쿠버네티스 배포 및 기초 지식
Published: 2023-10-21 16:19:52

### Overview
CloudNet@ 에서 운영하고 있는 DOIK (Database Operator In Kubernetes)  2기 스터디에 참석하여 1주차 스터디에서 실습한 내용을 정리했습니다.

### 01. 쿠버네티스 스토리지와 클라우드 스토리지 서비스

쿠버네티스의 파드는 Stateless로 파드 정지시 모든 데이터가 삭제됨.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xkbk7t98qubd5zhptym6.png)

임시 Pod 생성 
```
apiVersion: v1
kind: Pod
metadata: 
  name: busybox
spec: 
  terminationGracePeriodSeconds: 3
  containers: 
  - name: busybox
    image: busybox
    command: 
    - "/bin/sh"
    - "-c"
    - "while true; do date >> /home/pod-out.txt; cd /home; sync; sync; sleep 10; done"
```

`kubectl exec busybox -- tail -f /home/pod-out.txt`

```
Sat Oct 20 22:49:06 UTC 2023
Sat Oct 20 22:49:16 UTC 2023
Sat Oct 20 22:49:26 UTC 2023
Sat Oct 20 22:49:36 UTC 2023
Sat Oct 20 22:49:46 UTC 2023
Sat Oct 20 22:49:56 UTC 2023
Sat Oct 20 22:50:06 UTC 2023
Sat Oct 20 22:50:17 UTC 2023
```

busybox pod 를 삭제하고 다시 생성하면 데이터가 처음부터 다시 적재됨.



쿠버네티스에서 데이터베이스를 운영하려면 데이터 보존이 필요함.

```
cat <<EOT > awsebs-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: ebs-claim
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 4Gi
  storageClassName: gp3
EOT
```

`kubectl apply -f awsebs-pvc.yaml`

_스토리지 클래스가 gp3인 PVC 리소스를 사용하기 위해서는 gp3 스토리지 클래스 리소스를 생성해야함._

```
kubectl apply -f https://raw.githubusercontent.com/gasida/DOIK/main/1/gp3-sc.yaml
```


PVC를 이용하여 볼륨을 생성하고 아래의 파드에 연결.

```
cat <<EOT > awsebs-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: app
spec:
  terminationGracePeriodSeconds: 3
  containers:
  - name: app
    image: centos
    command: ["/bin/sh"]
    args: ["-c", "while true; do echo \$(date -u) >> /data/out.txt; sleep 5; done"]
    volumeMounts:
    - name: persistent-storage
      mountPath: /data
  volumes:
  - name: persistent-storage
    persistentVolumeClaim:
      claimName: ebs-claim
EOT
```

아래 명령을 통해 Pod 내 파일 확인
`kubectl exec app -- tail -f /data/out.txt`

```
Sat Oct 20 23:01:13 UTC 2023
Sat Oct 20 23:01:18 UTC 2023
Sat Oct 20 23:01:23 UTC 2023
Sat Oct 20 23:01:28 UTC 2023
Sat Oct 20 23:01:33 UTC 2023
Sat Oct 20 23:01:38 UTC 2023
```

아래 명령을 통해 Pod 삭제 후 재 기동
```
k delete pod app
kubectl apply -f awsebs-pod.yaml
```

```
Sat Oct 20 23:01:18 UTC 2023
Sat Oct 20 23:01:23 UTC 2023
Sat Oct 20 23:01:28 UTC 2023
Sat Oct 20 23:01:33 UTC 2023
Sat Oct 20 23:01:38 UTC 2023
```

파일에 찍힌 데이터를 확인해보면, 데이터가 그대로 보존되고 있음을 확인할 수 있다.

### 02. 쿠버네티스의 스테이트 풀셋, 헤드리스 서비스

Nginx Pod 2개를 기동시키는 스테이트풀셋을 생성.
```
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  serviceName: "nginx"
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: registry.k8s.io/nginx-slim:0.8
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
      name: www
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 1Gi
```

스테이트 풀셋은 생성, 삭제되는 순서가 중요하다.

생성되는 과정을 모니터링 해보면 인덱스가 0인 앱이 먼저 생성되고 그 다음 인덱스가 1인 앱이 생성되는 것을 알 수 있다.
```
web-0   0/1     ContainerCreating
web-0   1/1     Running
web-1   0/1     ContainerCreating
web-1   1/1     Running
```

스테이트 풀셋으로 구동되는 Nginx 를 위한 서비스 생성. (헤드리스 서비스)
```
apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None
  selector:
    app: nginx
```

서비스 스펙을 살펴보면 ClusterIP 값이 None 으로 정의되어 있다.
이렇게 생성된 서비스 리소스를 **헤드리스 서비스**라고 한다.

로드 밸런싱이 필요하지 않은 애플리케이션 * 서비스 또는 명시적으로 쿠버네티스 구현인 서비스에 의존하지 않도록 구성된 애플리케이션에서 사용하며 헤드리스 서비스로 구현된 서비스는 ClusterIP가 할당되지 않고, kube-proxy 가 서비스를 처리하지 않는다.

단, 서비스 스펙에 selector 를 지정할 경우 DNS가 구성됨. 

서비스 리소스를 확인해보면 ClusterIP 가 없는 것을 확인할 수 있음.
```
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.100.0.1   <none>        443/TCP   46h
nginx        ClusterIP   None         <none>        80/TCP    9m26s
```

netshoot pod 를 기동시키고 nginx DNS를 조회해보면 DNS를 찾을 수 있음.

`nslookup nginx`

```
Server:		10.100.0.10
Address:	10.100.0.10#53

Name:	nginx.default.svc.cluster.local
Address: 192.168.3.189
Name:	nginx.default.svc.cluster.local
Address: 192.168.2.83
```

### 03. 쿠버네티스 오퍼레이터란?

> Operators are software extensions to Kubernetes that make use of custom resources to manage applications and their components. Operators follow Kubernetes principles, notably the control loop.
{% embed https://kubernetes.io/docs/concepts/extend-kubernetes/operator/ %}

오퍼레이터는 사용자 정의 리소스를 사용하여 애플리케이션 및 해당 컴포넌트를 관리하는 쿠버네티스의 소프트웨어 익스텐션이다. 

사용자가 정의한 리소스를 만들고, 그 리소스의 컨트롤러 역할을 할 수 있는 컴포넌트를 오퍼레이터라고 이해했다.

* 쿠버네티스 오퍼레이터를 개발하기 위한 operator-sdk
https://github.com/operator-framework/operator-sdk


### Wrap-Up
쿠버네티스 환경에서 데이터베이스를 운영하기 위해 많은 것들을 고려해야 한다.
데이터베이스 구축을 위한 스토리지, 클러스터링을 위해 네트워크와 관련된 부분도 건드려야하고, 관리 작업을 자동화하고 모니터링 해야하며, 장애가 발생했을 경우 이를 조치할 수 있는 운영 프로세스도 수립해야 한다.

1주차 스터디 내용은 데이터베이스를 쿠버네티스에서 기동시키기 위해 필요한 제반 지식에 대한 내용이었다.

쿠버네티스 기능인 퍼시스턴트 볼륨과 볼륨 클레임 그리고 스토리지 클래스를 통해 데이터베이스 기동을 위한 볼륨을 마련하는 방법과, 스테이트풀셋, 헤드리스 서비스를 통해 데이터베이스 클러스터링이 가능할 것으로 예상된다.

추가로 데이터베이스 관리의 자동화 등을 위한 쿠버네티스 오퍼레이터 패턴에 대해서 학습하면서 앞으로 학습하게될 다양한 데이터베이스 오퍼레이터의 기반이 되는 지식을 알게된것 같다.


#### References.
* https://www.redhat.com/en/topics/containers/what-is-a-kubernetes-operator