쿠버네티스 MySQL 배포

쿠버네티스에 MySQL을 올릴 때는 컨테이너만 실행해서는 부족합니다. 비밀번호는 Secret으로 분리하고, 데이터는 PVC에 보존하며, 고정된 이름과 종료 순서가 필요한 워크로드는 StatefulSet으로 관리하는 편이 좋습니다.

이 예시는 실습과 소규모 내부 환경을 위한 단일 인스턴스입니다. 복제·자동 장애 전환·백업까지 필요한 운영 데이터베이스라면 관리형 서비스나 검증된 MySQL Operator를 먼저 검토하세요.

네임스페이스와 비밀번호

kubectl create namespace database
kubectl -n database create secret generic mysql-auth \
  --from-literal=root-password='[강한 비밀번호]'

명령 기록에 비밀번호를 남기고 싶지 않다면 별도 파일이나 비밀 관리 도구를 사용합니다. Secret은 기본 상태에서 암호화가 아닌 Base64 인코딩이므로 etcd 암호화와 RBAC도 함께 설정해야 합니다.

설정과 PVC

apiVersion: v1
kind: ConfigMap
metadata:
  name: mysql-config
  namespace: database
data:
  custom.cnf: |
    [mysqld]
    character-set-server=utf8mb4
    collation-server=utf8mb4_unicode_ci
    slow_query_log=ON
    long_query_time=1
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-data
  namespace: database
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: nfs-client
  resources:
    requests:
      storage: 10Gi

storageClassName은 클러스터 환경에 맞게 바꿉니다. NFS 프로비저너 구성은 쿠버네티스 NFS 프로비저닝을 참고하세요.

Service와 StatefulSet

apiVersion: v1
kind: Service
metadata:
  name: mysql
  namespace: database
spec:
  clusterIP: None
  selector:
    app: mysql
  ports:
    - name: mysql
      port: 3306
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
  namespace: database
spec:
  serviceName: mysql
  replicas: 1
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      terminationGracePeriodSeconds: 60
      containers:
        - name: mysql
          image: mysql:8.4
          ports:
            - containerPort: 3306
          env:
            - name: MYSQL_ROOT_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: mysql-auth
                  key: root-password
          volumeMounts:
            - name: data
              mountPath: /var/lib/mysql
            - name: config
              mountPath: /etc/mysql/conf.d/custom.cnf
              subPath: custom.cnf
          readinessProbe:
            exec:
              command: ["sh", "-c", "mysqladmin ping -uroot -p$MYSQL_ROOT_PASSWORD"]
            initialDelaySeconds: 20
            periodSeconds: 10
          resources:
            requests:
              cpu: 250m
              memory: 512Mi
            limits:
              cpu: "1"
              memory: 2Gi
      volumes:
        - name: data
          persistentVolumeClaim:
            claimName: mysql-data
        - name: config
          configMap:
            name: mysql-config
kubectl apply -f mysql.yaml
kubectl -n database rollout status statefulset/mysql
kubectl -n database get pod,pvc,svc

접속과 점검

클러스터 내부에서는 mysql.database.svc.cluster.local:3306으로 접근합니다. 외부에 3306을 바로 공개하지 말고, 점검 시에는 포트포워딩을 사용합니다.

kubectl -n database port-forward service/mysql 3306:3306
kubectl -n database logs statefulset/mysql

마지막으로 PVC를 붙였다는 사실만으로 백업이 되는 것은 아닙니다. mysqldump, 물리 백업 또는 스토리지 스냅샷을 별도 위치에 보관하고 복원 테스트까지 해야 합니다.

참고: MySQL 공식 Docker 이미지, StatefulSet 공식 문서