OpenKeel: die souveräne französische Cloud-Lösung mit europäischer Reichweite der inherent-Gruppe inherent entdecken
Ressourcen
Ironic in OpenKeel: upstream Python in einem Helm-Chart.
Status: decided and deployed on a test cluster (2026-10-31): Kolla images, Redfish virtual media, flat and noop, json-rpc, sushy-tools on a new kind cluster. Ironic stays upstream Python at OpenStack 2026.2 (user decision); openkeel-ironic is a Helm chart around it, not a Go rewrite. Evidence below was measured on this host on 2026-10-31.
Kolla quay.io/openstack.kolla/ironic-{api,conductor,pxe} | Metal3 quay.io/metal3-io/ironic:release-39.0 | |
|---|---|---|
| Ironic version | 39.0.1.dev38 (stable/2026.2) | 39.0.1.dev33 (39.0.0-33-g39703221e) |
| Architectures | amd64 and aarch64 (-aarch64 tag suffix, not one multi-arch tag) | amd64 only: emulated on this host, unusable natively on arm64 nodes |
| Base, size | Debian trixie, Python 3.13; 535 MB (api), 573 MB (conductor) | CentOS Stream 9; 206 MB, one image for everything |
| Keystone | keystonemiddleware present, standard use | middleware present, but ironic.conf.j2 only renders noauth or http_basic: Keystone means bypassing Metal3's scripts |
| Configuration | none imposed once kolla_start is bypassed: ironic.conf from a ConfigMap | environment variables through configure-ironic.sh and Jinja templates, single-process oriented |
| Hardening | default entrypoint uses sudo kolla_set_configs, but ironic-api and ironic-conductor --version run with uid 42422, read-only root, all capabilities dropped and no-new-privileges (only --version tested so far) | image default user is root; not tested further |
| Boot tooling | ipmitool, mkisofs, qemu-img in conductor; iPXE and TFTP in ironic-pxe; no HTTP server: needs a separate image | dnsmasq, httpd, ipmitool, xorrisofs and ESP images all included |
| Tags | moving, rebuilt daily, one per series: pin by digest | moving release-39.0, plus dated tags |
**Decision: Kolla, debian-trixie, pinned by digest, with binaries run directly** (no kolla_start, no sudo), plus a standard unprivileged nginx image for the conductor's HTTP server. Metal3 solves a standalone, Keystone-less use case and would run only under emulation here.
Consequences for okadm: it assumes <imageRepository>/openkeel-<project>:<imageTag> (internal/deploy/values.go:78) and an image per architecture is new. The manifest gets an external image declaration per architecture for this component, and okadm selects it from the node architecture, as it does for the base image.
Redfish virtual media first (redfish-virtual-media): no DHCP or TFTP in the cluster, only conductor to BMC and node to conductor HTTP. iPXE and DHCP come next (ipxe, dnsmasq sidecar with NET_ADMIN, NET_RAW, Multus attachment).
Limits of virtual media:
VirtualMedia InsertMedia by URL (on some vendors this needs a licence) and must reach the conductor's HTTP server;network_data on the node (DHCP-less boot, not tested here). It must then reach the Ironic API and the conductor's HTTP server;[conductor]/bootloader) or a prebuilt deploy_iso.QCOW2 images: the server never boots the QCOW2 itself. It boots the IPA ISO, IPA writes the image to the local disk, then the server reboots from disk. With the defaults (force_raw_images, [agent]/stream_raw_images, [agent]/image_download_source = http) the conductor converts a Glance image to raw with qemu-img in its cache, so the PVC must hold the raw size. An image given by URL goes directly to IPA, which converts it in the ramdisk's memory, unless image_download_source = local. The image must be a whole-disk image with a bootloader matching the server's architecture and firmware. Go Glance serves the original QCOW2 only with glance_store.csi.keep_original (default true); otherwise, and for images made by Cinder upload-to-image, it serves raw while disk_format may say otherwise (to test).
The brief recommends flat. The code adds a constraint: flat is a Neutron interface. ironic/drivers/modules/network/flat.py requires [neutron]/cleaning_network in validate and raises NetworkError when no port has a VIF to bind, so a deployment without Nova or Neutron VIFs fails. noop needs no Neutron.
**Decision: enable flat and noop, default flat,** with noop on standalone nodes (tests, operator-driven deployments). neutron and ironic-networking come later.
json-rpc (conductor port 8089, per-pod DNS name from the StatefulSet's headless Service, Keystone auth): no RabbitMQ user for a component that needs it for nothing else. Notifications stay off.
To be supplied by the user for real hardware: provisioning network (VLAN, IP range, who runs DHCP), BMC network, one Redfish machine. Without them, tests use sushy-tools in a test-only image on a new kind cluster.
What sushy-tools on kind can prove: chart, okadm, Keystone, openstack baremetal, Redfish power and boot-device calls, enroll to available with automated cleaning off. What it cannot prove: a real deployment. Kind nodes have no KVM and the ramdisk would not boot, so IPA, virtual media boot, image writing and active stay unverified.
baremetal:node:create needs system_scope:all, but baremetal:node:create:self_owned_node lets a project-scoped admin or service create nodes its project owns. Measured through Go Keystone: a system-scoped admin (--os-system-scope all) sees and manages everything; a project-scoped admin creates its own nodes, does not see others', and cannot list conductors.ironic-api binds in each worker (Address already in use with api_workers: 2): one worker per pod, scaled by replicas.httpboot/agent_images holds absolute symlinks into images/: nginx mounts the whole volume at the conductor's path, or cached images answer 404.openkeel-keystone bootstrap.services.ironic (user ironic, role service, catalog type baremetal, port 6385). openkeel-chart adds a database-url key in SQLAlchemy form next to the Go database-dsn. PyMySQL connects without TLS: same network trust as the lab, to review for production.okadm deploys it only with --components ironic; the role provisioning is checked by okadm plan.ok-ironic, arm64, openkeel-ironic/test/smoke.sh)| Verified | How |
|---|---|
chart renders and lints; okadm tests pass; okadm install from the embedded chart; okadm status healthy | commands run |
| Kolla aarch64 images run as uid 42422, read-only root, no capabilities; dbsync and post-install hook Jobs succeed | real pods |
openstack baremetal through Go Keystone, catalog baremetal, JSON-RPC with Keystone auth | client pod, python-ironicclient 6.3.0 |
enroll to manageable to available, power, boot device, over Redfish | sushy-tools fake driver |
deploy to wait call-back: QCOW2 downloaded and converted to raw, ISO mounted over virtual media and fetched from nginx, node powered on; undeploy back to available | sushy-tools fake driver, image_download_source=local, a test ISO |
| BMC password masked in the API | driver_info output |
Multus attachment: net1 used for my_ip and http_url | with ptp, not macvlan, not a real network |
| okadm install --components ironic in lab mode (kind, 3 nodes) and in production mode (3 API, 2 conductors, Galera 3), then smoke.sh on each, on 2026-11-02 | production on kind needed two test-only additions: the lab's DNS NetworkPolicy workaround (kindnet drops DNS replies to pods selected by ingress policies; Keystone fails the same way) and automated_clean: false (no ramdisk) |
Production gaps seen on 2026-11-02: okadm checks the provisioning role label (warning only) but no chart receives global.nodeRoles, so conductors are not pinned to provisioning nodes (one ran on an unlabelled node). Two conductors with required anti-affinity need two schedulable nodes, while okadm plan asks for one provisioning node.
Not verified: a real machine or IPA, active, flat with Neutron, Glance as image source, Nova's driver against this chart, amd64 digests (rendered, never run), networkPolicy.bmcCIDRs (rendered only), automated cleaning, okadm upgrade.
| Gap | Effect | Treatment |
|---|---|---|
| No Nova agent publishes Ironic nodes to Placement | openstack server create on bare metal cannot schedule | outside this chart; Go work in openkeel-nova, proposed as a follow-up |
Neutron Go writes no extra_dhcp_opts and has no external ports | iPXE through Neutron DHCP impossible; OVN DHCP does not reach a physical server on a flat network | virtual media avoids the first; the second needs static addressing |
openkeel-nova/internal/driver/ironic/ironic.go sends network_data with networks: [] | with no OVN DHCP on the server, a Nova bare metal server gets no IP configuration | same follow-up as above |
| No Swift | no temp URLs | [agent]/image_download_source = http, [deploy]/configdrive_use_object_store = false, [redfish]/use_swift = false: images served by the conductor |
| IPA ramdisk | tarballs.opendev.org answers with a self-signed chain from this host (TLS interception not trusted): the ramdisk could not be fetched here | chart takes operator-supplied kernel and ramdisk (config.conductor) |
| Pinned digests | upstream tags move daily, and quay.io may remove untagged digests | mirror for production (global.imageRegistry); refresh the manifest otherwise |
| Credentials at rest | Ironic masks driver_info in its API, and its database holds it unencrypted | protect the database and the conductor; the earlier reference wrongly said encrypted |
| Separate namespace | NODE-PLACEMENT asks for one for the conductor; okadm installs everything in one namespace | not done |
| JSON-RPC in clear | no TLS on port 8089 in this version, tokens travel on the pod network | NetworkPolicy limits it to the API; use_ssl with cert-manager later |
| Rescue, console | disabled; Nova's Rescue fails on these nodes | later |
| Skill reference says Go rewrite | references/backends/ironic-baremetal.md and SKILL.md:32 are wrong after this decision | updated once decisions are made, diagram model regenerated |
Quelle: openkeel-docs/IRONIC-DESIGN.md