aws-samples / aws-samples/sample-eks-enterprise-quickstart
Consider nodeadm localStorage (RAID0) for GPU containerd storage instead of hand-rolled LVM+rsync
- Dominant language
- Shell
- Stars
- 5
- Forks
- 3
- Avg merge
- 34m
- Merged PRs (30d)
- 2
Description
## Background
PRs #9 / #10 / #11 fixed a bootstrap race in the hand-rolled LVM + `rsync` migration that moves `/var/lib/containerd` onto a data disk (root cause: containerd not fully stopped before the copy, swallowed copy errors, no `sync` before umount → metadata.db referencing blobs whose files never landed → intermittent `blob not found` / ImagePullBackOff, matching [awslabs/amazon-eks-ami#2122](https://github.com/awslabs/amazon-eks-ami/issues/2122)).
The current fix (mask containerd → wait-for-exit → fail-fast `rsync --delete` → `sync` → unmask, plus abandon-on-failure to preserve the pre-cached `localhost/kubernetes/pause`) is correct and well tested, but the underlying approach is still a hand-rolled migration we own and must maintain.
This issue records a **potential alternative for GPU nodes** and, importantly, **why we are NOT adopting it right now**.
## The alternative: nodeadm `localStorage`
AL2023 EKS AMIs ship a native mechanism for instance-store-backed node storage, driven by the nodeadm NodeConfig API:
```yaml
apiVersion: node.eks.aws/v1alpha1
kind: NodeConfig
spec:
instance:
localStorage:
strategy: RAID0 # or Mount
```
Verified against the upstream `awslabs/amazon-eks-ami` source (`nodeadm/internal/system/local_disk.go` → `setup-local-disks`):
- It can target `/var/lib/kubelet`, **`/var/lib/containerd`**, `/var/lib/soci-snapshotter-grpc`, `/var/log/pods`.
- It **stops the dependent unit** (`containerd.service`) before migrating.
- It **preserves pre-baked content**: `cp -a "${mount_point}/" "${array_mount_point_unit}/"` — so the pre-cached pause image survives (this is exactly what our `rsync` does by hand).
- It then bind-mounts the copied dir back and restarts the service.
So it does, natively and inside the controlled nodeadm lifecycle, what our LVM+rsync does — **without the bootstrap race**, because it isn't running concurrently with the rest of cloud-init.
## What is / isn't "official"
- **Official AWS mechanisms**: `spec.instance.localStorage.strategy` is a first-class nodeadm API field; `setup-local-disks` is baked into the AL2023 EKS AMI by AWS; instance-store-backed `/var/lib/containerd` is an AWS-documented pattern.
- **NOT an official fix for #2122**: using it *in place of* our EBS+LVM+rsync path is an **architecture decision**, not an AWS-issued remediation. AWS did not roll back the #2000 pause change; the `localStorage` suggestion on #2122 is community discussion.
## Why we are NOT adopting it now
1. **It changes the storage medium, not just the mechanism.** `localStorage` uses **Instance Store (ephemeral NVMe)**, not EBS. containerd data would be lost on stop/replace. That's usually fine for stateless GPU nodes (images re-pull), but it is a behavior change, not a drop-in replacement for the EBS-backed path.
2. **Not all GPU instance types have instance store.** `RAID0` requires local NVMe. Types without it (or with a different disk layout) would need the EBS path anyway — so we'd still have to keep and maintain the LVM+rsync code, ending up with *two* mechanisms instead of one.
3. **It collides with our existing instance-store usage.** The GPU module already consumes instance store for scratch (`enable_local_lvm` → `setup-local-lvm.sh` → `/data`). `RAID0` grabs **all** local NVMe disks, so we'd have to redesign how scratch and containerd share (or don't share) the local disks.
4. **CPU / system / karpenter paths still need the EBS mask-based fix regardless.** Those are the majority of nodes and are EBS-backed; `localStorage` doesn't help them, so the hand-rolled path doesn't go away.
5. **Not clean enough yet.** Given 1–4, adopting it would mean a config switch (`ebs` vs `instance_store`), two code paths, and a scratch-vs-containerd disk-sharing redesign — more surface area, not less. The elegance win isn't there until the storage model is rethought holistically.
## Possible future direction (not now)
If/when we revisit GPU node storage holistically, consider:
- A `containerd_storage = "ebs" | "instance_store"` switch on the GPU module.
- `instance_store` mode → delegate to nodeadm `localStorage.strategy: RAID0`, dropping the hand-rolled LVM/rsync/mask block for that mode.
- Redesign scratch (`/data`) vs containerd disk allocation so RAID0 grabbing all NVMe doesn't starve scratch.
- Guard the mode against GPU instance types that lack instance store.
- Keep EBS + mask-based fix as the default / fallback (and for CPU/system/karpenter).
## References
- awslabs/amazon-eks-ami#2000 — pre-cached `localhost/kubernetes/pause` (all AL2023 K8s versions after 2024-11-12)
- awslabs/amazon-eks-ami#2122 — new-disk-without-migration drops the pause image
- This repo: #9 (race fix), #10 (abandon-on-failure preserves pause), #11 (karpenter EBS-only disk detection + GPU restart guard)
- Upstream source: `nodeadm/internal/system/local_disk.go`, `templates/al2023/runtime/bin/setup-local-disks`
---
_Recording only — no code change intended for now (current LVM+rsync+mask fix stays)._
Contributor guide
Research direction
This is a recording-only architecture discussion, with no code change intended now. If revisited, start by reading nodeadm/internal/system/local_disk.go, templates/al2023/runtime/bin/setup-local-disks, and the GPU module's setup-local-lvm.sh entry point. Done would require an explicit storage-mode design covering instance-store availability, scratch allocation, and the existing EBS fallback.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- aws, kubernetes, shell, terraform
- Domain
- cloud, devops, infrastructure
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100