Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Ubuntu AMIs #288

Merged
merged 1 commit into from
Oct 29, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ not unsecure in principle, yet some compromised workload can risk access violati

If that functionality doesn't suite you, the following options are currently available.

#### chage VPC CIDR
#### change VPC CIDR

If you need to setup peering with another VPC, or simply need larger or smaller range of IPs, you can use `--vpc-cidr` flag to
change it. You cannot use just any sort of CIDR, there only certain ranges that can be used in [AWS VPC](vpcsizing).
Expand Down Expand Up @@ -230,7 +230,7 @@ kubectl create -f https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v1.

### Latest & Custom AMI Support

With the the 0.1.2 release we have introduced the `--node-ami` flag for use when creating a cluster. This enables a number of advanced use cases such as using a custom AMI or querying AWS in realtime to determine which AMI to use (non-GPU and GPU instances).
With the 0.1.2 release we have introduced the `--node-ami` flag for use when creating a cluster. This enables a number of advanced use cases such as using a custom AMI or querying AWS in realtime to determine which AMI to use (non-GPU and GPU instances).

The `--node-ami` can take the AMI image id for an image to explicitly use. It also can take the following 'special' keywords:

Expand All @@ -245,6 +245,15 @@ If, for example, AWS release a new version of the EKS node AMIs and a new versio
eksctl create cluster --node-ami=auto
```

With the 0.1.9 release we have introduced the `--node-ami-family` flag for use when creating the cluster. This makes it possible to choose between different offically supported EKS AMI families.

The `--node-ami-family` can take following keywords:

| Keyword | Description |
| --- | --- |
| AmazonLinux2 | Indicates that the EKS AMI image based on Amazon Linux 2 should be used. (default)|
| Ubuntu1804 | Indicates that the EKS AMI image based on Ubuntu 18.04 should be used. |

<!-- TODO for 0.3.0
To use more advanced configuration options, [Cluster API](https://github.com/kubernetes-sigs/cluster-api):

Expand Down
5 changes: 4 additions & 1 deletion pkg/ami/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ const (
DefaultImageFamily = ImageFamilyAmazonLinux2

// ImageFamilyAmazonLinux2 represents Amazon Linux 2 family
ImageFamilyAmazonLinux2 = "AmazonLinux2"
ImageFamilyAmazonLinux2 = "AmazonLinux2" // Owner 602401143452

// ImageFamilyUbuntu1804 represents Ubuntu 18.04 family
ImageFamilyUbuntu1804 = "Ubuntu1804" // Owner 099720109477

// ResolverStatic is used to indicate that the static (i.e. compiled into eksctl) AMIs should be used
ResolverStatic = "static"
Expand Down
16 changes: 9 additions & 7 deletions pkg/ami/auto_resolver.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package ami

import (
"fmt"

"github.com/aws/aws-sdk-go/service/ec2/ec2iface"
"github.com/kubicorn/kubicorn/pkg/logger"
"github.com/pkg/errors"
Expand All @@ -16,6 +14,9 @@ var ImageSearchPatterns = map[string]map[int]string{
ImageClassGeneral: "amazon-eks-node-*",
ImageClassGPU: "amazon-eks-gpu-node-*",
},
ImageFamilyUbuntu1804: {
ImageClassGeneral: "ubuntu-eks/1.10.3/*",
},
}

// AutoResolver resolves the AMi to the defaults for the region
Expand All @@ -26,15 +27,16 @@ type AutoResolver struct {

// Resolve will return an AMI to use based on the default AMI for
// each region
func (r *AutoResolver) Resolve(region string, instanceType string) (string, error) {
logger.Debug("resolving AMI using AutoResolver for region %s and instanceType %s", region, instanceType)
func (r *AutoResolver) Resolve(region string, instanceType string, imageFamily string) (string, error) {
logger.Debug("resolving AMI using AutoResolver for region %s, instanceType %s and imageFamily %s", region, instanceType, imageFamily)

p := ImageSearchPatterns[DefaultImageFamily][ImageClassGeneral]
p := ImageSearchPatterns[imageFamily][ImageClassGeneral]
if utils.IsGPUInstanceType(instanceType) {
var ok bool
p, ok = ImageSearchPatterns[DefaultImageFamily][ImageClassGPU]
p, ok = ImageSearchPatterns[imageFamily][ImageClassGPU]
if !ok {
return "", fmt.Errorf("image family %s doesn't support GPU image class", DefaultImageFamily)
logger.Critical("image family %s doesn't support GPU image class", imageFamily)
return "", NewErrFailedResolution(region, instanceType, imageFamily)
}
}

Expand Down
10 changes: 6 additions & 4 deletions pkg/ami/auto_resolver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ var _ = Describe("AMI Auto Resolution", func() {
err error
region string
instanceType string
imageFamily string
resolvedAmi string
expectedAmi string
imageState string
Expand All @@ -41,6 +42,7 @@ var _ = Describe("AMI Auto Resolution", func() {
Context("and non-gpu instance type", func() {
BeforeEach(func() {
instanceType = "t2.medium"
imageFamily = "AmazonLinux2"
})

Context("and ami is available", func() {
Expand All @@ -51,7 +53,7 @@ var _ = Describe("AMI Auto Resolution", func() {
addMockDescribeImages(p, "amazon-eks-node-*", expectedAmi, imageState, "2018-08-20T23:25:53.000Z")

resolver := NewAutoResolver(p.MockEC2())
resolvedAmi, err = resolver.Resolve(region, instanceType)
resolvedAmi, err = resolver.Resolve(region, instanceType, imageFamily)
})

It("should not error", func() {
Expand All @@ -75,7 +77,7 @@ var _ = Describe("AMI Auto Resolution", func() {
addMockDescribeImagesMultiple(p, "amazon-eks-node-*", []returnAmi{})

resolver := NewAutoResolver(p.MockEC2())
resolvedAmi, err = resolver.Resolve(region, instanceType)
resolvedAmi, err = resolver.Resolve(region, instanceType, imageFamily)
})

It("should not error", func() {
Expand Down Expand Up @@ -113,7 +115,7 @@ var _ = Describe("AMI Auto Resolution", func() {
addMockDescribeImagesMultiple(p, "amazon-eks-node-*", images)

resolver := NewAutoResolver(p.MockEC2())
resolvedAmi, err = resolver.Resolve(region, instanceType)
resolvedAmi, err = resolver.Resolve(region, instanceType, imageFamily)
})

It("should not error", func() {
Expand Down Expand Up @@ -143,7 +145,7 @@ var _ = Describe("AMI Auto Resolution", func() {
addMockDescribeImages(p, "amazon-eks-gpu-node-*", expectedAmi, imageState, "2018-08-20T23:25:53.000Z")

resolver := NewAutoResolver(p.MockEC2())
resolvedAmi, err = resolver.Resolve(region, instanceType)
resolvedAmi, err = resolver.Resolve(region, instanceType, imageFamily)
})

It("should not error", func() {
Expand Down
10 changes: 6 additions & 4 deletions pkg/ami/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,26 @@ import (
)

// ErrFailedResolution is an error type that represents
// failure to resolve a region/instance type to an AMI
// failure to resolve a region/instance type/image family to an AMI
type ErrFailedResolution struct {
region string
instanceType string
imageFamily string
}

// NewErrFailedResolution creates a new instance of ErrFailedResolution for a
// give region and instance type
func NewErrFailedResolution(region string, instanceType string) *ErrFailedResolution {
// give region, instance type and image family
func NewErrFailedResolution(region string, instanceType string, imageFamily string) *ErrFailedResolution {
return &ErrFailedResolution{
region: region,
instanceType: instanceType,
imageFamily: imageFamily,
}
}

// Error return the error message
func (e *ErrFailedResolution) Error() string {
return fmt.Sprintf("Unable to determine AMI for region %s and instance type %s", e.region, e.instanceType)
return fmt.Sprintf("Unable to determine AMI for region %s, instance type %s and image family %s", e.region, e.instanceType, e.imageFamily)
}

// ErrNotFound is an error type that represents
Expand Down
14 changes: 6 additions & 8 deletions pkg/ami/resolver.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package ami

import "github.com/pkg/errors"

var (
// DefaultResolvers contains a list of resolvers to try in order
DefaultResolvers = []Resolver{&StaticGPUResolver{}, &StaticDefaultResolver{}}
Expand All @@ -10,22 +8,22 @@ var (
// Resolve will resolve an AMI from the supplied region
// and instance type. It will invoke a specific resolver
// to do the actual determining of AMI.
func Resolve(region string, instanceType string) (string, error) {
func Resolve(region string, instanceType string, imageFamily string) (string, error) {
for _, resolver := range DefaultResolvers {
ami, err := resolver.Resolve(region, instanceType)
ami, err := resolver.Resolve(region, instanceType, imageFamily)
if err != nil {
return "", errors.Wrap(err, "error whilst resolving AMI")
return "", err
}
if ami != "" {
return ami, nil
}
}

return "", NewErrFailedResolution(region, instanceType)
return "", NewErrFailedResolution(region, instanceType, imageFamily)
}

// Resolver provides an interface to enable implementing multiple
// ways to determine which AMI to use from the region/instance type.
// ways to determine which AMI to use from the region/instance type/image family.
type Resolver interface {
Resolve(region string, instanceType string) (string, error)
Resolve(region string, instanceType string, imageFamily string) (string, error)
}
22 changes: 11 additions & 11 deletions pkg/ami/static_resolver.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package ami

import (
"fmt"

"github.com/kubicorn/kubicorn/pkg/logger"
"github.com/weaveworks/eksctl/pkg/utils"
)
Expand All @@ -15,10 +13,10 @@ type StaticDefaultResolver struct {

// Resolve will return an AMI to use based on the default AMI for each region
// currently source of truth for these is here
func (r *StaticDefaultResolver) Resolve(region string, instanceType string) (string, error) {
logger.Debug("resolving AMI using StaticDefaultResolver for region %s and instanceType %s", region, instanceType)
func (r *StaticDefaultResolver) Resolve(region string, instanceType string, imageFamily string) (string, error) {
logger.Debug("resolving AMI using StaticDefaultResolver for region %s, instanceType %s and imageFamily %s", region, instanceType, imageFamily)

regionalAMIs := StaticImages[DefaultImageFamily][ImageClassGeneral]
regionalAMIs := StaticImages[imageFamily][ImageClassGeneral]
return regionalAMIs[region], nil
}

Expand All @@ -27,17 +25,19 @@ type StaticGPUResolver struct {
}

// Resolve will return an AMI based on the region for GPU instance types
func (r *StaticGPUResolver) Resolve(region string, instanceType string) (string, error) {
logger.Debug("resolving AMI using StaticGPUResolver for region %s and instanceType %s", region, instanceType)
func (r *StaticGPUResolver) Resolve(region string, instanceType string, imageFamily string) (string, error) {
logger.Debug("resolving AMI using StaticGPUResolver for region %s, instanceType %s and imageFamily %s", region, instanceType, imageFamily)

regionalAMIs, ok := StaticImages[DefaultImageFamily][ImageClassGPU]
if !ok {
return "", fmt.Errorf("image family %s doesn't support GPU image class", DefaultImageFamily)
}
if !utils.IsGPUInstanceType(instanceType) {
logger.Debug("can't resolve AMI using StaticGPUResolver as instance type %s is non-GPU", instanceType)
return "", nil
}

regionalAMIs, ok := StaticImages[imageFamily][ImageClassGPU]
if !ok {
logger.Critical("image family %s doesn't support GPU image class", imageFamily)
return "", NewErrFailedResolution(region, instanceType, imageFamily)
}

return regionalAMIs[region], nil
}
32 changes: 18 additions & 14 deletions pkg/ami/static_resolver_ami.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,22 @@ package ami
// This file was generated by static_resolver_ami_generate.go; DO NOT EDIT.

// StaticImages is a map that holds the list of AMIs to be used by for static resolution
var StaticImages = map[string]map[int]map[string]string{"AmazonLinux2": {

ImageClassGPU: {

"eu-west-1": "ami-0706dc8a5eed2eed9",
"us-east-1": "ami-058bfb8c236caae89",
"us-west-2": "ami-0731694d53ef9604b",
},
ImageClassGeneral: {

"eu-west-1": "ami-0c7a4976cb6fafd3a",
"us-east-1": "ami-0440e4f6b9713faf6",
"us-west-2": "ami-0a54c984b9f908c81",
var StaticImages = map[string]map[int]map[string]string{
"AmazonLinux2": {
ImageClassGPU: {
"eu-west-1": "ami-0706dc8a5eed2eed9",
"us-east-1": "ami-058bfb8c236caae89",
"us-west-2": "ami-0731694d53ef9604b",
},
ImageClassGeneral: {
"eu-west-1": "ami-0c7a4976cb6fafd3a",
"us-east-1": "ami-0440e4f6b9713faf6",
"us-west-2": "ami-0a54c984b9f908c81",
},
},
}}
"Ubuntu1804": {ImageClassGeneral: {
"eu-west-1": "ami-07036622490f7e97b",
"us-east-1": "ami-06fd8200ac0eb656d",
"us-west-2": "ami-6322011b",
}},
}
4 changes: 2 additions & 2 deletions pkg/ami/static_resolver_ami_generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ func main() {
}
classImages[Lit(region)] = Lit(image)
}
familyImages[Id(ami.ImageClasses[class])] = Block(classImages)
familyImages[Id(ami.ImageClasses[class])] = Values(classImages)
}
d[Lit(family)] = Block(familyImages)
d[Lit(family)] = Values(familyImages)
}

f.Comment("StaticImages is a map that holds the list of AMIs to be used by for static resolution")
Expand Down
Loading