With Talos 1.14 we introduced alpha Kubernetes-less mode. As of now, the way to generate initial config for this special mode is to pass the hidden flag --skip-k8s-etcd=true to the talosctl gen config command.

With Talos 1.15, I've contributed a new community extension - nfs-server1.

Here is the customization I am using in Image Factory:

customization:
    systemExtensions:
        officialExtensions:
            - siderolabs/nfs-server
            - siderolabs/nfs-utils
            - siderolabs/nfsd
            - siderolabs/nfsrahead
            # Intel specific microcode
            - siderolabs/i915
            - siderolabs/intel-ucode

After booting Talos, we will need to apply some configs. There are some assumptions below, that I am making for the current shape of my appliance - e.g. I have 2 extra disks, that will be used for exported storage as RAID0.

First, the KernelModuleConfig - we need to load this kernel module manually, so that the kernel nfs server can be started.

apiVersion: v1alpha1
kind: KernelModuleConfig
name: nfsd

Next, our volume configuration. We start with building a Volume Group2 config. In Talos, VG configuration will automatically provision underlying Physical Volumes3 - there is no separate document to mark the disks/partitions with LVM metadata.

apiVersion: v1alpha1
kind: LVMVolumeGroupConfig
name: vgdata
provisioning:
  volumeSelector:
    match: >-
      disk.serial == "CVPF636600YC450RGN" ||
      disk.serial == "CVPF6333002Y450RGN"

After that, we can provision Logical Volume on the VG we just created.

apiVersion: v1alpha1
kind: LVMLogicalVolumeConfig
name: lvnfs
volumeGroup: vgdata
type: raid0
stripes: 2
provisioning:
  volumeGroup: vgdata
  maxSize: 100%

The last step in our configuration is User Volume - this configuration file will trigger creation of an actual mount point on our server under /var/mnt/$name.

apiVersion: v1alpha1
kind: UserVolumeConfig
name: nfs
volumeType: disk
provisioning:
  diskSelector:
    match: >-
      disk.device_mapper_kind == "lvm" &&
      disk.device_mapper_name == "vgdata-lvnfs"
filesystem:
  type: xfs
mount:
  secure: true

And last, but not least, we need to pass configs that are required by our extension - those two files will write /etc/{exports,netconfig}.

In exports, the options mean:

  • rw allows reading and writing, subject to filesystem permissions.

  • sync makes the server commit changes to stable storage before acknowledging them.

  • root_squash stops a client's root user from automatically becoming root on the server. It maps that identity to an unprivileged account.

  • no_subtree_check disables extra checks about where files sit inside the exported directory tree.

  • fsid=0 makes this the NFSv4 root export. Clients mount SERVER:/.

  • mountpoint requires the real filesystem to be mounted before it is exported. This prevents accidentally sharing the empty directory underneath it while storage is unavailable.

apiVersion: v1alpha1
kind: EtcFileConfig
name: exports
mode: 0o644
contents: |
  /var/mnt/nfs 192.0.2.0/24(rw,sync,root_squash,no_subtree_check,fsid=0,mountpoint)
---
apiVersion: v1alpha1
kind: EtcFileConfig
name: netconfig
mode: 0o644
contents: |
  udp tpi_clts v inet udp - -
  tcp tpi_cots_ord v inet tcp - -