Private cloud với OpenStack 2025.1 + OVN + Ceph Squid — 3 Node All-in-One
Lab này kết hợp 3 thành phần: OpenStack 2025.1 (Epoxy) làm cloud orchestration, Ceph Squid làm distributed storage backend (Cinder block + Glance image + Nova ephemeral qua RBD), và OVN xử lý toàn bộ virtual networking — distributed L2/L3, security groups, floating IP — mà không cần thêm agent hay process bên ngoài. Toàn bộ deploy qua kolla-ansible chính thức.
Compact version này gom toàn bộ role vào 3 node — mỗi ctrl01–03 chạy đồng thời OpenStack control plane, Nova KVM, OVN Controller và Ceph OSD — phù hợp cho private cloud team nhỏ, remote office, hoặc lab tài nguyên hạn chế muốn có HA control plane.
Stack gồm 4 VMs Ubuntu 24.04, deploy qua kolla-ansible 2025.1:
registry01— local Docker Registry v2, mirror toàn bộ images trước khi deployctrl01–03— all-in-one: OpenStack HA + OVN + Ceph mon/mgr/OSD + Nova KVM,ctrl01kiêm deploy node


Mục lục
- 1. Stack \& Kiến trúc
- 2. Node Layout, Tài nguyên \& IP Planning
- 3. Base OS (Tất cả nodes)
- 4. Local Docker Registry (registry01)
- 5. Ceph Hyperconverged (cephadm) — trên ctrl01-03
- 6. Setup kolla-ansible trên ctrl01
- 7. globals.yml \& inventory multinode
- 8. Copy Ceph configs vào Kolla
- 9. Deploy OpenStack
- 10. Service URLs \& Credentials
- 11. Workload đầu tiên — Demo Private Cloud multi tenant
- 12. Lời kết
1. Stack & Kiến trúc
1.1 Stack phiên bản
Mình dùng kolla-ansible chính thức từ PyPI — host OS và container base image đều là Ubuntu 24.04 Noble.
| Thành phần | Phiên bản | Ghi chú |
|---|---|---|
| OpenStack | 2025.1 (Epoxy) | kolla-ansible chính thức |
| OVN | bundled với Neutron | neutron_plugin_agent: ovn trong globals.yml |
| Kolla images | 2025.1-ubuntu-noble |
quay.io/openstack.kolla/<service>:2025.1-ubuntu-noble |
| Ubuntu host | 24.04 LTS Noble | Kolla Epoxy yêu cầu tối thiểu Noble |
| Ceph | Squid 19.x | quay.io/ceph/ceph:v19 — deploy bằng cephadm |
| Python | 3.12 | Mặc định Ubuntu 24.04, trên ctrl01 |
| Ansible | 10.x (ansible-core 2.17) | Theo kolla-ansible requirements |
| Docker | 29.x | docker-ce từ Docker official repo |
1.2 Topology 4 nodes
┌──────────────────────────────────────────────────────────────────┐
│ Hypervisor (ESXi) — ~60 GB RAM │
│ │
│ ┌──────────────┐ REGISTRY │
│ │ registry01 │ Docker Registry v2 (mirror quay.io) │
│ │ 2vCPU, 4 GB │ 10.10.200.5 │
│ └──────────────┘ │
│ │
│ ─────── 3 NODE ALL-IN-ONE (Controller + Compute + Storage) ─── │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ ctrl01 │ │ ctrl02 │ │ ctrl03 │ │
│ │ Deploy │ │ │ │ │ │
│ ├─────────────┤ ├─────────────┤ ├─────────────┤ │
│ │ OS Control │ │ OS Control │ │ OS Control │ ← OpenStack │
│ │ OVN NB/SB │ │ OVN NB/SB │ │ OVN NB/SB │ HA │
│ │ Ceph mon/mgr│ │ Ceph mon/mgr│ │ Ceph mon │ + OVN SDN │
│ ├─────────────┤ ├─────────────┤ ├─────────────┤ │
│ │ Nova KVM │ │ Nova KVM │ │ Nova KVM │ ← Compute │
│ │ OVN Ctrl │ │ OVN Ctrl │ │ OVN Ctrl │ │
│ ├─────────────┤ ├─────────────┤ ├─────────────┤ │
│ │ Ceph OSD │ │ Ceph OSD │ │ Ceph OSD │ ← Storage │
│ │ /dev/sdb │ │ /dev/sdb │ │ /dev/sdb │ │
│ │ 8vCPU,16 GB │ │ 8vCPU,16 GB │ │ 8vCPU,16 GB │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
│ ╔══════════════════════════════════════════════════════════╗ │
│ ║ Management / API: 10.10.200.0/24 ║ │
│ ║ VIP OpenStack API: 10.10.200.50 (HAProxy + Keepalived) ║ │
│ ╚══════════════════════════════════════════════════════════╝ │
│ ╔══════════════════════════════════════════════════════════╗ │
│ ║ Geneve Tunnel / Ceph: 10.10.201.0/24 ║ │
│ ║ OVN Geneve tunnel + Ceph OSD replication ║ │
│ ╚══════════════════════════════════════════════════════════╝ │
│ ╔══════════════════════════════════════════════════════════╗ │
│ ║ Provider / External: ens224 (no IP, VLAN 200) ║ │
│ ║ OVN br-ex — floating IP pool 10.10.200.61–69 ║ │
│ ╚══════════════════════════════════════════════════════════╝ │
└──────────────────────────────────────────────────────────────────┘
Resource tổng:
vCPU: 2 + 3×8 = 26 vCPU
RAM: 4 + 3×16 = 52 GB
Disk OS: 200 GB (registry01) + 3 × 100 GB = 500 GB
Disk OSD: 3 × 200 GB = 600 GB (raw) → usable ~300 GB (replication size=2)
ctrl01–03cần 3 NIC:ens160(mgmt/API),ens192(Geneve tunnel + Ceph),ens224(provider/external — no IP, OVN tạo bridgebr-extrên interface này).
1.3 Phân bổ RAM 16 GB per node
Phần quan trọng nhất khi làm AIO là hiểu RAM đang đi đâu. OVN footprint nhỏ — toàn bộ SDN layer chỉ chiếm ~1 GB, phần lớn RAM dành cho OpenStack services và VM tenants:
| Service group | Ước tính |
|---|---|
| OS + system daemons | ~0.5 GB |
| OpenStack services (MariaDB, RabbitMQ, Memcached, HAProxy, Keystone, Glance, Cinder, Nova api/scheduler/conductor, Heat, Horizon, Barbican, Placement) | ~4–5 GB |
| Prometheus + Grafana | ~1 GB |
| OVN (ovn-northd, ovn-nb-db, ovn-sb-db, ovn-controller) | ~0.5 GB |
| Neutron Server + Metadata Agent | ~0.5 GB |
| Ceph OSD + mon/mgr | ~1 GB |
| Nova compute + libvirt | ~0.5 GB |
| Khả dụng cho VM tenant | ~7–8 GB |
Tổng ~21–24 GB khả dụng toàn cluster — đủ chạy nhiều VM nhỏ đến vừa để lab.
1.4 Trade-off AIO cần biết
Mình liệt kê rõ để dễ quyết định trước khi bắt tay lab:
| Điểm | Ghi chú |
|---|---|
| HA control plane | 3 node → Galera/RabbitMQ/Ceph mon quorum, mất 1 node vẫn OK |
| OVN NB/SB HA | RAFT cluster 3 node — mất 1 node vẫn hoạt động |
| Blast radius | Mất 1 node = mất 1/3 compute + 1/3 storage đồng thời |
| Noisy neighbor | Nova KVM và OVN Controller chia sẻ core với OpenStack API |
| Ceph OSD trên ctrl | OSD replication traffic dùng ens192 riêng — không ảnh hưởng management |
| VM capacity | ~21–24 GB khả dụng toàn cluster — lab OK, không dùng cho production nặng |
1.5 Luồng traffic OVN
VM tenant
│
▼
OVS (Open vSwitch) — local br-int trên ctrl node
│ Geneve tunnel (ens192 — 10.10.201.x)
▼
OVN Controller (ovn-controller) ← sync flows từ OVN SB DB
│ OVSDB protocol
▼
OVN Southbound DB ←→ OVN Northbound DB ←→ Neutron Server
│
OVN Northd
(compile logical → physical flows)
Floating IP:
VM → OVS br-int → OVN DNAT/SNAT → OVS br-ex (ens224) → external network
OVN xử lý L2 (switching), L3 (routing), security groups và DNAT/SNAT cho floating IP — tất cả dưới dạng OpenFlow rules trên OVS, không cần Linux network namespace hay iptables chain như Neutron-OVS cũ.
2. Node Layout, Tài nguyên & IP Planning
2.1 Tài nguyên
Mình dùng template ubuntu-24.04.4 với disk thứ hai /dev/sdb riêng cho Ceph OSD. ctrl01–03 cần 3 NIC — ens224 không cần IP, OVN sẽ tạo bridge br-ex trên interface này.
| # | Hostname | Role | vCPU | RAM | Disk OS | Disk Ceph | NIC |
|---|---|---|---|---|---|---|---|
| 0 | registry01 |
Local Docker Registry | 2 | 4 GB | 200 GB | — | 1 |
| 1 | ctrl01 |
Controller + Deploy + OVN + Ceph mon/mgr + Nova KVM + Ceph OSD | 8 | 16 GB | 100 GB | 200 GB | 3 |
| 2 | ctrl02 |
Controller + OVN + Ceph mon/mgr + Nova KVM + Ceph OSD | 8 | 16 GB | 100 GB | 200 GB | 3 |
| 3 | ctrl03 |
Controller + OVN + Ceph mon + Nova KVM + Ceph OSD | 8 | 16 GB | 100 GB | 200 GB | 3 |
| — | TỔNG | 26 vCPU | 52 GB | 500 GB | 600 GB |
2.2 IP planning
Mình dùng 3 NIC trên ctrl nodes: ens160 management/API, ens192 tunnel+Ceph, ens224 provider network (no IP).
| Hostname | ens160 (MGMT 200.x) | ens192 (TUNNEL 201.x) | ens224 (PROVIDER) |
|---|---|---|---|
| registry01 | 10.10.200.5 | — | — |
| ctrl01 | 10.10.200.11 | 10.10.201.11 | no IP |
| ctrl02 | 10.10.200.12 | 10.10.201.12 | no IP |
| ctrl03 | 10.10.200.13 | 10.10.201.13 | no IP |
| VIP OpenStack API | 10.10.200.50 | — | — |
| Floating IP Pool | 10.10.200.61–69 | — | — |
| Gateway | 10.10.200.1 | — | — |
| Network | Subnet | Traffic |
|---|---|---|
| Management / API | 10.10.200.0/24 | SSH, Kolla deploy, OpenStack API, Horizon |
| Geneve Tunnel / Ceph | 10.10.201.0/24 | OVN Geneve tunnel, Ceph OSD replication |
| Provider / External | VLAN 200 via ens224 | OVN br-ex — floating IP, external VM access |
| Tenant overlay | 192.168.10.0/24 | Tạo sau deploy qua Neutron API |
3. Base OS (Tất cả nodes)
Mình cài Ubuntu 24.04 LTS minimal trên 4 VMs (chọn openssh-server ở phase select packages), sau đó thực hiện các bước sau trên từng node.
3.1 Set hostname + IP Config
hostnamectl set-hostname ctrl01 # thay: registry01 | ctrl01 | ctrl02 | ctrl03
network:
version: 2
ethernets:
ens160:
dhcp4: false
dhcp6: false
addresses:
- "10.10.200.11/24"
routes:
- to: "default"
via: "10.10.200.1"
nameservers:
addresses: [8.8.8.8]
ens192:
dhcp4: false
dhcp6: false
addresses:
- "10.10.201.11/24"
ens224:
dhcp4: false
dhcp6: false
sed -i 's|http://archive.ubuntu.com/ubuntu|http://mirror.bizflycloud.vn/ubuntu|g; s|http://security.ubuntu.com/ubuntu|http://mirror.bizflycloud.vn/ubuntu|g' /etc/apt/sources.list.d/ubuntu.sources
3.2 Swap OFF
OpenStack và Ceph đều yêu cầu tắt swap — mình tắt luôn và xóa khỏi fstab để không bị bật lại sau reboot:
swapoff -a
sed -i '/swap/d' /etc/fstab
free -h # Swap: phải là 0B
3.3 NTP (Chrony)
apt install -y chrony
timedatectl set-timezone Asia/Ho_Chi_Minh
systemctl enable --now chrony
chronyc tracking
3.4 Kernel params
cat >> /etc/sysctl.conf <<'EOF'
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv4.ip_forward = 1
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.default.rp_filter = 0
net.core.somaxconn = 1024
net.ipv4.tcp_max_syn_backlog = 2048
EOF
sysctl -p
3.5 Base packages
Mình cài Docker CE từ official repo thay vì để kolla-ansible tự bootstrap — cách này tránh conflict phiên bản và giữ daemon.json dưới kiểm soát:
apt update
apt install -y \
python3 python3-pip python3-venv python3-dev \
openssh-server openssh-client \
net-tools curl wget git jq \
vim htop tmux iotop \
build-essential libssl-dev libffi-dev \
qemu-guest-agent \
ca-certificates gnupg
# Docker CE — official repo
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
| gpg --dearmor -o /etc/apt/keyrings/docker.gpg
chmod a+r /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" \
| tee /etc/apt/sources.list.d/docker.list > /dev/null
apt update
apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
systemctl enable --now docker
# OVS — OVN Controller cần ovsdb-server chạy trên host (chỉ ctrl nodes)
apt install -y openvswitch-switch
systemctl enable --now openvswitch-switch
3.6 /etc/hosts
cat >> /etc/hosts <<'EOF'
10.10.200.5 registry01
10.10.200.11 ctrl01
10.10.200.12 ctrl02
10.10.200.13 ctrl03
10.10.200.50 openstack-vip
EOF
3.7 Docker daemon — insecure local registry
cat > /etc/docker/daemon.json <<'EOF'
{
"insecure-registries": ["10.10.200.5:5000"],
"log-driver": "json-file",
"log-opts": { "max-size": "10m", "max-file": "3" },
"storage-driver": "overlay2"
}
EOF
systemctl restart docker
docker info | grep -A2 "Insecure Registries"
4. Local Docker Registry (registry01)
Mình pull images một lần duy nhất từ quay.io, lưu vào registry01:5000. 3 ctrl nodes pull từ đây — tránh rate-limit và kéo chậm lúc deploy. Tổng 54 images: 53 Kolla 2025.1 + 1 Ceph Squid.
4.1 Khởi chạy Registry v2
# Trên registry01 (10.10.200.5)
mkdir -p /opt/registry/data
cat > /opt/registry/docker-compose.yml <<'EOF'
services:
registry:
image: registry:2
container_name: registry
restart: always
ports:
- "5000:5000"
volumes:
- /opt/registry/data:/var/lib/registry
environment:
REGISTRY_STORAGE_DELETE_ENABLED: "true"
REGISTRY_LOG_LEVEL: info
EOF
cd /opt/registry
docker compose up -d
docker compose ps
curl http://localhost:5000/v2/_catalog # → {"repositories":[]}
4.2 Pull & push images Kolla + Ceph
Mình chia script thành 2 phần: Ceph từ quay.io và Kolla images từ quay.io. Mỗi image pull → tag → push → rmi local để tiết kiệm disk trên registry01:
# Chạy trên registry01
set -e
LOCAL_REG="10.10.200.5:5000"
# ── PHẦN 1 — Ceph Squid v19 ───────────────────────────────────────────────
# cephadm dùng 1 image cho TẤT CẢ daemon types (mon, mgr, osd, crash, mds)
docker pull quay.io/ceph/ceph:v19
docker tag quay.io/ceph/ceph:v19 "${LOCAL_REG}/ceph/ceph:v19"
docker push "${LOCAL_REG}/ceph/ceph:v19"
docker rmi quay.io/ceph/ceph:v19 "${LOCAL_REG}/ceph/ceph:v19" || true
# ── PHẦN 2 — Kolla images quay.io/openstack.kolla ───────────────────────
KOLLA_SRC="quay.io/openstack.kolla"
KOLLA_TAG="2025.1-ubuntu-noble"
KOLLA_NS="openstack.kolla"
kolla_push() {
local img=$1
local max=3 n=0
until docker pull "${KOLLA_SRC}/${img}:${KOLLA_TAG}"; do
n=$((n+1)); [ $n -ge $max ] && { echo "FAIL: $img after $max tries"; return 1; }
echo "Retry $n/$max for $img ..."; sleep 5
done
docker tag "${KOLLA_SRC}/${img}:${KOLLA_TAG}" "${LOCAL_REG}/${KOLLA_NS}/${img}:${KOLLA_TAG}"
docker push "${LOCAL_REG}/${KOLLA_NS}/${img}:${KOLLA_TAG}"
docker rmi "${KOLLA_SRC}/${img}:${KOLLA_TAG}" "${LOCAL_REG}/${KOLLA_NS}/${img}:${KOLLA_TAG}" || true
}
# Infra
for img in kolla-toolbox cron fluentd; do kolla_push "$img"; done
# DB / MQ / Cache
for img in mariadb-server mariadb-clustercheck rabbitmq memcached proxysql valkey-server valkey-sentinel; do kolla_push "$img"; done
# HA / LB
for img in haproxy haproxy-ssh keepalived; do kolla_push "$img"; done
# Keystone
for img in keystone keystone-fernet keystone-ssh; do kolla_push "$img"; done
# Placement
kolla_push placement-api
# Nova
for img in nova-api nova-scheduler nova-conductor nova-compute nova-libvirt nova-novncproxy nova-ssh; do kolla_push "$img"; done
# Glance
kolla_push glance-api
# Cinder
for img in cinder-api cinder-volume cinder-scheduler cinder-backup; do kolla_push "$img"; done
# Neutron
for img in neutron-server neutron-metadata-agent; do kolla_push "$img"; done
# OVN — 5 images riêng biệt: controller, northd, nb-db-server, sb-db-server, sb-db-relay
for img in ovn-controller ovn-northd ovn-nb-db-server ovn-sb-db-server ovn-sb-db-relay; do kolla_push "$img"; done
# Heat
for img in heat-api heat-api-cfn heat-engine; do kolla_push "$img"; done
# Horizon
kolla_push horizon
# Barbican
for img in barbican-api barbican-keystone-listener barbican-worker; do kolla_push "$img"; done
# Prometheus + Grafana
for img in prometheus-server prometheus-node-exporter prometheus-mysqld-exporter \
prometheus-memcached-exporter prometheus-cadvisor prometheus-alertmanager \
prometheus-openstack-exporter prometheus-blackbox-exporter \
prometheus-libvirt-exporter grafana; do
kolla_push "$img"
done
TOTAL=$(curl -s "http://${LOCAL_REG}/v2/_catalog" | python3 -c 'import sys,json;print(len(json.load(sys.stdin)["repositories"]))')
echo "Done. Total repos: ${TOTAL} (expect 54)"
4.3 Verify từ node khác
# Trên ctrl01
ping -c2 registry01
curl -s http://10.10.200.5:5000/v2/_catalog | jq '.repositories | length' # → 54
docker pull 10.10.200.5:5000/openstack.kolla/keystone:2025.1-ubuntu-noble

5. Ceph Hyperconverged (cephadm) — trên ctrl01-03
Mình đặt OSD trực tiếp trên ctrl node để tận dụng /dev/sdb 100 GB mỗi node. Thiết kế Ceph cho lab này:
- 3 monitors + 2 managers trên ctrl01-03 → quorum HA
- 3 OSD (1 OSD / ctrl node) trên
/dev/sdb200 GB → hyperconverged - Replication
size=2,min_size=1→ usable ≈ 300 GB (600 GB raw / 2)
5.1 Bootstrap từ ctrl01
Mình bootstrap Ceph từ ctrl01 — node này sẽ là mon/mgr chính.
# Trên ctrl01 (10.10.200.11)
apt install -y cephadm ceph-common
cephadm --image 10.10.200.5:5000/ceph/ceph:v19 bootstrap \
--mon-ip 10.10.201.11 \
--cluster-network 10.10.201.0/24 \
--initial-dashboard-user admin \
--initial-dashboard-password 'admin' \
--skip-monitoring-stack \
--allow-mismatched-release
ceph -s # 1 mon up (ctrl01), 0 OSD, HEALTH_WARN — bình thường
# Verify bootstrap dùng image local
docker images | grep ceph
# Set lại container_image_base TRƯỚC khi add host
ceph config set mgr mgr/cephadm/container_image_base 10.10.200.5:5000/ceph/ceph
ceph config get mgr mgr/cephadm/container_image_base
# → 10.10.200.5:5000/ceph/ceph ← phải là local registry
# Dashboard bind 0.0.0.0 → truy cập https://10.10.200.11:8443 (admin/admin)
echo -n 'admin' | ceph dashboard ac-user-set-password admin --force-password -i -




5.2 Add host & deploy OSD
Mình pause orchestrator trước khi add host để ngăn cephadm auto-deploy mon lên compute node:
# Chia ssh-pubkey cephadm tới ctrl02, ctrl03
ssh-copy-id -f -i /etc/ceph/ceph.pub root@ctrl02
ssh-copy-id -f -i /etc/ceph/ceph.pub root@ctrl03
# Pause orchestrator
ceph orch pause
# ctrl01 đã tự đăng ký sau bootstrap — thêm labels
ceph orch host label add ctrl01 mon
ceph orch host label add ctrl01 mgr
ceph orch host label add ctrl01 osd
# Add ctrl02, ctrl03 với IP tunnel network
ceph orch host add ctrl02 10.10.201.12 --labels mon,mgr,osd
ceph orch host add ctrl03 10.10.201.13 --labels mon,osd
ceph orch host ls --detail # 3 hosts: ctrl01, ctrl02, ctrl03
# Lock placement — mon chỉ trên ctrl nodes, mgr trên 2 node đầu
ceph orch apply mon --placement="ctrl01,ctrl02,ctrl03"
ceph orch apply mgr --placement="ctrl01,ctrl02"
# Resume — cephadm bắt đầu deploy theo spec đã lock
ceph orch resume
watch -n3 ceph -s # Chờ "mon: 3 daemons, quorum ctrl01,ctrl02,ctrl03"

# Xem disk có sẵn
ceph orch device ls
# Deploy 3 OSD trên /dev/sdb
ceph orch daemon add osd ctrl01:/dev/sdb
ceph orch daemon add osd ctrl02:/dev/sdb
ceph orch daemon add osd ctrl03:/dev/sdb
watch -n5 ceph -s # Chờ "3 osds: 3 up, 3 in"
# Verify toàn bộ cluster
ceph -s
ceph health detail
ceph orch host ls --detail
ceph orch ps
ceph config get mgr mgr/cephadm/container_image_base # phải là local registry


5.3 Tạo pools & keyrings cho OpenStack
Mình tạo 4 pool với replication factor 2 (phù hợp 3 OSD nhỏ) và 4 keyring tương ứng cho từng service OpenStack:
ceph config set global osd_pool_default_size 2
ceph config set global osd_pool_default_min_size 1
ceph osd pool create volumes 64 # Cinder
ceph osd pool create images 32 # Glance
ceph osd pool create vms 64 # Nova ephemeral
ceph osd pool create backups 32 # Cinder backups
for p in volumes images vms backups; do rbd pool init "$p"; done
ceph auth get-or-create client.glance \
mon 'allow r' \
osd 'allow class-read object_prefix rbd_children, allow rwx pool=images' \
> /etc/ceph/ceph.client.glance.keyring
ceph auth get-or-create client.cinder \
mon 'profile rbd' \
osd 'profile rbd pool=volumes, profile rbd pool=vms, profile rbd-read-only pool=images' \
> /etc/ceph/ceph.client.cinder.keyring
ceph auth get-or-create client.nova \
mon 'profile rbd' \
osd 'profile rbd pool=vms, profile rbd-read-only pool=images' \
> /etc/ceph/ceph.client.nova.keyring
ceph auth get-or-create client.cinder-backup \
mon 'profile rbd' \
osd 'profile rbd pool=backups' \
> /etc/ceph/ceph.client.cinder-backup.keyring
ceph -s # HEALTH_OK · 3 osds: 3 up, 3 in
ceph osd lspools
ceph df



6. Setup kolla-ansible trên ctrl01
Mình dùng kolla-ansible từ PyPI. Python venv riêng tránh conflict với system Python:
# Trên ctrl01 — kiêm Deploy node
apt update && apt install -y python3-venv python3-pip git sshpass
# SSH key từ ctrl01 tới các node còn lại
ssh-keygen -t ed25519 -N "" -f ~/.ssh/id_ed25519 -q || true
for node in ctrl01 ctrl02 ctrl03 registry01; do
ssh-copy-id -o StrictHostKeyChecking=no anhlx@$node
done
# Venv riêng cho deploy
python3 -m venv /opt/kolla-venv
source /opt/kolla-venv/bin/activate
pip install --upgrade pip setuptools wheel
# kolla-ansible 2025.1 (version 20.x)
pip install 'kolla-ansible>=20.0.0,<21.0.0'
kolla-ansible install-deps
kolla-ansible --version # kolla-ansible 20.x.x
ansible --version # core 2.17.x (≥ 2.16 là OK)

7. globals.yml & inventory multinode
Thực hiện trên ctrl01.
mkdir -p /etc/kolla
cat > /etc/kolla/globals.yml << 'EOF'
---
# Docker Registry
docker_registry: "10.10.200.5:5000"
docker_registry_insecure: "yes"
docker_namespace: "openstack.kolla"
# Base
kolla_base_distro: "ubuntu"
openstack_release: "2025.1"
openstack_tag: "2025.1-ubuntu-noble"
# Network interfaces
network_interface: "ens160" # Management / API (VLAN 200)
tunnel_interface: "ens192" # OVN Geneve + Ceph (VLAN 201)
neutron_external_interface: "ens224" # Provider network (no IP, OVN br-ex)
# VIP & HA
kolla_internal_vip_address: "10.10.200.50"
kolla_external_vip_address: "10.10.200.50"
enable_haproxy: "yes"
enable_keepalived: "yes"
# Neutron + OVN
enable_neutron: "yes"
neutron_plugin_agent: "ovn"
enable_neutron_provider_networks: "yes"
neutron_ovn_distributed_fip: "yes"
# External Ceph (cephadm — deploy riêng ở bước 5)
enable_ceph: "no"
glance_backend_ceph: "yes"
cinder_backend_ceph: "yes"
nova_backend_ceph: "yes"
cinder_backup_driver: "ceph"
ceph_glance_user: "glance"
ceph_cinder_user: "cinder"
ceph_nova_user: "nova"
ceph_cinder_backup_user: "cinder-backup"
# Compute — AIO: Nova chạy cùng node với controller
nova_compute_virt_type: "kvm"
nova_reserved_host_memory_mb: "512"
# Services
enable_cinder: "yes"
enable_cinder_backup: "yes"
cinder_cluster_name: "cinder-cluster"
enable_heat: "yes"
enable_horizon: "yes"
enable_barbican: "yes"
enable_chrony: "no"
enable_octavia: "no"
enable_designate: "no"
# Coordination backend (bắt buộc khi dùng Cinder Ceph backend)
enable_valkey: "yes"
# Monitoring
enable_prometheus: "yes"
enable_grafana: "yes"
EOF
cat > /etc/kolla/multinode << 'EOF'
[control]
ctrl01 ansible_host=10.10.200.11
ctrl02 ansible_host=10.10.200.12
ctrl03 ansible_host=10.10.200.13
[network]
ctrl01
ctrl02
ctrl03
[loadbalancer]
ctrl01
ctrl02
ctrl03
# AIO: compute + storage = ctrl nodes
[compute]
ctrl01
ctrl02
ctrl03
[storage]
ctrl01
ctrl02
ctrl03
[monitoring]
ctrl01
[deployment]
localhost ansible_connection=local
[baremetal:children]
control
network
compute
storage
monitoring
# ── Nova sub-groups ────────────────────────────────────────────────────────
[nova:children]
control
[nova-api:children]
nova
[nova-metadata:children]
nova
[nova-conductor:children]
nova
[nova-scheduler:children]
nova
[nova-super-conductor:children]
nova
[nova-novncproxy:children]
nova
[nova-spicehtml5proxy:children]
[nova-serialproxy:children]
[nova-compute:children]
compute
[nova-compute-ironic:children]
[nova-libvirt:children]
compute
[nova-ssh:children]
compute
# ── Placement ──────────────────────────────────────────────────────────────
[placement:children]
control
[placement-api:children]
placement
# ── Keystone ───────────────────────────────────────────────────────────────
[keystone:children]
control
# ── Glance ─────────────────────────────────────────────────────────────────
[glance:children]
control
[glance-api:children]
glance
# ── Cinder ─────────────────────────────────────────────────────────────────
[cinder:children]
control
[cinder-api:children]
cinder
[cinder-scheduler:children]
cinder
[cinder-volume:children]
storage
[cinder-backup:children]
storage
# ── Neutron ────────────────────────────────────────────────────────────────
[neutron:children]
control
[neutron-server:children]
neutron
[neutron-dhcp-agent:children]
network
[neutron-l3-agent:children]
network
[neutron-metadata-agent:children]
network
[neutron-ovn-metadata-agent:children]
network
[neutron-ovn-agent:children]
[neutron-bgp-dragent:children]
[neutron-infoblox-ipam-agent:children]
[neutron-metering-agent:children]
[ironic-neutron-agent:children]
# ── OVN ────────────────────────────────────────────────────────────────────
# ovn-controller = ovn-controller-compute + ovn-controller-network
# Phải khai báo đủ 3 sub-group, thiếu bất kỳ group nào → lỗi deploy:
# 'dict object' has no attribute 'ovn-controller-compute/network'
[ovn-controller:children]
ovn-controller-compute
ovn-controller-network
[ovn-controller-compute:children]
compute
[ovn-controller-network:children]
network
# ovn-database gom NB DB + SB DB + northd — chạy trên control nodes
[ovn-database:children]
control
[ovn-northd:children]
ovn-database
[ovn-nb-db:children]
ovn-database
[ovn-sb-db:children]
ovn-database
[ovn-sb-db-relay:children]
ovn-database
# ── Heat ───────────────────────────────────────────────────────────────────
[heat:children]
control
[heat-api:children]
heat
[heat-api-cfn:children]
heat
[heat-engine:children]
heat
# ── Horizon ────────────────────────────────────────────────────────────────
[horizon:children]
control
# ── Barbican ───────────────────────────────────────────────────────────────
[barbican:children]
control
[barbican-api:children]
barbican
[barbican-keystone-listener:children]
barbican
[barbican-worker:children]
barbican
# ── DB / MQ / Cache ────────────────────────────────────────────────────────
[valkey:children]
control
[valkey-server:children]
valkey
[valkey-sentinel:children]
valkey
[mariadb:children]
control
[rabbitmq:children]
control
[memcached:children]
control
# ── HA / LB ────────────────────────────────────────────────────────────────
[haproxy:children]
loadbalancer
# ── Monitoring ─────────────────────────────────────────────────────────────
[grafana:children]
monitoring
[prometheus:children]
monitoring
[prometheus-server:children]
monitoring
[prometheus-node-exporter:children]
baremetal
[prometheus-mysqld-exporter:children]
mariadb
[prometheus-memcached-exporter:children]
memcached
[prometheus-cadvisor:children]
baremetal
[prometheus-alertmanager:children]
monitoring
[prometheus-openstack-exporter:children]
monitoring
[prometheus-elasticsearch-exporter:children]
[prometheus-blackbox-exporter:children]
monitoring
[prometheus-libvirt-exporter:children]
nova-libvirt
# ── Kolla infrastructure ────────────────────────────────────────────────────
[kolla-toolbox:children]
control
[cron:children]
control
[fluentd:children]
control
[kolla-logs:children]
control
# Required by etc_hosts role — để trống nếu không dùng Bifrost
[bifrost]
[all:vars]
ansible_become_method=sudo
EOF
passwords.ymlsinh tự động ở bướckolla-genpwd. Kolla tự fan-out các service group con từ[control],[compute],[storage],[network].
8. Copy Ceph configs vào Kolla
Mình copy ceph.conf và các keyring vào từng service directory. Lưu ý: Kolla INI parser không chịu leading TAB trong ceph.conf (sinh ra khi dùng ceph config generate-minimal-conf) — phải sed trước khi copy:
# Trên ctrl01 — vừa là deploy node vừa là ceph bootstrap node
mkdir -p /etc/kolla/config/{glance,cinder/cinder-volume,cinder/cinder-backup,nova/nova-compute}
cp /etc/ceph/ceph.conf /etc/kolla/config/
cp /etc/ceph/ceph.client.glance.keyring /etc/kolla/config/glance/
cp /etc/ceph/ceph.client.cinder.keyring /etc/kolla/config/cinder/cinder-volume/
cp /etc/ceph/ceph.client.cinder-backup.keyring /etc/kolla/config/cinder/cinder-backup/
cp /etc/ceph/ceph.client.nova.keyring /etc/kolla/config/nova/
# cinder-backup cần cả 2 keyring: cinder (đọc volume) và cinder-backup (ghi backup pool)
cp /etc/kolla/config/cinder/cinder-volume/ceph.client.cinder.keyring \
/etc/kolla/config/cinder/cinder-backup/ceph.client.cinder.keyring
# nova-cell role dùng ceph_nova_keyring = ceph_cinder_keyring → tìm ceph.client.cinder.keyring trong nova/
cp /etc/ceph/ceph.client.cinder.keyring /etc/kolla/config/nova/
# Strip leading TAB
sed -i 's/^\t//' /etc/kolla/config/ceph.conf
# Copy ceph.conf vào từng service directory
for d in glance cinder/cinder-volume cinder/cinder-backup nova; do
cp /etc/kolla/config/ceph.conf /etc/kolla/config/$d/
done
# Verify — mỗi service dir phải có ceph.conf + keyring tương ứng
(kolla-venv) root@ctrl01:/root/# tree /etc/kolla/
/etc/kolla/
├── config
│ ├── ceph.conf
│ ├── cinder
│ │ ├── cinder-backup
│ │ │ ├── ceph.client.cinder-backup.keyring
│ │ │ ├── ceph.client.cinder.keyring
│ │ │ └── ceph.conf
│ │ └── cinder-volume
│ │ ├── ceph.client.cinder.keyring
│ │ └── ceph.conf
│ ├── glance
│ │ ├── ceph.client.glance.keyring
│ │ └── ceph.conf
│ └── nova
│ ├── ceph.client.cinder.keyring
│ ├── ceph.client.nova.keyring
│ ├── ceph.conf
│ └── nova-compute
├── globals.yml
└── multinode
8 directories, 13 files
(kolla-venv) root@ctrl01:/root/#
9. Deploy OpenStack
Mình chạy deploy theo thứ tự: bootstrap-servers → OVS pre-config → prechecks → pull → deploy → post-deploy. Bước pull mất 5–10 phút, deploy mất 20–40 phút.
source /opt/kolla-venv/bin/activate
# 1. Sinh passwords.yml
cp /opt/kolla-venv/share/kolla-ansible/etc_examples/kolla/passwords.yml /etc/kolla/passwords.yml
kolla-genpwd
# → /etc/kolla/passwords.yml — sao lưu file này ra nơi an toàn
# 2. ansible.cfg
cat > /etc/kolla/ansible.cfg << 'EOF'
[defaults]
host_key_checking = False
interpreter_python = auto_silent
remote_user = anhlx
private_key_file = /root/.ssh/id_ed25519
[privilege_escalation]
become = True
become_method = sudo
EOF
export ANSIBLE_CONFIG=/etc/kolla/ansible.cfg
# 3. Test connectivity — expect: 3 ctrl nodes + localhost → SUCCESS
ansible -i /etc/kolla/multinode all -m ping
# 4. Bootstrap — cài Docker + python deps, apply daemon.json trên tất cả node
kolla-ansible bootstrap-servers -i /etc/kolla/multinode
# bootstrap-servers đổi daemon.json và restart Docker → Ceph daemons bị dead
# Start lại thủ công trên tất cả ctrl nodes
FSID=$(cephadm shell -- ceph fsid)
ansible -i /etc/kolla/multinode control -m shell \
-a "systemctl start ceph-${FSID}.target" --become
# Verify HEALTH_OK trước khi tiếp tục
ceph -s
# bootstrap-servers restart Docker nhưng không set OVS manager và br-ex — kolla openvswitch
# role chạy sau đó nhưng hay race với ovn-controller start. Set thủ công để chắc chắn:
ansible -i /etc/kolla/multinode baremetal --become -m shell -a "
ovs-vsctl set-manager ptcp:6640:127.0.0.1
ovs-vsctl --may-exist add-br br-ex
ovs-vsctl --may-exist add-port br-ex ens224
"
# 5. Prechecks
kolla-ansible prechecks -i /etc/kolla/multinode
# 6. Pull images từ local registry (~5–10 phút)
kolla-ansible pull -i /etc/kolla/multinode
# 7. Deploy (~20–40 phút)
kolla-ansible deploy -i /etc/kolla/multinode
# 8. Post-deploy → sinh admin-openrc.sh
kolla-ansible post-deploy -i /etc/kolla/multinode
# 9. Verify OpenStack core services
pip install python-openstackclient
source /etc/kolla/admin-openrc.sh
openstack service list
openstack compute service list # expect 3 nova-compute up, host = ctrl01/02/03
openstack network agent list # expect 3 "OVN Controller Gateway agent" trên ctrl01/02/03 — Alive :-)
# 10. Verify OVN containers (trên ctrl01 — đại diện cho cả cluster)
docker ps --format "" | grep -E "^neutron|^ovn" | sort
# OVN logical topology — phải empty trước khi tạo network
docker exec ovn_northd ovn-nbctl show
# OVN chassis đã đăng ký — phải thấy 3 entry (ctrl01, ctrl02, ctrl03)
docker exec ovn_northd ovn-sbctl list Chassis | grep -E "hostname|name\s+:"

Nếu deploy lỗi:
# Log của 1 service
docker logs -f neutron_server
# Reconfigure — re-render config, restart containers (KHÔNG mất data)
kolla-ansible -i /etc/kolla/multinode reconfigure
# Reset toàn bộ — XOÁ HẾT, chỉ dùng khi muốn làm lại từ đầu
kolla-ansible -i /etc/kolla/multinode destroy --yes-i-really-really-mean-it
docker volume prune -f
10. Service URLs & Credentials
Mình tổng hợp các endpoint để dễ bookmark — password lấy từ passwords.yml sau khi deploy xong.
| Service | URL | Credentials |
|---|---|---|
| Horizon | http://10.10.200.50 |
admin / grep keystone_admin_password /etc/kolla/passwords.yml |
| Ceph Dashboard | https://10.10.200.11:8443 |
admin / password đặt lúc bootstrap |
| Grafana | http://10.10.200.50:3000 |
admin / grep grafana_admin_password /etc/kolla/passwords.yml |
| Prometheus | http://10.10.200.50:9091 |
admin / grep prometheus_password /etc/kolla/passwords.yml |
| HAProxy Stats | http://10.10.200.11:1984/ |
openstack / grep haproxy_password /etc/kolla/passwords.yml |
HAProxy stats bind trên management IP của từng node (không phải VIP) — mỗi ctrl node có trang riêng:
.11:1984,.12:1984,.13:1984.Grafana deploy không kèm dashboard — Prometheus data source được Kolla auto-provision, nhưng dashboard phải import thủ công. Vào Connections → Data sources → Prometheus → Dashboards để import Node Exporter mặc định, hoặc import từ grafana.com: Node Exporter Full (ID
1860), RabbitMQ (ID10991), HAProxy 2 Full (ID12693).Ceph Dashboard chạy trên mgr active — kiểm tra node đang chạy:
ceph mgr services.








11. Workload đầu tiên — Demo Private Cloud multi tenant
Mình mô phỏng một công ty nhỏ với hai phòng ban IT và Dev — mỗi team có project riêng, quota độc lập, và tự quản lý network + VM của mình.
11.1 Admin — Projects, users và shared resources
Mình đăng nhập với quyền admin để tạo hạ tầng dùng chung trước.
source /etc/kolla/admin-openrc.sh
# Projects và users
openstack project create it-dept --description "Phong IT"
openstack project create dev-dept --description "Phong Dev"
openstack user create user-it --password <password-it> --project it-dept
openstack user create user-dev --password <password-dev> --project dev-dept
openstack role add --project it-dept --user user-it member
openstack role add --project dev-dept --user user-dev member
# Quota cho mỗi team
openstack quota set --cores 8 --ram 8192 --instances 5 --volumes 5 --gigabytes 100 it-dept
openstack quota set --cores 12 --ram 16384 --instances 5 --volumes 5 --gigabytes 100 dev-dept
# External / provider network — flat trên br-ex (ens224 → VLAN 200)
openstack network create \
--share --external \
--provider-network-type flat \
--provider-physical-network physnet1 \
external-net
openstack subnet create external-subnet \
--network external-net \
--subnet-range 10.10.200.0/24 \
--allocation-pool start=10.10.200.61,end=10.10.200.69 \
--gateway 10.10.200.1 \
--dns-nameserver 8.8.8.8 \
--no-dhcp
# Flavor và image dùng chung cho cả hai team
openstack flavor create --vcpus 1 --ram 1024 --disk 20 m1.small
wget https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img \
-O /root/jammy.img
openstack image create "Ubuntu-22.04" \
--file /root/jammy.img --disk-format qcow2 --container-format bare --public
# Verify
openstack project list
openstack user list
openstack network list
openstack subnet list
openstack flavor list
openstack image list
openstack quota show it-dept
openstack quota show dev-dept

11.2 Team IT — Ubuntu VM
Mình tạo openrc riêng cho user-it rồi deploy network và VM trong project it-dept.
cat > /etc/kolla/it-openrc.sh << 'EOF'
export OS_PROJECT_DOMAIN_NAME=Default
export OS_USER_DOMAIN_NAME=Default
export OS_PROJECT_NAME=it-dept
export OS_USERNAME=user-it
export OS_PASSWORD=<password-it>
export OS_AUTH_URL=http://10.10.200.50:5000
export OS_IDENTITY_API_VERSION=3
export OS_IMAGE_API_VERSION=2
EOF
source /etc/kolla/it-openrc.sh
# Tenant network của IT
openstack network create it-network
openstack subnet create it-subnet \
--network it-network \
--subnet-range 192.168.10.0/24 \
--allocation-pool start=192.168.10.10,end=192.168.10.250 \
--dns-nameserver 8.8.8.8
openstack router create it-router
openstack router set it-router --external-gateway external-net
openstack router add subnet it-router it-subnet
# Keypair + security group
openstack keypair create --public-key ~/.ssh/id_ed25519.pub it-key
openstack security group rule create --protocol icmp default
openstack security group rule create --protocol tcp --dst-port 22 default
# Launch VM + floating IP
NET=$(openstack network show it-network -f value -c id)
openstack server create \
--flavor m1.small --image Ubuntu-22.04 \
--network $NET --key-name it-key \
--security-group default \
vm-it-01
FIP_IT=$(openstack floating ip create external-net -f value -c floating_ip_address)
openstack server add floating ip vm-it-01 $FIP_IT
openstack server show vm-it-01 -c status -c addresses
ssh -i ~/.ssh/id_ed25519 ubuntu@$FIP_IT


11.3 Team Dev — Ubuntu VM
Mình switch sang project dev-dept — network và VM hoàn toàn tách biệt với it-dept.
cat > /etc/kolla/dev-openrc.sh << 'EOF'
export OS_PROJECT_DOMAIN_NAME=Default
export OS_USER_DOMAIN_NAME=Default
export OS_PROJECT_NAME=dev-dept
export OS_USERNAME=user-dev
export OS_PASSWORD=<password-dev>
export OS_AUTH_URL=http://10.10.200.50:5000
export OS_IDENTITY_API_VERSION=3
export OS_IMAGE_API_VERSION=2
EOF
source /etc/kolla/dev-openrc.sh
# Tenant network của Dev — dải khác hoàn toàn
openstack network create dev-network
openstack subnet create dev-subnet \
--network dev-network \
--subnet-range 192.168.20.0/24 \
--allocation-pool start=192.168.20.10,end=192.168.20.250 \
--dns-nameserver 8.8.8.8
openstack router create dev-router
openstack router set dev-router --external-gateway external-net
openstack router add subnet dev-router dev-subnet
# Keypair + security group
openstack keypair create --public-key ~/.ssh/id_ed25519.pub dev-key
openstack security group rule create --protocol icmp default
openstack security group rule create --protocol tcp --dst-port 22 default
# Launch VM + floating IP
NET=$(openstack network show dev-network -f value -c id)
openstack server create \
--flavor m1.small --image Ubuntu-22.04 \
--network $NET --key-name dev-key \
--security-group default \
vm-dev-01
FIP_DEV=$(openstack floating ip create external-net -f value -c floating_ip_address)
openstack server add floating ip vm-dev-01 $FIP_DEV
openstack server show vm-dev-01 -c status -c addresses
ssh -i ~/.ssh/id_ed25519 ubuntu@$FIP_DEV


11.4 Verify isolation
Mình kiểm tra nhanh để xác nhận mỗi project chỉ thấy tài nguyên của mình.
source /etc/kolla/it-openrc.sh
openstack server list # chỉ thấy vm-it-01
source /etc/kolla/dev-openrc.sh
openstack server list # chỉ thấy vm-dev-01
source /etc/kolla/admin-openrc.sh
openstack server list --all-projects # thấy cả hai



12. Lời kết
Lab này cho mình thấy rõ điểm mạnh của OVN trong AIO setup: toàn bộ SDN layer — distributed L3, security groups qua OVS ACL, DNAT/SNAT cho floating IP — chỉ cần vài container nhẹ tích hợp sẵn trong kolla-ansible, không cần component ngoài nào thêm. Kết hợp với Ceph hyperconverged, 3 node này đủ chạy một private cloud HA hoàn chỉnh trên tài nguyên vừa phải.