跳至主要内容

Volume - ConfigMap

在 Kubernetes 中,ConfigMap 是一種用於儲存非機密性設定數據的物件,通常用來存放應用程式所需的設定,例如環境變量、命令列參數或配置文件。 ConfigMap 的目的是將應用程式的設定與其代碼解耦,讓配置可以在不改變容器映像的情況下進行更新。


ConfigMap 的用途

  1. 環境變量:用於向 Pod 中的容器注入設定數據。
  2. 命令列參數:提供啟動容器時所需的參數。
  3. 配置文件:將配置數據掛載為文件,供容器內的應用程式使用。
  4. 通用數據共享:用來儲存多個 Pod 共享的非機密性數據。

ConfigMap 的優點

  • 解耦應用程式與配置:使應用程式部署更靈活。
  • 共享配置:允許多個 Pod 使用同一份配置數據。
  • 可控性強:可以根據需要輕鬆修改或更新配置。

注意事項

  1. 非機密性數據:ConfigMap 不適合存放機密性數據(如密碼或 API 金鑰),這些數據應使用 Secret。
  2. 大數據量限制:ConfigMap 的單個鍵值對大小限制為 1MB,若需儲存更大的數據,需考慮其他方法。
  3. 動態更新:當 ConfigMap 發生變更時,掛載到 Pod 的數據可以自動更新,但容器內讀取方式需要支持重新加載機制。

ConfigMap 的建立方式

使用指令匯入整個設定檔

  1. 首先創建一個 initdb.sql 檔案,裡面儲存我們要用的欄位,目的是建立 DB 的初始欄位。
initdb.sql
DROP TABLE IF EXISTS posts CASCADE;
CREATE TABLE posts (
id BIGSERIAL PRIMARY KEY,
uuid VARCHAR(36) NOT NULL UNIQUE,
user_id NUMERIC NOT NULL,
title VARCHAR(255) NOT NULL,
content TEXT NOT NULL,
comments_count NUMERIC DEFAULT 0,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
deleted_at TIMESTAMP NULL,
);

CREATE INDEX user_id_key ON posts (user_id);

COMMENT ON COLUMN posts.title IS '標題';
COMMENT ON COLUMN posts.content is '內容';
COMMENT ON COLUMN posts.comments_count IS '評論數';
  1. 透過 kubectl 指令,將整個 sql 儲存成 configmap。
kubectl.exe create configmap pg-initsql --from-file=initdb.sql
---

configmap/pg-initsql created
  1. 查看產生出來的結果
kubectl.exe describe configmaps pg-initsql
---

Name: pg-initsql
Namespace: default
Labels: <none>
Annotations: <none>

Data
====
initdb.sql:
----
DROP TABLE IF EXISTS posts CASCADE;\r
CREATE TABLE posts (\r
id BIGSERIAL PRIMARY KEY,\r
uuid VARCHAR(36) NOT NULL UNIQUE,\r
user_id NUMERIC NOT NULL,\r
title VARCHAR(255) NOT NULL,\r
content TEXT NOT NULL,\r
comments_count NUMERIC DEFAULT 0,\r
created_at TIMESTAMP NOT NULL DEFAULT NOW(),\r
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),\r
deleted_at TIMESTAMP NULL,\r
);\r
\r
CREATE INDEX user_id_key ON posts (user_id);\r
\r
COMMENT ON COLUMN posts.title IS '標題';\r
COMMENT ON COLUMN posts.content is '內容';\r
COMMENT ON COLUMN posts.comments_count IS '評論數';

BinaryData
====

Events: <none>

使用 yaml 建立設定檔

  1. 同上面,但我們可以把 sql 放 yaml 中,雖然都是使用 yaml 整合再一起,但易讀性交低。
initdb-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: initdb
labels:
app: db
data:
initdb.sql: |
DROP TABLE IF EXISTS posts CASCADE;
CREATE TABLE posts (
id BIGSERIAL PRIMARY KEY,
uuid VARCHAR(36) NOT NULL UNIQUE,
user_id NUMERIC NOT NULL,
title VARCHAR(255) NOT NULL,
content TEXT NOT NULL,
comments_count NUMERIC DEFAULT 0,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
deleted_at TIMESTAMP NULL
);

CREATE INDEX user_id_key ON posts (user_id);

COMMENT ON COLUMN posts.title IS '標題';
COMMENT ON COLUMN posts.content is '內容';
COMMENT ON COLUMN posts.comments_count IS '評論數';
  1. 透過指令我們也可以運行起來。
kubectl.exe apply -f initdb-configmap.yaml
---

configmap/initdb created
  1. 查看運行結果。
kubectl.exe describe configmaps initdb
---

Name: initdb
Namespace: default
Labels: app=db
Annotations: <none>

Data
====
initdb.sql:
----
DROP TABLE IF EXISTS posts CASCADE;
CREATE TABLE posts (
id BIGSERIAL PRIMARY KEY,
uuid VARCHAR(36) NOT NULL UNIQUE,
user_id NUMERIC NOT NULL,
title VARCHAR(255) NOT NULL,
content TEXT NOT NULL,
comments_count NUMERIC DEFAULT 0,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
deleted_at TIMESTAMP NULL
);

CREATE INDEX user_id_key ON posts (user_id);

COMMENT ON COLUMN posts.title IS '標題';
COMMENT ON COLUMN posts.content is '內容';
COMMENT ON COLUMN posts.comments_count IS '評論數';


BinaryData
====

Events: <none>

使用指令建立 key-value 組合

  1. 使用指令建立一個 pg-connect,他定義了連線的 host 和 port,在--from-literal=後面接上 key=value。
kubectl.exe create configmap pg-connect --from-literal=host=127.0.0.1 --from-literal=port=5432
---

configmap/pg-connect created
  1. 使用指令查看一下運行的結果。
kubectl.exe describe configmaps pg-connect
---

Name: pg-connect
Namespace: default
Labels: <none>
Annotations: <none>

Data
====
host:
----
127.0.0.1
port:
----
5432

BinaryData
====

Events: <none>

使用 yaml 建立 key-value 組合

  1. 建立 key-value 的 yaml 設定檔
initdb-kv.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: initdb-kv
labels:
app: db
data:
host: '127.0.0.1'
port: '5432'
  1. 透過指令將設定檔運行起來。
kubectl.exe apply -f initdb-kv.yaml
---

configmap/initdb-kv created
  1. 查看運行的結果。
kubectl.exe describe configmaps initdb-kv
---

Name: initdb-kv
Namespace: default
Labels: app=db
Annotations: <none>

Data
====
port:
----
5432
host:
----
127.0.0.1

BinaryData
====

Events: <none>

實作 ConfigMap

  1. 首先我們想要建立一個 postgresql 服務,我們會定義兩個 ConfigMap, 一個是連線要用的 key-value 對,例如使用者名稱和密碼,另一個是初始化表格用的 sql,最後在定義 postgres 的 Pod。

  2. 需要使用 ConfigMap 裡面的 key-value 時,可以使用 configMapKeyRef,如果是要將整個 ConfigMap 直接映射成文件也可以,在 volume 中使用 configMap 即可。

pg-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: db
labels:
app: db
spec:
containers:
- name: db
image: postgres:12.4-alpine
env:
- name: POSTGRES_USER # 環境變量 POSTGRES_USER,指定 PostgreSQL 的用戶名
valueFrom:
configMapKeyRef:
name: initdb-kv-yaml # 從 ConfigMap "initdb-kv-yaml" 中取得值
key: PG_USER # 使用 ConfigMap 中的鍵 "PG_USER" 的值
- name: POSTGRES_PASSWORD # 環境變量 POSTGRES_PASSWORD,指定 PostgreSQL 的密碼
valueFrom:
configMapKeyRef:
name: initdb-kv-yaml # 從 ConfigMap "initdb-kv-yaml" 中取得值
key: PG_PASSWORD # 使用 ConfigMap 中的鍵 "PG_PASSWORD" 的值
- name: PGDATA
value: '/var/lib/postgresql/data/pgdata'
- name: POSTGRES_DB
value: 'posts'
ports:
- containerPort: 5432
volumeMounts:
- mountPath: /docker-entrypoint-initdb.d
name: initdb
volumes:
- name: initdb # 定義一個名為 "initdb" 的 Volume
configMap:
name: initdb # 將 Volume 與 ConfigMap "initdb" 綁定,ConfigMap 中的內容會掛載為文件
---
apiVersion: v1
kind: ConfigMap
metadata:
name: initdb
labels:
app: db
data:
# 定義初始化表格用的 sql
initdb.sql: |
DROP TABLE IF EXISTS posts CASCADE;
CREATE TABLE posts (
id BIGSERIAL PRIMARY KEY,
uuid VARCHAR(36) NOT NULL UNIQUE,
user_id NUMERIC NOT NULL,
title VARCHAR(255) NOT NULL,
content TEXT NOT NULL,
comments_count NUMERIC DEFAULT 0,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
deleted_at TIMESTAMP NULL
);

CREATE INDEX user_id_key ON posts (user_id);

COMMENT ON COLUMN posts.title IS '標題';
COMMENT ON COLUMN posts.content is '內容';
COMMENT ON COLUMN posts.comments_count IS '評論數';
---
apiVersion: v1
kind: ConfigMap
metadata:
name: initdb-kv-yaml
labels:
app: db
data:
# 定義連線要用的 key-value 對
PG_USER: PG_USER
PG_PASSWORD: PG_USER
  1. 透過指令來執行他們。
kubectl.exe apply -f pg-pod.yaml
---

pod/db created
configmap/initdb created
configmap/initdb-kv-yaml created
  1. 我們可以進到容器裡面看一下,看一下所有綁訂有沒有成功注入到 postgres 中,我們可以看見 initdb.sql 成功被映射成檔案。
kubectl.exe exec -it db -- sh
ls docker-entrypoint-initdb.d/
---

initdb.sql
cat docker-entrypoint-initdb.d/initdb.sql
---

DROP TABLE IF EXISTS posts CASCADE;
CREATE TABLE posts (
id BIGSERIAL PRIMARY KEY,
uuid VARCHAR(36) NOT NULL UNIQUE,
user_id NUMERIC NOT NULL,
title VARCHAR(255) NOT NULL,
content TEXT NOT NULL,
comments_count NUMERIC DEFAULT 0,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
deleted_at TIMESTAMP NULL
);

CREATE INDEX user_id_key ON posts (user_id);

COMMENT ON COLUMN posts.title IS '標題';
COMMENT ON COLUMN posts.content is '內容';
COMMENT ON COLUMN posts.comments_count IS '評論數';
  1. 在容器中我們可以查看 postgres 有沒有成初始化表格,首先使用 psql cli 登入 PG_USER 和 posts 的 database。
psql -U PG_USER -d posts
---

psql (12.4)
Type "help" for help.

posts=#
  1. 接著我們看 posts 這個 table 有沒有成功被初始化建立,如果有就大功告成囉~
posts-# \d posts
---

Table "public.posts"
Column | Type | Collation | Nullable | Default
----------------+-----------------------------+-----------+----------+-----------------------------------
id | bigint | | not null | nextval('posts_id_seq'::regclass)
uuid | character varying(36) | | not null |
user_id | numeric | | not null |
title | character varying(255) | | not null |
content | text | | not null |
comments_count | numeric | | | 0
created_at | timestamp without time zone | | not null | now()
updated_at | timestamp without time zone | | not null | now()
deleted_at | timestamp without time zone | | |
Indexes:
"posts_pkey" PRIMARY KEY, btree (id)
"posts_uuid_key" UNIQUE CONSTRAINT, btree (uuid)
"user_id_key" btree (user_id)