Skip to content

Commit 88a1dc5

Browse files
authored
Add support for custom Bottlerocket AMIs for MNG (#8418)
1 parent f2e8f0f commit 88a1dc5

File tree

6 files changed

+58
-72
lines changed

6 files changed

+58
-72
lines changed

pkg/apis/eksctl.io/v1alpha5/managed_nodegroup_test.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@ var _ = Describe("Managed Nodegroup Validation", func() {
8484
AMIFamily: "Bottlerocket",
8585
},
8686
},
87-
errMsg: "cannot set amiFamily to Bottlerocket when using a custom AMI",
8887
}),
8988
Entry("Custom AMI with overrideBootstrapCommand", &nodeGroupCase{
9089
ng: &ManagedNodeGroup{

pkg/apis/eksctl.io/v1alpha5/validation.go

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66
"net"
77
"regexp"
8+
"slices"
89
"strconv"
910
"strings"
1011

@@ -69,8 +70,9 @@ var (
6970
)
7071

7172
var (
72-
SupportedAmazonLinuxImages = supportedAMIFamiliesForOS(IsAmazonLinuxImage)
73-
SupportedUbuntuImages = supportedAMIFamiliesForOS(IsUbuntuImage)
73+
SupportedAmazonLinuxImages = supportedAMIFamiliesForOS(IsAmazonLinuxImage)
74+
SupportedBottlerocketImages = supportedAMIFamiliesForOS(IsBottlerocketImage)
75+
SupportedUbuntuImages = supportedAMIFamiliesForOS(IsUbuntuImage)
7476
)
7577

7678
// NOTE: we don't use k8s.io/apimachinery/pkg/util/sets here to keep API package free of dependencies
@@ -1391,11 +1393,11 @@ func ValidateManagedNodeGroup(index int, ng *ManagedNodeGroup) error {
13911393
if ng.AMIFamily == "" {
13921394
return errors.New("when using a custom AMI, amiFamily needs to be explicitly set via config file or via --node-ami-family flag")
13931395
}
1394-
if !IsAmazonLinuxImage(ng.AMIFamily) && !IsUbuntuImage(ng.AMIFamily) {
1396+
if !IsAmazonLinuxImage(ng.AMIFamily) && !IsBottlerocketImage(ng.AMIFamily) && !IsUbuntuImage(ng.AMIFamily) {
13951397
return fmt.Errorf("cannot set amiFamily to %s when using a custom AMI for managed nodes, only %s are supported", ng.AMIFamily,
1396-
strings.Join(append(SupportedAmazonLinuxImages, SupportedUbuntuImages...), ", "))
1398+
strings.Join(slices.Concat(SupportedAmazonLinuxImages, SupportedBottlerocketImages, SupportedUbuntuImages), ", "))
13971399
}
1398-
if ng.OverrideBootstrapCommand == nil && ng.AMIFamily != NodeImageFamilyAmazonLinux2023 {
1400+
if ng.OverrideBootstrapCommand == nil && ng.AMIFamily != NodeImageFamilyAmazonLinux2023 && ng.AMIFamily != NodeImageFamilyBottlerocket {
13991401
return fmt.Errorf("%[1]s.overrideBootstrapCommand is required when using a custom AMI based on %s (%[1]s.ami)", path, ng.AMIFamily)
14001402
}
14011403
notSupportedWithCustomAMIErr := func(field string) error {
@@ -1618,6 +1620,16 @@ func IsAmazonLinuxImage(imageFamily string) bool {
16181620
}
16191621
}
16201622

1623+
func IsBottlerocketImage(imageFamily string) bool {
1624+
switch imageFamily {
1625+
case NodeImageFamilyBottlerocket:
1626+
return true
1627+
1628+
default:
1629+
return false
1630+
}
1631+
}
1632+
16211633
func IsUbuntuImage(imageFamily string) bool {
16221634
switch imageFamily {
16231635
case NodeImageFamilyUbuntuPro2404,

pkg/apis/eksctl.io/v1alpha5/validation_test.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2281,9 +2281,7 @@ var _ = Describe("ClusterConfig validation", func() {
22812281
mng.AMIFamily = api.NodeImageFamilyBottlerocket
22822282
mng.OverrideBootstrapCommand = nil
22832283
err = api.ValidateManagedNodeGroup(0, mng)
2284-
errorMsg := fmt.Sprintf("cannot set amiFamily to %s when using a custom AMI for managed nodes, only %s are supported", mng.AMIFamily,
2285-
strings.Join(append(api.SupportedAmazonLinuxImages, api.SupportedUbuntuImages...), ", "))
2286-
Expect(err).To(MatchError(errorMsg))
2284+
Expect(err).NotTo(HaveOccurred())
22872285

22882286
mng.AMIFamily = api.NodeImageFamilyAmazonLinux2023
22892287
err = api.ValidateManagedNodeGroup(0, mng)

pkg/nodebootstrap/managed_bottlerocket.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package nodebootstrap
22

33
import (
44
"encoding/base64"
5-
"errors"
65
"fmt"
76

87
toml "github.com/pelletier/go-toml"
@@ -47,12 +46,13 @@ func (b *ManagedBottlerocket) UserData() (string, error) {
4746
settings.Set(adminContainerEnabledKey, *enableAdminContainer)
4847
}
4948

50-
userData := settings.String()
51-
if userData == "" {
52-
return "", errors.New("generated unexpected empty TOML user-data from input")
49+
// Generate TOML for launch in this NodeGroup.
50+
data, err := bottlerocketSettingsTOML(b.clusterConfig, b.ng.NodeGroupBase, settings)
51+
if err != nil {
52+
return "", err
5353
}
5454

55-
return base64.StdEncoding.EncodeToString([]byte(userData)), nil
55+
return base64.StdEncoding.EncodeToString([]byte(data)), nil
5656
}
5757

5858
// setDerivedSettings configures settings that are derived from top-level nodegroup config

pkg/nodebootstrap/managed_bottlerocket_test.go

Lines changed: 34 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55

66
. "github.com/onsi/ginkgo/v2"
77
. "github.com/onsi/gomega"
8+
toml "github.com/pelletier/go-toml"
89

910
api "github.com/weaveworks/eksctl/pkg/apis/eksctl.io/v1alpha5"
1011
"github.com/weaveworks/eksctl/pkg/nodebootstrap"
@@ -15,8 +16,8 @@ var _ = Describe("Managed Bottlerocket", func() {
1516
type bottlerocketEntry struct {
1617
setFields func(group *api.ManagedNodeGroup)
1718

18-
expectedErr string
19-
expectedUserData string
19+
expectedErr string
20+
verifyUserData func(tree *toml.Tree)
2021
}
2122

2223
DescribeTable("User data", func(e bottlerocketEntry) {
@@ -47,41 +48,37 @@ var _ = Describe("Managed Bottlerocket", func() {
4748
Expect(err).NotTo(HaveOccurred())
4849
actual, err := base64.StdEncoding.DecodeString(userData)
4950
Expect(err).NotTo(HaveOccurred())
50-
Expect(string(actual)).To(Equal(e.expectedUserData))
51+
52+
tree, err := toml.LoadBytes(actual)
53+
Expect(err).NotTo(HaveOccurred())
54+
if e.verifyUserData != nil {
55+
e.verifyUserData(tree)
56+
}
5157
},
5258
Entry("no settings", bottlerocketEntry{
53-
expectedUserData: `
54-
[settings]
55-
56-
[settings.kubernetes]
57-
`,
59+
verifyUserData: func(tree *toml.Tree) {
60+
// Default kubernetes settings include api-server, cluster-certificate, and cluster-name
61+
Expect(tree.HasPath([]string{"settings", "kubernetes", "api-server"})).To(BeTrue())
62+
Expect(tree.HasPath([]string{"settings", "kubernetes", "cluster-certificate"})).To(BeTrue())
63+
Expect(tree.HasPath([]string{"settings", "kubernetes", "cluster-name"})).To(BeTrue())
64+
},
5865
}),
5966
Entry("maxPods set", bottlerocketEntry{
6067
setFields: func(ng *api.ManagedNodeGroup) {
6168
ng.MaxPodsPerNode = 44
6269
},
63-
expectedUserData: `
64-
[settings]
65-
66-
[settings.kubernetes]
67-
max-pods = 44
68-
`,
70+
verifyUserData: func(tree *toml.Tree) {
71+
Expect(tree.GetPath([]string{"settings", "kubernetes", "max-pods"})).To(Equal(int64(44)))
72+
},
6973
}),
7074

7175
Entry("enableAdminContainer set", bottlerocketEntry{
7276
setFields: func(ng *api.ManagedNodeGroup) {
7377
ng.Bottlerocket.EnableAdminContainer = api.Enabled()
7478
},
75-
expectedUserData: `
76-
[settings]
77-
78-
[settings.host-containers]
79-
80-
[settings.host-containers.admin]
81-
enabled = true
82-
83-
[settings.kubernetes]
84-
`,
79+
verifyUserData: func(tree *toml.Tree) {
80+
Expect(tree.GetPath([]string{"settings", "host-containers", "admin", "enabled"})).To(BeTrue())
81+
},
8582
}),
8683

8784
Entry("host containers enabled", bottlerocketEntry{
@@ -94,16 +91,9 @@ var _ = Describe("Managed Bottlerocket", func() {
9491
},
9592
}
9693
},
97-
expectedUserData: `
98-
[settings]
99-
100-
[settings.host-containers]
101-
102-
[settings.host-containers.example]
103-
enabled = true
104-
105-
[settings.kubernetes]
106-
`,
94+
verifyUserData: func(tree *toml.Tree) {
95+
Expect(tree.GetPath([]string{"settings", "host-containers", "example", "enabled"})).To(BeTrue())
96+
},
10797
}),
10898

10999
Entry("retain user-specified admin container setting", bottlerocketEntry{
@@ -116,16 +106,9 @@ var _ = Describe("Managed Bottlerocket", func() {
116106
},
117107
}
118108
},
119-
expectedUserData: `
120-
[settings]
121-
122-
[settings.host-containers]
123-
124-
[settings.host-containers.admin]
125-
enabled = true
126-
127-
[settings.kubernetes]
128-
`,
109+
verifyUserData: func(tree *toml.Tree) {
110+
Expect(tree.GetPath([]string{"settings", "host-containers", "admin", "enabled"})).To(BeTrue())
111+
},
129112
}),
130113

131114
Entry("labels and taints set", bottlerocketEntry{
@@ -141,12 +124,10 @@ var _ = Describe("Managed Bottlerocket", func() {
141124
},
142125
}
143126
},
144-
145-
expectedUserData: `
146-
[settings]
147-
148-
[settings.kubernetes]
149-
`,
127+
verifyUserData: func(tree *toml.Tree) {
128+
Expect(tree.HasPath([]string{"settings", "kubernetes", "node-labels"})).To(BeFalse())
129+
Expect(tree.HasPath([]string{"settings", "kubernetes", "node-taints"})).To(BeFalse())
130+
},
150131
}),
151132

152133
Entry("preserve dotted keys", bottlerocketEntry{
@@ -155,13 +136,9 @@ var _ = Describe("Managed Bottlerocket", func() {
155136
"a.b.c": "value",
156137
}
157138
},
158-
159-
expectedUserData: `
160-
[settings]
161-
"a.b.c" = "value"
162-
163-
[settings.kubernetes]
164-
`,
139+
verifyUserData: func(tree *toml.Tree) {
140+
Expect(tree.GetPath([]string{"settings", "a.b.c"})).To(Equal("value"))
141+
},
165142
}),
166143

167144
Entry("cluster bootstrap settings set", bottlerocketEntry{

userdocs/src/usage/custom-ami-support.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ managedNodeGroups:
8989
The `--node-ami-family` flag can also be used with `eksctl create nodegroup`. `eksctl` requires AMI Family to be explicitly set via config file or via `--node-ami-family` CLI flag, whenever working with a custom AMI.
9090

9191
???+ note
92-
At the moment, EKS managed nodegroups only support the following AMI Families when working with custom AMIs: `AmazonLinux2023`, `AmazonLinux2`, `Ubuntu2004`, `Ubuntu2204` and `Ubuntu2404`
92+
At the moment, EKS managed nodegroups only support the following AMI Families when working with custom AMIs: `AmazonLinux2023`, `AmazonLinux2`, `Bottlerocket`, `Ubuntu2004`, `Ubuntu2204` and `Ubuntu2404`
9393

9494
## Windows custom AMI support
9595
Only self-managed Windows nodegroups can specify a custom AMI. `amiFamily` should be set to a valid Windows AMI family.

0 commit comments

Comments
 (0)