---
# System prepended metadata

title: '[db] PostgreSQL 配置指南 - 能與 Slinky 相容？不相容！'
tags: [k8s, Slurm / SlinkyProject / db, Slurm, PostgreSQL, app, SlinkyProject, Kubernetes]

---

[db] PostgreSQL 配置指南 - 能與 Slinky 相容？不相容！
===
###### tags: `Slurm / SlinkyProject / db`
###### tags: `Slurm`, `SlinkyProject`, `Kubernetes`, `k8s`, `app`, `PostgreSQL`

<br>

[TOC]

<br>



<br>

---
---

<br>


# PostgreSQL 在 K8s 上的安裝及與 Slinky 整合指南
> by TJ, Claude Sonnet4 (2025/11/05)

## 概述

本指南說明如何在 Kubernetes 上部署 PostgreSQL，並將其與 Slinky (Slurm Operator) 整合作為 Slurm accounting 資料庫。

<br>

## PostgreSQL 安裝方式
> - 資料來源：[[應用] PostgreSQL](https://hackmd.io/flWpoya6QqSUfd13v9AOHQ)
> - 方案一(驗證過) (選用簡單方案即可)
> - 方案二(尚未驗證)

### 方案一：使用 Bitnami PostgreSQL Helm Chart (推薦)

Bitnami 提供穩定且易於維護的 PostgreSQL Helm Chart。

- ### 1. 新增 Bitnami Helm Repository

    ```bash
    helm repo add bitnami https://charts.bitnami.com/bitnami
    helm repo update
    ```

- ### 2. 建立 Namespace

    ```bash
    kubectl create namespace postgresql
    ```

- ### 3. 準備 values 檔案
    > 請參考 [[SlinkyProject] values.yaml#L385-L402](https://github.com/SlinkyProject/slurm-operator/blob/main/helm/slurm/values.yaml#L385-L402)
    > ```yaml
    > accounting:
    >   ...
    >   # The storage configuration.
    >   storageConfig:
    >     # -- The name of the host where the database is running.
    >     # Ref: https://slurm.schedmd.com/slurmdbd.conf.html#OPT_StorageHost
    >     host: mariadb
    >     # -- The port number to communicate with the database with.
    >     # Ref: https://slurm.schedmd.com/slurmdbd.conf.html#OPT_StoragePort
    >     port: 3306
    >     # -- The name of the database where records are written into.
    >     # Ref: https://slurm.schedmd.com/slurmdbd.conf.html#OPT_StorageLoc
    >     database: slurm_acct_db
    >     # -- The name of the user used to connect to the database with.
    >     # Ref: https://slurm.schedmd.com/slurmdbd.conf.html#OPT_StorageUser
    >     username: slurm
    >     # -- (secretKeyRef) The password used to connect to the database, from secret reference.
    >     # Ref: https://slurm.schedmd.com/slurmdbd.conf.html#OPT_StoragePass
    >     passwordKeyRef:
    >       name: mariadb-password
    >       key: password
    > ```
    > ---

    建立 `postgres-values.yaml`：

    ```yaml=
    global:
      postgresql:
        auth:
          username: "slurm"
          password: "slurm_password"
          database: "slurm_acct_db"
          postgresPassword: "admin_password"

    primary:
      persistence:
        enabled: true
        size: 10Gi
        storageClass: ""

      resources:
        limits:
          memory: 2Gi
          cpu: 1000m
        requests:
          memory: 512Mi
          cpu: 250m

      livenessProbe:
        enabled: true
        initialDelaySeconds: 30
        periodSeconds: 10
        timeoutSeconds: 5
        failureThreshold: 6

      readinessProbe:
        enabled: true
        initialDelaySeconds: 5
        periodSeconds: 10
        timeoutSeconds: 5
        failureThreshold: 6

      startupProbe:
        enabled: true
        initialDelaySeconds: 30
        periodSeconds: 10
        timeoutSeconds: 5
        failureThreshold: 15

    service:
      type: ClusterIP
      ports:
        postgresql: 5432

    metrics:
      enabled: true
      serviceMonitor:
        enabled: false
    ```

    #### 4. 安裝 PostgreSQL

    ```bash
    helm install postgresql bitnami/postgresql \
      --namespace postgresql \
      --values postgres-values.yaml
    ```
    - :::spoiler 執行過程
        ```
        NAME: postgresql
        LAST DEPLOYED: Wed Nov  5 12:29:09 2025
        NAMESPACE: postgresql
        STATUS: deployed
        REVISION: 1
        TEST SUITE: None
        NOTES:
        CHART NAME: postgresql
        CHART VERSION: 18.0.15
        APP VERSION: 18.0.0
        ```

        ⚠ WARNING: Since August 28th, 2025, only a limited subset of images/charts are available for free.
            Subscribe to Bitnami Secure Images to receive continued support and security updates.
            More info at https://bitnami.com and https://github.com/bitnami/containers/issues/83267

        **Please be patient while the chart is being deployed**

        PostgreSQL can be accessed via port 5432 on the following DNS names from within your cluster:

            postgresql.postgresql.svc.cluster.local - Read/Write connection

        To get the password for "postgres" run:

            export POSTGRES_ADMIN_PASSWORD=$(kubectl get secret --namespace postgresql postgresql -o jsonpath="{.data.postgres-password}" | base64 -d)

        To get the password for "slurm" run:

            export POSTGRES_PASSWORD=$(kubectl get secret --namespace postgresql postgresql -o jsonpath="{.data.password}" | base64 -d)

        To connect to your database run the following command:

            kubectl run postgresql-client --rm --tty -i --restart='Never' --namespace postgresql --image registry-1.docker.io/bitnami/postgresql:latest --env="PGPASSWORD=$POSTGRES_PASSWORD" \
              --command -- psql --host postgresql -U slurm -d slurm_acct_db -p 5432

            > NOTE: If you access the container using bash, make sure that you execute "/opt/bitnami/scripts/postgresql/entrypoint.sh /bin/bash" in order to avoid the error "psql: local user with ID 1001} does not exist"

        To connect to your database from outside the cluster execute the following commands:

            kubectl port-forward --namespace postgresql svc/postgresql 5432:5432 &
            PGPASSWORD="$POSTGRES_PASSWORD" psql --host 127.0.0.1 -U slurm -d slurm_acct_db -p 5432

        WARNING: The configured password will be ignored on new installation in case when previous PostgreSQL release was deleted through the helm command. In that case, old PVC will have an old password, and setting it through helm won't take effect. Deleting persistent volumes (PVs) will solve the issue.
        WARNING: Rolling tag detected (bitnami/postgresql:latest), please note that it is strongly recommended to avoid using rolling tags in a production environment.
        +info https://techdocs.broadcom.com/us/en/vmware-tanzu/application-catalog/tanzu-application-catalog/services/tac-doc/apps-tutorials-understand-rolling-tags-containers-index.html
        WARNING: Rolling tag detected (bitnami/os-shell:latest), please note that it is strongly recommended to avoid using rolling tags in a production environment.
        +info https://techdocs.broadcom.com/us/en/vmware-tanzu/application-catalog/tanzu-application-catalog/services/tac-doc/apps-tutorials-understand-rolling-tags-containers-index.html

        WARNING: There are "resources" sections in the chart not set. Using "resourcesPreset" is not recommended for production. For production installations, please set the following values according to your workload needs:
          - metrics.resources
          - readReplicas.resources
        +info https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
        :::

    #### 5. 等待 PostgreSQL 就緒

    ```bash
    kubectl wait --for=condition=ready pod -l app.kubernetes.io/name=postgresql \
      -n postgresql --timeout=600s
    ```
    - **直接查看資源狀況**
        ```
        $ kubectl -n postgresql get pod -l app.kubernetes.io/name=postgresql
        NAME           READY   STATUS    RESTARTS   AGE
        postgresql-0   2/2     Running   0          2m3s
        ```

    #### 6. 驗證安裝

    ```bash
    kubectl -n postgresql get all  # show pod & svc
    ```
    
    #### 7. 移除 PostgreSQL
    ```
    helm -n postgresql uninstall postgresql
    ```
    
    #### Troubleshooting
    - ### ImagePullBackOff

        Bitnami 宣布自 2025-08-28 起，Docker Hub 的大部分版本化影像不再免費提供，舊版本移往 `bitnamilegacy/*`（停止更新），僅提供少量 “latest” 作為開發用，或走付費的 Secure Images；因此舊的 `bitnami/*` tag 會出現 **manifest not found**。

        > 補充：你安裝 chart 時 `NOTES` 內也會出現 2025-08-28 的警示文字。
        
        ---
        
        **暫時解法**：把來源改到 `bitnamilegacy/*`，用仍存在的 tag：

        ```bash
        # 建議用 helm 升級（在同一個 namespace）
        helm upgrade --install postgresql bitnami/postgresql \
          -n postgresql \
          --set image.repository=bitnamilegacy/postgresql \
          --set image.tag=17.6.0-debian-12-r4 \
          --set metrics.enabled=true \
          --set metrics.image.repository=bitnamilegacy/postgres-exporter \
          --set metrics.image.tag=0.17.1-debian-12-r14
        ```

        > 說明：`bitnamilegacy/postgresql:17.6.0-debian-12-r4` 與 `bitnamilegacy/postgres-exporter:0.17.1-debian-12-r14` 目前可抓到；`-r16` 未必存在於 legacy。([Docker Hub](https://hub.docker.com/r/bitnamilegacy/postgresql/tags))

    - ### `[ImagePullBackOff] Back-off pulling image "docker.io/bitnami/postgresql:17.6.0-debian-12-r4"`
        **解法**：`bitnami` -> `bitnamilegacy`
        ```bash
        # 直接測試節點能否拉到影像（containerd）
        sudo ctr -n k8s.io images pull docker.io/bitnamilegacy/postgresql:17.6.0-debian-12-r4
        ```
        
    - ### `[ImagePullBackOff] Back-off pulling image "docker.io/bitnami/postgres-exporter:0.17.1-debian-12-r16"`
        **解法**：`bitnami` -> `bitnamilegacy`
        ```bash
        # 直接測試節點能否拉到影像（containerd）
        sudo ctr -n k8s.io images pull quay.io/prometheuscommunity/postgres-exporter:v0.18.1
        ```


<br>

---

### 方案二：使用 CloudNativePG Operator

CloudNativePG 是專為 Kubernetes 設計的 PostgreSQL Operator，提供更進階的功能如高可用性、備份恢復等。

- ### 1. 安裝 CloudNativePG Operator

    ```bash
    kubectl apply -f https://raw.githubusercontent.com/cloudnative-pg/cloudnative-pg/release-1.23/releases/cnpg-1.23.0.yaml
    ```

- ### 2. 建立 PostgreSQL Cluster

    建立 `postgres-cluster.yaml`：

    ```yaml=
    apiVersion: postgresql.cnpg.io/v1
    kind: Cluster
    metadata:
      name: postgresql
      namespace: postgresql
    spec:
      instances: 1

      postgresql:
        parameters:
          max_connections: "200"
          shared_buffers: "256MB"

      bootstrap:
        initdb:
          database: slurm_acct_db
          owner: slurm
          secret:
            name: postgresql-credentials

      storage:
        size: 10Gi
        storageClass: ""

      resources:
        requests:
          memory: "512Mi"
          cpu: "500m"
        limits:
          memory: "2Gi"
          cpu: "2"

      monitoring:
        enablePodMonitor: false
    ```

- ### 3. 建立 Credentials Secret

    ```bash
    kubectl create namespace postgresql

    kubectl create secret generic postgresql-credentials \
      --namespace postgresql \
      --from-literal=username=slurm \
      --from-literal=password=slurm_password
    ```

- ### 4. 部署 Cluster

    ```bash
    kubectl apply -f postgres-cluster.yaml
    ```

<br>

---
---

<br>

## 測試 PostgreSQL 連線與查詢
> - 資料來源：[[應用] PostgreSQL](https://hackmd.io/flWpoya6QqSUfd13v9AOHQ)
> - 使用方案一驗證

### 當前 PostgreSQL server 提供的資訊
| 屬性 | 屬性值 | |
|-----|-----|-----|
| **host** | `postgresql.postgresql.svc.cluster.local` | 叢集內的服務 DNS（ClusterIP），供 K8s 內部連線使用 |
| **port** | `5432` | PostgreSQL 連接埠（預設 5432） |
| **database** | `slurm_acct_db` | 目標資料庫名稱 |
| **username** | `slurm` | 使用者帳號 |
| **password** | `slurm_password` | 使用者密碼 |

<br>

### 方式 A：用一次性 psql 客戶端 Pod 直接測

> 不用搬 Secret，直接把密碼讀出來塞進環境變數。

1. 先把密碼讀到本機變數（Secret 在 `postgresql` ns）：

    ```bash
    PW=$(kubectl -n postgresql get secret postgresql \
      -o jsonpath='{.data.password}' | base64 -d)

    echo $PW
    # 預期：PW=slurm_password
    ```

2. 在 **default** ns 起一個一次性 Pod，立刻執行查詢：

    ```bash
    kubectl -n default run psql-test \
      --image=postgres:16 \
      --restart=Never \
      --env="PGPASSWORD=$PW" \
      --command -- psql \
        -h postgresql.postgresql.svc.cluster.local \
        -p 5432 \
        -U slurm \
        -d slurm_acct_db \
        -c 'select current_database(), current_user, version();'
    ```
    
3. **驗證結果**
    
    ```bash
    kubectl -n default get pod
    kubectl -n default logs pod/psql-test
    ```
    - **執行結果**
        ```
        $ kubectl -n default get pod
        NAME                               READY   STATUS      RESTARTS      AGE
        psql-test                          0/1     Completed   0             88s

        $ kubectl -n default logs pod/psql-test
         current_database | current_user |                                   version
        ------------------+--------------+------------------------------------------------------------------------------
         slurm_acct_db    | slurm        | PostgreSQL 18.0 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 12.2.0, 64-bit
        (1 row)
        ```

4. （可選）清掉測試 Pod：

    ```bash
    kubectl -n default delete pod psql-test --ignore-not-found
    ```

成功時你會看到目前資料庫、使用者與 PostgreSQL 版本。

<br>

---

### 方式 B：先起一個「工具箱」Pod，再進去測

> 方便多次測試或跑 `pg_isready`、`nslookup` 等工具。

1. 起一個空轉的工具箱 Pod：

    ```bash
    kubectl -n default run toolbox --image=postgres:16 --restart=Never -- sleep 3600
    ```
    
2. 先把密碼讀到本機變數（Secret 在 `postgresql` ns）：

    ```bash
    PW=$(kubectl -n postgresql get secret postgresql \
      -o jsonpath='{.data.password}' | base64 -d)

    echo $PW
    # 預期：PW=slurm_password
    ```
    
3. 進去執行測試（把上面取到的 `$PW` 帶進去）：

    ```bash
    kubectl -n default exec -it toolbox -- bash -lc \
    'PGPASSWORD='"$PW"' psql -h postgresql.postgresql.svc.cluster.local -p 5432 -U slurm -d slurm_acct_db -c "select current_database(), current_user, version()"'
    ```
    - **執行結果**
        ```
         current_database | current_user |                                   version
        ------------------+--------------+------------------------------------------------------------------------------
         slurm_acct_db    | slurm        | PostgreSQL 18.0 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 12.2.0, 64-bit
        (1 row)
        ```

4. 也可做純連線健康檢查：

    ```bash
    kubectl -n default exec toolbox -- pg_isready -h postgresql.postgresql.svc.cluster.local -p 5432 -U slurm -d slurm_acct_db
    ```
    - **執行結果**
        ```
        postgresql.postgresql.svc.cluster.local:5432 - accepting connections
        ```

4. 測完刪掉：

    ```bash
    kubectl -n default delete pod toolbox
    ```

<br>

---

### 方式 C：本機 psql + 轉址（如果你偏好在自己電腦上測）

```bash
kubectl -n postgresql port-forward svc/postgresql 5432:5432
# 另開一個終端
PGPASSWORD="$PW" psql -h 127.0.0.1 -p 5432 -U slurm -d slurm_acct_db -c 'select 1'
```

<br>

---

### 注意事項

* **Secrets 是有命名空間的**：`default` 裡的 Pod 不能直接掛載 `postgresql` 命名空間的 Secret；上面做法是把密碼讀出後用環境變數傳給一次性 Pod。若你要長期跑的 Pod 讀 Secret，請把 Secret 複製一份到 `default`（或用 External Secrets 同步），再掛載使用。
* 若有 **NetworkPolicy**，請確認 `default → postgresql` 的 5432/TCP 沒被擋。
* 若你實際的使用者/資料庫不是 `slurm`/`slurm_acct_db`，把指令中的 `-U` 與 `-d` 改掉即可。

<br>

---
---

<br>


## 與 Slinky 整合

### 1. 建立資料庫密碼 Secret

```bash
kubectl create namespace slurm

kubectl create secret generic postgresql-password \
  --namespace slurm \
  --from-literal=password=slurm_password
```

### 2. 建立 Slurm 資料庫配置檔案

建立 `deploy_cluster/values-db-custom-postgresql.yaml`：

```yaml
accounting:
  enabled: true
  storageConfig:
    host: postgresql.postgresql.svc.cluster.local
    port: 5432
    database: slurm_acct_db
    username: slurm
    passwordKeyRef:
      name: postgresql-password
      key: password
```

**說明**：
- `host`: PostgreSQL 服務的 FQDN (格式：`<service-name>.<namespace>.svc.cluster.local`)
- `port`: PostgreSQL 服務 port (預設 5432)
- `database`: 資料庫名稱 (必須與 PostgreSQL 初始化時建立的資料庫一致)
- `username`: 資料庫使用者 (必須與 PostgreSQL 初始化時建立的使用者一致)
- `passwordKeyRef`: 密碼 Secret 的參考

### 3. 部署 Slurm Cluster

確保在 `helm upgrade -i` 命令中包含 PostgreSQL 配置檔案：

```bash
cd deploy_cluster

helm upgrade -i slurm ./slurm-0.4.1 \
  --namespace=slurm \
  --values=values-v0.4.1.yaml \
  -f values-custom-image-policy-1008.yaml \
  -f values-custom-cluster-1008.yaml \
  -f values-custom-worker-1008.yaml \
  -f values-db-custom-postgresql.yaml
```

<br>

---
---

<br>

## 配置範例

### 完整的 PostgreSQL 部署配置

建立 `deploy_cluster/config-postgresql-v1.yaml`：

```yaml
apiVersion: v1
kind: Secret
metadata:
  name: postgresql-credentials
  namespace: postgresql
type: Opaque
stringData:
  username: slurm
  password: slurm_password
  postgres-password: admin_password

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: postgresql-init
  namespace: postgresql
data:
  init.sql: |
    -- 初始化 Slurm accounting 資料庫
    CREATE DATABASE slurm_acct_db OWNER slurm;
    GRANT ALL PRIVILEGES ON DATABASE slurm_acct_db TO slurm;

---
apiVersion: v1
kind: Service
metadata:
  name: postgresql
  namespace: postgresql
  labels:
    app: postgresql
spec:
  type: ClusterIP
  ports:
    - name: postgresql
      port: 5432
      targetPort: 5432
      protocol: TCP
  selector:
    app: postgresql

---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgresql
  namespace: postgresql
spec:
  serviceName: postgresql
  replicas: 1
  selector:
    matchLabels:
      app: postgresql
  template:
    metadata:
      labels:
        app: postgresql
    spec:
      containers:
      - name: postgresql
        image: postgres:16
        ports:
        - containerPort: 5432
          name: postgresql
        env:
        - name: POSTGRES_DB
          value: "slurm_acct_db"
        - name: POSTGRES_USER
          valueFrom:
            secretKeyRef:
              name: postgresql-credentials
              key: username
        - name: POSTGRES_PASSWORD
          valueFrom:
            secretKeyRef:
              name: postgresql-credentials
              key: password
        - name: PGDATA
          value: /var/lib/postgresql/data/pgdata
        volumeMounts:
        - name: postgresql-data
          mountPath: /var/lib/postgresql/data
        resources:
          requests:
            memory: "512Mi"
            cpu: "500m"
          limits:
            memory: "2Gi"
            cpu: "2"
        livenessProbe:
          exec:
            command:
            - /bin/sh
            - -c
            - pg_isready -U $POSTGRES_USER -d $POSTGRES_DB
          initialDelaySeconds: 30
          periodSeconds: 10
          timeoutSeconds: 5
          failureThreshold: 6
        readinessProbe:
          exec:
            command:
            - /bin/sh
            - -c
            - pg_isready -U $POSTGRES_USER -d $POSTGRES_DB
          initialDelaySeconds: 5
          periodSeconds: 10
          timeoutSeconds: 5
          failureThreshold: 6
  volumeClaimTemplates:
  - metadata:
      name: postgresql-data
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 10Gi
```

部署方式：

```bash
kubectl create namespace postgresql
kubectl apply -f deploy_cluster/config-postgresql-v1.yaml
```

<br>

---
---

<br>

## 驗證與測試

### 1. 檢查 PostgreSQL Pod 狀態

```bash
kubectl get pods -n postgresql
```

預期輸出：
```
NAME           READY   STATUS    RESTARTS   AGE
postgresql-0   1/1     Running   0          5m
```

<br>

### 2. 測試資料庫連線

```bash
kubectl exec -it postgresql-0 -n postgresql -- psql -U slurm -d slurm_acct_db -c "\dt"
```
- `password: "slurm_password"`

<br>

### 3. 查看 log

- ### 檢查 Slurm accounting 連線狀態
    ```
    $ kubectl -n slurm describe pod/slurm-accounting-0
    Events:
      Type     Reason     Age                  From               Message
      ----     ------     ----                 ----               -------
      ...
      Normal   Created    44m                  kubelet            Created container: slurmdbd
      Normal   Started    44m                  kubelet            Started container slurmdbd
      Warning  Unhealthy  50s (x301 over 44m)  kubelet            Readiness probe failed: dial tcp 192.168.0.143:6819: connect: connection refused
    ```

    ```
    $ kubectl -n slurm logs pod/slurm-accounting-0
    ...
    [2025-11-07T03:04:30] error: mysql_real_connect failed: 2013 Lost connection to server at 'handshake: reading initial communication packet', system error: 110
    [2025-11-07T03:04:30] error: The database must be up when starting the MYSQL plugin.  Trying again in 5 seconds.
    ```

- ### 檢查 Slurm login 連線狀態
    ```
    $ kubectl -n slurm logs pod/slurm-login-slinky-5fd986d8f7-w4mxj
    ...
    [2025-11-07T03:01:26.404] error: _fetch_child: failed to fetch remote configs: Socket timed out on send/recv operation
    [2025-11-07T03:01:26.406] error: Failed to load configs from slurmctld. Retrying in 10 seconds.
    ```
- ### 檢查 Slurm Controller 連線狀態
    ```
    $ kubectl logs -n slurm slurm-controller-0 -c slurmctld | grep -i accounting
    ...
    [2025-11-07T03:13:50] error: _open_persist_conn: failed to open persistent connection to host:slurm-accounting:6819: Connection refused
    [2025-11-07T03:13:50] accounting_storage/slurmdbd: _load_dbd_state: recovered 0 pending RPCs
    [2025-11-07T03:13:50] accounting_storage/slurmdbd: clusteracct_storage_p_register_ctld: Registering slurmctld at port 6817 with slurmdbd
    ```


<br>

---
---

<br>

## 故障排除

### 問題 1: PostgreSQL Pod 無法啟動

- **症狀**：Pod 處於 `CrashLoopBackOff` 狀態
- **解決方法**：
    1. 檢查 Pod 日誌：
       ```bash
       kubectl logs -n postgresql postgresql-0
       ```
    2. 檢查 PVC 是否正常綁定：
       ```bash
       kubectl get pvc -n postgresql
       ```
    3. 檢查資源限制是否足夠：
       ```bash
       kubectl describe pod postgresql-0 -n postgresql
       ```

<br>

### 問題 2: Slurm Controller 無法連接 PostgreSQL

- **症狀**：Controller 日誌顯示連線錯誤
- **解決方法**：
    1. 驗證 Service 名稱和 Namespace：
       ```bash
       kubectl get svc -n postgresql
       ```
    2. 測試從 Slurm Namespace 連線到 PostgreSQL：
       ```bash
       kubectl run -it --rm --restart=Never pg-test \
         --image=postgres:16 \
         --namespace=slurm \
         --env PGPASSWORD='slurm_password' -- \
         -- psql -h postgresql.postgresql.svc.cluster.local -U slurm -d slurm_acct_db -c "\dt"
       ```
       - **[選用][動態取得密碼] 從 K8s Secret 取密碼再塞進環境變數**
           ```
           kubectl run -it --rm --restart=Never pg-test \
             --image=postgres:16 -n slurm \
             --env PGPASSWORD="$(kubectl -n slurm get secret postgresql-password -o jsonpath='{.data.password}' | base64 -d)" -- \
             psql -h postgresql.postgresql.svc.cluster.local -U slurm -d slurm_acct_db -c '\dt'
           ```
    3. 檢查密碼 Secret 是否存在：
       ```bash
       kubectl get secret postgresql-password -n slurm
       ```
    4. 確認資料庫配置檔案中的參數正確：
       ```bash
       cat deploy_cluster/values-db-custom-postgresql.yaml
       ```

<br>

### 問題 3: 權限錯誤

- **症狀**：Slurm 無法寫入資料庫
- **解決方法**：
    進入 PostgreSQL Pod 並檢查權限：
    ```bash
    kubectl exec -it postgresql-0 -n postgresql -- bash

    psql -U postgres

    # 檢查使用者權限
    \du

    # 授予必要權限
    GRANT ALL PRIVILEGES ON DATABASE slurm_acct_db TO slurm;
    GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO slurm;
    GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO slurm;
    ```

<br>

### 問題 4: 資料庫初始化失敗

- **症狀**：Slurm Controller 報告資料庫 schema 不存在
- **解決方法**：
    Slurm 需要特定的資料庫 schema。確認 Slurm Controller 已執行資料庫初始化：
    ```bash
    kubectl logs -n slurm slurm-controller-0 -c slurmctld | grep -i "database"
    ```
    如果需要手動初始化，可以進入 Controller Pod：
    ```bash
    kubectl exec -it slurm-controller-0 -n slurm -- bash

    # 執行 sacctmgr 初始化
    sacctmgr add cluster $(hostname -s)
    ```

<br>

---
---

<br>


## PostgreSQL 與 MariaDB 的比較

| 特性 | PostgreSQL | MariaDB |
|------|-----------|---------|
| 授權 | PostgreSQL License (BSD-like) | GPL v2 |
| ACID 合規性 | ✅ 完整支援 | ✅ 完整支援 |
| JSON 支援 | ✅ 原生支援 JSONB | ⚠️ 基本支援 |
| 並發控制 | MVCC | MVCC |
| 複寫 | 內建 streaming replication | 內建 binlog replication |
| 效能 (大型查詢) | ✅ 較佳 | ⚠️ 中等 |
| 效能 (簡單查詢) | ⚠️ 中等 | ✅ 較佳 |
| Slurm 官方支援 | ✅ 支援 | ✅ 主要支援 |
| K8s Operator 選擇 | 多種 (CloudNativePG, Zalando, Crunchy) | MariaDB Operator |
| 社群活躍度 | ✅ 非常活躍 | ✅ 活躍 |

**建議**：
- 如果需要進階功能（如複雜查詢、JSON、地理空間資料）→ 選擇 **PostgreSQL**
- 如果優先考慮簡單性和 Slurm 原生整合 → 選擇 **MariaDB**（專案預設）
- 對於大多數 Slurm 部署，兩者都能良好運作

<br>

---
---

<br>

## 參考資料

- [Bitnami PostgreSQL Helm Chart](https://github.com/bitnami/charts/tree/main/bitnami/postgresql)
- [CloudNativePG Documentation](https://cloudnative-pg.io/)
- [PostgreSQL Official Documentation](https://www.postgresql.org/docs/)
- [Slurm Database Configuration](https://slurm.schedmd.com/accounting.html)
- [Slinky Project GitHub](https://github.com/SlinkyProject/slurm-operator)

<br>

---
---

<br>

## 附錄：快速命令參考

```bash
# 檢查 PostgreSQL 狀態
kubectl -n postgresql get pods
kubectl -n postgresql get svc

# 連接到 PostgreSQL
kubectl -n postgresql exec -it postgresql-0 \
  -- env PGPASSWORD='slurm_password' psql -U slurm -d slurm_acct_db

# 查看 PostgreSQL 日誌
kubectl logs -n postgresql postgresql-0 -f

# 備份資料庫
kubectl exec postgresql-0 -n postgresql -- pg_dump -U slurm slurm_acct_db > backup.sql

# 恢復資料庫
cat backup.sql | kubectl exec -i postgresql-0 -n postgresql -- psql -U slurm -d slurm_acct_db

# 刪除 PostgreSQL (危險操作)
helm uninstall postgresql -n postgresql
kubectl delete namespace postgresql
```

<br>

---
---

<br>

## 討論
### 為何 Slinky 官方不願意支援 PostgreSQL？
> [[Feature]: PostgreSQL Database Support Inquiry #76](https://github.com/SlinkyProject/slurm-operator/issues/76)

- ### gpt-5 (2025/11/13)
    簡短結論：因為 **上游 Slurm 本身就不支援 PostgreSQL（僅支援 MySQL / MariaDB）**，而 Slinky/Slurm Operator 的設計是「包上游、不中魔改」。只要上游不支援，Operator 這層就算做了參數，也無法讓 `slurmdbd` 接上 PostgreSQL──這就是官方不納入 PG 支援的主因。([Slurm][1])

    ### 為什麼不上 PG？（重點理由）

    * **上游移除 PG 支援已久**：Slurm 早期曾有 `accounting_storage/pgsql`，但大約在 2013 年前後就移除了；官方與社群郵件列表亦多次指出目前僅支援 MySQL/MariaDB。([Google Groups][2])
    * **官方文件一貫寫法**：最新的 Slurm accounting 與 `slurmdbd.conf` 文件都以 MySQL/MariaDB 為唯一路線（甚至直接寫「preferred」）。Operator 若硬加 PG 選項，`slurmdbd` 仍無相對應驅動可用。([Slurm][1])
    * **技術成本與風險**：
      * Slurm 的 accounting 外掛與 SQL 查詢長期貼近 MySQL 生態（例如 schema、`ON DUPLICATE KEY UPDATE` 等寫法與行為）。([hpc.rz.rptu.de][3])
      * 維運與相容性測試矩陣會大幅膨脹（兩套不同 SQL 方言、不同驅動/連線庫），超出目前維護能量與優先序。這點從社群經驗談與搭配文件可推知。([Google Groups][2])

    ### 這代表什麼？

    * **Operator 層「改不了上游事實」**：就算在 CRD/Chart 中加入 `postgresql` 的 `StorageType` 參數，`slurmdbd` 端沒有 PG 外掛也無法運作；因此官方不會把「看得到但不能用」的選項收進去。([Slurm][4])
    * **官方態度（可合理推定）**：短期內不計畫支援 PG；若要重啟，應由 SchedMD 在 Slurm 內新增/維護 `accounting_storage/postgresql` 外掛並提供文件與測試。歷史紀錄與文件走向皆看不出回頭支援 PG 的跡象。([Slurm][1])

    ### 你可以怎麼做（替代方案）

    1. **採用 MariaDB / MySQL**：這是官方且成熟的路線（含各種部署指南）。([Slurm][1])
    2. **需要 PG 生態做分析？用「旁路複寫」**：
       * Slurm →（MySQL/MariaDB）→ 以 CDC/複寫（如 Debezium、Maxwell）導入 PostgreSQL，供 BI/報表使用；不動核心 `slurmdbd`。此為常見資料落地策略（社群多有相似討論脈絡）。([Reddit][5])
    3. **想推動官方支援**：
       * 與 SchedMD 洽談商務支援與開發委託，或在社群/基金會型式集資維護新外掛（但這是「上游工程」，非 Operator 階段能解）。([Slurm][6])

    ### 小結

    Slinky 官方不願意（也實際上 **無法有效**）支援 PostgreSQL，是因為 **Slurm 上游當前只支援 MySQL/MariaDB**；Operator 忠實包裝上游，避免引入不可運作的選項與長期維護債。若有 PG 生態需求，建議走「MySQL/MariaDB 作為權威庫 + 外掛型複寫到 PG 做分析」這條路。([Slurm][1])

    [1]: https://slurm.schedmd.com/accounting.html?utm_source=chatgpt.com "Accounting and Resource Limits - Slurm Workload Manager"
    [2]: https://groups.google.com/g/slurm-users/c/y2XiPbYwCoo?utm_source=chatgpt.com "[slurm-users] slurmdbd database usage"
    [3]: https://hpc.rz.rptu.de/documentation/accounting_storageplugins.html?utm_source=chatgpt.com "Slurm Accounting Storage Plugin API"
    [4]: https://slurm.schedmd.com/slurmdbd.conf.html?utm_source=chatgpt.com "slurmdbd.conf - Slurm Workload Manager - SchedMD"
    [5]: https://www.reddit.com/r/HPC/comments/1n155ag/tips_on_setting_up_slurmdbd_without_sql/?utm_source=chatgpt.com "tips on setting up slurmdbd without SQL : r/HPC"
    [6]: https://slurm.schedmd.com/SLUG19/Slurm_on_Sherlock.pdf?utm_source=chatgpt.com "on Sherlock - Slurm Workload Manager - SchedMD"

<br>

---

### 支援資料庫不是有共同界面？像是 O ? 開頭？
- ### gpt-5 (2025/11/13)
    你指的「共同界面」應該是指像 **ODBC（Open Database Connectivity）** 或 **ORM（Object-Relational Mapping）** 這類抽象層。理論上沒錯，很多系統用這層就能做到多資料庫支援，但 **Slurm 並沒有走這條路**。

    ---

    ### 🧩 為什麼 Slurm 雖有「StorageType」設定，卻不能自由換資料庫

    在 `slurmdbd`（Slurm Accounting Daemon）裡，資料庫不是透過 ODBC 或 ORM，而是用 **Slurm 自家的外掛機制（plugin system）**。
    設定檔中這一行：

    ```ini
    StorageType=accounting_storage/mysql
    ```

    會載入對應的 C 動態外掛：

    ```
    accounting_storage_mysql.so
    ```

    也就是說每一種資料庫都要有一個「外掛」去實作以下功能：

    * 建立連線（connect/disconnect）
    * 查詢與更新（query/insert/update）
    * schema 與交易控制（transaction management）
    * 資料結構轉換（Slurm internal structs ↔ SQL rows）

    目前官方只維護這個：

    ```
    src/plugins/accounting_storage/mysql/
    ```

    其他例如 `pgsql` 的外掛早期曾存在，但後來被移除。Slurm 並沒有採用 ODBC、libpq、libsql 等通用層，因此無法直接用驅動切換成 PostgreSQL。

    ---

    ### ⚙️ 若要支援 PostgreSQL 必須做的事

    1. 開發新的外掛：
       ```
       src/plugins/accounting_storage/postgresql/
       ```
    2. 使用 libpq API（PostgreSQL 原生 C 函式庫）實作完整 CRUD 與查詢邏輯。
    3. 重寫 schema migration、transaction handling、error code mapping。
    4. 通過完整的 Slurm accounting 測試（job 完成、sacct、sreport 等）。

    換句話說，這是一個 C-level plugin 開發案，不是改設定就能解決的問題。

    ---

    ### 🧠 延伸補充：為什麼沒用 ORM 或 ODBC

    * **ODBC**：在 HPC 環境中被視為額外依賴層，容易成為維運與效能瓶頸。
    * **ORM（如 SQLAlchemy、GORM）**：Slurm 是純 C 專案，不使用高階語言。
    * **一致性與效能考量**：Slurm accounting 追求最低延遲與確定性寫入，直接用 MySQL C API 最穩定。

    ---

    所以總結來說：

    > 雖然資料庫之間可以透過 ODBC/ORM 提供共同介面，
    > 但 **Slurm 並未採用這類抽象層，而是綁定在 C-plugin 機制上**。
    > 因此 Slinky（Slurm Operator）也只能支援上游現有的 MySQL/MariaDB。

<br>

---

### 目前沒有 C-level ODBC/ORM？
- ### gpt-5 (2025/11/13)
    非常好問題。
    要嚴格來說，其實 **有 C-level 的通用資料庫介面**（例如 ODBC），但 **沒有通用到能取代 Slurm 那種「高效能、內部結構緊耦合」需求的 ORM**。我們可以分兩個層面來看：

    ---

    ### 🧩 一、C 語言層級的「共同介面」有哪些？

    #### 1️⃣ **ODBC (Open Database Connectivity)**

    * **本質**：一個跨資料庫的標準 API（以 C 為主），由 Microsoft 制定。
    * **程式庫**：常見的實作是 `unixODBC` 或 `iODBC`。
    * **用途**：讓應用程式透過一組固定 API（`SQLConnect()`, `SQLExecDirect()`, `SQLFetch()` 等）連接任何有驅動的 DB（MySQL、PostgreSQL、SQL Server...）。
    * **優點**：
      * 統一 API，不必管底層 DB 驅動。
      * 可以在執行階段換成不同 DB。
    * **缺點**：
      * 效能會比 native driver 慢。
      * 各家 SQL 方言仍需額外處理。
      * 需要安裝 DSN、driver manager、driver 等一整套環境。
    * **Slurm 為何不用？**
      * Slurm 在 HPC 環境要求極高穩定性與最低延遲，ODBC 增加了一層中介與錯誤源。
      * 整個 `accounting_storage_mysql.c` 都直接呼叫 MySQL C API (`mysql_real_query`, `mysql_stmt_execute`)，省去 ODBC overhead。

    ---

    #### 2️⃣ **libdbi (Database Independent Abstraction Layer for C)**

    * **本質**：C 語言版本的簡易 ORM/adapter，透過 driver plugin 支援多 DB。
    * **支援資料庫**：MySQL、PostgreSQL、SQLite、ODBC 等。
    * **使用方式**：提供抽象 API，如 `dbi_conn_queryf(conn, "SELECT ...")`。
    * **缺點**：
      * 功能簡單、發展緩慢。
      * 難以滿足 Slurm 複雜的 transaction 與 schema 邏輯。
    * **實務上**：常見於小型 daemon 或 logging agent，不太用於大型 HPC 管理系統。

    ---

    #### 3️⃣ **GDA (GNOME Data Access)**

    * **本質**：GNOME 專案的資料存取抽象層，使用 GObject C API。
    * **特性**：支援多資料庫、具 SQL parser。
    * **缺點**：
      * 體積龐大、依賴 GLib。
      * 不適合 headless HPC 服務。

    ---

    ### 🧠 二、C 世界幾乎沒有「完整 ORM」

    在 Python 有 SQLAlchemy，Go 有 GORM，Rust 有 Diesel，但 **C 幾乎沒有真正的 ORM**。原因如下：

    | 項目       | 說明                                        |
    | -------- | ----------------------------------------- |
    | 🧩 語言特性  | C 沒有反射、沒有動態型別，不適合自動 mapping。              |
    | 💾 記憶體管理 | ORM 通常會自動生成物件結構，C 需手動配置釋放記憶體，開銷大。         |
    | 🧠 社群習慣  | C 世界偏向手動調 SQL，直接呼叫 driver（如 MySQL C API）。 |
    | 🏗️ 系統特性 | HPC、嵌入式系統要求穩定與可控，不喜歡額外抽象層。                |

    ---

    ### 🧱 三、如果 Slurm 要加「通用介面」該怎麼做

    理論上可行，但代價極高：

    ```text
    slurmdbd -> ODBC/libdbi adapter layer -> PostgreSQL / MySQL driver
    ```

    要改：

    * Slurm plugin 接口（storage plugin）
    * 所有 schema、transaction 與 SQL 語法（PG 和 MySQL 差異大）
    * 新增錯誤碼對應、migration、CI 測試矩陣

    結果：
    👉 「效能下降 + 維護成本上升 + 測試量爆炸」

    因此官方才選擇「固定 MySQL 路線」最簡單、最穩。

    ---

    ### ✅ 小結

    | 分類                  | 名稱               | 能力            | 為何沒用於 Slurm     |
    | ------------------- | ---------------- | ------------- | --------------- |
    | C-level API         | **ODBC**         | 通用 API，但慢、依賴多 | 適合商用軟體，不適合 HPC  |
    | C-level Abstraction | **libdbi / GDA** | 簡易抽象層         | 太輕量或太重度         |
    | ORM                 | **幾乎沒有**         | C 語言結構限制      | 需手動 mapping，不實用 |

    **→ 結論：目前 C 世界只有「ODBC」算是通用介面，但它的效能與維運成本不符合 Slurm 設計哲學，因此官方選擇不採用。**


<br>

{%hackmd vaaMgNRPS4KGJDSFG0ZE0w %}