MySQL 컨테이너 환경 문제 1 - InnoDB init failed

 개요

컴퓨터를 껏다가 키는 동작을 여러 날 시겼으며,

잘 동작하던 MySQL 파드가 어느날 갑자기 동작하지 않았습니다. 

복구 설차를 설명 합니다.


진단 및 해결절차

로그를 보면 innoDB 엔진 초기화가 안되는데, 데이터 파일에 문제가 생긴듯 하다.

"""

mysql 05:51:19.18 INFO  ==> Starting mysql in background

2025-07-28T05:51:19.188987Z 0 [System] [MY-015015] [Server] MySQL Server - start.

2025-07-28T05:51:19.389196Z 0 [System] [MY-010116] [Server] /opt/bitnami/mysql/bin/mysqld (mysqld 9.3.0) starting as process 38

2025-07-28T05:51:19.391364Z 0 [Warning] [MY-013242] [Server] --character-set-server: 'utf8' is currently an alias for the character set UTF8MB3, but will be an alias for UTF8MB4 in a future release. Please consider using UTF8MB4 in order to be unambiguous.

2025-07-28T05:51:19.394161Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started.

2025-07-28T05:51:19.589469Z 1 [ERROR] [MY-012960] [InnoDB] Cannot create redo log files because data files are corrupt or the database was not shut down cleanly after creating the data files.

2025-07-28T05:51:19.589512Z 1 [ERROR] [MY-012930] [InnoDB] Plugin initialization aborted with error Generic error.

2025-07-28T05:51:19.933979Z 1 [ERROR] [MY-010334] [Server] Failed to initialize DD Storage Engine

2025-07-28T05:51:19.934131Z 0 [ERROR] [MY-010020] [Server] Data Dictionary initialization failed.

2025-07-28T05:51:19.934155Z 0 [ERROR] [MY-010119] [Server] Aborting

2025-07-28T05:51:19.935204Z 0 [System] [MY-010910] [Server] /opt/bitnami/mysql/bin/mysqld: Shutdown complete (mysqld 9.3.0)  Source distribution.

2025-07-28T05:51:19.935221Z 0 [System] [MY-015016] [Server] MySQL Server - end.

"""

스테이트 풀셋을 리클리카를 0으로 하고, 디스크를 정상적인 파드를 마운트해서 체크해 봐야 하겠다.

"""
kubectl run debug-pod \
  --image=bitnami/minideb \
  --namespace=coinauto \
  --overrides='
{
  "apiVersion": "v1",
  "spec": {
    "volumes": [
      {
        "name": "mysql-data",
        "persistentVolumeClaim": {
          "claimName": "data-mysql-0"
        }
      }
    ],
    "containers": [
      {
        "name": "debug",
        "image": "bitnami/minideb",
        "command": ["sleep", "3600"],
        "volumeMounts": [
          {
            "mountPath": "/data",
            "name": "mysql-data"
          }
        ]
      }
    ],
    "restartPolicy": "Never"
  }
}'
"""

진단용 파드로 파일 리스트를 체크해 봅니다.

binlog.index 파일 크기 0인상태인데, 비정상 종료시 흔하게 일어나는 현상으로 복구를 시도해야 하는 상황 입니다.

root@debug-pod:/data# du -sh /data/data/*
6.0M    /data/data/#ib_16384_0.dblwr
14M     /data/data/#ib_16384_1.dblwr
101M    /data/data/#innodb_redo
804K    /data/data/#innodb_temp
4.0K    /data/data/auto.cnf
0       /data/data/binlog.index
12M     /data/data/ibdata1
12M     /data/data/ibtmp1
4.0K    /data/data/mysql
980K    /data/data/mysql.ibd
16M     /data/data/undo_001
16M     /data/data/undo_002

파일을 로컬로 복사해 놓자

kubectl cp coinauto/debug-mysql:/data/data ./mysql_recovery

그리고 도커로 해당 파일로 마운트 합니다.

docker run -it --rm \
  -v ./mysql_recovery:/var/lib/mysql \
  --entrypoint /bin/bash \
  mysql:9.3.0

파일확인 합니다.

bash-5.1# cd /var/lib/mysql
bash-5.1# ls -al

새로운 정상적인 SQL 도커를 실행 합니다.

docker run -it --rm \
  --name mysql-recover \
  -v ./mysql_clean:/var/lib/mysql \
  -e MYSQL_ROOT_PASSWORD=admin1234 \
  mysql:8.0

새로운 정상적인 SQL 도커에 접속

docker exec -it mysql-recover mysql -uroot -padmin1234

DB작업

CREATE DATABASE mydb;
USE mydb;

테이블 작업

-- 1. trades 테이블 생성
CREATE TABLE IF NOT EXISTS trades (
    id               INT AUTO_INCREMENT PRIMARY KEY,
    timestamp        DATETIME,
    action           VARCHAR(10),
    entry_price      DOUBLE,
    amount           DOUBLE,
    order_size       DOUBLE,
    leverage         INT,
    stop_loss        DOUBLE,
    take_profit      DOUBLE,
    kelly_fraction   DOUBLE,
    win_probability  DOUBLE,
    volatility       DOUBLE,
    status           VARCHAR(10) DEFAULT 'open'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 2. trade_results 테이블 생성
CREATE TABLE IF NOT EXISTS trade_results (
    id               INT AUTO_INCREMENT PRIMARY KEY,
    trade_id         INT,
    close_timestamp  DATETIME,
    close_price      DOUBLE,
    pnl              DOUBLE,
    pnl_percentage   DOUBLE,
    duration         VARCHAR(50),
    result           VARCHAR(20),
    FOREIGN KEY (trade_id) REFERENCES trades(id)
        ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 3. account_history 테이블 생성
CREATE TABLE IF NOT EXISTS account_history (
    id              INT AUTO_INCREMENT PRIMARY KEY,
    timestamp       DATETIME,
    balance         DOUBLE,
    equity          DOUBLE,
    unrealized_pnl  DOUBLE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

테이블 내용 지우기

ALTER TABLE trades DISCARD TABLESPACE;
ALTER TABLE trade_results DISCARD TABLESPACE;
ALTER TABLE account_history DISCARD TABLESPACE;

.ibd 파일 복사 : 호스트 OS에서 .ibd 파일을 복사하여 컨테이너 내부에 덮어씌웁니다:


docker cp ./mysql_recovery/mydb/users.ibd mysql-recover:/var/lib/mysql/mydb/users.ibd

권한 맞추기

docker exec -it mysql-recover bash -c "chown mysql:mysql /var/lib/mysql/mydb/users.ibd"

테이블스페이스 가져오기

-- 다시 MySQL 접속
USE mydb;
ALTER TABLE trades IMPORT TABLESPACE;
ALTER TABLE trade_results IMPORT TABLESPACE;
ALTER TABLE account_history IMPORT TABLESPACE;

데이터 확인

SELECT * FROM trades;
SELECT * FROM trade_results;
SELECT * FROM account_history;

✅ 주요 원인과 대응 방안

1. 컨테이너 강제 종료 (docker kill, 시스템 다운 등)

원인

컨테이너가 SIGKILL로 종료되면 MySQL은 버퍼에 있던 데이터를 디스크에 flush하지 못합니다.

이로 인해 ibdata1, *.ibd, undo_log, redo_log 파일 불일치 발생 → 복구 어려움.

예방

반드시 **docker stop**으로 정상 종료하도록 합니다.

종료 전 FLUSH TABLES WITH READ LOCK 등으로 동기화 시도 가능.

2. tmpfs, overlayFS, bind mount로 인한 flush 실패

원인

일부 스토리지 드라이버는 MySQL의 fsync, fdatasync() 요청을 무시하거나 느리게 처리.

특히 aufs, overlay2, tmpfs 등에서 문제가 발생하기도 함.

예방

반드시 -v /data/mysql:/var/lib/mysql 처럼 직접적인 host volume mount 사용.

Longhorn, EBS, GCE Persistent Disk 등 정식 블록 스토리지를 마운트하는 것이 가장 안정적.

3. 도커 환경에서 MySQL 설정값 부족

원인

innodb_flush_method, innodb_log_file_size, sync_binlog 등의 설정이 기본값이면 장애에 매우 취약.

예방 (추천 my.cnf 설정):

ini
복사
편집
[mysqld]
innodb_flush_method=O_DIRECT
innodb_flush_log_at_trx_commit=1
sync_binlog=1
flush_method=O_DIRECT는 버퍼를 우회하여 디스크에 직접 기록, 더 안전.

 하루 1회 안전 종료/재시작을 위한 Job 구성

안전 종료 절차 요약

MySQL 내부에 접속
FLUSH TABLES WITH READ LOCK
mysqladmin shutdown 호출
Pod가 재시작되도록 트리거

 Kubernetes CronJob 예제

apiVersion: batch/v1
kind: CronJob
metadata:
  name: mysql-daily-restart
  namespace: default
spec:
  schedule: "0 4 * * *"  # 매일 새벽 4시
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: shutdown
            image: mysql:8.0
            command:
              - /bin/bash
              - -c
              - |
                echo "[INFO] Attempting MySQL shutdown"
                mysql -h my-mysql.default.svc.cluster.local -uroot -padmin1234 -e "FLUSH TABLES WITH READ LOCK;"
                mysqladmin -h my-mysql.default.svc.cluster.local -uroot -padmin1234 shutdown
          restartPolicy: Never


파드 재기동

kubectl rollout restart statefulset my-mysql

preStop Hook으로 종료 시 flush 처리 추가 (안정성 추가)

lifecycle:
  preStop:
    exec:
      command:
        - /bin/bash
        - -c
        - |
          mysql -uroot -p$MYSQL_ROOT_PASSWORD -e "FLUSH TABLES WITH READ LOCK;"
          sleep 10

암호시크릿 만들기

kubectl create secret generic mysql-secret \
  --from-literal=MYSQL_ROOT_PASSWORD=admin1234 -n coinauto

댓글

이 블로그의 인기 게시물

10.15 부동산 대책, 오피스텔도 LTV 40%인가요? 혼선 정리

Kubernetes Pod Pending 해결법: FailedScheduling 원인별 실전 점검 가이드

애플 비전 프로 새 밴드 착용감 어떨까? Dual Knit Band 착용 경험 리뷰