Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 79 additions & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# THIS FILE WAS AUTOMATICALLY GENERATED BY KRES, PLEASE DO NOT EDIT.
#
# Generated on 2026-07-24T07:08:42Z by kres 5f4a4c6.
# Generated on 2026-08-11T20:37:35Z by kres 93d28ca.

concurrency:
group: ${{ github.head_ref || github.run_id }}
Expand Down Expand Up @@ -4938,6 +4938,84 @@ jobs:
/tmp/logs-*.tar.gz
/tmp/support-*.zip
retention-days: "5"
integration-qemu-ephemeral:
permissions:
actions: read
contents: write
issues: read
packages: write
pull-requests: read
runs-on:
group: large
if: contains(fromJSON(needs.default.outputs.labels || '[]'), 'integration/qemu-ephemeral')
|| contains(fromJSON(needs.default.outputs.labels || '[]'), 'integration/release-gate')
needs:
- default
steps:
- name: gather-system-info
id: system-info
uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0
continue-on-error: true
- name: print-system-info
run: |
MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))

OUTPUTS=(
"CPU Core: ${{ steps.system-info.outputs.cpu-core }}"
"CPU Model: ${{ steps.system-info.outputs.cpu-model }}"
"Hostname: ${{ steps.system-info.outputs.hostname }}"
"NodeName: ${NODE_NAME}"
"Kernel release: ${{ steps.system-info.outputs.kernel-release }}"
"Kernel version: ${{ steps.system-info.outputs.kernel-version }}"
"Name: ${{ steps.system-info.outputs.name }}"
"Platform: ${{ steps.system-info.outputs.platform }}"
"Release: ${{ steps.system-info.outputs.release }}"
"Total memory: ${MEMORY_GB} GB"
)

for OUTPUT in "${OUTPUTS[@]}";do
echo "${OUTPUT}"
done
continue-on-error: true
- name: checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # version: v7.0.0
- name: Unshallow
run: |
git fetch --prune --unshallow
- name: Set up Docker Buildx
id: setup-buildx
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # version: v4.2.0
with:
driver: remote
endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234
timeout-minutes: 10
- name: Download artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # version: v8.0.1
with:
name: talos-artifacts
path: _out
- name: Fix artifact permissions
run: |
xargs -a _out/executable-artifacts -I {} chmod +x {}
- name: ci-temp-release-tag
run: |
make ci-temp-release-tag
- name: e2e-qemu
env:
IMAGE_REGISTRY: registry.dev.siderolabs.io
QEMU_MEMORY_CONTROLPLANES: "6144"
WITH_EPHEMERAL_NODE: "true"
run: |
sudo -E make e2e-qemu
- name: save artifacts
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # version: v7.0.1
with:
name: talos-logs-integration-qemu-ephemeral
path: |-
/tmp/logs-*.tar.gz
/tmp/support-*.zip
retention-days: "5"
integration-qemu-race:
permissions:
actions: read
Expand Down
88 changes: 88 additions & 0 deletions .github/workflows/integration-qemu-ephemeral-triggered.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# THIS FILE WAS AUTOMATICALLY GENERATED BY KRES, PLEASE DO NOT EDIT.
#
# Generated on 2026-08-11T20:37:35Z by kres 93d28ca.

concurrency:
group: ${{ github.head_ref || github.run_id }}
cancel-in-progress: true
'on':
workflow_run:
workflows:
- default
types:
- completed
name: integration-qemu-ephemeral-triggered
jobs:
default:
permissions:
actions: read
runs-on:
group: large
if: github.event.workflow_run.conclusion == 'success'
steps:
- name: gather-system-info
id: system-info
uses: kenchan0130/actions-system-info@59699597e84e80085a750998045983daa49274c4 # version: v1.4.0
continue-on-error: true
- name: print-system-info
run: |
MEMORY_GB=$((${{ steps.system-info.outputs.totalmem }}/1024/1024/1024))

OUTPUTS=(
"CPU Core: ${{ steps.system-info.outputs.cpu-core }}"
"CPU Model: ${{ steps.system-info.outputs.cpu-model }}"
"Hostname: ${{ steps.system-info.outputs.hostname }}"
"NodeName: ${NODE_NAME}"
"Kernel release: ${{ steps.system-info.outputs.kernel-release }}"
"Kernel version: ${{ steps.system-info.outputs.kernel-version }}"
"Name: ${{ steps.system-info.outputs.name }}"
"Platform: ${{ steps.system-info.outputs.platform }}"
"Release: ${{ steps.system-info.outputs.release }}"
"Total memory: ${MEMORY_GB} GB"
)

for OUTPUT in "${OUTPUTS[@]}";do
echo "${OUTPUT}"
done
continue-on-error: true
- name: checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # version: v7.0.0
- name: Unshallow
run: |
git fetch --prune --unshallow
- name: Set up Docker Buildx
id: setup-buildx
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # version: v4.2.0
with:
driver: remote
endpoint: tcp://buildkit-amd64.ci.svc.cluster.local:1234
timeout-minutes: 10
- name: Download artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # version: v8.0.1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
name: talos-artifacts
path: _out
run-id: ${{ github.event.workflow_run.id }}
- name: Fix artifact permissions
run: |
xargs -a _out/executable-artifacts -I {} chmod +x {}
- name: ci-temp-release-tag
run: |
make ci-temp-release-tag
- name: e2e-qemu
env:
IMAGE_REGISTRY: registry.dev.siderolabs.io
QEMU_MEMORY_CONTROLPLANES: "6144"
WITH_EPHEMERAL_NODE: "true"
run: |
sudo -E make e2e-qemu
- name: save artifacts
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # version: v7.0.1
with:
name: talos-logs-integration-qemu-ephemeral
path: |-
/tmp/logs-*.tar.gz
/tmp/support-*.zip
retention-days: "5"
3 changes: 2 additions & 1 deletion .github/workflows/slack-notify-ci-failure.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# THIS FILE WAS AUTOMATICALLY GENERATED BY KRES, PLEASE DO NOT EDIT.
#
# Generated on 2026-07-07T09:19:50Z by kres 14a38a3.
# Generated on 2026-08-11T20:37:35Z by kres 93d28ca.

'on':
workflow_run:
Expand All @@ -9,6 +9,7 @@
- grype-scan-cron
- artifacts-cron
- integration-qemu-triggered
- integration-qemu-ephemeral-triggered
- integration-embedded-triggered
- integration-conformance-triggered
- integration-trusted-boot-triggered
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/slack-notify.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# THIS FILE WAS AUTOMATICALLY GENERATED BY KRES, PLEASE DO NOT EDIT.
#
# Generated on 2026-07-07T09:19:50Z by kres 14a38a3.
# Generated on 2026-08-11T20:37:35Z by kres 93d28ca.

'on':
workflow_run:
Expand All @@ -9,6 +9,7 @@
- grype-scan-cron
- artifacts-cron
- integration-qemu-triggered
- integration-qemu-ephemeral-triggered
- integration-embedded-triggered
- integration-conformance-triggered
- integration-trusted-boot-triggered
Expand Down
36 changes: 36 additions & 0 deletions .kres.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ spec:
integration/qemu-default: "Run QEMU integration tests on default variant"
integration/qemu-encrypted-vip: "Run QEMU integration tests with disk encryption and virtual IP"
integration/qemu-enforcing: "Run QEMU integration tests on enforcing variant"
integration/qemu-ephemeral: "Run QEMU integration tests for a fully ephemeral single-node cluster"
integration/qemu-race: "Run QEMU integration tests with the race detector"
integration/qemu-13: "Run QEMU integration tests with Talos version contract v1.13"
integration/release-gate: "Run all release-gate integration tests"
Expand Down Expand Up @@ -553,6 +554,41 @@ spec:
artifactPath: /tmp/logs-*.tar.gz
additionalArtifacts:
- "/tmp/support-*.zip"
- name: integration-qemu-ephemeral
buildxOptions:
enabled: true
depends:
- default
runnerGroup: large
onWorkflowRun:
workflows: [default]
types: [completed]
triggerLabels:
- integration/qemu-ephemeral
- integration/release-gate
steps:
- name: download-artifacts
artifactStep:
type: download
artifactName: talos-artifacts
artifactPath: _out
- name: ci-temp-release-tag
- name: e2e-qemu
withSudo: true
environment:
IMAGE_REGISTRY: registry.dev.siderolabs.io
WITH_EPHEMERAL_NODE: "true"
QEMU_MEMORY_CONTROLPLANES: "6144"
- name: save-talos-logs
conditions:
- always
artifactStep:
type: upload
artifactName: talos-logs-integration-qemu-ephemeral
disableExecutableListGeneration: true
artifactPath: /tmp/logs-*.tar.gz
additionalArtifacts:
- "/tmp/support-*.zip"
- name: integration-embedded
buildxOptions:
enabled: true
Expand Down
1 change: 1 addition & 0 deletions api/resource/definitions/enums/enums.proto
Original file line number Diff line number Diff line change
Expand Up @@ -788,6 +788,7 @@ enum BlockVolumeType {
VOLUME_TYPE_SYMLINK = 4;
VOLUME_TYPE_OVERLAY = 5;
VOLUME_TYPE_EXTERNAL = 6;
VOLUME_TYPE_MEMORY = 7;
}

// StorageLVMLogicalVolumeType describes the layout of an LVM logical volume.
Expand Down
46 changes: 46 additions & 0 deletions hack/release.toml
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,52 @@ Use CSI drivers instead — a CSI node plugin performs the attach/mount itself i
unaffected by the sandbox. For iSCSI, `kubernetes-csi/csi-driver-iscsi` (or `democratic-csi`) consumes a
target the same way. All in-tree (non-CSI) volume plugins are deprecated for the kubelet and support for them
may be removed in a later release.
"""

[notes.ephemeralNode]
title = "Ephemeral Talos Node (tmpfs STATE and EPHEMERAL)"
description = """\
Both the `STATE` and `EPHEMERAL` system volumes can now be backed by `tmpfs` instead of a disk
partition, turning a node into a fully ephemeral machine that loses **all** machine state,
including the machine configuration itself, on every reboot.

Enable per volume with a `VolumeConfig` document:

```yaml
apiVersion: v1alpha1
kind: VolumeConfig
name: STATE
volumeType: memory
---
apiVersion: v1alpha1
kind: VolumeConfig
name: EPHEMERAL
volumeType: memory
provisioning:
minSize: 3GiB
```

Semantics and constraints:

- `STATE: memory` uses a fixed 100 MiB tmpfs; no `provisioning` or `encryption` may be configured.
- `EPHEMERAL: memory` requires `provisioning.minSize` (minimum 2 GiB, taken straight out of RAM)
and rejects `diskSelector`, `grow`, `maxSize`, and `encryption`.
- Machine configuration must be supplied on every boot via kernel cmdline, platform metadata,
or the maintenance API — nothing is persisted to disk. `talosctl apply-config --mode=no-reboot`
is accepted; `--mode=reboot` and `--mode=staged` succeed but the staged config is lost when
the node reboots.
- The node joins the cluster with a freshly generated identity each boot; this is intended for
workers and single-node clusters where ephemerality is the goal. Production multi-node control
planes should keep `STATE` on disk.
- Sizing: every byte of `EPHEMERAL` comes out of RAM. Plan for `minSize` + workload RAM +
~512 MiB of kernel/system overhead. A 4 GiB node with a 3 GiB ephemeral volume will OOM
under load; for the integration test suite the QEMU controlplane VM is provisioned with 6 GiB.
- `META` is **not yet** supported on tmpfs; it stays on disk. A fully diskless node is not yet
supported in this release.
- The `talosctl dashboard` Talos info pane now reports the ephemeral mode of each node.

A dedicated CI variant `integration-qemu-ephemeral` runs a single-node cluster end-to-end with
both STATE and EPHEMERAL on tmpfs.
"""

[make_deps]
Expand Down
14 changes: 14 additions & 0 deletions hack/test/e2e-qemu.sh
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,20 @@ case "${WITH_4K_DISK_IMAGE:-false}" in
;;
esac

case "${WITH_EPHEMERAL_NODE:-false}" in
false)
;;
*)
# Fully ephemeral node: STATE and EPHEMERAL on tmpfs. Forced single-node cluster.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess if we want to be closer to real usecase, we should have tmpfs only for workers

I think we should still test a cluster (that is more than a single worker, and at least a single controlplane)

QEMU_FLAGS+=("--config-patch-control-plane=@hack/test/patches/ephemeral-memory.yaml")
QEMU_CONTROLPLANES=1
QEMU_WORKERS=0
QEMU_MEMORY_CONTROLPLANES="${QEMU_MEMORY_CONTROLPLANES:-6144}"
EXTRA_TEST_ARGS="${EXTRA_TEST_ARGS:-} -talos.ephemeral-node"
export EXTRA_TEST_ARGS
;;
esac

case "${WITH_UKI_BOOT:-false}" in
false)
;;
Expand Down
19 changes: 19 additions & 0 deletions hack/test/patches/ephemeral-memory.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
apiVersion: v1alpha1
kind: VolumeConfig
name: STATE
volumeType: memory
---
apiVersion: v1alpha1
kind: VolumeConfig
name: EPHEMERAL
volumeType: memory
provisioning:
minSize: 3GiB
---
# Single-node ephemeral cluster: schedule workloads on the control plane.
apiVersion: v1alpha1
kind: KubeNodeConfig
taints:
node-role.kubernetes.io/control-plane:
$patch: delete
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import (
// Close the encrypted volumes.
func Close(ctx context.Context, logger *zap.Logger, volumeContext ManagerContext) error {
switch volumeContext.Cfg.TypedSpec().Type {
case block.VolumeTypeTmpfs, block.VolumeTypeDirectory, block.VolumeTypeSymlink, block.VolumeTypeOverlay, block.VolumeTypeExternal:
case block.VolumeTypeTmpfs, block.VolumeTypeDirectory, block.VolumeTypeSymlink, block.VolumeTypeOverlay, block.VolumeTypeExternal, block.VolumeTypeMemory:
// volume types can be always closed
volumeContext.Status.Phase = block.VolumePhaseClosed

Expand Down
Loading