개요
MariaDB 리소스 제한 설정과 헬스체크(liveness/readiness probe) 구성을 자체 관리형 Kubernetes 클러스터에 반영했습니다. 기존 MariaDB Deployment는 리소스 request/limit이 전혀 설정되지 않은 상태(resources: {})로 2년 넘게 운영되고 있었고, liveness/readiness probe도 없어 mysqld 프로세스가 응답 없이 멈추더라도 Kubernetes가 이를 감지하고 자동으로 재시작할 방법이 없는 구조였습니다.
이번 글에서는 ① 현재 구성 점검 ② 운영 중인 리소스의 YAML 추출 및 Git 반영 ③ 리소스 제한/프로브 설계와 적용, 이렇게 세 가지 작업을 순서대로 정리합니다.
환경
- Kubernetes v1.33.7 (Control-plane 3대, Worker 3대 HA 구성)
- Container Runtime: Docker + cri-dockerd
- Storage: Rook-Ceph RBD (StorageClass
rook-ceph-block, ReadWriteOnce) - MariaDB: 10.11,
mariadb-system네임스페이스, Deployment 단일 replica - PVC: 10Gi, PV ReclaimPolicy:
Retain - 서비스 노출: MetalLB LoadBalancer (내부망 전용)
단계별 절차
1. 현재 구성 형상 점검
먼저 운영 중인 Deployment, PVC, Service, ConfigMap 현황과 실제 리소스 사용량을 확인했습니다.
$ kubectl get all -n mariadb-system -o wide $ kubectl get pvc -n mariadb-system -o wide $ kubectl top pod -n mariadb-system
점검 결과 Deployment의 strategy는 이미 Recreate로 설정되어 있었습니다. MariaDB처럼 ReadWriteOnce 볼륨을 사용하는 단일 파드 워크로드는 RollingUpdate 방식으로 배포하면 이전 파드가 볼륨을 반납하기 전에 새 파드가 같은 볼륨을 마운트하려다 충돌하는 경우가 있어, Recreate 전략이 올바른 선택이었습니다. PV의 reclaimPolicy도 Retain으로 설정되어 있어 PVC가 실수로 삭제되더라도 실제 데이터는 보존되는 안전한 구조였습니다.
반면 컨테이너 리소스는 request/limit이 전혀 없는 상태였고, 실제 메모리 사용량은 약 1.4Gi 수준이었습니다. ConfigMap으로 주입한 커스텀 설정은 다음과 같았습니다.
[mysqld] innodb_buffer_pool_size=512M innodb_log_file_size=256M max_connections=300
2. YAML 추출 및 Git 반영
운영 중인 리소스(PVC, ConfigMap, Deployment, Service)를 그대로 추출해 저장소에 매니페스트 파일로 문서화했습니다. Secret은 정책상 Git에 포함하지 않고, 클러스터 재구성 시 수동으로 생성할 수 있도록 커맨드만 주석으로 남겼습니다.
# root 비밀번호(mariadb-secret)는 Git에 없음 - 클러스터 재구성 시 수동 생성 필요 # kubectl create secret generic mariadb-secret -n mariadb-system \ # --from-literal=password='<ROOT_PASSWORD>'
추출한 매니페스트를 kubectl diff로 실제 클러스터 상태와 비교해, 새로 작성한 YAML이 운영 중인 리소스와 완전히 동일한지 먼저 확인했습니다. 차이가 없다는 것을 확인한 뒤에야 Git에 커밋했습니다.
3. 리소스 Request/Limit 및 Probe 설계
실제 메모리 사용량(~1.4Gi)과 innodb_buffer_pool_size(512M) 설정, 그리고 노드의 여유 용량을 함께 고려해 다음과 같이 값을 산정했습니다.
resources:
requests:
cpu: 250m
memory: 1Gi
limits:
cpu: "1"
memory: 2Gi
livenessProbe:
exec:
command:
- sh
- -c
- mysqladmin ping -uroot -p"$MYSQL_ROOT_PASSWORD" --silent
initialDelaySeconds: 30
periodSeconds: 20
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
exec:
command:
- sh
- -c
- mysqladmin ping -uroot -p"$MYSQL_ROOT_PASSWORD" --silent
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
Probe는 이미 컨테이너 환경변수로 주입되어 있던 MYSQL_ROOT_PASSWORD를 그대로 활용하는 mysqladmin ping exec 방식을 선택했습니다. 별도 Secret을 추가로 마운트할 필요 없이, 실제로 mysqld가 인증까지 정상 처리하는지 확인할 수 있는 방식입니다. Limit 산정 시에는 노드 전체 할당량 대비 여유가 충분한지(CPU 할당 비율, 메모리 할당 비율) 함께 확인한 뒤 값을 확정했습니다.
4. 적용 및 롤아웃 검증
kubectl apply 전에 반드시 kubectl diff로 변경 범위를 먼저 확인했습니다. Deployment의 strategy가 Recreate이기 때문에 적용 시 기존 파드가 먼저 종료되고 새 파드가 그 자리에 생성되는, 짧은 다운타임이 있는 변경이라는 점을 미리 인지하고 진행했습니다.
$ kubectl diff -f manifests/mariadb/mariadb.yaml $ kubectl apply -f manifests/mariadb/mariadb.yaml deployment.apps/mariadb configured $ kubectl rollout status deployment/mariadb -n mariadb-system --timeout=120s Waiting for deployment "mariadb" rollout to finish: 0 of 1 updated replicas are available... deployment "mariadb" successfully rolled out $ kubectl get pods -n mariadb-system -l app=mariadb NAME READY STATUS RESTARTS AGE mariadb-xxxxxxxxxx-xxxxx 1/1 Running 0 12s
새 파드가 정상적으로 Ready 상태가 되었고, readiness probe가 통과하는 것을 확인했습니다. 로그에도 mariadbd: ready for connections가 정상 출력되어 별다른 문제 없이 전환이 완료되었습니다.
트러블슈팅
mysql.event 테이블 정의 불일치
현상: 파드 재시작 로그에 Incorrect definition of table mysql.event 에러와 함께 Event Scheduler가 비활성화된다는 메시지가 출력되었습니다.
원인: 과거 MariaDB 마이너 버전 업그레이드 이후 mysql_upgrade를 실행하지 않아, 시스템 테이블(mysql.event)의 컬럼 정의가 현재 바이너리 버전이 기대하는 스키마와 어긋난 상태로 남아있었습니다.
해결: 현재 Event Scheduler(예약 이벤트) 기능을 사용하고 있지 않아 서비스에는 영향이 없는 것으로 확인해, 이번 작업 범위에서는 별도 조치 없이 별도 후속 작업으로 분리했습니다. Event Scheduler를 사용할 계획이라면 mysql_upgrade 실행이 선행되어야 합니다.
결과 확인
최종적으로 다음 항목들을 확인해 이번 MariaDB 리소스 제한 및 헬스체크 반영 작업을 마무리했습니다.
$ kubectl get deployment mariadb -n mariadb-system \
-o jsonpath='{.spec.template.spec.containers[0].resources}'
{"limits":{"cpu":"1","memory":"2Gi"},"requests":{"cpu":"250m","memory":"1Gi"}}
$ kubectl get pod -n mariadb-system -l app=mariadb
NAME READY STATUS RESTARTS AGE
mariadb-xxxxxxxxxx-xxxxx 1/1 Running 0 2m
- 리소스 request/limit 적용 완료 (request 250m/1Gi, limit 1core/2Gi)
- liveness/readiness probe 정상 동작 확인
- 클러스터 재기동 없이 무중단으로 서비스(LoadBalancer)가 재공지되어 애플리케이션 연결 영향 없음
참고
관련 포스트:
- Kubernetes MariaDB Failover with Rook Ceph — 동일한 MariaDB 워크로드의 장애 복구 구조를 다룬 글
- ceph storage class 사용 wordpress, mysql pod 생성 — MariaDB가 사용하는 Ceph 기반 스토리지 구성 배경
- Migrating Ingress Controller: ingress-nginx EOL to Traefik v3.7.5 — 같은 클러스터의 최근 인프라 개선 작업
참고 문서: Kubernetes – Configure Liveness, Readiness and Startup Probes · Kubernetes – Resource Management for Pods and Containers