1. 장애 개요
OpenStack Kolla 기반 All-in-One 환경에서 Horizon 대시보드 접속 시 Compute와 Volume 관련 정보가 정상적으로 조회되지 않는 문제가 발생했다.
Horizon 화면에서는 다음과 같은 오류가 나타났다.

Unable to retrieve compute limit information
제한 정보를 가져올 수 없습니다
사용량 정보를 찾지 못했습니다
처음에는 Horizon 자체 문제처럼 보였지만, 실제 원인은 Horizon이 아니라 뒤쪽 API 서비스 계층에 있었다.
OpenStack CLI에서도 다음 명령들이 모두 실패했다.
openstack compute service list
openstack hypervisor list
openstack volume service list
오류는 다음과 같았다.

503 Service Unavailable: No server is available to handle this request.
즉, Keystone 인증은 정상인데 Nova API와 Cinder API가 정상 응답하지 못하는 상태였다.
2. 초기 상태 확인
먼저 OpenStack 인증 환경을 로드했다.
source /etc/kolla/admin-openrc.sh
그리고 Keystone 토큰 발급을 확인했다.
openstack token issue

토큰은 정상적으로 발급되었다. 따라서 Keystone 인증 문제는 아니었다.
다음으로 비정상 컨테이너를 확인했다.
docker ps -a | egrep "unhealthy|Exited|start"
초기 상태에서는 다음 서비스들이 비정상이었다.

nova_conductor health: starting 또는 Exited
nova_scheduler Exited
nova_api unhealthy
nova_metadata unhealthy
placement_api unhealthy
cinder_api unhealthy
반면 keystone, rabbitmq, mariadb, proxysql, haproxy는 겉으로는 healthy 상태였다.
이때의 상태를 구조로 보면 다음과 같다.
Keystone 인증 정상
HAProxy 정상
Horizon 정상
하지만
Placement API unhealthy
Nova API unhealthy
Nova Conductor 비정상
Nova Scheduler 비정상
Cinder API unhealthy
따라서 Horizon 화면 오류는 단순 UI 문제가 아니라, Nova와 Cinder API가 뒤에서 정상 동작하지 못하면서 발생한 연쇄 장애였다.
3. Placement API 확인
Nova는 인스턴스 스케줄링과 자원 조회 과정에서 Placement API에 의존한다.
그래서 먼저 Placement API를 직접 호출했다.
curl -i http://192.168.111.130:8780/
장애 당시 응답은 다음과 같았다.
HTTP/1.1 503 Service Unavailable
No server is available to handle this request.
즉, HAProxy는 요청을 받고 있었지만, 뒤쪽의 Placement API 애플리케이션이 정상 응답하지 못하고 있었다.
이 상태에서 Nova 로그를 확인하면 다음과 같은 메시지가 반복되었다.
The placement service for 192.168.111.130:RegionOne exists but does not have any supported versions.
Failed to initialize placement client
Fatal error initializing placement client
이 의미는 Nova가 Placement API에 접속했지만 정상적인 Placement 버전 정보를 받지 못했다는 뜻이다. 그래서 nova-conductor와 nova-scheduler가 정상 기동하지 못했다.
장애 흐름은 다음과 같았다.
Placement API 비정상
↓
Nova conductor가 Placement client 초기화 실패
↓
Nova scheduler도 Placement client 초기화 실패
↓
Nova API unhealthy
↓
openstack compute service list 503
↓
Horizon Compute 화면 오류
4. Placement와 Cinder 로그에서 확인된 실제 원인
Kolla 환경에서는 docker logs만으로는 원인이 충분히 보이지 않을 수 있다.
실제 서비스 로그는 보통 아래 경로에 있다.
/var/log/kolla/
Placement 로그를 확인했다.
grep -iE "error|critical|traceback|operational|sql|database|proxysql|hostgroup|timeout|500|503" \
/var/log/kolla/placement/placement-api.log | tail -n 100
Cinder API 로그도 확인했다.
grep -iE "error|critical|traceback|operational|sql|database|proxysql|hostgroup|timeout|500|503" \
/var/log/kolla/cinder/cinder-api.log | tail -n 100
두 로그 모두 핵심 오류는 동일했다.
pymysql.err.OperationalError:
(9001, 'Max connect timeout reached while reaching hostgroup 0 after 11349ms')
Cinder에서도 동일하게 다음과 같은 오류가 발생했다.
sqlalchemy.exc.OperationalError:
(pymysql.err.OperationalError)
(9001, 'Max connect timeout reached while reaching hostgroup 0 after 11406ms')
즉, Placement와 Cinder가 각각의 DB에 접속하려고 했지만, ProxySQL의 hostgroup 0을 통해 MariaDB에 연결하지 못하고 있었다. 이 로그가 이번 장애의 핵심 원인이었다.
5. 왜 Nova, Cinder, Placement가 동시에 문제가 되었나?
Kolla-Ansible 환경에서는 OpenStack 서비스들이 보통 MariaDB에 직접 접속하지 않고 ProxySQL을 통해 DB에 접근한다.
이번 환경의 DB 접속 구조는 다음과 같았다.
OpenStack API 서비스
↓
192.168.111.130:3306
↓
ProxySQL
↓
192.168.111.128:3306
↓
MariaDB
실제 포트 상태도 다음과 같은 구조였다.
192.168.111.130:3306 → ProxySQL
192.168.111.128:3306 → MariaDB
192.168.111.130:8780 → HAProxy → Placement API
192.168.111.130:8774 → HAProxy → Nova API
192.168.111.130:8776 → HAProxy → Cinder API
따라서 DB/ProxySQL 계층이 완전히 안정화되기 전에 Placement, Cinder, Nova API가 먼저 올라오면 각 서비스가 DB 연결에 실패한다.
이후 DB가 정상화되더라도 이미 WSGI 애플리케이션 로딩에 실패한 API 컨테이너들은 계속 unhealthy 또는 503 상태로 남을 수 있다.
이번 장애의 실제 흐름은 다음과 같았다.
노트북 재부팅 또는 서비스 재시작
↓
MariaDB / ProxySQL 안정화 전 API 서비스 먼저 기동
↓
Placement API DB 접속 실패
↓
Cinder API DB 접속 실패
↓
Nova가 Placement discovery 실패
↓
Nova conductor / scheduler 비정상
↓
Compute / Volume API 503
↓
Horizon 화면 오류
6. DB 접속 문자열 확인
각 서비스가 어느 DB 주소를 바라보는지 확인했다.
echo "===== placement db target ====="
docker exec -it placement_api bash -lc "grep -n 'connection' /etc/placement/placement.conf"
echo "===== cinder db target ====="
docker exec -it cinder_api bash -lc "grep -n 'connection' /etc/cinder/cinder.conf"
echo "===== nova db target ====="
docker exec -it nova_api bash -lc "grep -n 'connection' /etc/nova/nova.conf"
확인 결과 Placement, Cinder, Nova 모두 192.168.111.130:3306으로 접속하도록 설정되어 있었다.
placement → 192.168.111.130:3306/placement
cinder → 192.168.111.130:3306/cinder
nova → 192.168.111.130:3306/nova_cell0
nova_api → 192.168.111.130:3306/nova_api
즉, OpenStack API 서비스들은 MariaDB 실제 IP가 아니라 ProxySQL/VIP 주소를 통해 DB에 접근하는 구조였다.
보안상 실제 운영 환경에서는 이 명령으로 출력된 DB 비밀번호를 외부에 노출하지 않도록 주의해야 한다.
7. 서비스 컨테이너 내부에서 DB 접속 테스트
단순히 mariadb와 proxysql 컨테이너가 healthy라고 해서 실제 애플리케이션이 DB에 접속 가능한 것은 아니다.
그래서 Placement API 컨테이너 내부에서 실제 DB 접속을 테스트했다.
docker exec -it placement_api bash -lc '
python3 - << "PY"
import configparser, re, urllib.parse, pymysql
cfg=configparser.ConfigParser()
cfg.read("/etc/placement/placement.conf")
url=cfg["placement_database"]["connection"] if "placement_database" in cfg else cfg["database"]["connection"]
m=re.match(r".*://([^:]+):([^@]+)@([^:/]+):?([0-9]*)/([^?]+)", url)
user, pw, host, port, db = m.group(1), urllib.parse.unquote(m.group(2)), m.group(3), int(m.group(4) or 3306), m.group(5)
print("TARGET=", host, port, db, user)
try:
conn=pymysql.connect(host=host, port=port, user=user, password=pw, database=db, connect_timeout=5, read_timeout=5, write_timeout=5)
cur=conn.cursor()
cur.execute("select 1")
print("PLACEMENT_DB_OK", cur.fetchone())
conn.close()
except Exception as e:
print("PLACEMENT_DB_FAIL", repr(e))
PY
'
결과는 정상이었다.
TARGET= 192.168.111.130 3306 placement placement
PLACEMENT_DB_OK (1,)
Cinder API 컨테이너 내부에서도 동일하게 테스트했다.
docker exec -it cinder_api bash -lc '
python3 - << "PY"
import configparser, re, urllib.parse, pymysql
cfg=configparser.ConfigParser()
cfg.read("/etc/cinder/cinder.conf")
url=cfg["database"]["connection"]
m=re.match(r".*://([^:]+):([^@]+)@([^:/]+):?([0-9]*)/([^?]+)", url)
user, pw, host, port, db = m.group(1), urllib.parse.unquote(m.group(2)), m.group(3), int(m.group(4) or 3306), m.group(5)
print("TARGET=", host, port, db, user)
try:
conn=pymysql.connect(host=host, port=port, user=user, password=pw, database=db, connect_timeout=5, read_timeout=5, write_timeout=5)
cur=conn.cursor()
cur.execute("select 1")
print("CINDER_DB_OK", cur.fetchone())
conn.close()
except Exception as e:
print("CINDER_DB_FAIL", repr(e))
PY
'
결과도 정상이었다.
TARGET= 192.168.111.130 3306 cinder cinder
CINDER_DB_OK (1,)
이 결과로 볼 때, 현재 시점에서는 DB와 ProxySQL 접속 자체는 정상으로 회복된 상태였다.
즉, 남은 문제는 DB가 정상화되기 전에 먼저 떠서 실패 상태가 남아 있는 API 서비스들을 순서대로 다시 올리는 것이었다.
8. 복구 순서
DB 접속이 정상임을 확인한 뒤에는 MariaDB와 ProxySQL을 계속 재시작하지 않고, API 서비스들을 순서대로 재시작했다.
가장 중요한 순서는 다음과 같다.
Placement
↓
Cinder
↓
Nova
↓
Horizon
Placement는 Nova가 의존하기 때문에 Nova보다 먼저 정상화해야 한다.
실제 재시작 순서는 다음과 같다.
docker restart placement_api
sleep 30
docker restart cinder_api cinder_scheduler cinder_volume cinder_backup
sleep 30
docker restart nova_api nova_metadata nova_conductor nova_scheduler
sleep 30
docker restart horizon
sleep 10
복구 이후 컨테이너 상태를 확인했다.
docker ps -a
결과적으로 기존에 문제가 있던 서비스들이 모두 healthy로 올라왔다.
placement_api healthy
nova_api healthy
nova_metadata healthy
nova_conductor healthy
nova_scheduler healthy
nova_compute healthy
cinder_api healthy
cinder_scheduler healthy
cinder_volume healthy
cinder_backup healthy
mariadb healthy
proxysql healthy
rabbitmq healthy
haproxy healthy
horizon healthy
이 시점에서 컨테이너 기준으로는 정상 상태에 가까워졌다.
9. API 레벨 정상 확인
컨테이너가 healthy라고 해서 OpenStack API가 실제로 정상이라는 보장은 없다.
그래서 OpenStack CLI와 HTTP API로 다시 확인했다.
Placement API 확인
curl -i http://192.168.111.130:8780/
정상 응답:
HTTP/1.1 200 OK
openstack-api-version: placement 1.0
{"versions": [{"id": "v1.0", "max_version": "1.39", "min_version": "1.0", "status": "CURRENT"}]}
Placement API가 정상적으로 버전 정보를 반환했다.
Nova Compute 서비스 확인
openstack compute service list
정상 결과:
nova-conductor enabled up
nova-compute enabled up
nova-scheduler enabled up
Hypervisor 확인
openstack hypervisor list
정상 결과:
openstack1 QEMU 192.168.111.128 up
Cinder Volume 서비스 확인
openstack volume service list
정상 결과:
cinder-scheduler enabled up
cinder-volume enabled up
cinder-backup enabled down
여기서 cinder-backup은 down으로 보였지만, 기본 볼륨 생성/삭제 기능에 직접적으로 필요한 핵심 서비스는 cinder-api, cinder-scheduler, cinder-volume이다.
따라서 기본 Cinder 기능은 다음 볼륨 생성 테스트로 확인했다.
Endpoint 확인
openstack endpoint list --service placement
openstack endpoint list --service nova
openstack endpoint list --service cinderv3
Placement, Nova, Cinder endpoint 모두 192.168.111.130 기준으로 정상 등록되어 있었다.
10. DB Sync 및 Upgrade Check 확인
복구 후에는 단순히 서비스만 확인하지 않고, Placement와 Nova의 upgrade check도 수행했다.
Placement upgrade check
docker exec -it placement_api placement-status upgrade check
결과:
Check: Missing Root Provider IDs
Result: Success
Check: Incomplete Consumers
Result: Success
Check: Policy File JSON to YAML Migration
Result: Success
Nova upgrade check
docker exec -it nova_api nova-status upgrade check
결과:
Check: Cells v2
Result: Success
Check: Placement API
Result: Success
Check: Cinder API
Result: Success
Check: Policy File JSON to YAML Migration
Result: Success
Check: Older than N-1 computes
Result: Success
Check: hw_machine_type unset
Result: Success
Check: Service User Token Configuration
Result: Success
Nova 기준으로도 Placement API와 Cinder API 연동이 정상으로 확인되었다.
Cinder DB version 확인
docker exec -it cinder_api cinder-manage db version
결과:
9c74c1c6971f
Cinder DB 버전도 정상 조회되었다.
11. 최종 볼륨 생성/삭제 테스트
Cinder가 실제로 동작하는지 확인하기 위해 1GB 테스트 볼륨을 생성했다.
openstack volume create --size 1 test-vol-01
생성 직후 상태는 creating이었다.
name test-vol-01
size 1
status creating
이후 볼륨 목록을 확인했다.
openstack volume list
결과:
test-vol-01 available 1
볼륨 상태가 available로 변경되었으므로 Cinder API, Scheduler, Volume, LVM backend가 정상 동작하는 것을 확인했다.
마지막으로 테스트 볼륨을 삭제했다.
openstack volume delete test-vol-01
이 테스트까지 성공했기 때문에, 단순 서비스 상태뿐 아니라 실제 Cinder 볼륨 생성/삭제 기능까지 정상 확인되었다.
12. 최종 복구 상태
최종적으로 확인된 정상 항목은 다음과 같다.
Keystone token 발급 정상
Placement API HTTP 200 정상
Nova conductor enabled / up
Nova scheduler enabled / up
Nova compute enabled / up
Hypervisor openstack1 / QEMU / up
Cinder scheduler enabled / up
Cinder volume enabled / up
Cinder API 정상
Placement upgrade check Success
Nova upgrade check Success
Cinder DB version 정상 조회
Volume create 성공
Volume available 성공
Volume delete 성공
따라서 이번 장애는 최종적으로 정상 복구되었다고 판단할 수 있다.
단, cinder-backup은 서비스 리스트에서 down으로 보였기 때문에 백업 기능까지 사용할 계획이라면 별도 확인이 필요하다. 기본 볼륨 생성/삭제 기능에는 문제가 없었다.
13. 이번 장애의 핵심 원인 정리
이번 장애의 핵심은 Horizon이나 Nova 단독 문제가 아니었다.
최종 원인은 다음과 같다.
DB/ProxySQL 안정화 지연
↓
Placement / Cinder / Nova API가 먼저 기동
↓
각 서비스가 DB 연결 실패
↓
Placement API WSGI 로딩 실패
↓
Nova가 Placement 버전 discovery 실패
↓
Nova conductor / scheduler 비정상
↓
Cinder API unhealthy
↓
Compute / Volume API 503
↓
Horizon 화면 오류 발생
특히 핵심 로그는 다음이었다.
Max connect timeout reached while reaching hostgroup 0
이 메시지가 보이면 단순히 Nova나 Cinder만 재시작하지 말고, 반드시 다음 순서로 확인해야 한다.
1. MariaDB 상태
2. ProxySQL 상태
3. API 컨테이너 내부에서 DB 접속 가능 여부
4. Placement API 응답
5. Nova conductor/scheduler 상태
6. Cinder API/scheduler/volume 상태
14. 다음에 같은 문제가 발생했을 때 빠른 대처 순서
1단계. 인증 확인
source /etc/kolla/admin-openrc.sh
openstack token issue
토큰이 나오면 Keystone 인증은 정상이다.
2단계. 비정상 컨테이너 확인
docker ps -a | egrep "unhealthy|Exited|start"
3단계. API 응답 확인
curl -i http://192.168.111.130:8780/
openstack compute service list
openstack volume service list
4단계. DB/ProxySQL 계층 확인
docker ps -a | egrep 'mariadb|proxysql|rabbitmq|haproxy'
ss -lntp | egrep '3306|6032|6033|5672|8780|8774|8776'
5단계. 핵심 로그 확인
grep -iE "error|critical|traceback|operational|sql|database|proxysql|hostgroup|timeout|500|503" \
/var/log/kolla/placement/placement-api.log | tail -n 100
grep -iE "error|critical|traceback|operational|sql|database|proxysql|hostgroup|timeout|500|503" \
/var/log/kolla/cinder/cinder-api.log | tail -n 100
grep -iE "error|critical|traceback|placement|discovery|NotSupported|operational|sql|database" \
/var/log/kolla/nova/nova-conductor.log | tail -n 100
6단계. 서비스 내부 DB 접속 테스트
Keystone → keystone DB
Nova API → nova_api DB
Nova Cell → nova_cell0 또는 nova DB
Placement → placement DB
Cinder → cinder DB
Neutron → neutron DB
Glance → glance DB
→ heat DB
Placement:
docker exec -it placement_api bash -lc '
python3 - << "PY"
import configparser, re, urllib.parse, pymysql
cfg=configparser.ConfigParser()
cfg.read("/etc/placement/placement.conf")
url=cfg["placement_database"]["connection"] if "placement_database" in cfg else cfg["database"]["connection"]
m=re.match(r".*://([^:]+):([^@]+)@([^:/]+):?([0-9]*)/([^?]+)", url)
user, pw, host, port, db = m.group(1), urllib.parse.unquote(m.group(2)), m.group(3), int(m.group(4) or 3306), m.group(5)
print("TARGET=", host, port, db, user)
try:
conn=pymysql.connect(host=host, port=port, user=user, password=pw, database=db, connect_timeout=5, read_timeout=5, write_timeout=5)
cur=conn.cursor()
cur.execute("select 1")
print("PLACEMENT_DB_OK", cur.fetchone())
conn.close()
except Exception as e:
print("PLACEMENT_DB_FAIL", repr(e))
PY
'
Cinder:
docker exec -it cinder_api bash -lc '
python3 - << "PY"
import configparser, re, urllib.parse, pymysql
cfg=configparser.ConfigParser()
cfg.read("/etc/cinder/cinder.conf")
url=cfg["database"]["connection"]
m=re.match(r".*://([^:]+):([^@]+)@([^:/]+):?([0-9]*)/([^?]+)", url)
user, pw, host, port, db = m.group(1), urllib.parse.unquote(m.group(2)), m.group(3), int(m.group(4) or 3306), m.group(5)
print("TARGET=", host, port, db, user)
try:
conn=pymysql.connect(host=host, port=port, user=user, password=pw, database=db, connect_timeout=5, read_timeout=5, write_timeout=5)
cur=conn.cursor()
cur.execute("select 1")
print("CINDER_DB_OK", cur.fetchone())
conn.close()
except Exception as e:
print("CINDER_DB_FAIL", repr(e))
PY
'
Nova API :
docker exec -it nova_api bash -lc '
python3 - << "PY"
import configparser, re, urllib.parse, pymysql
cfg=configparser.ConfigParser()
cfg.read("/etc/nova/nova.conf")
targets = []
if "database" in cfg and "connection" in cfg["database"]:
targets.append(("NOVA_DATABASE", cfg["database"]["connection"]))
if "api_database" in cfg and "connection" in cfg["api_database"]:
targets.append(("NOVA_API_DATABASE", cfg["api_database"]["connection"]))
for name, url in targets:
m=re.match(r".*://([^:]+):([^@]+)@([^:/]+):?([0-9]*)/([^?]+)", url)
user, pw, host, port, db = m.group(1), urllib.parse.unquote(m.group(2)), m.group(3), int(m.group(4) or 3306), m.group(5)
print("TARGET=", name, host, port, db, user)
try:
conn=pymysql.connect(host=host, port=port, user=user, password=pw, database=db,
connect_timeout=5, read_timeout=5, write_timeout=5)
cur=conn.cursor()
cur.execute("select 1")
print(name + "_OK", cur.fetchone())
conn.close()
except Exception as e:
print(name + "_FAIL", repr(e))
PY
'
Glance:
docker exec -it glance_api bash -lc '
python3 - << "PY"
import configparser, re, urllib.parse, pymysql
cfg=configparser.ConfigParser()
cfg.read("/etc/glance/glance-api.conf")
url=cfg["database"]["connection"]
m=re.match(r".*://([^:]+):([^@]+)@([^:/]+):?([0-9]*)/([^?]+)", url)
user, pw, host, port, db = m.group(1), urllib.parse.unquote(m.group(2)), m.group(3), int(m.group(4) or 3306), m.group(5)
print("TARGET=", host, port, db, user)
try:
conn=pymysql.connect(host=host, port=port, user=user, password=pw, database=db,
connect_timeout=5, read_timeout=5, write_timeout=5)
cur=conn.cursor()
cur.execute("select 1")
print("GLANCE_DB_OK", cur.fetchone())
conn.close()
except Exception as e:
print("GLANCE_DB_FAIL", repr(e))
PY
'
Neutron:
docker exec -it neutron_server bash -lc '
python3 - << "PY"
import configparser, re, urllib.parse, pymysql
cfg=configparser.ConfigParser()
cfg.read("/etc/neutron/neutron.conf")
url=cfg["database"]["connection"]
m=re.match(r".*://([^:]+):([^@]+)@([^:/]+):?([0-9]*)/([^?]+)", url)
user, pw, host, port, db = m.group(1), urllib.parse.unquote(m.group(2)), m.group(3), int(m.group(4) or 3306), m.group(5)
print("TARGET=", host, port, db, user)
try:
conn=pymysql.connect(host=host, port=port, user=user, password=pw, database=db,
connect_timeout=5, read_timeout=5, write_timeout=5)
cur=conn.cursor()
cur.execute("select 1")
print("NEUTRON_DB_OK", cur.fetchone())
conn.close()
except Exception as e:
print("NEUTRON_DB_FAIL", repr(e))
PY
'
Keystone:
docker exec -it keystone bash -lc '
python3 - << "PY"
import configparser, re, urllib.parse, pymysql
cfg=configparser.ConfigParser()
cfg.read("/etc/keystone/keystone.conf")
url=cfg["database"]["connection"]
m=re.match(r".*://([^:]+):([^@]+)@([^:/]+):?([0-9]*)/([^?]+)", url)
user, pw, host, port, db = m.group(1), urllib.parse.unquote(m.group(2)), m.group(3), int(m.group(4) or 3306), m.group(5)
print("TARGET=", host, port, db, user)
try:
conn=pymysql.connect(host=host, port=port, user=user, password=pw, database=db,
connect_timeout=5, read_timeout=5, write_timeout=5)
cur=conn.cursor()
cur.execute("select 1")
print("KEYSTONE_DB_OK", cur.fetchone())
conn.close()
except Exception as e:
print("KEYSTONE_DB_FAIL", repr(e))
PY
'
echo "===== Heat Service Check ====="
docker ps -a | egrep 'heat'
openstack endpoint list --service heat
openstack endpoint list --service heat-cfn
echo "===== Heat API Check ====="
curl -i http://192.168.111.130:8004/
curl -i http://192.168.111.130:8000/
echo "===== Heat DB Check ====="
docker exec -it heat_api bash -lc '
python3 - << "PY"
import configparser, re, urllib.parse, pymysql
cfg=configparser.ConfigParser()
cfg.read("/etc/heat/heat.conf")
url=cfg["database"]["connection"]
m=re.match(r".*://([^:]+):([^@]+)@([^:/]+):?([0-9]*)/([^?]+)", url)
user, pw, host, port, db = m.group(1), urllib.parse.unquote(m.group(2)), m.group(3), int(m.group(4) or 3306), m.group(5)
print("TARGET=", host, port, db, user)
try:
conn=pymysql.connect(host=host, port=port, user=user, password=pw, database=db, connect_timeout=5, read_timeout=5, write_timeout=5)
cur=conn.cursor()
cur.execute("select 1")
print("HEAT_DB_OK", cur.fetchone())
conn.close()
except Exception as e:
print("HEAT_DB_FAIL", repr(e))
PY
'
7단계. DB 접속이 정상일 때 재시작 순서
docker restart placement_api
sleep 30
docker restart cinder_api cinder_scheduler cinder_volume cinder_backup
sleep 30
docker restart nova_api nova_metadata nova_conductor nova_scheduler
sleep 30
docker restart horizon
sleep 10
8단계. 최종 확인
curl -i http://192.168.111.130:8780/
openstack compute service list
openstack hypervisor list
openstack volume service list
docker exec -it placement_api placement-status upgrade check
docker exec -it nova_api nova-status upgrade check
docker exec -it cinder_api cinder-manage db version
9단계. 실제 볼륨 기능 테스트
openstack volume create --size 1 test-vol-01
openstack volume list
openstack volume delete test-vol-01
볼륨이 available까지 올라오면 Cinder 실사용 기능은 정상으로 판단할 수 있다.
마무리
이번 장애는 Horizon 화면에서 시작된 것처럼 보였지만, 실제 원인은 DB/ProxySQL 안정화 전에 OpenStack API 서비스들이 먼저 기동되면서 발생한 DB 연결 실패였다.
핵심 원인은 다음 메시지로 요약된다.
Max connect timeout reached while reaching hostgroup 0
복구 핵심은 다음이었다.
1. Keystone 인증 정상 확인
2. Placement API 503 확인
3. Placement/Cinder 로그에서 DB timeout 확인
4. 서비스 컨테이너 내부에서 실제 DB 접속 테스트
5. DB 접속 정상 확인 후 Placement → Cinder → Nova 순서로 재시작
6. Upgrade Check 확인
7. 실제 볼륨 생성/삭제 테스트로 최종 검증
결론적으로 현재 OpenStack 환경은 Compute, Placement, Cinder 기본 기능 기준으로 정상 복구되었다.
다음에 동일한 문제가 발생하면 Nova나 Horizon부터 보지 말고, Placement와 Cinder의 DB 접속 상태, ProxySQL hostgroup 0 상태, 그리고 API 서비스 재시작 순서를 먼저 확인하는 것이 빠른 복구에 도움이 된다.
'시스템 엔지니어 일상 > OPENSTACK' 카테고리의 다른 글
| OpenStack(Kolla-Ansible) 점검 체크리스트 정리 (0) | 2026.04.28 |
|---|---|
| Kolla-Ansible OpenStack Horizon 오류 및 Nova/Placement/Cinder API 장애 조치 정리 (0) | 2026.04.28 |