티스토리 뷰

카테고리 없음

Kubernetes MySQL Pod

미니대왕님 2023. 4. 25. 14:30

Kubernetes Cluster 에 MySQL 설치하기(Deployment, Local Persistent Volume)

 
 

Kubernetes  MySQL Pod 생성 

 
  • 작업폴더 설정
$ sudo mkdir -p /workspace/kubernetes/mysql
$ sudo chown -R tommypagy:tommypagy /workspace/kubernetes
$ cd /workspace/kubernetes/mysql

먼저 mysql 배포를 위한 폴더를 생성 후 적절한 권한을 설정해줍니다.

 
  • StorageClass 생성
$ vi storageClass-local-storage.yaml

vi 편집기로 StorageClass 생성을 위한 yaml 파일을 생성합니다.

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer

Local Persistent Volume 은 Dynamic Provisioning 을 지원하지 않으므로 Static Provisioner 를 통해 직접 PV 를 생성하도록 하겠습니다. 또한 Persistent Volume Claim(pvc)의 Binding 시점을 Pod 가 생성된 후로 연기하도록 VolumeBindingMode 를 설정합니다. 위의 내용을 입력하고 파일을 저장합니다.

$ kubectl apply -f storageClass-local-storage.yaml

kubectl 명령을 통해 StorageClass 를 생성해 줍니다.

storageclass.storage.k8s.io/local-storage created

정상적으로 생성이 되었다면 위와 같은 메세지가 출력됩니다.

 
  • 각 노드에 볼륨 디렉토리를 생성해줘야 합니다.
  • Persistent Volume 생성
$ sudo mkdir -p /workspace/data/kubernetes/pv/mysql
$ sudo chmod 777 /workspace/data/kubernetes/pv/mysql

우선 worker1, worker2 각각 위의 명령을 통해 mysql 의 데이터가 저장될 폴더를 생성하고 적절한 권한을 부여합니다. 우선은 777으로 권한을 설정했으나 향후 RBAC 기반으로 전체적인 권한체계를 구성할 예정입니다.

$ vi pv-mysql.yaml

vi 편집기로 pv 생성을 위한 yaml 파일을 생성합니다.

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-mysql
spec:
  capacity:
    storage: 10Gi
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: local-storage
  local:
    path: /workspace/data/kubernetes/pv/mysql
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - worker1

10GB 의 용량으로 설정하고 하나의 pod 만 접근하기 때문에 ReadWriteOnce, pod 가 삭제되더라도 데이터 보존을 위해 Retain 전략으로 설정합니다. NodeAffinity 설정을 통해 worker1 에 pv 를 생성하도록 합니다. 즉, MySQL pv 는 worker1 노드에 만들어지고 MySQL pod 역시 worker1 노드에 생성되게 됩니다.

$ kubectl apply -f pv-mysql.yaml

kubectl 명령을 통해 pv 를 생성해 줍니다.

persistentvolume/pv-mysql created

정상적으로 생성이 되었다면 위와 같은 메세지가 출력됩니다.

 
  • Persistent Volume Claim 생성
$ vi pvc-mysql.yaml

vi 편집기로 pvc 생성을 위한 yaml 파일을 생성합니다.

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: pvc-mysql
spec:
  accessModes:
  - ReadWriteOnce
  storageClassName: local-storage
  resources:
    requests:
      storage: 10Gi

위에서 생성한 local-storage 타입으로 10GB 의 용량의 pvc 를 생성합니다.

$ kubectl apply -f pvc-mysql.yaml

kubectl 명령을 통해 pv 를 생성해 줍니다.

persistentvolumeclaim/pvc-mysql created

정상적으로 생성이 되었다면 위와 같은 메세지가 출력됩니다.

$ kubectl get pvc

생성된 pvc 의 상태를 조회해봅니다.

root@master:/home/mysql# k get pvc
NAME        STATUS   VOLUME     CAPACITY   ACCESS MODES   STORAGECLASS    AGE
pvc-mysql   Bound    pv-mysql   10Gi       RWO            local-storage   83m
root@master:/home/mysql#

생성된 pv 의 상태도 조회해봅니다.

root@master:/home/mysql# k get pv
NAME       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM             STORAGECLASS    REASON   AGE
pv-mysql   10Gi       RWO            Retain           Bound    mysql/pvc-mysql   local-storage            83m
root@master:/home/mysql#

VolumeBindingMode 를 WaitForFirstConsumer로 설정했기 때문에 Status 가 아직 Available 인 점을 확인할 수 있습니다.

 
  • Configmap, Secret 생성

기본적으로 MySQL 의 설정은 Remote Access 를 허용하지 않습니다. 또한 사용자 계정역시 root 외에는 생성되어 있지 않습니다. 이 설정들을 Deployment yaml 파일에 설정해도 되지만 배포 Context 라던지 상황에 따라 Variation 이 존재할 수 있으므로 유연한 설정을 위해 Configmap 으로 관리하도록 하겠습니다.

$ kubectl create configmap configmap-mysql --from-literal MYSQL_USER=truelifer --from-literal MYSQL_ROOT_HOST=%

사용자 계정을 생성하고 외부에서 접속가능한 설정을 Configmap 으로 생성합니다.

configmap/configmap-mysql created

정상적으로 생성이 되었다면 위와 같은 메세지가 출력됩니다.

$ kubectl create secret generic secret-mysql --from-literal MYSQL_PASSWORD=12345 --from-literal MYSQL_ROOT_PASSWORD=12345

위에서 생성한 사용자 계정에 매핑되는 비밀번호와 기본계정인 root 의 비밀번호를 Secret 을 통해 관리하겠습니다.

secret/secret-mysql created

정상적으로 생성이 되었다면 위와 같은 메세지가 출력됩니다.

 
  • Deployment 생성
$ vi deployment-mysql.yaml

vi 편집기로 deployment 생성을 위한 yaml 파일을 생성합니다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql
spec:
  selector:
    matchLabels:
      app: mysql
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - image: mysql/mysql-server:latest
        name: mysql
        env:
        - name: MYSQL_USER
          valueFrom:
            configMapKeyRef:
              name: configmap-mysql
              key: MYSQL_USER
        - name: MYSQL_PASSWORD
          valueFrom:
            secretKeyRef:
              name: secret-mysql
              key: MYSQL_PASSWORD
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: secret-mysql
              key: MYSQL_ROOT_PASSWORD
        - name: MYSQL_ROOT_HOST
          valueFrom:
            configMapKeyRef:
              name: configmap-mysql
              key: MYSQL_ROOT_HOST
        ports:
        - containerPort: 3306
          name: mysql
        volumeMounts:
        - name: volume-mysql
          mountPath: /var/lib/mysql
      volumes:
      - name: volume-mysql
        persistentVolumeClaim:
          claimName: pvc-mysql

arm 기반의 Raspberry Pi 4B 에 몇가지 MySQL Docker Image 를 테스트해봤으나 모두 실패하고 mysql/mysql-server:latest 만 정상적으로 작동함을 확인했습니다. 위에서 생성한 pv, pvc, configmap, secret 을 기반으로 deployment yaml 파일을 작성합니다.

$ kubectl apply -f deployment-mysql.yaml

kubectl 명령을 통해 deployment 를 생성해 줍니다.

deployment.apps/mysql created

정상적으로 생성이 되었다면 위와 같은 메세지가 출력됩니다.

root@master:/home/mysql# k get po
NAME                    READY   STATUS    RESTARTS   AGE
mysql-5c8676c85-4bj6h   1/1     Running   0          79m
root@master:/home/mysql#

생성된 pod 를 조회해봅니다.

NAME                     READY   STATUS    RESTARTS   AGE
mysql-78b9dbcf7b-hzsjz   1/1     Running   0          108s

Status 가 Running 상태로 정상적으로 배포되었음을 확인할 수 있습니다. 참고로 물리적인 H/W 의 성능에 따라서 배포가 되었음에도 불구하고 바로 로그인 되지 않을 수 있습니다. Pod 가 배포되더라도 기본적인 Initialization 이 완료되기까지는 조금의 시간이 필요하기 때문입니다. 제가 구성한 Kubernetes Cluster 의 H/W 기반이 Raspberry Pi 4B 이기에, 대략 1분정도의 Delay 가 발생함을 확인하였습니다.

 
  • Service 생성
$ vi service-mysql.yaml

vi 편집기로 service 생성을 위한 yaml 파일을 생성합니다.

apiVersion: v1
kind: Service
metadata:
  name: service-mysql
spec:
  type: NodePort
  selector:
    app: mysql
  ports:
    - protocol: TCP
      port: 3306
      nodePort: 30000
      targetPort: 3306

보안 등의 이유로 MySQL 을 Kubernetes Cluster 내부에서만 접근 가능하도록 하기 위해서는 Service 의 Type 을 ClusterIP 로 설정하면 됩니다. 하지만 저는 Database 의 상태 및 데이터 조회를 위해 Kubernetes Cluster 외부에서 Client 툴을 통해 접속할 예정입니다. 이를 위해 NodePort 타입으로 설정하도록 합니다. Node 의 Port 기본 범위는 30000 ~ 32767로 정해져있습니다. 저는 30000 포트를 사용하도록 하겠습니다.

$ kubectl apply -f ./service-mysql.yaml

kubectl 명령을 통해 service 를 생성해 줍니다.

service/service-mysql created

정상적으로 생성이 되었다면 위와 같은 메세지가 출력됩니다.

$ kubectl get services

생성된 service를 조회해봅니다.

root@master:/home/mysql# k get service
NAME            TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
service-mysql   NodePort   10.103.211.20   <none>        3306:30000/TCP   69m
root@master:/home/mysql#

NodePort 타입으로 service 가 정상적으로 생성되었음을 확인할 수 있습니다.

# k exec -it mysql-5c8676c85-kxddn bash

bash-4.4# mysql -u root -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 15
Server version: 8.0.32 MySQL Community Server - GPL

Copyright (c) 2000, 2023, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.


mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.02 sec)
##########################################

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.00 sec)

mysql> CREATE DATABASE study_db;
Query OK, 1 row affected (0.00 sec)

mysql> CREATE DATABASE example_db;
Query OK, 1 row affected (0.00 sec)

mysql> SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| example_db         |
| information_schema |
| mysql              |
| performance_schema |
| study_db           |
| sys                |
+--------------------+
6 rows in set (0.00 sec)



mysql> use study_db
Database changed
mysql> INSERT INTO professor
    -> (name, belong, phone)
    -> VALUES('', 'IDE','01112345678');
ERROR 1146 (42S02): Table 'study_db.professor' doesn't exist
mysql> CREATE TABLE professor
    -> (
    ->      _id INT AUTO_INCREMENT,
    ->      name VARCHAR(32) NOT NULL,
    ->      belong VARCHAR(12) DEFAULT 'FOO',
    ->      phone VARCHAR(12),
    ->      PRIMARY KEY(_id)
    -> ) ENGINE=INNODB;
Query OK, 0 rows affected (0.01 sec)

mysql> 
mysql> INSERT INTO professor
    -> (name, belong, phone)
    -> VALUES('', 'IDE','01112345678');
Query OK, 1 row affected (0.01 sec)

mysql> 
mysql> INSERT INTO professor
    -> (name, belong, phone)
    -> VALUES('', 'MSE', '01121342443');
Query OK, 1 row affected (0.00 sec)

mysql> 
mysql> INSERT INTO professor
    -> (name, belong, phone)
    -> VALUES('', 'ESE', '01123424343');
Query OK, 1 row affected (0.00 sec)

mysql> 
mysql> INSERT INTO professor
    -> (_id, name, belong, phone)
    -> VALUES(256, '', 'IME', '01134343222');
Query OK, 1 row affected (0.00 sec)

mysql> 
mysql> INSERT INTO professor
    -> (name, belong, phone)
    -> VALUES( '', 'IDE', '01123432432');
SELECT _id, belong, phone FROM professor;
Query OK, 1 row affected (0.00 sec)

mysql> SELECT _id, belong, phone FROM professor;
+-----+--------+-------------+
| _id | belong | phone       |
+-----+--------+-------------+
|   1 | IDE    | 01112345678 |
|   2 | MSE    | 01121342443 |
|   3 | ESE    | 01123424343 |
| 256 | IME    | 01134343222 |
| 257 | IDE    | 01123432432 |
+-----+--------+-------------+
5 rows in set (0.00 sec)

mysql> SELECT * FROM professor;
+-----+------+--------+-------------+
| _id | name | belong | phone       |
+-----+------+--------+-------------+
|   1 |      | IDE    | 01112345678 |
|   2 |      | MSE    | 01121342443 |
|   3 |      | ESE    | 01123424343 |
| 256 |      | IME    | 01134343222 |
| 257 |      | IDE    | 01123432432 |
+-----+------+--------+-------------+
5 rows in set (0.00 sec)

mysql>
댓글