Bottlerocket 与 Amazon EKS 实战指南:从 eksctl 自动化到手动部署的完整接入流程
2026/9/24 13:45:58 网站建设 项目流程
  • 操作系统
  • 云原生
  • 安全

【免费下载链接】bottlerocket

An operating system designed for hosting containers

项目地址:https://gitcode.com/gh_mirrors/bo/bottlerocket
点击查看免费下载

Bottlerocket 是一个专为托管容器而设计的开源 Linux 操作系统,其首个发布版本即聚焦于 Kubernetes,尤其是作为 Kubernetes Pod 的宿主操作系统。本文以仓库中的 QUICKSTART-EKS.md 为骨架,完整讲解两种将 Bottlerocket AMI 接入 Amazon EKS 集群的路径:一是借助eksctl完成自动化集群与节点创建,二是完全手动的方式(从查询 AMI、生成 user-data、配置 IAM 角色到最终用run-instances启动实例)。读完本文,你将掌握 Bottlerocket EKS 变体的选择规则、SSM 参数获取 AMI 的方法、TOML 格式用户数据(user data)的编写方式,以及 NVIDIA 与 Neuron 加速实例的启用配置。

背景:为什么用 Bottlerocket 作为 EKS 节点

Bottlerocket 的设计目标是“只包含运行容器所需的最小集”,并把安全与可维护性放在首位。从 README.md 可以看到,其基础系统仅包含运行容器所必需的组件,Bottlerocket 自身的增量工作集中在可靠的更新机制API 配置模型上:

  • 系统配置通过 API 调用完成,而不是手工修改文件;
  • 配置项在版本更新时会被自动迁移;
  • 更新基于分区翻转(partition flip)机制,快速且可靠。

在 AWS EKS 场景下,Bottlerocket 以 AMI 的形式提供,天然适合作为托管 Kubernetes 集群的工作节点。本文所有示例均以 EKS 为主线,但如文档所述,"There's nothing that limits Bottlerocket to EKS or AWS"——Bottlerocket 并不局限于 EKS 或 AWS,仓库中还提供了 Amazon ECS、VMware 与裸金属(PROVISIONING-METAL.md)等接入路径。

环境依赖

在开始之前,需要准备以下命令行工具:

工具用途说明
eksctl创建和管理 EKS 集群0.15.0-rc.2开始原生支持 Bottlerocket,建议下载最新版本以获得完整支持
kubectl管理 Kubernetes 集群与运行 Pod在集群搭建期间补充eksctl,之后用于运行工作负载
aws-cli与 AWS 交互需要支持 EKS 的较新版本(v1 系列中的较新发布版)

大部分流程都是一次性设置,仓库文档也明确说明计划后续进一步自动化。一旦集群创建完成,之后的操作可以直接跳到最后的"Launch!"(启动)步骤。

路径一:使用 eksctl 的自动化设置

只要eksctl版本满足要求,Bottlerocket 在 EKS 中的大部分设置都是自动化的。

集群设置配置文件

eksctl支持通过配置文件简化集群创建。仓库根目录提供了两个可直接使用的示例文件:

  • sample-eksctl.yaml:适用于大多数场景(推荐)。
  • sample-eksctl-ssh.yaml:适用于确定需要 SSH 访问的测试集群,使用时务必把publicKeyName改为你在 EC2 中注册的密钥对名称。

以 sample-eksctl.yaml 为例,其核心结构如下:

apiVersion: eksctl.io/v1alpha5 kind: ClusterConfig metadata: name: bottlerocket region: us-west-2 version: '1.24' nodeGroups: - name: ng-bottlerocket instanceType: m5.large desiredCapacity: 4 amiFamily: Bottlerocket disableIMDSv1: true iam: attachPolicyARNs: - arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy - arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy - arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore bottlerocket: settings: motd: "Hello from eksctl!"

使用方法:复制一份,例如命名为my-eksctl.yaml,然后按需修改:

  • 节点数量:修改desiredCapacity(示例中为 4 个节点)。
  • Bottlerocket 设置bottlerocket.settings段可以预先写入任意 Bottlerocket settings(例如示例中的motd)。
  • AWS 区域:配置文件中包含 region 字段,若你不在us-west-2运行,请同步修改。

关于 eksctl 配置文件的完整 schema 与官方示例,可参考 eksctl 官方文档;eksctl create cluster会自动选择与集群 Kubernetes 版本匹配的 Bottlerocket AMI,无需手工指定。

版本提示:仓库示例文件中的 Kubernetesversion'1.24',而当前仓库支持的 EKS 变体为aws-k8s-1.31aws-k8s-1.37(详见下文"变体选择"一节),实际使用时建议将version更新为与你的集群规划一致的较新版本,并同步确认eksctl对该版本的支持情况。

创建集群

指向你修改好的配置文件,执行:

eksctl create cluster --config-file ./my-eksctl.yaml

该命令会花几分钟时间创建 EKS 集群并拉起 Bottlerocket 工作节点。

可选集群配置

CSI 插件(持久化存储)

如果需要在 Bottlerocket 主机上创建持久卷(Persistent Volume),必须使用 EBS CSI Plugin。原因是 EKS 默认的 EBS 驱动依赖的文件系统工具并未包含在 Bottlerocket 镜像中。AWS EKS 用户指南中有关于使用该驱动创建 StorageClass 的完整演练,可按官方文档操作。

conntrack 配置

默认情况下,kube-proxy会把nf_conntrack_max内核参数设置为一个可能与 Bottlerocket 启动时设定的默认值不同的值。如果你希望保留 Bottlerocket 的默认设置,可以编辑 kube-proxy-config 这个 ConfigMap:

kubectl edit -n kube-system cm/kube-proxy-config

conntrackmaxPerCoremin字段改为 0(0 表示不改变):

conntrack: maxPerCore: 0 min: 0 tcpCloseWaitTimeout: 1h0m0s tcpEstablishedTimeout: 24h0m0s

完成

Bottlerocket 实例会被放置在一个自动扩缩组(ASG)中,数量与你配置文件中指定的节点数一致(之后也可以通过 AWS 控制台按常规方式调整该 ASG 的大小)。实例会自动注册到eksctl创建的 EKS 集群中,之后你可以完全使用常规的 Kubernetes 工具(如kubectl)管理集群与 Bottlerocket 节点。例如运行一个简单的 busybox Pod:

kubectl run -i -t busybox --image=busybox --restart=Never

路径二:手动设置(完全掌控)

如果你需要eksctl目前尚不能提供的更高控制粒度,或想了解底层到底发生了什么,可以按下面的手动步骤操作。手动路径的完整信息收集流程包括:查询 AMI → 创建集群 → 生成集群信息 → 配置 IAM → 调整 kube-proxy → 最后启动实例。

查找 AMI

官方 AMI ID 存储在 AWS Systems Manager 公共参数(public SSM parameters) 中,参数名形如:

/aws/service/bottlerocket/aws-k8s-1.32/x86_64/latest/image_id

只需把其中的变体名(如aws-k8s-1.32)和架构x86_64)替换为你要使用的值。关于支持哪些变体与架构,见 README.md;对于 SSM 参数而言,合法的架构名为x86_64arm64(即aarch64)。如果知道具体版本(例如1.11.0),可以把参数名中的latest替换为版本号。

变体选择规则

结合仓库 README.md 与 variants 目录,当前仓库中支持 EKS 的变体包括:

  • 常规 K8s 变体:aws-k8s-1.31aws-k8s-1.32aws-k8s-1.33aws-k8s-1.34aws-k8s-1.35aws-k8s-1.36aws-k8s-1.37
  • NVIDIA 变体:上述各版本对应的aws-k8s-*-nvidia(变体名追加-nvidia后缀,例如aws-k8s-1.32-nvidia)。

文档中同时说明:所有 Bottlerocket EKS 变体(v1.30.0+)都支持 Neuron 实例类型。以 Kubernetes 1.28 为例,支持 Neuron 的变体即为aws-k8s-1.28(此处为文档示例;当前仓库中最低 K8s 变体为 1.31,旧版本已不再维护)。

以某个变体的 Cargo 清单为例,variants/aws-k8s-1.32/Cargo.toml 展示了该变体实际打包的内容,可帮助你理解"变体"在构建层面的含义——它决定了一组被包含的软件包(included-packages)、镜像特性(image-features)与内核启动参数:

[package.metadata.build-variant.image-features] grub-set-private-var = true uefi-secure-boot = true xfs-data-partition = true erofs-root-partition = true systemd-networkd = true [package.metadata.build-variant] included-packages = [ "release", "kernel-6.1", "whippet", "cni", "cni-plugins", "kubelet-1.32", "aws-iam-authenticator", "soci-snapshotter", ] kernel-parameters = [ "console=tty0", "console=ttyS0,115200n8", "net.ifnames=0", "netdog.default-interface=eth0:dhcp4,dhcp6?", "quiet", ]
直接使用 SSM 参数

拿到参数名后,最简单的用法是把它直接传给 EC2(同样适用于 CloudFormation 等代你启动 EC2 实例的服务)——只要在参数名前加resolve:ssm:前缀,EC2 就会替你获取当前值。例如:

resolve:ssm:/aws/service/bottlerocket/aws-k8s-1.32/x86_64/latest/image_id
手动查询 SSM

如果你希望自己获取 AMI ID,可以使用 aws-cli。以us-west-2区域查询上文示例参数为例:

aws ssm get-parameter --region us-west-2 --name "/aws/service/bottlerocket/aws-k8s-1.32/x86_64/latest/image_id" --query Parameter.Value --output text

如果安装了jq并且想要更多信息,可以同时查询 image_id 与 image_version:

aws ssm get-parameters --region us-west-2 \ --names "/aws/service/bottlerocket/aws-k8s-1.32/x86_64/latest/image_id" \ "/aws/service/bottlerocket/aws-k8s-1.32/x86_64/latest/image_version" \ --output json | jq -r '.Parameters | .[] | "\(.Name): \(.Value) (updated \(.LastModifiedDate | gmtime | strftime("%c")) UTC)"'

集群设置

注意:以下大多数命令都带 region 参数,如果你不想在us-west-2部署,请相应修改。另外,在GovCloud环境中操作时,IAM ARN 需要把arn:aws:iam改为arn:aws-us-gov:iam。例如arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy需改为arn:aws-us-gov:iam::aws:policy/AmazonEKSWorkerNodePolicy

创建集群:

eksctl create cluster --region us-west-2 --name bottlerocket

该命令会自动添加一个 "context",让kubectl知道如何与集群交互,并将其设为默认 context。你可以用kubectl config get-contexts查看所有 context(集群),用kubectl config use-context 'NEW-CONTEXT-HERE'切换当前 context。

集群信息收集

这一节帮助你确定后续实例启动命令所需的一些集群信息。

Kubernetes 集群信息

Bottlerocket 使用TOML 格式的配置文件作为 user data(用户数据),其中可以包含刚创建的 Kubernetes 集群配置。运行下面的命令生成包含 API endpoint 与 base64 编码的证书颁发机构(CA)的配置文件:

eksctl get cluster --region us-west-2 --name bottlerocket -o json \ | jq --raw-output '.[] | "[settings.kubernetes]\napi-server = \"" + .Endpoint + "\"\ncluster-certificate =\"" + .CertificateAuthority.Data + "\"\ncluster-name = \"bottlerocket\""' > user-data.toml

这会把 TOML 格式的配置数据保存到名为user-data.toml的文件中,供最后一步的实例启动命令使用。

生成的 TOML 内容实质是向settings.kubernetes写入集群接入信息。这一点与源码中 aws-k8s 变体的设置模型一致——sources/settings-plugins/aws-k8s/src/lib.rs 定义了该变体可配置的kubernetes设置结构,而 sources/settings-defaults/aws-k8s-1.32/defaults.d/50-kubernetes-aws.toml 则给出了该设置的默认值(例如cluster-domain = "cluster.local"authentication-mode = "aws"server-tls-bootstrap = truecloud-provider = "aws")。这说明手动流程写入的api-servercluster-certificatecluster-name会与变体自带的默认 Kubernetes 设置共同生效。

子网信息

接下来运行下面的命令获取eksctl创建的子网信息,它会列出各子网并标明是公网还是私网:

aws ec2 describe-subnets \ --subnet-ids $(eksctl get cluster --region us-west-2 --name bottlerocket -o json | jq --raw-output '.[].ResourcesVpcConfig.SubnetIds[]') \ --region us-west-2 \ --query "Subnets[].[SubnetId, Tags[?Key=='aws:cloudformation:logical-id'].Value]" \ | xargs -L2

选择一个子网,保存起来供最后的启动命令使用。选择公网还是私网:

  • 私网(private):适合生产部署,工作节点隔离性最好。
  • 公网(public):更适合调试实例。这些子网带 Internet Gateway,如果给实例加上公网 IP 就能直接访问它(之后也可以手动为私网子网添加 Internet Gateway,因此这个决定是可逆的)。

注意:如果使用公网子网,实例必须拥有可公开访问的 IP——要么在下面的启动命令中加--associate-public-ip-address,要么在启动后绑定一个弹性 IP(Elastic IP)。此外,如果希望在特定可用区(AZ)启动,请选择匹配的子网(AZ 就列在公网/私网状态旁边)。

IAM 角色

要启动的实例必须关联一个允许其与 EKS 和 ECR 通信的 IAM 角色。

eksctl默认已经在创建集群节点组(nodegroup)时创建了这样的角色(以及允许使用该角色的实例配置文件 instance profile)。

用以下命令获取 IAM 角色的 ARN:

eksctl get iamidentitymapping --region us-west-2 --cluster bottlerocket

输出应类似:

ARN USERNAME GROUPS arn:aws:iam::YOUR_AWS_ACCOUNT_ID:role/INSTANCE_ROLE_NAME system:node:{{EC2PrivateDNSName}} system:bootstrappers,system:nodes

记下其中的INSTANCE_ROLE_NAME供后续步骤使用。

启用 SSM

如果为角色添加 SSM 权限,就可以使用 Bottlerocket 默认的 SSM agent 在实例上获得 shell 会话。

为角色附加 SSM 权限的策略:

aws iam attach-role-policy \ --role-name INSTANCE_ROLE_NAME \ --policy-arn arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore

如果收到下面的错误,说明INSTANCE_ROLE_NAME需要截断到 64 个字符以内(仓库文档注明正在改进这一限制):

1 validation error detected: Value 'INSTANCE_ROLE_NAME' at 'role Name' failed to satisfy constraint: Member must have length less than or equal to 64

接下来,获取用于启动实例的实例配置文件名称:

aws iam list-instance-profiles-for-role --role-name INSTANCE_ROLE_NAME --query "InstanceProfiles[*].InstanceProfileName" --output text

应该只有一个,形如:

eksctl-bottlerocket-nodegroup-ng-IDENTIFIER-NodeInstanceProfile-IDENTIFIER

把它记为INSTANCE_PROFILE_NAME,用于最后的启动命令。

关联到源码层面,Bottlerocket 的 EKS 变体默认会在用户数据之外自动配置 host container(控制容器)与 SSM agent,参见 sources/settings-defaults/aws-k8s-1.32/defaults.d/20-aws-host-containers.toml:host-containers.control默认enabled = true(非 superpowered),而host-containers.admin默认enabled = false。也就是说,只要实例 IAM 角色带有 SSM 权限,即可直接通过 Session Manager 进入控制容器。

kube-proxy 设置

与自动化路径同理:默认情况下kube-proxy会把nf_conntrack_max内核参数设置为可能与 Bottlerocket 启动默认值不同的值。如果希望保留 Bottlerocket 的默认设置,可以编辑 kube-proxy 的 DaemonSet:

kubectl edit -n kube-system daemonset kube-proxy

在 kube-proxy 的参数中追加--conntrack-max-per-core--conntrack-min(设为 0 表示不改变):

containers: - command: - kube-proxy - --v=2 - --config=/var/lib/kube-proxy-config/config - --conntrack-max-per-core=0 - --conntrack-min=0

最终启动细节

为了让实例能与 EKS 集群控制平面及其它工作节点通信,需要确保实例以正确的安全组(security group)启动。

运行以下命令:

aws ec2 describe-security-groups --region us-west-2 \ --filters 'Name=tag:Name,Values=*bottlerocket*' \ --query "SecurityGroups[*].{Name:GroupName,ID:GroupId}"

输出会列出若干安全组名称与 ID,你需要保存其中...ClusterSharedNodeSecurityGroup......nodegroup...两项的 ID。示例输出:

[ { "Name": "eksctl-bottlerocket-cluster-ClusterSharedNodeSecurityGroup-IDENTIFIER", "ID": "SECURITY_GROUP_ID_1" }, { "Name": "eksctl-bottlerocket-cluster-ControlPlaneSecurityGroup-IDENTIFIER", "ID": *ignore* }, { "Name": "eksctl-bottlerocket-nodegroup-ng-IDENTIFIER-SG-IDENTIFIER", "ID": "SECURITY_GROUP_ID_2" } ]

如果选择了公网子网,并且计划 SSH 到实例(通过 admin container),还需要允许 SSH 流量进入安全组。执行类似下面的命令(替换上一步得到的某个安全组 ID,以及你的源网络 CIDR):

aws ec2 authorize-security-group-ingress --region us-west-2 \ --group-id SECURITY_GROUP_ID_1 --cidr YOUR_NETWORK_CIDR \ --protocol tcp --port 22

如果选择了私网子网并想 SSH 进入,可以从同一子网和同一安全组中的另一台实例进行。

Launch!(启动实例)

现在可以在集群中启动 Bottlerocket 实例了。启动命令中有几个值必须替换:

  • YOUR_KEY_NAME:你在 EC2 中注册的 SSH 密钥对名称;
  • SUBNET_ID:之前选择的子网——若选的是公网子网,请为命令添加--associate-public-ip-address,或在之后绑定弹性 IP;
  • SECURITY_GROUP_ID_1SECURITY_GROUP_ID_2:之前找到的两个安全组 ID;
  • BOTTLEROCKET_AMI_ID:你注册的 AMI ID,或 AWS 提供的 AMI ID(即通过 SSM 参数解析得到的值,如resolve:ssm:/aws/service/bottlerocket/aws-k8s-1.32/x86_64/latest/image_id);
  • user-data.toml:之前生成的用户数据文件路径;
  • INSTANCE_PROFILE_NAMEeksctl为集群节点组创建的实例配置文件名称。
aws ec2 run-instances --key-name YOUR_KEY_NAME \ --subnet-id SUBNET_ID \ --security-group-ids SECURITY_GROUP_ID_1 SECURITY_GROUP_ID_2 \ --image-id BOTTLEROCKET_AMI_ID \ --instance-type c7.large \ --region us-west-2 \ --tag-specifications 'ResourceType=instance,Tags=[{Key=kubernetes.io/cluster/bottlerocket,Value=owned}]' \ --user-data file://user-data.toml \ --iam-instance-profile Name=INSTANCE_PROFILE_NAME

再次提醒:如果使用公网子网,记得加--associate-public-ip-address或启动后绑定弹性 IP。

启动完成后,你就可以用常规的 Kubernetes 工作流在 Bottlerocket 实例上运行 Pod 了,例如:

kubectl run -i -t busybox --image=busybox --restart=Never
命令中的关键设计解读
  • --tag-specifications中的kubernetes.io/cluster/bottlerocket=owned标签让集群自动发现该节点并纳入管理;
  • --user-data file://user-data.toml对应 Bottlerocket 的"user data 即配置"机制:Bottlerocket 的 early-boot-config 组件会在启动时读取 TOML 格式的用户数据并将其发送给本地 API 服务(见 README.md 中关于 early-boot-config 的说明),从而在实例启动阶段就把settings.kubernetes等配置写入系统。

aws-k8s-*-nvidia 变体:启用 NVIDIA GPU

aws-k8s-*-nvidia变体打包了利用 NVIDIA GPU 所需的全部软件包与配置:自带 NVIDIA Tesla 驱动、NVIDIA 容器运行时 所需的库,以及 NVIDIA k8s device plugin。如果你的集群中已有 device plugin 的 DaemonSet,可能需要通过 taints 和 tolerations 避免它在 Bottlerocket 节点上重复运行。

其他 NVIDIA 工具,如 DCGM exporter 和 GPU Feature Discovery,均可正常工作,可按各项目提供的helm install说明安装。GPU Operator 也可用于安装这些工具,但要选出合适的特性子集以避免与变体内置软件冲突比较繁琐,因此文档建议在需要时逐个单独安装这些工具。

在具有多 GPU 的主机(如 EC2g4dn实例)上,可以在容器 spec 中通过资源声明按 GPU 分配(详见 Kubernetes 官方文档):

apiVersion: v1 kind: Pod metadata: name: test spec: restartPolicy: OnFailure containers: - name: test image: amazonlinux:2 resources: limits: nvidia.com/gpu: 1 # requesting 1 GPU

Neuron 支持:为推理工作负载配置设备

Bottlerocketv1.30.0+支持 Neuron 实例类型,例如inf1inf2trn1trn2。要启用 Neuron 工作负载,需要在用户数据(user data)中添加如下配置:

[settings] [settings.kubernetes] device-ownership-from-security-context = true

该设置允许容器根据 Pod spec 中提供的runAsUserrunAsGroup值获得所挂载 Neuron 设备的所有权(详细原理参见 Kubernetes 关于非 root 容器与设备的官方说明)。配合该设置部署一个请求 Neuron 设备的 Pod 示例:

apiVersion: v1 kind: Pod metadata: name: test spec: hostNetwork: true securityContext: runAsUser: 1001 runAsGroup: 2001 fsGroup: 3001 restartPolicy: OnFailure containers: - name: test image: amazonlinux:2023 resources: limits: aws.amazon.com/neuron: "1"

除了device-ownership-from-security-context设置外,还需要部署 neuron-device-plugin,可选部署 neuron-scheduler。仓库的 README.md 也确认了这些变体包含利用 Neuron 加速实例所需的包与配置。

总结

无论选择哪种路径,接入流程的核心都围绕三条主线展开:选择正确的变体(普通 /-nvidia,匹配 Kubernetes 版本与架构)、提供集群接入信息(通过 eksctl 配置文件或手动生成的 TOML user data 写入settings.kubernetes)、保证实例具备正确的 IAM 角色与安全组。自动化路径下,eksctl会替你完成 AMI 选择、节点组、IAM 角色与安全组的全套配置;手动路径则把这些步骤逐一暴露出来,适合需要精细控制的场景。启动完成后,Bottlerocket 节点会自动注册进集群,你可以完全使用标准的 Kubernetes 工作流在其上运行容器负载。

  • 操作系统
  • 云原生
  • 安全

【免费下载链接】bottlerocket

An operating system designed for hosting containers

项目地址:https://gitcode.com/gh_mirrors/bo/bottlerocket
点击查看免费下载

相关推荐

上一篇:深度解析Batocera.linux构建系统:从模块化架构到多平台游戏发行版
下一篇:TaskBoard:简洁高效的任务管理工具

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询