[應用] Mariadb === ###### tags: `K8s / app` ###### tags: `Kubernetes`, `k8s`, `app`, `Mariadb` <br> [TOC] <br> # SQL, maria, mariadb-admin commands ## SQL Commands ### `SELECT 1` - 不從任何資料表讀取,直接回傳**一列一欄、值為 1**;常用來測試連線/健康檢查。 - **執行範例** ``` +---+ | 1 | +---+ | 1 | +---+ ``` <br> ### `SELECT 1 FROM DUAL;` - 做的事與 `SELECT 1` 一樣,但透過虛擬表 **DUAL** 寫法;源自 Oracle 習慣。 - **在 MariaDB/MySQL 可省略 `FROM DUAL`,兩者等價。** - **執行範例** ``` +---+ | 1 | +---+ | 1 | +---+ ``` <br> ### `SHOW databases` - **用途**:列出「目前使用者**可見**」的資料庫清單。是否看得到,取決於你是否對該資料庫有任何權限或有 `SHOW DATABASES` 權限。 - **你會看到**:系統資料庫(`information_schema`, `mysql`, `performance_schema`, `sys`)+ 你自己的業務資料庫(例如 `slurm_acct_db`)。 - **小訣竅** * 只看特定名稱:`SHOW DATABASES LIKE 'slurm%';` * 也可用等價語法:`SHOW SCHEMAS;` * 切換資料庫:`USE slurm_acct_db;` - **執行範例** ``` +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | slurm_acct_db | | sys | +--------------------+ ``` <br> ### `SELECT user,host,plugin FROM mysql.user` - **用途**:從系統表 `mysql.user` 查看**帳號清單**與**認證方式**。 - `user`:帳號名稱 - `host`:允許連入的來源(可含萬用字元,如 `%` 代表任意主機、`localhost` 僅本機、`127.0.0.1`/`::1` 分別為 IPv4/IPv6 本機) - `plugin`:**認證外掛**(如 `mysql_native_password`、`auth_socket`、`ed25519`、`pam` 等) - **執行範例** ``` +-------------+-----------+-----------------------+ | User | Host | plugin | +-------------+-----------+-----------------------+ | mariadb.sys | localhost | mysql_native_password | | root | localhost | mysql_native_password | | root | % | mysql_native_password | | healthcheck | 127.0.0.1 | mysql_native_password | | healthcheck | ::1 | mysql_native_password | | healthcheck | localhost | mysql_native_password | | slurm | % | mysql_native_password | +-------------+-----------+-----------------------+ ``` - **匹配規則重點**: - 連線時會用「`user`@`host`」去**精確匹配**這張表(最具體的 `host` 規則優先)。因此 `root@localhost` 與 `root@%` 是**兩個不同帳號**。 - **常見維運動作** - 看清楚是哪一個實際帳號被匹配: ```sql SELECT CONCAT(user, '@', host) AS account, plugin FROM mysql.user ORDER BY user, host; ``` - 查某帳號的權限:`SHOW GRANTS FOR 'slurm'@'%';` - 變更認證外掛(示例): ```sql ALTER USER 'slurm'@'%' IDENTIFIED VIA mysql_native_password USING PASSWORD('yourStrongPwd'); -- 或在部分版本可用: -- ALTER USER 'slurm'@'%' IDENTIFIED BY 'yourStrongPwd'; ``` - **安全建議**:避免不必要的 `user@'%'`(開放過大);管理者帳號(例如 `root`)通常限制在 `localhost`。 - **權限提示**:查 `mysql.user` 需要足夠的系統權限;在受限環境可改用 `INFORMATION_SCHEMA`(如 `USER_PRIVILEGES` 等)查詢權限相關資訊。 - **變更plugin**:將 root plugin 方式設置為 使用密碼 ``` ALTER USER 'root'@'localhost' IDENTIFIED VIA mysql_native_password USING PASSWORD('$ROOT'); ALTER USER 'root'@'127.0.0.1' IDENTIFIED VIA mysql_native_password USING PASSWORD('$ROOT'); ALTER USER 'root'@'::1' IDENTIFIED VIA mysql_native_password USING PASSWORD('$ROOT'); FLUSH PRIVILEGES; ``` <br> --- <br> ## `mariadb` Commands > 也可用 `mysql` command ### [重要] :warning::warning::warning: 留意 password 參數用法 - ### Usage ``` -p, --password[=name] Password to use when connecting to server. If password is not given it's asked from the tty. ``` - ### 正確使用: - `-p"2KwBph3kX0(-S8HU"` - `--password="2KwBph3kX0(-S8HU"` - ### 錯誤使用: - `-p="2KwBph3kX0(-S8HU"` - `--password"2KwBph3kX0(-S8HU"` - `--password "2KwBph3kX0(-S8HU"` - 會要求輸入 password 且後面的 `"2KwBph3kX0(-S8HU"` 不是作為 password 參數 而是作為 database 名稱 - `ERROR 1049 (42000): Unknown database '2KwBph3kX0(-S8HU'` <br> ### 用 root 密碼連上 MariaDB 並跑 `SELECT 1` ``` mariadb -u root -p"${MARIADB_ROOT_PASSWORD}" -e "SELECT 1;" ``` - **說明** - `mariadb`:MariaDB 的**用戶端程式**(連到伺服器執行 SQL)。 - `-u root`:用 **root** 帳號登入。 - `-p"${MARIADB_ROOT_PASSWORD}"`:用環境變數 **MARIADB_ROOT_PASSWORD** 當密碼(`-p` 後**不留空白**,用雙引號讓變數展開並保留特殊字元)。 - `-e "SELECT 1;"`:**非互動模式**執行一條 SQL 後離開。`SELECT 1;` 是最簡單的健康檢查查詢,成功會印出一個 `1`。 - **小提醒** - 在 K8s Probe 裡,**Exit Code=0** 代表成功(可連且能跑查詢);非 0 代表失敗(密碼錯、尚未啟動好、連線失敗等)。 - 若 root 啟用了 `unix_socket` 認證,**密碼登入會失敗**,需改用對應帳號或調整 root 認證方式。 <br> ### 用 Unix Socket 連上 MariaDB 並跑 `SELECT 1` ``` mariadb -u root -S /run/mysqld/mysqld.sock -e "SELECT 1;" ``` - **說明** - `mariadb`:MariaDB 的**用戶端程式**(連到伺服器執行 SQL)。 - `-u root`:以 **root** 帳號登入(搭配 socket 時是否需要密碼,取決於認證外掛)。 - `-S /run/mysqld/mysqld.sock`:指定 **Unix socket 檔**連線(走檔案 I/O,不走 TCP)。 - 常見路徑為 - `/run/mysqld/mysqld.sock` - `/var/run/mysqld/mysqld.sock` - `-e "SELECT 1;"`:**非互動模式**執行一條 SQL 後離開。 - **適用情境** - 跑在**同一台主機 / 同一個 Pod**內,想避開網路堆疊(速度快、少依賴)。 - `root@localhost` 啟用 **`unix_socket` 認證**時,**以本機 OS 使用者登入可免密碼**(多數套件預設如此);此時用 `-S` 最符合預期。 - **小提醒** - **socket 路徑查法**: `grep -R "^\s*socket" /etc/mysql /etc/my.cnf* 2>/dev/null || my_print_defaults mysqld | grep socket` - 執行範例 ``` /etc/mysql/my.cnf:socket = /run/mysqld/mysqld.sock /etc/mysql/mariadb.cnf:socket = /run/mysqld/mysqld.sock ``` - **權限**:執行者需能讀寫該 socket(通常屬主/群組為 `mysql`)。非 root 身分可能需要加入 `mysql` 群組或改用 `sudo -u mysql`。 - **`-h` 差異**:`-h 127.0.0.1` 強制走 TCP;`-h localhost`(未指定 `--protocol=tcp`)通常會走 socket;**指定 `-S` 時會以 socket 為準**。 - **路徑差異**:不同映像/發行版路徑可能不同(`/run/...` 或 `/var/run/...`)。若檔案不存在,通常是 mysqld 尚未啟動好或路徑/權限不正確。 <br> --- <br> ## `mariadb-admin` Commands ### 能不能回應 ping ```bash mariadb-admin \ --user=root \ --password="$MARIADB_ROOT_PASSWORD" \ ping --silent ``` - **正常回應** ``` mysqld is alive ``` - **密碼錯誤** ``` error: 'Access denied for user 'root'@'localhost' (using password: YES)' ``` - **無法連線** ``` mariadb-admin: connect to server at 'localhost' failed ``` <br> --- --- <br> # kubernetes ## kubectl commands ### 查詢 root 密碼 ```bash NAMESPACE=slurm ROOT=$(kubectl -n ${NAMESPACE} get secret mariadb-root -o jsonpath='{.data.password}' | base64 -d) echo $ROOT # 1T2qHJ~0sRGjiW=3 ``` - ### 查看 secret ```yaml= $ kubectl -n slurm get secret/mariadb-root -o yaml apiVersion: v1 data: password: MVQycUhKfjBzUkdqaVc9Mw== kind: Secret metadata: creationTimestamp: "2025-10-03T06:51:19Z" name: mariadb-root namespace: slurm resourceVersion: "166297201" uid: 0986903e-a2a9-4e1c-99fc-de43ad0822f1 type: Opaque ``` - **驗證 `password` 解碼後的明碼** ``` $ echo -n "MVQycUhKfjBzUkdqaVc9Mw==" | base64 -d 1T2qHJ~0sRGjiW=3 ``` - ### 環境變數 - secret 中的密碼,會存放到環境變數 `MARIADB_ROOT_PASSWORD` - **檢查環境變數** ```bash env | grep -i password ``` 或 ```bash env | grep -i root ``` - ### 使用 root 帳號測試 ``` mariadb -u root -p"${MARIADB_ROOT_PASSWORD}" -e "SELECT 1;" ``` <br> --- <br> ## 在 Kubernetes 上部署 mariadb > https://github.com/SlinkyProject/slurm-operator/blob/main/docs/installation.md#mariadb-community-edition ### 步驟一:安裝 mariadb operator ```bash= helm repo add mariadb-operator https://helm.mariadb.com/mariadb-operator helm repo update helm install mariadb-operator-crds mariadb-operator/mariadb-operator-crds helm install mariadb-operator mariadb-operator/mariadb-operator \ --namespace mariadb --create-namespace ``` - ### 缺點 - 移除 mariadb-operator 時,mariadb CRD 不會跟著移除 - ### crds 與 operator 一起安裝 ```bash helm install mariadb-operator mariadb-operator/mariadb-operator \ --namespace mariadb-operator --create-namespace \ --set 'crds.enabled=true' ``` - ### 優點: - 移除 operator 時,CRD 會跟著移除 (有驗證過) - 升版 operator 時,CRD 會跟著升版 ### 步驟二:部署 MariaDB CR ```yaml= # mariadb.yaml apiVersion: k8s.mariadb.com/v1alpha1 kind: MariaDB metadata: name: mariadb namespace: slurm spec: rootPasswordSecretKeyRef: name: mariadb-root key: password generate: true username: slurm database: slurm_acct_db passwordSecretKeyRef: name: mariadb-password key: password generate: true storage: size: 1Gi myCnf: | [mariadb] bind-address=* default_storage_engine=InnoDB binlog_format=row innodb_autoinc_lock_mode=2 innodb_buffer_pool_size=4096M innodb_lock_wait_timeout=900 innodb_log_file_size=1024M max_allowed_packet=256M ``` ### probe 設定1 ```yaml startupProbe: initialDelaySeconds: 20 # 20 periodSeconds: 10 # 10 timeoutSeconds: 5 # 5 failureThreshold: 3 # 3 livenessProbe: initialDelaySeconds: 180 # 20 periodSeconds: 60 # 10 timeoutSeconds: 60 # 5 failureThreshold: 10 # 3 readinessProbe: initialDelaySeconds: 180 # 20 periodSeconds: 60 # 10 timeoutSeconds: 60 # 5 failureThreshold: 10 # 3 ``` ### probe 設定2:使用 tcpSocket ```yaml startupProbe: tcpSocket: port: 3306 initialDelaySeconds: 10 periodSeconds: 10 failureThreshold: 30 livenessProbe: tcpSocket: port: 3306 initialDelaySeconds: 30 periodSeconds: 10 timeoutSeconds: 5 readinessProbe: tcpSocket: port: 3306 initialDelaySeconds: 5 periodSeconds: 5 timeoutSeconds: 5 ``` - **優勢** - 不需要任何密碼驗證 - 檢查 MariaDB 服務是否在監聽 3306 埠 - 執行速度最快 - 避免了密碼錯誤導致的失敗 ### 其他設定 - [Storage](https://mariadb.com/docs/tools/mariadb-enterprise-operator/storage) <br> --- --- <br> ## 測試 mariadb 連線與查詢 > 假設 mariadb server 位於 -n slurm ### 在其他 namespace 下連接 mariadb server - ### 使用 Bitnami MariaDB 映像檔 ```bash # 先把連線參數與密碼變數抓好(密碼從 slurm namespace 的 Secret 取) DB_HOST=mariadb.slurm.svc.cluster.local DB_PORT=3306 DB_NAME=slurm_acct_db DB_USER=slurm DB_PASS=$(kubectl -n slurm get secret mariadb-password -o jsonpath='{.data.password}' | base64 -d) # 在 default 起一個臨時 client 容器並直接測試 kubectl run -n default -it --rm mariadb-client \ --image=bitnami/mariadb:latest \ --restart=Never \ --env=MYSQL_PWD="$DB_PASS" \ --command -- sh -lc \ "mariadb -h ${DB_HOST} -P ${DB_PORT} -u ${DB_USER} -D ${DB_NAME} -e 'SELECT 1 AS ok; SHOW DATABASES; SELECT DATABASE(); SHOW TABLES;'" ``` - **說明** - 在執行 `kubectl run` 前,shell 就會將變數置換成字串 - 用環境變數 `MYSQL_PWD` 避免在命令列明文出現密碼;測試會列出資料庫/目前 DB/資料表。 - 或是進入到 pod 在執行 mariadb 指令 ``` mariadb \ -h mariadb.slurm.svc.cluster.local \ -P 3306 \ -u slurm \ -D slurm_acct_db \ -e 'SELECT 1 AS ok; SHOW DATABASES; SELECT DATABASE(); SHOW TABLES;' ``` - **執行結果** ``` WARNING: option --ssl-verify-server-cert is disabled, because of an insecure passwordless login. +----+ | ok | +----+ | 1 | +----+ +--------------------+ | Database | +--------------------+ | information_schema | | slurm_acct_db | +--------------------+ +---------------+ | DATABASE() | +---------------+ | slurm_acct_db | +---------------+ +-------------------------------------+ | Tables_in_slurm_acct_db | +-------------------------------------+ | acct_coord_table | | acct_table | | clus_res_table | | cluster_table | | convert_version_table | | federation_table | | qos_table | | res_table | | slurm_slurm_assoc_table | | slurm_slurm_assoc_usage_day_table | | slurm_slurm_assoc_usage_hour_table | | slurm_slurm_assoc_usage_month_table | | slurm_slurm_event_table | | slurm_slurm_job_env_table | | slurm_slurm_job_script_table | | slurm_slurm_job_table | | slurm_slurm_last_ran_table | | slurm_slurm_qos_usage_day_table | | slurm_slurm_qos_usage_hour_table | | slurm_slurm_qos_usage_month_table | | slurm_slurm_resv_table | | slurm_slurm_step_table | | slurm_slurm_suspend_table | | slurm_slurm_usage_day_table | | slurm_slurm_usage_hour_table | | slurm_slurm_usage_month_table | | slurm_slurm_wckey_table | | slurm_slurm_wckey_usage_day_table | | slurm_slurm_wckey_usage_hour_table | | slurm_slurm_wckey_usage_month_table | | table_defs_table | | tres_table | | txn_table | | user_table | +-------------------------------------+ pod "mariadb-client" deleted ``` <br> - ### 若想用官方 `mariadb` 映像檔 ```bash DB_PASS=$(kubectl -n slurm get secret mariadb-password -o jsonpath='{.data.password}' | base64 -d) kubectl run -n default -it --rm mariadb-client \ --image=mariadb:11 \ --restart=Never \ --env=MYSQL_PWD="$DB_PASS" \ --command -- bash -lc \ "mariadb -h mariadb.slurm.svc.cluster.local -P 3306 -u slurm slurm_acct_db -e 'SELECT VERSION(); SELECT 1;'" ``` - **執行結果** ``` WARNING: option --ssl-verify-server-cert is disabled, because of an insecure passwordless login. +------------------------+ | VERSION() | +------------------------+ | 11.8.2-MariaDB-ubu2404 | +------------------------+ +---+ | 1 | +---+ | 1 | +---+ pod "mariadb-client" deleted ``` <br> ### 連線不通時快速檢查 ```bash # 確認 DNS 能解 kubectl run -n default -it --rm dnsutils --image=busybox --restart=Never \ --command -- sh -lc "nslookup mariadb.slurm.svc.cluster.local" # 確認 TCP 可達 kubectl run -n default -it --rm netshoot --image=nicolaka/netshoot --restart=Never \ --command -- sh -lc "nc -vz mariadb.slurm.svc.cluster.local 3306" ``` > 若這裡失敗,通常是 NetworkPolicy、Service 名稱或 Port 設定問題;能通但認證失敗再回頭檢查帳密與 DB 名稱是否一致。 <br> --- --- <br> ## 討論 ### MARIADB_AUTO_UPGRADE 參數用途為何? - ### Question ```yaml apiVersion: k8s.mariadb.com/v1alpha1 kind: MariaDB metadata: name: mariadb spec: ... env: - name: MARIADB_AUTO_UPGRADE value: "1" ... ``` MARIADB_AUTO_UPGRADE 參數用途為何? - ### gpt-5 (2025/10/09) 簡單說:`MARIADB_AUTO_UPGRADE=1` 會讓 **MariaDB Docker 官方映像**在容器啟動時,自動執行 `mariadb-upgrade`(若判斷有需要),以**升級系統表**並標記/快速檢查資料表,使資料目錄與新版本相容。這可減少你在**更換映像標籤或版本升級**(甚至 MySQL→MariaDB 的遷移)時的手動步驟。([Docker Hub][1]) ### 要點 * **觸發時機**:只要設為非空值(如 `"1"`),入口腳本會在需要時執行 `mariadb-upgrade`;若版本未變更或不需升級則不做事。([Docker Hub][1]) * **做了什麼**:更新 `mysql` 系統資料表,並快速檢查/標記資料表與新版本相容(必要時修復)。([man7.org][2]) * **常見用途**: * 容器升級版本時自動處理系統表升級。([Docker Hub][1]) * 使用舊版 MySQL/MariaDB 的資料目錄啟動新版 MariaDB(官方示例就要求設 `MARIADB_AUTO_UPGRADE=1`)。([MariaDB.org][3]) ### 注意事項 * 這個變數**主要涵蓋系統表的升級**;若你的應用需要特定的**使用者資料表結構變更**,仍可能需要你自行執行對應的 DDL 或維護腳本。([GitHub][4]) * 在少數環境設定(例如特定 SSL 設定)下,曾有自動升級失敗的回報;若遇到啟動失敗,請先檢查容器日誌,必要時暫時關閉自動升級(設為 `"0"` 或移除變數)並改採手動流程。([GitHub][5]) ### 與你這份 CR 的關聯 你在 `spec.env` 放入: ```yaml - name: MARIADB_AUTO_UPGRADE value: "1" ``` 代表 MariaDB Pod 每次以新映像啟動時,會自動執行必要的 `mariadb-upgrade`,協助完成升級所需的系統表更新,減少人工介入。([Docker Hub][1]) > 延伸閱讀:MariaDB 官方對 Docker 自動升級/遷移的說明與範例。([MariaDB.org][3]) [1]: https://hub.docker.com/_/mariadb?utm_source=chatgpt.com "mariadb - Official Image" [2]: https://man7.org/linux/man-pages/man1/mariadb-upgrade.1.html?utm_source=chatgpt.com "mariadb-upgrade(1) - Linux manual page" [3]: https://mariadb.org/migration-with-docker-official-images/?utm_source=chatgpt.com "Migration with Docker Official Images" [4]: https://github.com/MariaDB/mariadb-docker/issues/562?utm_source=chatgpt.com "Add option to auto upgrade user tables · Issue #562" [5]: https://github.com/MariaDB/mariadb-docker/issues/592?utm_source=chatgpt.com "MARIADB_AUTO_UPGRADE=1/mariadb-upgrade not ..." <br> --- ### startupProbe 時間軸 - ### Question ```yaml apiVersion: k8s.mariadb.com/v1alpha1 kind: MariaDB metadata: name: mariadb spec: ... startupProbe: tcpSocket: port: 3306 initialDelaySeconds: 20 periodSeconds: 10 failureThreshold: 30 ``` 給出 startupProbe 時間軸,並標注做了什麼? - ### gpt-5 (2025/10/09) 下面用你的設定值畫出「**startupProbe 時間軸**」+每一步 kubelet 做了什麼。 ### 你的參數 * `tcpSocket.port`: **3306** * `initialDelaySeconds`: **20s** * `periodSeconds`: **10s** * `failureThreshold`: **30** * `timeoutSeconds`: 未設定 ⇒ **預設 1s** * `successThreshold`: 固定為 **1**(startupProbe 不可調) --- ### 時間軸(第一次容器啟動) ``` t=0s Container 進入 Running;啟動 startupProbe 計時。(若有 liveness/readiness,這時都「暫停」,直到 startup 成功) t=20s 第 1 次探針:對 3306 建立 TCP 連線(成功 ⇒ startup 完成;失敗 ⇒ 累計失敗 1/30) t=30s 第 2 次探針(成功 ⇒ 完成;失敗 ⇒ 2/30) t=40s 第 3 次探針(…) ... t=300s 第 29 次探針(失敗 ⇒ 29/30) t=310s 第 30 次探針(失敗 ⇒ 30/30 達到門檻)⇒ **kubelet 立即重啟容器**(加上單次 probe 的 timeout,最晚約 311s) ``` * **最長允許啟動時間(直到第一次被重啟)** ≈ `initialDelaySeconds + (failureThreshold - 1) * periodSeconds + timeoutSeconds` = `20 + (30 - 1) * 10 + 1` ≈ **311 秒** (說法白話點:第 1 次在 20s,之後每 10s 一次,連續 30 次都失敗就重啟;每次最多等 1s 超時) --- ### 成功與後續行為 * **任何一次探針成功**(TCP 連上 3306)⇒ `startupProbe` **完成**,之後**不再執行**。 * 這時(如果你**有**定義)才會開始套用 **livenessProbe / readinessProbe**。 * 你目前 **未定義 readiness/liveness**: * 沒有 readinessProbe 時,容器一旦 Running 通常就被視為 Ready(可能過早納入 Service 後端)。 * 建議再補一個 `readinessProbe`(例如 `mariadb -S /run/mysqld/mysqld.sock -e "SELECT 1"`)來**真正等資料庫可用**才對外服務;另行加上 `livenessProbe` 做長期健康檢查。 --- ### 速查表(每一步做了什麼) * **等待期**(0–20s):不做檢查,等初始延遲。 * **週期檢查**(每 10s 一次):嘗試 **TCP 連線到 3306**;連上即成功;連不上或逾時(>1s)算失敗。 * **失敗累計**:連續失敗 **30 次** ⇒ **重啟容器**,並進入 Kubernetes 的重啟退避(back-off)機制。 * **成功一次就收工**:`startupProbe` 結束,之後交由 readiness/liveness(若有)接手。 <br> ### startupProbe 時間軸 - ### Question ```yaml Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 18m default-scheduler Successfully assigned slurm/mariadb-0 to ocis-esc4000a-e11 Normal Pulled 18m kubelet Container image "docker-registry1.mariadb.com/library/mariadb:11.8.2" already present on machine Normal Created 18m kubelet Created container: mariadb Normal Started 18m kubelet Started container mariadb Warning Unhealthy 15m kubelet Startup probe failed: ERROR 2002 (HY000): Can't connect to local server through socket '/run/mysqld/mysqld.sock' (2) ``` 為何是不健康? - ### gpt-5 (2025/10/09) <br> {%hackmd vaaMgNRPS4KGJDSFG0ZE0w %}