Ironic 中 Clean/deploy Step 延迟执行的原因分析

Ironic 中 Clean Step 延迟执行的原因分析

当使用 OpenStack client 执行 clean step 后,确实不会立即执行,而是需要等待一段时间。这是由 Ironic 的架构设计和工作机制决定的,主要原因如下:


1. 异步架构设计

1.1 API 与 Conductor 分离

python 复制代码
# ironic/api/controllers/v1/nodes.py
@expose.expose(None, types.uuid, body=types.jsontype,
               status_code=http_client.ACCEPTED)
def set_provision_state(self, node_ident, target, configdrive=None):
    """设置节点的供应状态"""
    
    # API 只是接收请求并更新节点状态
    node = api_utils.get_rpc_node(node_ident)
    
    # 通过 RPC 发送到 conductor
    topic = pecan.request.rpcapi.get_topic_for(node)
    pecan.request.rpcapi.do_node_clean(
        pecan.request.context, node.uuid, clean_steps, topic)
    
    # 立即返回 202 Accepted,而不等待执行完成
    return None

关键点

  • API 服务接收请求后立即返回 202 状态
  • 实际执行由 Conductor 服务异步处理
  • 这种设计避免了 API 请求超时

1.2 RPC 消息队列机制

python 复制代码
# ironic/conductor/rpcapi.py
def do_node_clean(self, context, node_id, clean_steps, topic=None):
    """通过 RPC 发送清理任务"""
    
    # 消息放入队列,等待 conductor 处理
    cctxt = self._prepare_call(topic=topic)
    return cctxt.cast(context, 'do_node_clean',
                      node_id=node_id, 
                      clean_steps=clean_steps)

2. Conductor 的处理延迟

2.1 节点锁定机制

python 复制代码
# ironic/conductor/manager.py
def do_node_clean(self, context, node_id, clean_steps):
    """执行节点清理"""
    
    # 等待获取节点锁(可能需要等待)
    with task_manager.acquire(context, node_id, shared=False) as task:
        node = task.node
        
        # 验证节点状态
        if node.provision_state != states.MANAGEABLE:
            raise exception.InvalidStateRequested(...)
        
        # 开始清理流程
        self._do_node_clean(task, clean_steps)

延迟原因

  • 需要获取节点独占锁
  • 如果节点正在被其他操作使用,需要等待
  • 多个 conductor 可能竞争同一节点

2.2 状态转换验证

python 复制代码
def _do_node_clean(self, task, clean_steps):
    """实际执行清理"""
    
    # 状态转换:MANAGEABLE -> CLEANING
    task.process_event('clean', target_state=states.CLEANING)
    
    # 准备清理环境(可能需要时间)
    task.driver.deploy.prepare_cleaning(task)
    
    # 启动 ramdisk(需要等待节点启动)
    self._spawn_worker(self._do_node_clean_steps, task, clean_steps)

3. 节点启动和 Agent 连接延迟

3.1 Ramdisk 启动过程

python 复制代码
# ironic/drivers/modules/pxe.py
def prepare_ramdisk(self, task, ramdisk_params):
    """准备 ramdisk 启动"""
    
    # 1. 生成 PXE 配置文件
    pxe_utils.create_pxe_config(task, ramdisk_params)
    
    # 2. 设置启动设备为 PXE
    task.driver.management.set_boot_device(task, 'pxe')
    
    # 3. 重启节点
    manager_utils.node_power_action(task, states.REBOOT)
    
    # 节点需要时间来:
    # - 关机
    # - 启动
    # - PXE 启动
    # - 下载 ramdisk
    # - 启动 agent

3.2 Agent 心跳等待

python 复制代码
# ironic/conductor/manager.py
def _spawn_worker(self, func, *args, **kwargs):
    """在后台线程中执行任务"""
    
    # 创建后台任务
    self._spawn(func, *args, **kwargs)

def _do_node_clean_steps(self, task, clean_steps):
    """执行清理步骤"""
    
    # 等待 agent 上线并发送心跳
    # 这可能需要几分钟时间
    self._wait_for_agent_heartbeat(task)
    
    # 开始执行清理步骤
    for step in clean_steps:
        self._execute_clean_step(task, step)

4. 实际时间线分析

4.1 典型的 Clean Step 执行时间线

bash 复制代码
# T+0s: 用户执行命令
openstack baremetal node clean --clean-steps '[...]' <node-uuid>

# T+0.1s: API 返回 202 Accepted
# 节点状态: MANAGEABLE -> CLEANING

# T+0.5s: Conductor 获取节点锁,开始准备清理
# 节点状态: CLEANING

# T+1-30s: 准备 ramdisk,设置 PXE,重启节点
# 等待时间取决于:
# - 节点关机时间
# - BIOS 启动时间
# - 网络速度(下载 ramdisk)

# T+30s-2min: Agent 启动并发送第一次心跳
# 节点状态: CLEANING (等待 agent)

# T+2min+: 开始执行实际的清理步骤
# 节点状态: CLEANING (执行中)

4.2 查看实际进度

bash 复制代码
# 查看节点当前状态
openstack baremetal node show <node-uuid> -c provision_state -c last_error

# 查看详细的 provision_state 信息
openstack baremetal node show <node-uuid> -c provision_updated_at -c target_provision_state

# 查看 conductor 日志
sudo journalctl -u ironic-conductor -f

# 查看 API 日志
sudo journalctl -u ironic-api -f

5. 配置优化建议

5.1 减少启动等待时间

ini 复制代码
# /etc/ironic/ironic.conf
[conductor]
# 减少心跳超时时间
heartbeat_timeout = 60

# 增加并发处理数量
workers_pool_size = 100

[deploy]
# 启用快速启动
fast_track = true

# 减少电源操作等待时间
power_state_change_timeout = 30

5.2 使用本地 ramdisk 缓存

ini 复制代码
[pxe]
# 启用 HTTP 服务
enable_pxe_http = true
http_root = /tftpboot
http_url = http://ironic-conductor:8088

# 预缓存 ramdisk 镜像
kernel = file:///var/lib/ironic/images/deploy.kernel
ramdisk = file:///var/lib/ironic/images/deploy.ramdisk

6. 监控和调试

6.1 实时监控节点状态

python 复制代码
#!/usr/bin/env python3
# monitor_clean_progress.py

import time
import subprocess
import json

def monitor_node_cleaning(node_uuid):
    """监控节点清理进度"""
    
    while True:
        # 获取节点状态
        result = subprocess.run([
            'openstack', 'baremetal', 'node', 'show', 
            node_uuid, '-f', 'json'
        ], capture_output=True, text=True)
        
        node_data = json.loads(result.stdout)
        provision_state = node_data['provision_state']
        
        print(f"[{time.strftime('%H:%M:%S')}] "
              f"State: {provision_state}")
        
        if provision_state in ['available', 'clean failed']:
            break
            
        time.sleep(10)

if __name__ == '__main__':
    import sys
    monitor_node_cleaning(sys.argv[1])

6.2 查看详细日志

bash 复制代码
# 过滤特定节点的日志
sudo journalctl -u ironic-conductor | grep "node-uuid-here"

# 查看 agent 相关日志
sudo journalctl -u ironic-conductor | grep -i "agent\|heartbeat"

# 查看清理步骤执行日志
sudo journalctl -u ironic-conductor | grep -i "clean.*step"

7. 常见延迟问题和解决方案

7.1 节点启动慢

原因

  • BIOS 启动时间长
  • 网络下载 ramdisk 慢
  • 硬件自检时间长

解决方案

ini 复制代码
# 优化 BIOS 设置
# - 禁用不必要的自检
# - 设置快速启动
# - 优化启动顺序

# 使用本地镜像服务器
[glance]
glance_api_servers = http://local-glance:9292

# 启用镜像缓存
[agent]
image_download_source = local

7.2 心跳超时

原因

  • Agent 启动失败
  • 网络连接问题
  • 防火墙阻塞

解决方案

bash 复制代码
# 检查网络连接
ping <node-ip>

# 检查端口访问
telnet <ironic-api-ip> 6385

# 查看 DHCP 分配
sudo journalctl -u isc-dhcp-server

总结

Ironic Clean Step 延迟执行的主要原因:

  1. 架构设计:异步处理模式,API 立即返回
  2. 资源竞争:节点锁定和 conductor 调度
  3. 物理限制:节点重启和 ramdisk 启动时间
  4. 网络因素:镜像下载和心跳建立

这种设计虽然增加了等待时间,但提供了更好的可扩展性稳定性并发处理能力。通过合理的配置优化和监控,可以有效减少延迟时间。

相关推荐
哈里谢顿2 天前
OpenStack 中的 nova-conductor 与 ironic-conductor 及其分布式锁机制详解
openstack
哈里谢顿6 天前
OpenStack oslo-config 详解
openstack
感哥11 天前
OpenStack Cinder 创建卷
openstack
感哥11 天前
OpenStack Cinder 架构
openstack
感哥11 天前
OpenStack Nova Scheduler 计算节点选择机制
openstack
感哥14 天前
OpenStack Nova 创建虚拟机
openstack
感哥14 天前
OpenStack Glance(镜像)
openstack
感哥15 天前
OpenStack Keystone详解
openstack
安全菜鸟24 天前
传统方式部署OpenStack具体教程
openstack