C12-OpenStack 網路服務 1:Neutron 架構與 OpenStack 網路模型
0. 環境與準備
0.1 本課環境
| 主機 | 角色 | 管理網 IP |
|---|---|---|
| jmp001 | 學員操作機(OpenStack CLI),同時接在外部網段 192.168.100.0/24 | 10.127.0.3 |
| ctl001 / ctl002 / ctl003 | 控制節點(neutron-server、OVN 控制元件、對外閘道) | 10.127.0.4 / .14 / .15 |
| scp001 / scp002 | 運算節點 | 10.127.0.7 / .18 |
| — | VIP | 10.127.0.250 |
- 認證檔:jmp001 的
/home/ubuntu/creds/stuNN-openrc.sh(即~/creds/;NN 為學員編號 01–20) - 外部網路:
public1(192.168.100.0/24,Floating IP 位址池 .100–.200)。jmp001 本身就接在這個網段上,可以直接 ping / SSH 到 Floating IP - 你建立的資源一律以
c12-stuNN-開頭;你的子網是10.12.N.0/24(N 是去掉前導 0 的編號,例如 01 →10.12.1.0/24、15 →10.12.15.0/24)
本課要建立的拓樸(藍色字母是建立該元件的小節):
0.2 連線方式
全班與講師共用 jmp001 與控制節點上的 ubuntu 帳號(具 sudo 權限)。先登入 jmp001,所有指令都在 jmp001 執行。
⚠️ 規則
- 你使用的是和講師相同的管理員權限,只操作名稱有你編號的資源
- 不要使用或修改
defaultsecurity group:它已被講師加了 ICMP、SSH 等規則,用它就看不到本課要觀察的現象- 預期輸出是示意,UUID、IP、數字可能與你看到的不同
0.3 準備
指令
# [jmp001]
export NN=01 # ← 換成你的學員編號(01–20)
source ~/venv/bin/activate
source ~/creds/stu${NN}-openrc.sh
export SUB=10.12.$((10#$NN))
echo "c12-stu${NN} ${SUB}.0/24"預期輸出:
預期輸出
c12-stu01 10.12.1.0/24SUB:你的子網前三段。IP 位址不能有前導 0(10.12.01.0/24會被 Neutron 以 400 拒絕),$((10#$NN))把01轉成1- 若印出
c12-stu 10.12.0.0/24或出現錯誤,代表NN沒設好,先修正再往下做 - 換終端機或重新 SSH 後,這一段要重新執行一次
Part A:後端與外部網路(p.5、8)
指令
# [jmp001]
ssh 10.127.0.4 "sudo grep mechanism_drivers /etc/kolla/neutron-server/ml2_conf.ini"
openstack network list --external
openstack subnet show public1-subnet -c cidr -c gateway_ip -c allocation_pools預期輸出:
預期輸出
mechanism_drivers = ovn
+--------------------------------------+---------+--------------------------------------+
| ID | Name | Subnets |
+--------------------------------------+---------+--------------------------------------+
| 351d82a1-2a0e-42d5-a428-3c7baa0be512 | public1 | b7dabca1-dc52-47dd-b3ba-22e03e7f2851 |
+--------------------------------------+---------+--------------------------------------+
+------------------+---------------------------------+
| Field | Value |
+------------------+---------------------------------+
| allocation_pools | 192.168.100.100-192.168.100.200 |
| cidr | 192.168.100.0/24 |
| gateway_ip | 192.168.100.1 |
+------------------+---------------------------------+mechanism_drivers = ovn:本環境的後端是 OVN(p.5)。在 Kolla 中設定檔放在/etc/kolla/neutron-server/,不是/etc/neutron/public1是管理者建立的 external network(router:external = True),Router 的對外閘道與 Floating IP 都從它的allocation_pools配發- 本課接下來的指令與任何後端都一樣;到節點上看實際轉送是 C13 的內容
Part B:Network 與 Subnet(p.8、9、14)
指令
# [jmp001]
openstack network create c12-stu${NN}-net
openstack subnet create c12-stu${NN}-subnet --network c12-stu${NN}-net \
--subnet-range ${SUB}.0/24 --gateway ${SUB}.1預期輸出(節錄 subnet create):
預期輸出
+----------------------+--------------------------------------+
| Field | Value |
+----------------------+--------------------------------------+
| allocation_pools | 10.12.99.2-10.12.99.254 |
| cidr | 10.12.99.0/24 |
| enable_dhcp | True |
| gateway_ip | 10.12.99.1 |
| name | c12-stu99-subnet |
| network_id | 2c057a7e-4c9d-459a-9aef-6bdef3ea9f48 |
...
+----------------------+--------------------------------------+gateway_ip一定要有:E 節接 Router 時,Router Interface 會使用這個位址(p.14)allocation_pools自動設為 .2–.254,.1 留給 gateway
指令
# [jmp001]
openstack network show c12-stu${NN}-net -c mtu -c provider:network_type -c provider:segmentation_id -c router:external -c subnets
openstack port list --network c12-stu${NN}-net --long -c "Fixed IP Addresses" -c "Device Owner" -c Status預期輸出:
預期輸出
+--------------------------+--------------------------------------+
| Field | Value |
+--------------------------+--------------------------------------+
| mtu | 8492 |
| provider:network_type | geneve |
| provider:segmentation_id | 1967 |
| router:external | Internal |
| subnets | c0a24db3-c603-474b-8770-8f77aed3e1b6 |
+--------------------------+--------------------------------------+
+---------------------------------------------------------------------------+---------------------+--------+
| Fixed IP Addresses | Device Owner | Status |
+---------------------------------------------------------------------------+---------------------+--------+
| ip_address='10.12.99.2', subnet_id='c0a24db3-c603-474b-8770-8f77aed3e1b6' | network:distributed | DOWN |
+---------------------------------------------------------------------------+---------------------+--------+| 欄位 | 意義 |
|---|---|
provider:network_type = geneve | type driver 用 Geneve tunnel 隔離各租戶網路(p.6) |
provider:segmentation_id | 這個網路在 Geneve 中的識別碼(VNI),每個網路不同 |
mtu = 8492 | 底層 MTU 8550 扣掉 Geneve 封裝的開銷 |
router:external = Internal | 一般租戶網路,不是外部網路 |
- 還沒建 VM,網路上已經有一個 Port:
network:distributed是 OVN 提供 DHCP 與 metadata 服務用的 Port。所有接上 Network 的東西都是 Port(p.9)
Part C:Security Group(p.11)
指令
# [jmp001]
openstack security group create c12-stu${NN}-sg -c name -c stateful
openstack security group rule list c12-stu${NN}-sg預期輸出:
預期輸出
+----------+--------------+
| Field | Value |
+----------+--------------+
| name | c12-stu99-sg |
| stateful | True |
+----------+--------------+
+--------------------------------------+-------------+-----------+-----------+------------+-----------+-----------------------+----------------------+
| ID | IP Protocol | Ethertype | IP Range | Port Range | Direction | Remote Security Group | Remote Address Group |
+--------------------------------------+-------------+-----------+-----------+------------+-----------+-----------------------+----------------------+
| 1954e378-833b-402d-85c4-d8e2b4e450f9 | None | IPv6 | ::/0 | | egress | None | None |
| 6de6267f-06cc-4016-9d94-75a125e86491 | None | IPv4 | 0.0.0.0/0 | | egress | None | None |
+--------------------------------------+-------------+-----------+-----------+------------+-----------+-----------------------+----------------------+- 新建的 Security Group 只有兩條 egress(出向)規則:VM 可以主動往外連,但外面連進來的流量全部擋掉
stateful = True:VM 主動發出的連線,回應封包會自動放行,不需要另外開 ingress- 先不要加 ingress 規則,F 節會看到少了它會發生什麼事
Part D:Port 與 VM(p.9、10、14)
D1. 先建 Port
指令
# [jmp001]
openstack keypair create c12-stu${NN}-key --private-key ~/c12-stu${NN}-key.pem
chmod 600 ~/c12-stu${NN}-key.pem
openstack port create c12-stu${NN}-port --network c12-stu${NN}-net --security-group c12-stu${NN}-sg \
-c fixed_ips -c mac_address -c status
openstack port show c12-stu${NN}-port -c status -c binding_host_id -c device_owner -c device_id預期輸出:
預期輸出
+-------------+-----------------------------------------------------------------------------+
| Field | Value |
+-------------+-----------------------------------------------------------------------------+
| fixed_ips | ip_address='10.12.99.195', subnet_id='c0a24db3-c603-474b-8770-8f77aed3e1b6' |
| mac_address | fa:16:3e:b3:a7:4e |
| status | DOWN |
+-------------+-----------------------------------------------------------------------------+
+-----------------+-------+
| Field | Value |
+-----------------+-------+
| binding_host_id | |
| device_id | |
| device_owner | |
| status | DOWN |
+-----------------+-------+- Port 一建立就分到 MAC 與 IP,但還沒有主人:
device_id、device_owner、binding_host_id都是空的,status = DOWN - 這就是 p.4 說的「建立成功 ≠ 網路可用」:控制面已經記錄了這個連接點,但還沒有任何節點把它接上
D2. 用這個 Port 建立 VM
指令
# [jmp001]
openstack server create c12-stu${NN}-vm --image cirros --flavor m1.tiny --key-name c12-stu${NN}-key \
--nic port-id=c12-stu${NN}-port --wait -c status -c OS-EXT-SRV-ATTR:host -c addresses
openstack port show c12-stu${NN}-port -c status -c binding_host_id -c device_owner -c device_id預期輸出(約 20 秒):
預期輸出
+----------------------+----------------------------+
| Field | Value |
+----------------------+----------------------------+
| OS-EXT-SRV-ATTR:host | scp002-6164930-iaas |
| addresses | c12-stu99-net=10.12.99.195 |
| status | ACTIVE |
+----------------------+----------------------------+
+-----------------+--------------------------------------+
| Field | Value |
+-----------------+--------------------------------------+
| binding_host_id | scp002-6164930-iaas |
| device_id | 5bfce014-dcc7-469b-99ff-41ab2f840f23 |
| device_owner | compute:nova |
| status | ACTIVE |
+-----------------+--------------------------------------+| 欄位 | 建立 VM 前 | 建立 VM 後 | 告訴你什麼(p.10) |
|---|---|---|---|
device_owner | 空 | compute:nova | 這是 VM 的網卡 |
device_id | 空 | VM 的 UUID | 屬於哪一台 VM |
binding_host_id | 空 | scp002-… | 下發到哪一台節點 |
status | DOWN | ACTIVE | 後端回報綁定完成 |
- VM 的 IP(10.12.99.195)就是 D1 Port 分到的 IP:VM 插上的是 Port,不是 Network
--nic port-id=用自己建的 Port;如果改用--network,Nova 會代建一個 Port(p.14)。差別在 G 節刪除時會看到
Part E:Router(p.10、15)
指令
# [jmp001]
openstack router create c12-stu${NN}-router -c name -c external_gateway_info -c status
openstack router add subnet c12-stu${NN}-router c12-stu${NN}-subnet
openstack router set --external-gateway public1 c12-stu${NN}-router預期輸出(只有 router create 有輸出):
預期輸出
+-----------------------+------------------+
| Field | Value |
+-----------------------+------------------+
| external_gateway_info | null |
| name | c12-stu99-router |
| status | ACTIVE |
+-----------------------+------------------+add subnet:接內部子網,建立一個 Router Interface,位址就是子網的gateway_ipset --external-gateway:接外部網路,在 public1 上建立一個 Gateway Port
指令
# [jmp001]
openstack router show c12-stu${NN}-router -c external_gateway_info -f yaml
openstack port list --router c12-stu${NN}-router --long -c "Fixed IP Addresses" -c "Device Owner" -c Status預期輸出:
預期輸出
external_gateway_info:
enable_snat: true
external_fixed_ips:
- ip_address: 192.168.100.126
subnet_id: b7dabca1-dc52-47dd-b3ba-22e03e7f2851
network_id: 351d82a1-2a0e-42d5-a428-3c7baa0be512
+--------------------------------------------------------------------------------+--------------------------+--------+
| Fixed IP Addresses | Device Owner | Status |
+--------------------------------------------------------------------------------+--------------------------+--------+
| ip_address='192.168.100.126', subnet_id='b7dabca1-dc52-47dd-b3ba-22e03e7f2851' | network:router_gateway | ACTIVE |
| ip_address='10.12.99.1', subnet_id='c0a24db3-c603-474b-8770-8f77aed3e1b6' | network:router_interface | ACTIVE |
+--------------------------------------------------------------------------------+--------------------------+--------+enable_snat: true:設定對外閘道後 SNAT 預設開啟,子網內的 VM 已經可以主動連外(p.11、25)external_fixed_ips的 192.168.100.126:沒有 Floating IP 的 VM 出外網時,都共用這個位址(p.26)- Router 的兩個 Port 由
device_owner區分:router_gateway接外網、router_interface接內部子網
加了
-f yaml是因為external_gateway_info是一個 JSON 物件,表格格式會擠成一長行。
Part F:Floating IP 與 Security Group(p.11、20、22)
F1. 配發並綁定 Floating IP
指令
# [jmp001]
FIP=$(openstack floating ip create -f value -c floating_ip_address public1)
echo $FIP
openstack server add floating ip c12-stu${NN}-vm $FIP
openstack server show c12-stu${NN}-vm -c addresses
openstack floating ip show $FIP -c fixed_ip_address -c port_id -c status預期輸出:
預期輸出
192.168.100.194
+-----------+---------------------------------------------+
| Field | Value |
+-----------+---------------------------------------------+
| addresses | c12-stu99-net=10.12.99.195, 192.168.100.194 |
+-----------+---------------------------------------------+
+------------------+--------------------------------------+
| Field | Value |
+------------------+--------------------------------------+
| fixed_ip_address | 10.12.99.195 |
| port_id | 063cb631-4187-47a3-bbb4-27946f0e0759 |
| status | ACTIVE |
+------------------+--------------------------------------+- Floating IP 是獨立資源:
floating ip create時就從 public1 的位址池配發,之後才綁到 VM(p.20) server show的addresses把 fixed IP 與 floating IP 印在一起,不區分類型(p.16)port_id就是 D1 建立的c12-stu${NN}-port:FIP 綁的是 Port- 綁定成功的前提是 E 節做好的兩件事:子網接在 Router 上、Router 有對外閘道
F2. 從外部 ping:不通
指令
# [jmp001]
ping -c 3 $FIP預期輸出:
預期輸出
PING 192.168.100.194 (192.168.100.194) 56(84) bytes of data.
--- 192.168.100.194 ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 2073msFIP 綁好了、位址也看得到,但就是 ping 不到。這是 p.22 最常見的卡點:Security Group 沒有開 ingress。
F3. 加上 ingress 規則:馬上通
指令
# [jmp001]
openstack security group rule create --ingress --protocol icmp c12-stu${NN}-sg -c direction -c protocol
ping -c 3 $FIP預期輸出:
預期輸出
+-----------+---------+
| Field | Value |
+-----------+---------+
| direction | ingress |
| protocol | icmp |
+-----------+---------+
PING 192.168.100.194 (192.168.100.194) 56(84) bytes of data.
64 bytes from 192.168.100.194: icmp_seq=1 ttl=63 time=25.5 ms
64 bytes from 192.168.100.194: icmp_seq=2 ttl=63 time=2.99 ms
64 bytes from 192.168.100.194: icmp_seq=3 ttl=63 time=2.28 ms
--- 192.168.100.194 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms- 規則掛在 Port 上,改規則立即生效,不需要重建或重開 VM(p.11)
ttl=63:封包經過 Router 一跳,TTL 從 64 減為 63
F4.(選做)SSH 進 VM,從裡面看
再開 SSH:
指令
# [jmp001]
openstack security group rule create --ingress --protocol tcp --dst-port 22 c12-stu${NN}-sg -c direction -c protocol -c port_range_min
ssh -i ~/c12-stu${NN}-key.pem cirros@$FIP第一次連線會問 Are you sure you want to continue connecting (yes/no/[fingerprint])?,輸入 yes。看到 $ 提示字元後,在 VM 裡執行:
指令
# [c12-stuNN-vm]
ip addr show eth0
ip route
ping -c 2 8.8.8.8
exit預期輸出(ip addr 只節錄 IP 位址那幾行):
預期輸出
inet 10.12.99.195/24 brd 10.12.99.255 scope global dynamic noprefixroute eth0
inet6 fe80::f816:3eff:feb3:a74e/64 scope link
default via 10.12.99.1 dev eth0 src 10.12.99.195 metric 1002
10.12.99.0/24 dev eth0 scope link src 10.12.99.195 metric 1002
169.254.169.254 via 10.12.99.2 dev eth0 src 10.12.99.195 metric 1002
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=112 time=57.8 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=112 time=6.11 ms| 觀察 | 說明 |
|---|---|
| VM 裡只有 10.12.99.195,看不到 192.168.100.194 | FIP 是 Router 上的 1:1 NAT,VM 本身不知道自己有 FIP(p.21) |
default via 10.12.99.1 | 第一跳就是 Router Interface(子網的 gateway) |
169.254.169.254 via 10.12.99.2 | metadata 服務走 B 節看到的 network:distributed Port |
| 可以 ping 8.8.8.8 | egress 預設放行;這台 VM 有 FIP,所以出外網時來源位址是 FIP 而不是 Router 的 .126(p.28) |
Part G:清除(p.14、15)
刪除順序要和建立順序相反,被別人依賴的資源要最後刪。
指令
# [jmp001]
openstack server remove floating ip c12-stu${NN}-vm $FIP
openstack floating ip delete $FIP
openstack server delete --wait c12-stu${NN}-vm
openstack port show c12-stu${NN}-port -c status -c device_owner -c device_id預期輸出:
預期輸出
+--------------+-------+
| Field | Value |
+--------------+-------+
| device_id | |
| device_owner | |
| status | DOWN |
+--------------+-------+VM 刪掉了,Port 還在,只是又變回沒有主人的狀態。Nova 只會刪除它自己代建的 Port;用 --nic port-id= 帶進去的 Port 要自己刪(p.14)。
指令
# [jmp001]
openstack port delete c12-stu${NN}-port
openstack router delete c12-stu${NN}-router預期輸出:
預期輸出
Failed to delete router with name or ID 'c12-stu99-router': ConflictException: 409: Client Error for url: http://10.127.0.250:9696/v2.0/routers/66bea3a4-..., Router 66bea3a4-... has ports still attached: 9be455f1-547a-4e36-b93e-c85d43988f41
1 of 1 routers failed to delete.Router 還有 Port 接著(錯誤訊息最後的 UUID 就是 E 節看到的 Router Interface),不能直接刪。先拆掉兩種介面:
指令
# [jmp001]
openstack router remove subnet c12-stu${NN}-router c12-stu${NN}-subnet
openstack router unset --external-gateway c12-stu${NN}-router
openstack router delete c12-stu${NN}-router
openstack network delete c12-stu${NN}-net
openstack security group delete c12-stu${NN}-sg
openstack keypair delete c12-stu${NN}-key
rm -f ~/c12-stu${NN}-key.pem
openstack network list --name c12-stu${NN}-net
openstack router list --name c12-stu${NN}-router預期輸出:(最後兩行沒有輸出)
預期輸出
network delete會連同 subnet 與network:distributedPort 一起刪除- 最後兩行沒有列出任何東西,代表清除完成
| 建立順序 | 刪除順序 |
|---|---|
| Network → Subnet → SG → Port → VM → Router → FIP | FIP → VM → Port → Router(先拆介面)→ Network → SG |