Build and verify your own node image
This page describes how to build the reference node OS image from the os-image/ recipe in dsx-ai-factory/nvke, boot it, and check it with nvke-os-image-check. Use it to develop and test changes to the image.
Run the checker against every image you build, in the environment where its nodes will run. A pass shows that a node booted from the image attests to your SPIRE server, and that its nvke-agent accepts mTLS calls from an NVKE service identity, which is what the management plane needs to manage the node.
For HTTP(S) hosting and provisioning after the build, see Build and host node OS images.
Note: The image is built from Canonical Ubuntu. For internal/dev use only - contact Canonical before commercial production use.
The build produces one QCOW2 disk image: Ubuntu Server with the NVIDIA-tuned kernel (linux-nvidia on amd64, linux-nvidia-64k on arm64), nvke-agent and the SPIRE agent. It is not a ready Kubernetes node: nvke-agent installs Kubernetes later, and the NVIDIA GPU Operator installs GPU drivers. The agent is built from your checkout’s agent/ source. SPEC is the image contract.
Before you begin
- You have read Plan your installation.
- You have a Linux build host of the image’s architecture with a writable
/dev/kvm. A build takes about 15 minutes with KVM and hours under TCG emulation, which the build uses when KVM is unavailable. The build VM uses 4 vCPUs, 8 GiB of memory and a 12 GiB disk by default. - You have the build tools: Packer 1.15.4, Python 3.10 or later,
curl,ssh-keygen, QEMU (qemu-system-x86_64orqemu-system-aarch64, andqemu-img),cloud-localds,swtpm, UEFI firmware (OVMF for amd64, AAVMF for arm64),xorriso,p7zip-fullanddpkg-dev. - You have Go, at the version in
go.work, and a C compiler. The build compilesnvke-agentagainst the host’s glibc, so the host must run the image’s Ubuntu release or an older one. On a newer Ubuntu the build compiles the packages in a NixOS VM instead; on another Linux distribution, setNKE_PACKAGE_BUILDER=nixto do the same. The VM needs Nix withnix-commandandflakesenabled; see Nix setup. - You have a clean checkout of
dsx-ai-factory/nvke. The build refuses to run on uncommitted or untracked changes. - You have a SPIRE server you control, with the
join_tokennode attestor enabled. For a test, a local one is enough; see Run a local SPIRE server. The image contains no SPIRE address, trust domain, trust bundle or join token; you supply them at first boot. - You have a hypervisor or machine that boots a UEFI QCOW2 with cloud-init user data and gives the node an address by DHCPv4. The image ignores cloud-init network configuration. The checker must reach the node on TCP port 15005. The FDE variant also needs a TPM 2.0 device.
Build the image
-
Choose the variant, architecture and Ubuntu release.
non-fdehas an unencrypted LVM root volume that grows to fill the disk on first boot. Use it unless you need disk encryption.fdeencrypts the root volume with LUKS2. Until first boot binds the key to the node’s TPM, the disk also opens with the build-time passphrase. After the bind removes the passphrase, losing or resetting the TPM makes the disk unrecoverable. See Full disk encryption.
-
From the repository root, build the image.
image-nativefails early if KVM is unavailable. To build without KVM, usemake -C os-image imagewith the same variables. For the FDE variant, also set the build-time passphrase:The default passphrase,
changeit, is a placeholder.The build downloads the Ubuntu installer ISO, builds the Debian packages, runs an unattended Ubuntu install in a QEMU VM under Packer, and compresses the result.
-
Find the image in
os-image/packer/output-non-fde/(oroutput-fde/). Its name carries the variant, release and architecture, for examplenvke-node-non-fde-ubuntu-26.04.1-amd64.qcow2. -
For the non-FDE variant, boot-test the image.
If you built without KVM, omit
REQUIRE_ACCELERATION=1. The test boots a copy of the image and checks that cloud-init completes, thatnvke-agentandspire-agentare installed and enabled, and that the root filesystem grew. It does not contact SPIRE. For the FDE variant, runos-image/demo-fde.sh;--helpprints its options.
To rebuild, first remove the previous output with make -C os-image/packer clean-non-fde-output or clean-fde-output.
Build nvke-os-image-check
-
From the repository root, build the checker.
The binary is
os-image/bin/nvke-os-image-check. -
Copy it to the host that runs the checker. That host needs a SPIRE agent configured for your server and trust domain, with the
join_tokennode attestor and theunixworkload attestor. The next section issues its join token.
Run a local SPIRE server
Skip this section if you have a SPIRE server. Otherwise, run one on the checker host, with a SPIRE agent beside it for the checker. Use SPIRE release binaries for your host.
-
Write
server.conf.<TRUST_DOMAIN>is a name you choose, such asexample.org. Nodes reach the server on port 8081. -
Start the server, and save its trust bundle for the agents.
-
Write
agent.conffor the checker host’s agent.You start this agent with the checker host’s join token in the next section:
Register SPIRE identities
Run these commands on your SPIRE server.
-
Create a join token for the node’s SPIRE agent.
<NODE_AGENT_PATH>is a path you choose for the node. The token works once and expires after-ttlseconds, so boot the node within the hour. -
Register
nvke-agent, which runs as root, under the node’s agent.<AGENT_WORKLOAD_PATH>is any path you choose. -
Create a join token for the checker host’s SPIRE agent, and start that agent with it.
-
Register the checker under the checker host’s agent.
<CHECKER_UID>is the user ID that runs the checker.nvke-agentaccepts only callers under/tenant/nvke/service/or a legacy prefix listed in Checker.
To attest the node by TPM instead of a join token, see Prepare nodes.
Boot with cloud-init
-
Write the first-boot user data.
<SSH_PUBLIC_KEY>: your key, for logging in asubuntu.<SPIRE_SERVER_ADDRESS>and<SPIRE_SERVER_PORT>: where the node reaches your SPIRE server.<JOIN_TOKEN>: the node token from the previous section.<SPIRE_TRUST_BUNDLE_PEM>: the output ofspire-server bundle show, indented undercontent.
-
Boot the image with this user data on your hypervisor or provisioning system.
make -C os-image run-vmcannot boot this user data: it injects only an SSH key and forwards only port 22.
On first boot the node writes its SPIRE agent configuration from these files, spire-agent attests, and nvke-agent starts once it has an identity.
Verify
-
On the checker host, run the checker against the node.
If the SPIRE agent’s workload API socket is not
/tmp/spire-agent/public/api.sock, add--spiffe-socket unix://<SOCKET_PATH>.A pass exits 0 and logs
nvke-agent reachablewith the agent version. It means the mTLS handshake succeeded in both directions and the agent answered a gRPC call. A failure exits 1 and logsprobe failedwith the stage that failed. Checker lists every flag and error. -
For the FDE variant, confirm the TPM binding on the node, as root.
Exit code 0 means the disk is bound to this node’s TPM.
Troubleshooting
Next steps
- Prepare nodes, to boot development nodes from the image and attest them by TPM.
- Supported platforms and versions for the Ubuntu releases, architectures and kernels NVKE supports.