C10-OpenStack 基礎服務與高可用配置 (下)
0. 環境與準備
0.1 本課環境
| 主機 | 角色 | 管理網 IP |
|---|---|---|
| jmp001 | 學員操作機(OpenStack CLI) | 10.127.0.3 |
| ctl001 | 控制節點 | 10.127.0.4 |
| ctl002 | 控制節點 | 10.127.0.14 |
| ctl003 | 控制節點 | 10.127.0.15 |
| — | VIP | 10.127.0.250 |
- 認證檔:jmp001 的
/home/ubuntu/creds/stuNN-openrc.sh(即~/creds/;NN 為學員編號 01–20) - 資料庫:MariaDB 以
root、ProxySQL 以kolla-admin登入(0.3 節),密碼直接從控制節點上的設定檔讀取
資料庫的連線路徑:
OpenStack 服務(nova、neutron、keystone …)
│ mysql://<服務帳號>@10.127.0.250:3306
▼
ProxySQL(每台控制節點都有一個,VIP 在哪台就由哪台的 ProxySQL 接手)
│ 依 hostgroup 規則選擇後端
▼
MariaDB-Galera 三節點叢集(ctl001 / ctl002 / ctl003,同步複寫)0.2 連線方式
全班與講師共用 jmp001 與控制節點上的 ubuntu 帳號(具 sudo 權限)。先登入 jmp001,再從 jmp001 SSH 到控制節點:
ssh ubuntu@10.127.0.4指令標示:[jmp001] 在 jmp001 執行;[ctl] 在任一台控制節點執行;[ctl003] 在指定節點執行。
⚠️ 規則
- 你使用的是和講師相同的管理員權限
- 預期輸出是示意,數字、時間、順序可能與你看到的不同
0.3 登入資料庫的方式
Part A、Part B 都是先登入,再直接輸入 SQL。登入指令會自己從控制節點上的設定檔讀出密碼,不需要另外查。
MariaDB(Part A),以 root 登入:
# [ctl]
sudo docker exec -it mariadb mysql -uroot -p$(sudo grep sst_auth /etc/kolla/mariadb/galera.cnf | cut -d: -f2)ProxySQL 管理介面(Part B),以 kolla-admin 登入:
# [ctl]
sudo docker exec -it mariadb mysql -h 10.127.0.250 -P 6032 -u kolla-admin -p$(sudo grep admin_credentials /etc/kolla/proxysql/proxysql.yaml | cut -d: -f3 | tr -d '"')| 帳號 | 密碼從哪裡讀 | 指令中的處理 |
|---|---|---|
root | /etc/kolla/mariadb/galera.cnf 的 wsrep_sst_auth = root:<密碼>(Galera 完整同步時用 root 登入,所以 kolla 把密碼放在這裡) | cut -d: -f2 取冒號後面的部分 |
kolla-admin | /etc/kolla/proxysql/proxysql.yaml 的 admin_credentials: "kolla-admin:<密碼>" | cut -d: -f3 取第二個冒號後面的部分,tr -d '"' 去掉結尾的引號 |
-p和$(...)之間不能有空格;$(...)會先執行,把結果接在-p後面當作密碼- 看到
MariaDB [(none)]>(MariaDB)或MySQL [(none)]>(ProxySQL)提示字元就是登入成功 - SQL 以分號
;結尾;結尾改成\G會把結果改成直式顯示,欄位多時比較好讀 - 輸入
exit離開,回到 shell - 兩個登入都借用
mariadbcontainer 裡的mysql用戶端,因為控制節點本身沒有安裝
Part A:MariaDB-Galera
Galera 是同步多主(multi-master)複寫:每一筆交易在 commit 時,會送到叢集所有節點完成認證,所以三台的資料隨時一致。
A0. 服務怎麼連到資料庫?
# [ctl]
sudo grep 'connection =' /etc/kolla/nova-api/nova.conf | cut -d@ -f2預期輸出:
10.127.0.250:3306/nova_cell0
10.127.0.250:3306/nova_apicut -d@ -f2 只留下 @ 後面的部分,把連線字串前段的帳號與密碼去掉。
- 連線位址是 VIP:3306,也就是 ProxySQL(Part B),不是某一台 MariaDB
/nova_api、/nova_cell0是資料庫名稱:每個服務使用自己的資料庫(A2 會登入看全部的資料庫)
A1. Galera 的連接埠與設定
# [ctl]
sudo ss -lntp | grep mariadbd
sudo grep wsrep_cluster /etc/kolla/mariadb/galera.cnf預期輸出(以 ctl001 為例):
LISTEN 0 900 10.127.0.4:3306 0.0.0.0:* users:(("mariadbd",pid=27082,fd=38))
LISTEN 0 4096 10.127.0.4:4567 0.0.0.0:* users:(("mariadbd",pid=27082,fd=8))
wsrep_cluster_address = gcomm://10.127.0.4:4567,10.127.0.14:4567,10.127.0.15:4567
wsrep_cluster_name = openstack| Port | 用途 | 現在有沒有在聽 |
|---|---|---|
| 3306 | SQL 連線 | 有 |
| 4567 | Galera 節點之間的複寫通訊(wsrep) | 有 |
| 4568 | IST(增量同步:節點短暫離線後只補缺少的交易) | 沒有,只在同步時才開 |
| 4444 | SST(完整同步:用 mariabackup 複製整個資料庫) | 沒有,只在同步時才開 |
wsrep_cluster_address 列出三台的 4567:節點啟動時就是照這份名單找到其他成員。設定檔就是投影片提到的 /etc/kolla/mariadb/galera.cnf。
A2. 登入 MariaDB:資料庫與 wsrep 健康指標
登入 MariaDB:
# [ctl]
sudo docker exec -it mariadb mysql -uroot -p$(sudo grep sst_auth /etc/kolla/mariadb/galera.cnf | cut -d: -f2)先看有哪些資料庫:
SHOW DATABASES;預期輸出:
+---------------------+
| Database |
+---------------------+
| cinder |
| glance |
| heat |
| information_schema |
| keystone |
| mysql |
| neutron |
| nova |
| nova_api |
| nova_cell0 |
| octavia |
| octavia_persistence |
| performance_schema |
| placement |
| sys |
+---------------------+對照投影片「各服務的資料庫」:keystone、nova / nova_api、placement、neutron、glance、cinder 都在這裡;information_schema、mysql、performance_schema、sys 是 MariaDB 自己的系統資料庫。
接著逐條輸入 wsrep 狀態變數:
SHOW STATUS LIKE 'wsrep_cluster_size';
SHOW STATUS LIKE 'wsrep_cluster_status';
SHOW STATUS LIKE 'wsrep_ready';
SHOW STATUS LIKE 'wsrep_local_state_comment';
SHOW STATUS LIKE 'wsrep_flow_control_paused';
SHOW STATUS LIKE 'wsrep_local_recv_queue';預期輸出:
+--------------------+-------+
| Variable_name | Value |
+--------------------+-------+
| wsrep_cluster_size | 3 |
+--------------------+-------+
+----------------------+---------+
| Variable_name | Value |
+----------------------+---------+
| wsrep_cluster_status | Primary |
+----------------------+---------+
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| wsrep_ready | ON |
+---------------+-------+
+---------------------------+--------+
| Variable_name | Value |
+---------------------------+--------+
| wsrep_local_state_comment | Synced |
+---------------------------+--------+
+---------------------------+------------+
| Variable_name | Value |
+---------------------------+------------+
| wsrep_flow_control_paused | 0.00358723 |
+---------------------------+------------+
+------------------------+-------+
| Variable_name | Value |
+------------------------+-------+
| wsrep_local_recv_queue | 0 |
+------------------------+-------+| 判斷 | 狀態變數 | 健康值 | 異常代表 |
|---|---|---|---|
| 叢集是否可用 | wsrep_cluster_size | 3 | 小於 3 代表有節點離線 |
wsrep_cluster_status | Primary | non-Primary 代表失去 quorum | |
wsrep_ready | ON | OFF 代表節點不接受查詢 | |
| 叢集是否健康 | wsrep_local_state_comment | Synced | Joining / Donor 代表正在同步 |
wsrep_flow_control_paused | 接近 0 | 偏高代表某節點複製落後,拖慢整體寫入 | |
wsrep_local_recv_queue | 接近 0 | 持續增加代表節點套用交易跟不上 |
日常巡檢至少確認 cluster_size = 3、status = Primary、ready = ON。做完輸入 exit 離開 MariaDB。
Quorum(p.07):3 節點的 Galera 需要過半數(2 台)存活。1 台故障仍是 Primary;2 台故障時剩下的節點變成 non-Primary 並拒絕查詢(wsrep_ready = OFF),避免網路分割時兩側各自寫入。
A3. 三台一次檢查:clustercheck
clustercheck 是 MariaDB container 內建的健康檢查,docker ps 看到的 (healthy) 就是它的結果。從 jmp001 一次檢查三台:
# [jmp001]
for i in 4 14 15; do ssh 10.127.0.$i "hostname; sudo docker exec mariadb clustercheck"; done預期輸出:
ctl001-6161060-iaas
HTTP/1.1 200 OK
Content-Type: text/plain
Connection: close
Content-Length: 32
Galera cluster node is synced.
ctl002-6161063-iaas
HTTP/1.1 200 OK
...
Galera cluster node is synced.
ctl003-6161069-iaas
HTTP/1.1 200 OK
...
Galera cluster node is synced.- 三台都回
200 OK與synced,代表每個節點都在 Synced 狀態 - 節點不在 Synced 時會回
503與Galera cluster node is not synced.,Docker 就會把 container 標成unhealthy
A4. 從日誌看節點加入叢集
# [ctl]
sudo grep Synchronized /var/log/kolla/mariadb/mariadb.log | tail -3預期輸出(以 ctl001 為例):
2026-10-17 11:47:48 8 [Note] WSREP: Synchronized with group, ready for connections
2026-10-17 11:48:12 2 [Note] WSREP: Synchronized with group, ready for connections
2026-10-17 11:48:29 2 [Note] WSREP: Synchronized with group, ready for connections每一行代表這個節點完成同步、開始接受連線,通常出現在部署或重啟之後。最後一行的時間就是這個節點最近一次加入叢集的時間。
Part B:ProxySQL
B1. ProxySQL 聽在哪裡?
# [ctl]
sudo ss -lntp | grep proxysql
sysctl net.ipv4.ip_nonlocal_bind預期輸出(以 ctl003 為例):
LISTEN 0 128 10.127.0.250:6032 0.0.0.0:* users:(("proxysql",pid=23819,fd=45))
LISTEN 0 128 10.127.0.15:6032 0.0.0.0:* users:(("proxysql",pid=23819,fd=44))
LISTEN 0 1024 10.127.0.250:3306 0.0.0.0:* users:(("proxysql",pid=23819,fd=43))
LISTEN 0 1024 10.127.0.250:3306 0.0.0.0:* users:(("proxysql",pid=23819,fd=42))
...
net.ipv4.ip_nonlocal_bind = 1| 監聽位址 | 用途 |
|---|---|
10.127.0.250:3306 | OpenStack 服務連的資料庫入口(VIP);有多行是因為 ProxySQL 開了多個執行緒同時接收 |
:6032 | ProxySQL 管理介面 |
和 A1 比較:MariaDB 聽在本機 IP 的 3306,ProxySQL 聽在 VIP 的 3306,兩者不衝突。
三台控制節點都會看到 10.127.0.250:3306,即使 VIP 不在這台。這是因為 ip_nonlocal_bind = 1 允許程式綁定「還不在本機」的 IP:每台的 ProxySQL 都先聽好 VIP,VIP 漂到哪一台,那台就立刻接手。
B2. 設定檔:權重 100 / 10 / 10
投影片提到的設定檔 /etc/kolla/proxysql/proxysql.yaml,最後 32 行是後端與 hostgroup 的設定:
# [ctl]
sudo tail -n 32 /etc/kolla/proxysql/proxysql.yaml預期輸出:
mysql_servers:
- address: "10.127.0.4"
port : 3306
hostgroup : 0
max_connections: 10000
max_replication_lag: 0
weight : 100
comment : "Writer ctl001"
- address: "10.127.0.14"
port : 3306
hostgroup : 0
max_connections: 10000
max_replication_lag: 0
weight : 10
comment : "Writer ctl002"
- address: "10.127.0.15"
port : 3306
hostgroup : 0
max_connections: 10000
max_replication_lag: 0
weight : 10
comment : "Writer ctl003"
mysql_galera_hostgroups:
- writer_hostgroup: 0
backup_writer_hostgroup: 1
reader_hostgroup: 2
offline_hostgroup: 3
max_connections: 10000
max_writers: 1
writer_is_also_reader: 0
comment: "Galera cluster for shard 0"- 三台都放在 hostgroup 0,weight 是 100 / 10 / 10:ctl001 對應投影片的 25b-mgt01(寫入),另外兩台是備援
max_writers: 1:同一時間只有一台負責寫入
B3. 執行中的狀態:只有一個寫入節點
設定檔是 ProxySQL 啟動時讀的內容;實際運作的狀態要登入管理介面看:
# [ctl]
sudo docker exec -it mariadb mysql -h 10.127.0.250 -P 6032 -u kolla-admin -p$(sudo grep admin_credentials /etc/kolla/proxysql/proxysql.yaml | cut -d: -f3 | tr -d '"')-h 10.127.0.250 連的是 VIP,也就是目前正在處理流量的那一台 ProxySQL。登入後輸入:
SELECT hostgroup_id, hostname, status, weight, comment FROM runtime_mysql_servers;
SELECT * FROM runtime_mysql_galera_hostgroups\G預期輸出:
+--------------+-------------+---------+--------+---------------+
| hostgroup_id | hostname | status | weight | comment |
+--------------+-------------+---------+--------+---------------+
| 0 | 10.127.0.14 | SHUNNED | 10 | Writer ctl002 |
| 0 | 10.127.0.15 | SHUNNED | 10 | Writer ctl003 |
| 0 | 10.127.0.4 | ONLINE | 100 | Writer ctl001 |
| 1 | 10.127.0.14 | ONLINE | 10 | Writer ctl002 |
| 1 | 10.127.0.15 | ONLINE | 10 | Writer ctl003 |
+--------------+-------------+---------+--------+---------------+
*************************** 1. row ***************************
writer_hostgroup: 0
backup_writer_hostgroup: 1
reader_hostgroup: 2
offline_hostgroup: 3
active: 1
max_writers: 1
writer_is_also_reader: 0
max_transactions_behind: 0
comment: Galera cluster for shard 0| hostgroup | 角色 | 成員 |
|---|---|---|
| 0 | writer:實際接收讀寫的節點 | 只有 ctl001 是 ONLINE(weight 最高);另外兩台是 SHUNNED(暫不使用) |
| 1 | backup writer:writer 故障時遞補 | ctl002、ctl003 |
| 2 | reader | 空的(writer_is_also_reader = 0) |
| 3 | offline:健康檢查失敗的節點 | 目前沒有 |
Galera 雖然每台都能寫入,但多台同時寫入同一筆資料時,會在 commit 時發生認證衝突,對 OpenStack 服務來說就是間歇性的 deadlock 錯誤。所以 kolla 用 max_writers = 1 讓所有讀寫集中在一台,另外兩台是熱備援。
保持登入,繼續 B4。
B4. 連線管理與健康監控
在同一個 ProxySQL 管理介面裡輸入:
SELECT hostgroup, srv_host, status, ConnUsed, ConnFree, ConnOK, ConnERR, Queries FROM stats_mysql_connection_pool;預期輸出:
+-----------+-------------+---------+----------+----------+--------+---------+---------+
| hostgroup | srv_host | status | ConnUsed | ConnFree | ConnOK | ConnERR | Queries |
+-----------+-------------+---------+----------+----------+--------+---------+---------+
| 0 | 10.127.0.15 | SHUNNED | 0 | 0 | 0 | 0 | 0 |
| 0 | 10.127.0.14 | SHUNNED | 0 | 0 | 0 | 0 | 0 |
| 0 | 10.127.0.4 | ONLINE | 0 | 105 | 115 | 0 | 7358151 |
| 1 | 10.127.0.14 | ONLINE | 0 | 0 | 0 | 0 | 0 |
| 1 | 10.127.0.15 | ONLINE | 0 | 0 | 0 | 0 | 0 |
+-----------+-------------+---------+----------+----------+--------+---------+---------+| 欄位 | 意義 |
|---|---|
| ConnUsed / ConnFree | 正在使用 / 閒置在連線池中的後端連線 |
| ConnOK / ConnERR | 成功 / 失敗建立的後端連線數 |
| Queries | 送到這個後端的查詢總數 |
所有查詢都送到 ctl001,而且 ProxySQL 只用了約 100 條後端連線,就承接了所有 OpenStack 服務的資料庫請求:這就是投影片說的連線管理。
再看 ProxySQL 的健康監控紀錄:
SELECT hostname, primary_partition, read_only, wsrep_local_state, error FROM monitor.mysql_server_galera_log ORDER BY time_start_us DESC LIMIT 3;預期輸出:
+-------------+-------------------+-----------+-------------------+-------+
| hostname | primary_partition | read_only | wsrep_local_state | error |
+-------------+-------------------+-----------+-------------------+-------+
| 10.127.0.4 | YES | NO | 4 | NULL |
| 10.127.0.15 | YES | NO | 4 | NULL |
| 10.127.0.14 | YES | NO | 4 | NULL |
+-------------+-------------------+-----------+-------------------+-------+- ProxySQL 每隔幾秒檢查一次每個後端,
wsrep_local_state = 4就是 Synced - 任何一項不符(不在 primary、
read_only = YES、state 不是 4),ProxySQL 就把該節點移到 offline hostgroup(3),不再送流量;如果它原本是 writer,會由 backup writer 遞補
做完輸入 exit 離開。
Part C:Keystone
C0. 準備
# [jmp001]
export NN=01 # ← 換成你的學員編號(01–20)
source ~/venv/bin/activate
source ~/creds/stu${NN}-openrc.sh # 你的管理員身分(admin project 的 admin)
openstack token issue -c expires -c project_id -c user_id預期輸出:
+------------+----------------------------------+
| Field | Value |
+------------+----------------------------------+
| expires | 2026-10-28T10:12:57+0000 |
| project_id | b090dcce347d41c6bf311869209e5364 |
| user_id | 947465eda0184458963bafb884996f01 |
+------------+----------------------------------+C1. Keystone 的容器與 Fernet keys
# [ctl]
sudo docker ps --filter name=keystone
sudo grep provider /etc/kolla/keystone/keystone.conf預期輸出:
CONTAINER ID IMAGE ... STATUS NAMES
e28ae35cde09 quay.io/openstack.kolla/keystone:2025.1-ubuntu-noble ... Up 10 days (healthy) keystone
846768e3ff92 quay.io/openstack.kolla/keystone-fernet:2025.1-ubuntu-noble ... Up 10 days (healthy) keystone_fernet
dbb6cd6ae04c quay.io/openstack.kolla/keystone-ssh:2025.1-ubuntu-noble ... Up 10 days (healthy) keystone_ssh
provider = fernet| 容器 | 用途 |
|---|---|
| keystone | Identity API,簽發與驗證 token |
| keystone_fernet | 定期輪替 Fernet keys(用來簽發 token) |
| keystone_ssh | 在三台控制節點之間同步 Fernet keys |
provider = fernet:token 用 Fernet keys 加密簽發。三台的 keys 必須一致,否則某台簽的 token 到另一台會驗證失敗。比對三台的 keys:
# [jmp001]
for i in 4 14 15; do ssh 10.127.0.$i "hostname; sudo docker exec keystone_fernet sh -c 'md5sum /etc/keystone/fernet-keys/*'"; done預期輸出(雜湊值只列前 8 碼):
ctl001-6161060-iaas
3779fb7e... /etc/keystone/fernet-keys/0
c752062e... /etc/keystone/fernet-keys/3
64b730e6... /etc/keystone/fernet-keys/4
ctl002-6161063-iaas
3779fb7e... /etc/keystone/fernet-keys/0
c752062e... /etc/keystone/fernet-keys/3
64b730e6... /etc/keystone/fernet-keys/4
ctl003-6161069-iaas
3779fb7e... /etc/keystone/fernet-keys/0
c752062e... /etc/keystone/fernet-keys/3
64b730e6... /etc/keystone/fernet-keys/4三台的檔名與雜湊值完全相同,代表 keys 一致。如果不一致,症狀是間歇性 401:token 只在部分節點驗證成功。
各服務 API 會快取 token 的驗證結果,看看 Nova 把快取放在哪裡:
# [ctl]
sudo grep memcached_servers /etc/kolla/nova-api/nova.conf預期輸出:
memcached_servers = 10.127.0.4:11211,10.127.0.14:11211,10.127.0.15:11211本環境的 keystonemiddleware 把驗證結果放在三台的 memcached(投影片寫的預設是 in-process 快取,memcached 為選用)。快取有效期間內,Keystone 短暫異常也不會讓既有的 token 立刻失效。
C2. Service Catalog 與 Endpoint
# [jmp001]
openstack catalog list -c Name -c Type
openstack endpoint list --service identity預期輸出:
+-----------+----------------+
| Name | Type |
+-----------+----------------+
| glance | image |
| octavia | load-balancer |
| heat-cfn | cloudformation |
| nova | compute |
| placement | placement |
| cinder | block-storage |
| cinderv3 | volumev3 |
| neutron | network |
| heat | orchestration |
| keystone | identity |
+-----------+----------------+
+----------------------------------+-----------+--------------+--------------+---------+-----------+--------------------------+
| ID | Region | Service Name | Service Type | Enabled | Interface | URL |
+----------------------------------+-----------+--------------+--------------+---------+-----------+--------------------------+
| 11783862106c4a408b8db6f955f7f784 | RegionOne | keystone | identity | True | internal | http://10.127.0.250:5000 |
| 23f875bd0bb245e09bf70de192d669d7 | RegionOne | keystone | identity | True | public | http://10.127.0.250:5000 |
+----------------------------------+-----------+--------------+--------------+---------+-----------+--------------------------+一個 endpoint = Service type + Region + Interface + URL:
| Interface | 給誰使用 | 本環境 |
|---|---|---|
| public | 外部使用者或公開網路 | 有,指向 VIP |
| internal | 服務之間或內部網路呼叫 | 有,指向 VIP(CLI 設定 OS_INTERFACE=internal) |
| admin | 管理者或控制平面使用 | 沒有建立(C5 會用到這一點) |
C3. 建立 project、user、group 與角色指派
# [jmp001]
openstack project create --domain Default --description "C10 lab stu${NN}" c10-stu${NN} -c name -c id
openstack user create --domain Default --project c10-stu${NN} --password "C10-Lab-${NN}" c10-stu${NN}-user -c name -c id
openstack group create --domain Default c10-stu${NN}-grp -c name -c id
openstack group add user c10-stu${NN}-grp c10-stu${NN}-user
openstack role add --project c10-stu${NN} --group c10-stu${NN}-grp member預期輸出:
+-------+----------------------------------+
| Field | Value |
+-------+----------------------------------+
| id | 677512d7cc3741ac8b417ad4129d407e |
| name | c10-stu01 |
+-------+----------------------------------+
+-------+----------------------------------+
| Field | Value |
+-------+----------------------------------+
| id | ebcae47b02f6455e8054ff2f26a8451a |
| name | c10-stu01-user |
+-------+----------------------------------+
+-------+----------------------------------+
| Field | Value |
+-------+----------------------------------+
| id | 7a6b5c4d3e2f41a0b9c8d7e6f5a4b3c2 |
| name | c10-stu01-grp |
+-------+----------------------------------+角色是指派給 group,不是直接給 user。看看 Keystone 記錄了什麼:
# [jmp001]
openstack role assignment list --project c10-stu${NN} --names
openstack role assignment list --project c10-stu${NN} --names --effective預期輸出:
+--------+------+-----------------------+-------------------+--------+--------+-----------+
| Role | User | Group | Project | Domain | System | Inherited |
+--------+------+-----------------------+-------------------+--------+--------+-----------+
| member | | c10-stu01-grp@Default | c10-stu01@Default | | | False |
+--------+------+-----------------------+-------------------+--------+--------+-----------+
+--------+------------------------+-------+-------------------+--------+--------+-----------+
| Role | User | Group | Project | Domain | System | Inherited |
+--------+------------------------+-------+-------------------+--------+--------+-----------+
| member | c10-stu01-user@Default | | c10-stu01@Default | | | False |
| reader | c10-stu01-user@Default | | c10-stu01@Default | | | False |
+--------+------------------------+-------+-------------------+--------+--------+-----------+| 觀察 | 說明 |
|---|---|
| 第一個表 | 實際存在的 role assignment:group + member + project |
--effective | 展開後,user 經由 group 取得 member;member 又隱含 reader |
--project 建 user | 只是設定預設 project,不給任何權限 |
角色的隱含關係(admin → manager → member → reader):
# [jmp001]
openstack implied role list -c "Prior Role Name" -c "Implied Role Name"預期輸出:
+-----------------+-------------------+
| Prior Role Name | Implied Role Name |
+-----------------+-------------------+
| manager | member |
| member | reader |
| admin | manager |
+-----------------+-------------------+C4. 切換成新使用者
開一個子 shell,只把帳號、密碼、project 換成新使用者,其他設定(auth URL、domain、interface)沿用原本的:
# [jmp001]
bash
export OS_USERNAME=c10-stu${NN}-user OS_PASSWORD=C10-Lab-${NN} OS_PROJECT_NAME=c10-stu${NN}
openstack token issue -c expires -c project_id -c user_id預期輸出:
+------------+----------------------------------+
| Field | Value |
+------------+----------------------------------+
| expires | 2026-10-28T10:13:11+0000 |
| project_id | 677512d7cc3741ac8b417ad4129d407e |
| user_id | ebcae47b02f6455e8054ff2f26a8451a |
+------------+----------------------------------+project_id和user_id跟 C3 建立的相同:這是c10-stuNN的 project-scoped token- 這個 user 沒有直接的角色,是經由 group 拿到 member,一樣能取得 token
- 子 shell 的提示字元看起來和原本一樣;不確定自己是誰時,執行
echo $OS_USERNAME
C5 在這個子 shell 裡繼續。
C5. 三種常見錯誤的診斷
每一組刻意製造一種錯誤,觀察錯誤碼,再對照投影片的診斷順序。指令前面的 變數=值 只對這一行有效。
① 401:無法取得 token(認證問題)
OS_PASSWORD=wrong-password openstack token issue
OS_USER_DOMAIN_NAME=heat_user_domain openstack token issue
OS_PROJECT_NAME=admin openstack token issue預期輸出:
The request you have made requires authentication. (HTTP 401) (Request-ID: req-7b9e38c7-...)
The request you have made requires authentication. (HTTP 401) (Request-ID: req-1dfd82db-...)
The request you have made requires authentication. (HTTP 401) (Request-ID: req-d9961439-...)| 指令 | 原因 |
|---|---|
| 密碼錯 | 憑證無效 |
| user domain 指錯 | heat_user_domain 裡沒有這個 user |
| 範圍指向 admin project | 帳密正確,但 user 在 admin project 沒有任何角色,Keystone 不發這個範圍的 token |
② 403:拿得到 token,但 API 被拒絕(授權問題)
openstack network create c10-stu${NN}-net -c name -c project_id
openstack user list
openstack server list --all-projects
openstack network show demo-net預期輸出:
+------------+----------------------------------+
| Field | Value |
+------------+----------------------------------+
| name | c10-stu01-net |
| project_id | 677512d7cc3741ac8b417ad4129d407e |
+------------+----------------------------------+
ForbiddenException: 403: Client Error for url: http://10.127.0.250:5000/v3/users, You are not authorized to perform the requested action: identity:list_users.
ForbiddenException: 403: Client Error for url: http://10.127.0.250:8774/v2.1/servers/detail?deleted=False&all_tenants=True, Policy doesn't allow os_compute_api:servers:detail:get_all_tenants to be performed.
Error while executing command: No Network found for demo-net| 指令 | 結果 | 說明 |
|---|---|---|
| 在自己的 project 建網路 | 成功 | member 在自己的 project 可以建立資源 |
user list | 403 | Keystone 的 policy:列出 user 需要 admin 或 domain / system 範圍的角色 |
server list --all-projects | 403 | Nova 的 policy:只有 admin 能看所有 project 的 VM |
network show demo-net | 找不到 | Neutron 直接把別人的網路藏起來,連「存在」都看不到 |
錯誤訊息裡的 identity:list_users、os_compute_api:servers:detail:get_all_tenants 就是被拒絕的 policy 規則名稱。
③ Endpoint not found:找不到服務(catalog 問題)
OS_REGION_NAME=RegionTwo openstack server list
OS_INTERFACE=admin openstack server list預期輸出:
internal endpoint for compute service in RegionTwo region not found
admin endpoint for compute service not foundtoken 是有效的,帳密和角色也都沒問題,只是 catalog 裡找不到符合「service type + region + interface」的 endpoint。
診斷順序(p.21)
| 現象 | 優先檢查 | 本節的例子 |
|---|---|---|
| 401 Unauthorized | auth URL、帳密、user domain、scope 的 project 是否有角色 | ① |
| 403 Forbidden | token scope、role assignment、目標服務 policy | ② |
| Endpoint not found | openstack catalog list、region、interface、service type | ③ |
| 無法管理 user / project | domain scope 與 Keystone policy | ② 的 user list |
做完離開子 shell,回到管理員身分:
exit
echo $OS_USERNAME預期輸出:
stu01C6. 角色不等於權限
建立一個自訂角色,並且只把這個角色指派給一個新的 user:
# [jmp001](管理員身分)
openstack role create c10-stu${NN}-compute -c name
openstack user create --domain Default --password "C10-Lab-${NN}" c10-stu${NN}-cu -c name
openstack role add --project c10-stu${NN} --user c10-stu${NN}-cu c10-stu${NN}-compute預期輸出:
+-------+-------------------+
| Field | Value |
+-------+-------------------+
| name | c10-stu01-compute |
+-------+-------------------+
+-------+--------------+
| Field | Value |
+-------+--------------+
| name | c10-stu01-cu |
+-------+--------------+用這個 user 取得 token,再試著列出 VM:
# [jmp001]
bash
export OS_USERNAME=c10-stu${NN}-cu OS_PASSWORD=C10-Lab-${NN} OS_PROJECT_NAME=c10-stu${NN}
openstack token issue -c project_id
openstack server list
exit預期輸出:
+------------+----------------------------------+
| Field | Value |
+------------+----------------------------------+
| project_id | 677512d7cc3741ac8b417ad4129d407e |
+------------+----------------------------------+
ForbiddenException: 403: Client Error for url: http://10.127.0.250:8774/v2.1/servers/detail?deleted=False, Policy doesn't allow os_compute_api:servers:detail to be performed.- 可以拿到 token:Keystone 只檢查「這個 user 在這個 project 有沒有角色」,有就發
server list被拒絕:Nova 的 policy 規定servers:detail需要reader(project_reader_api),而 Nova 不認得c10-stuNN-compute這個名字- Role 只是一個名稱,權限意義取決於各服務的 policy。新增角色不會自動獲得任何權限,必須在服務的 policy 中有規則承認它