aws-samples / aws-samples/sample-eks-enterprise-quickstart

Consider nodeadm localStorage (RAID0) for GPU containerd storage instead of hand-rolled LVM+rsync

Open
#12 0 comments 0 reactions 0 assignees View on GitHub
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.