Amazon EKS용 사용자 지정 Bottlerocket AMI 변형 구축

Amazon EKS용 사용자 지정 Bottlerocket AMI 변형 구축

Bottlerocket의 오픈 소스 저장소를 사용해 NVIDIA 드라이버 분기를 바꾼 사용자 지정 AMI 변형을 구축하는 전체 과정을 설명합니다.

출처: 문서

본문

Amazon Elastic Kubernetes Service(Amazon EKS)에서 GPU 워크로드를 실행할 때 Bottlerocket 변형을 선택합니다. 변형은 Kubernetes 버전과 가속기 유형과 일치해야 합니다. Bottlerocket은 일반적인 구성에 대해 검증된 변형을 제공합니다. 그러나 조직에서 다음 이유 중 하나로 다른 변형이 필요할 수 있습니다.

  • 더 새로운 NVIDIA 드라이버 분기
  • 규제 준수를 위한 고정된 드라이버 버전
  • 모니터링을 위한 추가 패키지
  • 보안 팀이 요구하는 강화된 기준(hardened baseline)

GitHub 웹사이트의 Bottlerocket은 완전한 오픈 소스이므로 이러한 요구를 충족하는 사용자 지정 변형을 만들 수 있습니다. 이 주제는 기존 변형을 복제하고 NVIDIA 드라이버를 R580 분기에서 R595(버전 595.71.05)로 교체하는 방법을 보여줍니다. 그런 다음 이미지를 빌드하고 개인 AMI로 등록합니다.

중요

g7 인스턴스 유형은 NVIDIA 드라이버 버전 595 이상을 요구합니다. EKS Bottlerocket NVIDIA AMI에는 현재 NVIDIA 드라이버 버전 580이 포함되어 있으며, 이는 g7 인스턴스를 지원하지 않습니다.

NVIDIA 드라이버 버전 595로 변형을 구축하는 방법은 GitHub 웹사이트의 Bottlerocket 저장소를 참조하세요. 이 주제는 Step 1부터 전체 과정을 안내합니다.

빌드 시스템 작동 방식

cargo make -e BUILDSYS_VARIANT=aws-k8s-1.36-nvidia를 실행하면 세 가지 일이 발생합니다.

  1. 의존성 가져오기 — Twoliter(Bottlerocket 빌드 오케스트레이터)가 Twoliter.toml을 읽고 public.ecr.aws/bottlerocket에서 세 가지 OCI(Open Container Initiative) 아티팩트를 가져옵니다.
    • bottlerocket-sdk — 전체 크로스 컴파일 도구 체인(GCC, Rust, Go, RPM 매크로)이 있는 컨테이너 이미지
    • bottlerocket-kernel-kit — 커널, 커널 모듈(NVIDIA kmod 패키지 포함), 펌웨어용 사전 빌드 RPM
    • bottlerocket-core-kit — kubelet, containerd, NVIDIA 디바이스 플러그인 및 컨테이너 툴킷, 설정 플러그인, 시스템 서비스 등 사용자 공간용 사전 빌드 RPM
    • Twoliter.toml은 버전을 고정하고 Twoliter.lock은 다이제스트를 잠급니다. 이를 변경하려면 ./tools/twoliter/twoliter update를 실행하여 다시 해석합니다.
  2. 변형 빌드 — Twoliter가 SDK 컨테이너 내부에서 Docker 빌드를 시작합니다. 변형의 settings-defaults 크레이트를 컴파일하고, 키트에서 RPM 의존성 트리를 해석하며, 모든 것을 디스크 이미지로 조합합니다.
  3. 출력 — Twoliter가 최종 .img.lz4 파일을 build/images/에 기록합니다. 빌드는 결정적(deterministic) 출력을 생성합니다. 동일한 Twoliter.toml 고정 값과 변형 Cargo.toml은 호스트와 무관하게 항상 동일한 이미지를 생성합니다.

저장소 구조

변형 작업과 관련된 디렉터리는 다음과 같습니다.

bottlerocket/
├── Cargo.toml                       # workspace: lists every variant
├── Twoliter.toml                    # pins SDK + kit versions
├── Twoliter.lock                    # locked digests for the above
├── Licenses.toml                    # you create this (NVIDIA license acknowledgement)
├── Infra.toml                       # you create this (AMI publish regions)
│
├── variants/
│   ├── aws-k8s-1.36-nvidia/         # example variant you'll copy
│   │   ├── Cargo.toml               #   package list + kernel params
│   │   └── amispec.toml             #   symlink → ../shared/amispec-split.toml
│   └── shared/                      # shared AMI spec templates
│
├── sources/
│   ├── Cargo.toml                   # workspace: lists every settings-defaults crate
│   ├── shared-defaults/             # the actual defaults (symlink targets)
│   └── settings-defaults/
│       └── aws-k8s-1.36-nvidia/
│           ├── Cargo.toml
│           └── defaults.d/          # 30+ symlinks into shared-defaults/
│
└── packages/
    ├── settings-defaults/
    │   └── settings-defaults.spec   # RPM: declares which variants exist
    └── settings-plugins/
        └── settings-plugins.spec    # RPM: maps variants to settings plugins

저장소 구조에 대한 다음 참고 사항을 검토하세요.

  • 변형은 대부분 메타데이터입니다. 외부 키트가 커널, 드라이버, 사용자 공간을 제공합니다.
  • Settings-defaults 파일은 복사본이 아니라 심볼릭 링크입니다. 이를 보존하려면 cp -R(macOS에서는 cp -r 아님)를 사용하세요.
  • 변형을 추가하려면 다섯 곳(워크스페이스 Cargo.toml 파일 두 개, .spec 파일 두 개, README.md)을 편집해야 합니다.

사전 요구 사항

연습을 완료하려면 다음이 필요합니다.

  • EC2 인스턴스를 시작하고 AMI를 등록할 권한이 있는 AWS 계정
  • 최소 8코어, 16 GiB 메모리, 150 GB 디스크를 가진 EC2 인스턴스(또는 이에 상응하는 Linux x86_64 호스트)
  • Ubuntu 24.04 LTS(또는 Fedora; macOS는 빌드 호스트로 지원되지 않음)
  • Docker 20.10 이상
  • Rust(rustup으로 설치한 stable 툴체인)
  • cargo-make(최신 버전)
  • Git, Rust의 Cargo, RPM 패키징 개념에 대한 이해

참고

이 연습을 완료하면 지속적인 비용을 피하기 위해 EC2 인스턴스를 종료하고 더 이상 필요 없는 AMI를 등록 해제하세요. 정리 지침은 Cleaning up을 참조하세요.

Step 1: 빌드 호스트 준비

  1. EC2 인스턴스를 시작합니다 — 예를 들어 c7i.8xlarge(32 vCPU, 64 GiB 메모리)입니다. 150 GB gp3 루트 볼륨을 사용하고 SSM 접근을 위해 AmazonSSMManagedInstanceCore 관리형 정책을 연결합니다.
  2. AWS Systems Manager(SSM) Session Manager를 사용하여 인스턴스에 연결합니다.
aws ssm start-session --target <instance-id>
cd ~
  1. 필수 운영 체제 패키지를 설치합니다.
apt-get update
apt-get install -y build-essential openssl libssl-dev pkg-config lz4 \
                   git ca-certificates curl gnupg

참고

공식 BUILDING.md는 liblz4-tool을 참조합니다. 최신 Ubuntu 버전에서는 패키지 이름이 lz4입니다.

  1. 다음 명령으로 Docker를 설치합니다.
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
  -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] \
  https://download.docker.com/linux/ubuntu noble stable" \
  > /etc/apt/sources.list.d/docker.list
apt-get update
apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin
systemctl enable --now docker
  1. 다음 명령으로 Rust와 cargo-make를 설치합니다.
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
. "$HOME/.cargo/env"
cargo install cargo-make

Step 2: 저장소 복제

GitHub 웹사이트의 Bottlerocket 저장소를 복제하고 디렉터리로 이동합니다.

cd ~/bottlerocket

재현 가능한 빌드를 만들려면 태그된 릴리스를 체크아웃합니다(예: git checkout v1.62.1). 최신 패키지를 사용하려면 develop 분기에 머무세요.

Step 3: 키트 버전 확인

Twoliter.toml을 열고 키트 버전을 확인합니다. R595 지원에는 bottlerocket-kernel-kit 버전 6.2.2 이상이 필요합니다.

[[kit]]
name = "bottlerocket-kernel-kit"
version = "6.2.2"
vendor = "bottlerocket"

버전이 더 오래되었다면 업데이트하고 잠금을 다시 생성합니다.

./tools/twoliter/twoliter update

Step 4: cargo-make 경로 문제 해결

Twoliter는 CARGO_HOME을 ~/bottlerocket/.cargo로 설정하여 내부 Cargo 프로세스가 전역으로 설치된 cargo-make를 찾지 못하게 합니다. 심볼릭 링크를 만듭니다.

mkdir -p ~/bottlerocket/.cargo/bin
ln -sf /root/.cargo/bin/cargo-make ~/bottlerocket/.cargo/bin/cargo-make

이 단계가 없으면 빌드가 error: no such command: make로 실패합니다.

Step 5: 사용 가능한 드라이버 분기 찾기

NVIDIA kmod 패키지는 bottlerocket-kernel-kit 안에 배포됩니다. 사용 가능한 드라이버 패키지에 대한 정보는 GitHub 웹사이트의 kernel-kit packages 디렉터리 또는 GitHub 웹사이트의 릴리스 노트를 참조하세요.

커널 6.18(aws-k8s-1.36 변형이 사용)의 경우:

kmod-6.18-nvidia-r580   ← driver 580.159.03 (current default)
kmod-6.18-nvidia-r595   ← driver 595.71.05

커널 6.12(aws-k8s-1.33, 1.34, 1.35가 사용)의 경우:

kmod-6.12-nvidia-r580
kmod-6.12-nvidia-r595

참고

각 kmod 패키지는 하위 패키지(-tesla, -open-gpu, -grid, -fabricmanager, -imex)를 제공합니다. 공식 Bottlerocket NVIDIA 변형은 -tesla를 참조하며, 이는 RPM 의존성을 통해 필요한 모든 하위 패키지를 가져옵니다. 부팅 시 Bottlerocket은 인스턴스 유형에 따라 적절한 드라이버 풍미(flavor)를 자동으로 선택합니다.

Step 6: 새 변형 만들기

  1. 심볼릭 링크를 보존하려면 cp -R을 사용하여 기존 변형을 복사합니다.
cp -R variants/aws-k8s-1.36-nvidia variants/aws-k8s-1.36-nvidia-595
cp -R sources/settings-defaults/aws-k8s-1.36-nvidia \
      sources/settings-defaults/aws-k8s-1.36-nvidia-595
  1. variants/aws-k8s-1.36-nvidia-595/Cargo.toml을 편집합니다.
- name = "aws-k8s-1_36-nvidia"
+ name = "aws-k8s-1_36-nvidia-595"

- "kmod-6.18-nvidia-r580-tesla",
+ "kmod-6.18-nvidia-r595-tesla",
  1. sources/settings-defaults/aws-k8s-1.36-nvidia-595/Cargo.toml을 편집합니다.
- name = "settings-defaults-aws-k8s-1_36-nvidia"
+ name = "settings-defaults-aws-k8s-1_36-nvidia-595"

Step 7: 변형 등록

다섯 개 파일에서 새 변형을 등록합니다.

  1. Cargo.toml — 워크스페이스 멤버를 추가합니다.
 "variants/aws-k8s-1.36-nvidia",
+    "variants/aws-k8s-1.36-nvidia-595",
 "variants/aws-k8s-1.36-nvidia-fips",
  1. sources/Cargo.toml — settings-defaults 멤버를 추가합니다.
 "settings-defaults/aws-k8s-1.36-nvidia",
+    "settings-defaults/aws-k8s-1.36-nvidia-595",
  1. packages/settings-defaults/settings-defaults.spec — %package 블록, 두 빌드 루프의 항목, %files 섹션을 추가합니다.
%package aws-k8s-1.36-nvidia-595
Summary: Settings defaults for the aws-k8s 1.36 nvidia-595 variant
Requires: %{_cross_os}variant(aws-k8s-1.36-nvidia-595)
Provides: %{_cross_os}settings-defaults(any)
Provides: %{_cross_os}settings-defaults(aws-k8s-1.36-nvidia-595)
Conflicts: %{_cross_os}settings-defaults(any)

%description aws-k8s-1.36-nvidia-595
%{summary}.

두 for defaults in 루프 모두에 추가합니다.

     aws-k8s-1.36-nvidia \
+   aws-k8s-1.36-nvidia-595 \
     metal-dev \

%files 섹션을 추가합니다.

%files aws-k8s-1.36-nvidia-595
%{_cross_defaultsdir}/aws-k8s-1.36-nvidia-595.toml
%{_cross_tmpfilesdir}/storewolf-defaults-aws-k8s-1.36-nvidia-595.conf
  1. packages/settings-plugins/settings-plugins.spec — %package aws-k8s-nvidia 아래에 Provides: 줄을 추가합니다.
 Provides: %{_cross_os}settings-plugin(aws-k8s-1.36-nvidia)
+Provides: %{_cross_os}settings-plugin(aws-k8s-1.36-nvidia-595)
 Conflicts: %{_cross_os}settings-plugin(any)

Step 8: 잠금 파일 갱신

워크스페이스 멤버를 추가하면 sources/Cargo.lock이 무효화됩니다. 이를 갱신합니다.

cd ~/bottlerocket/sources
cargo update --workspace

중요

cargo generate-lockfile을 사용하지 마세요. 잠금 파일 전체를 다시 쓰고 전이 의존성을 올려 cargo-deny 중복 버전 오류를 일으킵니다.

Step 9: NVIDIA 라이선스 파일 생성

NVIDIA는 드라이버 소스의 재배포를 제한합니다. 빌드 전에 명시적 라이선스 승인을 추가해야 합니다.

cat > ~/bottlerocket/Licenses.toml <<'EOF'
# SPDX comment for the NVIDIA driver
# license = ...
EOF

NVIDIA 드라이버를 포함하려면 라이선스 승인 파일과 게시 리전을 정의하는 Infra.toml이 필요합니다.

cat > ~/bottlerocket/Infra.toml <<'EOF'
# ...
EOF

원하는 변경에 따른 변형 Cargo.toml 변경 사항은 다음과 같습니다.

원하는 것 변형 Cargo.toml에서 변경할 내용
다른 NVIDIA 드라이버 분기 kmod-6.18-nvidia-r580-tesla → kmod-6.18-nvidia-r595-tesla
다른 커널 버전 kernel-6.18 → kernel-6.12(kmod도 그에 맞게 조정)
NVIDIA 완전 제거 included-packages에서 세 개의 nvidia-* 줄 삭제
EFA 지원 추가 included-packages에 kmod-6.18-efa 추가
컨테이너 런타임 버전 변경 containerd-2.2 → containerd-2.1

사용 가능한 패키지에 대한 정보는 GitHub 웹사이트의 kernel-kit과 GitHub 웹사이트의 core-kit을 참조하세요.

중요

Bottlerocket 루트 파일 시스템은 변경할 수 없습니다(immutable). 런타임에 패키지를 설치할 수 없습니다. 키트의 모든 패키지는 Bottlerocket용으로 특별히 크로스 컴파일되며 표준 업스트림 RPM은 작동하지 않습니다. 키트에 없는 소프트웨어가 필요하다면 런타임 대안으로 GitHub 웹사이트의 부트스트랩 컨테이너 또는 GitHub 웹사이트의 호스트 컨테이너를 고려하세요.

정리 (Cleaning up)

빌드 호스트가 더 이상 필요 없다면 지속적인 비용을 피하기 위해 EC2 인스턴스를 종료하세요. AMI는 계정에서 독립적으로 유지되며, 더 이상 필요 없다면 EC2 콘솔이나 CLI로 등록을 해제하세요.

요약

이 주제는 다른 NVIDIA 드라이버 분기를 가진 사용자 지정 Bottlerocket 변형을 만드는 방법을 보여주었습니다. 이 과정에는 기존 변형 복사, 하나의 패키지 참조 변경, 워크스페이스와 RPM 사양에 새 변형 등록, 빌드 실행이 포함됩니다. 동일한 접근 방식은 커널 버전 교체, 패키지 추가, 새 Kubernetes 릴리스용 변형 생성 등 모든 사용자 지정에 적용됩니다.

더 알아보기 (Learn more)