Post

Kubernetes를 사용해 MySQL 서버 구축 & 배포하기

Kubernetes를 사용해 MySQL 서버 구축 & 배포하기
MySQL Pod은 설정, Secret, volume이 연결된 뒤 Service로 제공된다

ConfigMap과 Secret은 설정과 자격 증명을, PVC는 data directory를 제공합니다. 두 입력은 Pod spec에 직접 값을 굽지 않고 Pod에 주입되거나 mount됩니다.

설정과 자격 증명
ConfigMap and Secret server config와 password를 분리해 보관합니다.
영속 데이터
PersistentVolumeClaim MySQL data directory를 보존합니다.
두 입력을 Pod에 주입하고 mount
MySQL Pod ConfigMap, Secret, PVC를 모두 연결한 뒤 시작합니다.
노출 관계: Pod를 Service로 제공
Service cluster 안에서 접근할 고정 주소를 제공합니다.
노출 관계: Client에 Service 주소 제공
Client Service 이름으로 MySQL에 접속합니다.

위 화살표는 설정 주입과 서비스 노출 관계입니다. 실제 접속 요청은 Client에서 Service 이름을 거쳐 MySQL Pod로 향합니다.

PNG 다운로드 원본 이미지 열기

2024년 07월 08일부터 Weasel 이라는 프로젝트를 시작했습니다. RDS를 띄우기 전, 개발 및 테스트 용도로 사용될 MySQL 서버가 필요했습니다. 해당 포스트에서는 Kubernetes Cluster에 MySQL 서버를 구축하고 배포하는 과정에 대해 다룹니다.

2024/08/28 - MySQL 같은 경우 클러스터링을 할 경우 여러 개의 Pods를 띄울 상황이 생깁니다. 해당 경우 Deployment가 아닌 StatefulSet을 사용해야 합니다.

TL;DR

  • RDS를 띄우기 전 개발과 테스트용으로 쓸 MySQL을 Kubernetes에 올리는 과정입니다.
  • PV와 PVC로 데이터를 보존하고, 설정은 ConfigMap으로, 계정 정보는 Secret으로 분리합니다.
  • Deployment로 배포한 뒤 Service로 노출해 클러스터 안에서 접근할 수 있게 합니다.

1. 사전 준비물

쿠버네티스


2. PV, PVC 생성

기본적으로 Pod가 실행되면서 생긴 데이터는 Pod가 삭제되거나 재시작될 때 유지되지 않습니다. 따라서 데이터를 영구적으로 저장할 PV, PVC를 생성해주었습니다. 해당 방법과 더불어 Storage Class를 사용하는 방법도 추천드립니다.

2.1. mysql-pv.yaml

1
2
3
4
5
6
7
8
9
10
11
apiVersion: v1
kind: PersistentVolume
metadata:
  name: mysql-pv
spec:
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/mnt/data"

2.2. mysql-pvc.yaml

1
2
3
4
5
6
7
8
9
10
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi

3. ConfigMap 생성

팀원들이 사용할 사용자 계정을 생성해야했고, ConfigMap의 데이터를 컨테이너의 /docker-entrypoint-initdb.d 디렉토리에 마운트하면 MySQL 컨테이너가 초기화 되면서 해당 파일이 같이 실행되는 것을 알게 되었습니다.

3.1. mysql-configmap.yaml

1
2
3
4
5
6
7
8
apiVersion: v1
kind: ConfigMap
metadata:
  name: mysql-initdb-config
data:
  init.sql: |
    GRANT ALL PRIVILEGES ON *.* TO 's5t1'@'%' WITH GRANT OPTION;
    FLUSH PRIVILEGES;

4. secrets 생성

MySQL 초기화에 필요한 환경변수들을 Secret으로 생성해주었습니다. 여기서 주의할 점은 시크릿을 암호화하지 않게되면 base64로 인코딩 한 값을 kubectl 명령어를 통해 확인할 수 있으므로, 쿠버네티스 클러스터 설정에서 EncryptionConfigure를 사용해주어야 합니다. 추가로 HashiCorp Vault, AWS Secret Manager를 사용하는 방법도 추천드립니다.

1
2
3
4
5
6
7
8
9
10
apiVersion: v1
kind: Secret
metadata:
  name: mysql-secret
type: Opaque
data:
  mysql-root-password: {mysql-root-password}
  mysql-user-id: {mysql-user-id}
  mysql-user-password: {mysql-user-password}
  mysql-database-name: {mysql-database-name}

5. Deployment 생성

앞에서 만든 ConfigMap, Secret을 사용해 MySQL Deployment를 생성해주었습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql
spec:
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - image: mysql:5.7
        name: mysql
        env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-secret
              key: mysql-root-password
        - name: MYSQL_USER
          valueFrom:
            secretKeyRef:
              name: mysql-secret
              key: mysql-user-id
        - name: MYSQL_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-secret
              key: mysql-user-password
        - name: MYSQL_DATABASE
          valueFrom:
            secretKeyRef:
              name: mysql-secret
              key: mysql-database-name
        ports:
        - containerPort: 3306
          name: mysql
        volumeMounts:
        - name: mysql-storage
          mountPath: /var/lib/mysql
        - name: initdb
          mountPath: /docker-entrypoint-initdb.d # 초기화 스크립트를 저장하는 특별한 위치 디렉토리에 있는 모든 .sh, .sql, .sql.gz 파일이 자동으로 실행
      volumes:
      - name: mysql-storage
        persistentVolumeClaim:
          claimName: mysql-pvc
      - name: initdb
        configMap:
          name: mysql-initdb-config

6. Service 생성

간단한 배포를 위해 NodePort를 사용했고, 30006번 포트로 배포했습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
apiVersion: v1
kind: Service
metadata:
  name: mysql
spec:
  type: NodePort
  ports:
  - name: mysql-port
    port: 3306
    targetPort: 3306
    nodePort: 30006
  selector:
    app: mysql

궁금하신 점이나 추가해야 할 부분은 댓글이나 아래의 링크를 통해 문의해주세요.
Written with KKamJi

This post is licensed under CC BY 4.0 by the author.