K8s · 工作負載 · 第 12 課 · · 9min read

在 K8s 上跑 MySQL:環境變數注入完整教學

直接用 docker run mysql 行,但 K8s 上要怎麼傳 MYSQL_ROOT_PASSWORD?env 區塊怎麼寫?這篇從零跑起 MySQL Pod,學會 env / envFrom / valueFrom 三種寫法。

#Kubernetes #MySQL #環境變數 #env
章節目錄 · 11

直接 docker run mysql 行,K8s 上要怎麼傳密碼?

docker run 跑 MySQL 你會這樣寫:

docker run -e MYSQL_ROOT_PASSWORD=root1234 -d mysql:8.0

-e 注入環境變數。但 K8s 沒有 -e 參數 — 它是聲明式的,要寫在 YAML 裡。

這篇學 env 區塊的三種寫法:直接寫值、從 ConfigMap、從 Secret

不給密碼會怎樣?親身體驗一下

先寫個沒密碼的 MySQL Pod:

# mysql-no-env.yaml
apiVersion: v1
kind: Pod
metadata:
  name: mysql-broken
spec:
  containers:
  - name: mysql
    image: mysql:8.0
    ports:
    - containerPort: 3306
kubectl apply -f mysql-no-env.yaml
kubectl get pods
# STATUS: CrashLoopBackOff   ← 跟你預期的一樣

kubectl logs mysql-broken
# [ERROR] [Entrypoint]: Database is uninitialized and password option is not specified
# You need to specify one of the following: -e MYSQL_ROOT_PASSWORD ... etc.

MySQL 啟動時要建一個 root 帳號,必須先給密碼。沒給就拒絕啟動。

清掉重來:

kubectl delete pod mysql-broken

寫法 1:直接寫值(env + value)

# mysql.yaml
apiVersion: v1
kind: Pod
metadata:
  name: mysql
spec:
  containers:
  - name: mysql
    image: mysql:8.0
    ports:
    - containerPort: 3306
    env:
    - name: MYSQL_ROOT_PASSWORD
      value: "root1234"
    - name: MYSQL_DATABASE
      value: "mydb"
    - name: MYSQL_USER
      value: "appuser"
    - name: MYSQL_PASSWORD
      value: "app1234"
kubectl apply -f mysql.yaml
kubectl get pods
# STATUS: Running

# 進去確認
kubectl exec -it mysql -- mysql -uroot -proot1234
mysql> SHOW DATABASES;
# information_schema, mydb, mysql, performance_schema, sys
mysql> exit

對應 docker run

DockerK8s YAML
-e MYSQL_ROOT_PASSWORD=root1234env: - name: MYSQL_ROOT_PASSWORD; value: "root1234"
-e MYSQL_DATABASE=mydbenv: - name: MYSQL_DATABASE; value: "mydb"
⚠️ value 一定要是字串,寫數字記得加引號value: "3306" 不是 value: 3306

寫法 2:從 ConfigMap 取(不敏感的設定)

把非敏感的設定(資料庫名、port、log level)放 ConfigMap,密碼類放 Secret。分開管理才好維護

ConfigMap:

# mysql-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: mysql-config
data:
  MYSQL_DATABASE: "mydb"
  MYSQL_USER: "appuser"

Pod 引用:

spec:
  containers:
  - name: mysql
    image: mysql:8.0
    env:
    - name: MYSQL_DATABASE
      valueFrom:
        configMapKeyRef:
          name: mysql-config
          key: MYSQL_DATABASE
    - name: MYSQL_USER
      valueFrom:
        configMapKeyRef:
          name: mysql-config
          key: MYSQL_USER

寫法 3:從 Secret 取(密碼類)

Secret:

# 用指令建(base64 自動處理)
kubectl create secret generic mysql-secret \
  --from-literal=MYSQL_ROOT_PASSWORD=root1234 \
  --from-literal=MYSQL_PASSWORD=app1234

Pod 引用:

spec:
  containers:
  - name: mysql
    image: mysql:8.0
    env:
    - name: MYSQL_ROOT_PASSWORD
      valueFrom:
        secretKeyRef:
          name: mysql-secret
          key: MYSQL_ROOT_PASSWORD
    - name: MYSQL_PASSWORD
      valueFrom:
        secretKeyRef:
          name: mysql-secret
          key: MYSQL_PASSWORD
📖 ConfigMap 跟 Secret 在 Day 6 會深入教,這裡先看寫法。

寫法 4:envFrom 一次塞整包(懶人寫法)

如果 ConfigMap / Secret 裡所有 key 都要當環境變數,逐個寫太煩:

spec:
  containers:
  - name: mysql
    image: mysql:8.0
    envFrom:
    - configMapRef:
        name: mysql-config
    - secretRef:
        name: mysql-secret

ConfigMap / Secret 裡的每個 key 都會自動變成環境變數。省事,但少了「明確指定哪些變數」的清晰度,看你取捨。

確認環境變數有進去

kubectl exec mysql -- env | grep MYSQL
# MYSQL_ROOT_PASSWORD=root1234
# MYSQL_DATABASE=mydb
# MYSQL_USER=appuser
# MYSQL_PASSWORD=app1234

三種寫法對照表

寫法用途特點
value: "xxx"不敏感、固定值直接寫死在 YAML
valueFrom.configMapKeyRef不敏感、要分離改 ConfigMap 不用改 Pod
valueFrom.secretKeyRef密碼、Token跟程式碼分離、能用 RBAC 管權限
envFrom整包塞偷懶,但欄位不夠明確

真實工作的最佳實踐

資料庫名、user、port、log level → ConfigMap
密碼、API Token、TLS 憑證 → Secret
程式內部固定值 → 直接 value

永遠不要把密碼 value: "xxx" 寫在 YAML 然後 commit 到 Git。即使是私有 repo 也一樣。

重點整理

  • K8s 沒有 docker run -e,環境變數寫在 env 區塊
  • 直接寫值用 value: "xxx"(記得字串加引號)
  • 從 ConfigMap 取用 valueFrom.configMapKeyRef
  • 從 Secret 取用 valueFrom.secretKeyRef
  • envFrom 一次塞整包(省事但欄位不明確)
  • 密碼類永遠用 Secret,不要 commit 到 Git

下一步

到目前為止你的 Pod 都是「一個人做事」 — Pod 一掛就什麼都沒了。下一篇正式進入 Deployment 入門:從一個人做事變成一個團隊做事,刪 Pod 自動補回。