Skip to content

Commit

Permalink
Add example of bottlerocket node groups
Browse files Browse the repository at this point in the history
Prior to this change, the examples only showed how to use bottlerocket
with the older worker_nodes configuration.

This change demonstrates the use of node_groups to create a bottlerocket
based cluster.
  • Loading branch information
scalen committed Oct 20, 2021
1 parent 259c997 commit 35948f9
Show file tree
Hide file tree
Showing 6 changed files with 299 additions and 0 deletions.
75 changes: 75 additions & 0 deletions examples/managed_bottlerocket_node_group/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# AWS EKS cluster running Bottlerocket AMI

Configuration in this directory creates EKS cluster with nodes group running [AWS Bottlerocket OS](https://github.com/bottlerocket-os/bottlerocket)

This is a minimalistic example which shows what knobs to turn to make Bottlerocket work.

See [the official documentation](https://docs.aws.amazon.com/eks/latest/userguide/eks-optimized-ami-bottlerocket.html) for more details.

## Usage

To run this example you need to execute:

```bash
$ terraform init
$ terraform plan
$ terraform apply
```

Note that this example may create resources which cost money. Run `terraform destroy` when you don't need these resources.

<!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 0.13.1 |
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 3.56.0 |
| <a name="requirement_kubernetes"></a> [kubernetes](#requirement\_kubernetes) | ~> 2.0 |
| <a name="requirement_local"></a> [local](#requirement\_local) | >= 1.4 |
| <a name="requirement_random"></a> [random](#requirement\_random) | >= 2.1 |
| <a name="requirement_tls"></a> [tls](#requirement\_tls) | >= 2.0 |

## Providers

| Name | Version |
|------|---------|
| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 3.56.0 |
| <a name="provider_random"></a> [random](#provider\_random) | >= 2.1 |
| <a name="provider_tls"></a> [tls](#provider\_tls) | >= 2.0 |

## Modules

| Name | Source | Version |
|------|--------|---------|
| <a name="module_eks"></a> [eks](#module\_eks) | ../.. | |
| <a name="module_vpc"></a> [vpc](#module\_vpc) | terraform-aws-modules/vpc/aws | ~> 3.0 |

## Resources

| Name | Type |
|------|------|
| [aws_iam_role_policy_attachment.ssm](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
| [aws_key_pair.nodes](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/key_pair) | resource |
| [random_string.suffix](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/string) | resource |
| [tls_private_key.nodes](https://registry.terraform.io/providers/hashicorp/tls/latest/docs/resources/private_key) | resource |
| [aws_ami.bottlerocket_ami](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ami) | data source |
| [aws_availability_zones.available](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/availability_zones) | data source |
| [aws_eks_cluster.cluster](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/eks_cluster) | data source |
| [aws_eks_cluster_auth.cluster](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/eks_cluster_auth) | data source |
| [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source |

## Inputs

No inputs.

## Outputs

| Name | Description |
|------|-------------|
| <a name="output_cluster_endpoint"></a> [cluster\_endpoint](#output\_cluster\_endpoint) | Endpoint for EKS control plane. |
| <a name="output_cluster_security_group_id"></a> [cluster\_security\_group\_id](#output\_cluster\_security\_group\_id) | Security group ids attached to the cluster control plane. |
| <a name="output_config_map_aws_auth"></a> [config\_map\_aws\_auth](#output\_config\_map\_aws\_auth) | A kubernetes configuration to authenticate to this EKS cluster. |
| <a name="output_kubectl_config"></a> [kubectl\_config](#output\_kubectl\_config) | kubectl config as generated by the module. |
| <a name="output_node_groups"></a> [node\_groups](#output\_node\_groups) | Outputs from node groups |
<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
159 changes: 159 additions & 0 deletions examples/managed_bottlerocket_node_group/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
provider "aws" {
region = local.region
}

locals {
name = "bottlerocket-${random_string.suffix.result}"
cluster_version = "1.20"
region = "eu-west-1"
}

################################################################################
# EKS Module
################################################################################

module "eks" {
source = "../.."

cluster_name = local.name
cluster_version = local.cluster_version

vpc_id = module.vpc.vpc_id
subnets = [module.vpc.private_subnets[0], module.vpc.public_subnets[1]]
fargate_subnets = [module.vpc.private_subnets[2]]

cluster_endpoint_private_access = true
cluster_endpoint_public_access = true

write_kubeconfig = false
manage_aws_auth = true

node_groups = {
bottlerocket = {
name = "bottlerocket-nodes"
ami_id = data.aws_ami.bottlerocket_ami.id
instance_types = ["t3a.small"]
desired_capacity = 2
key_name = aws_key_pair.nodes.key_name

# Since we are using default VPC there is no NAT gateway so we need to
# attach public ip to nodes so they can reach k8s API server
# do not repeat this at home (i.e. production)
public_ip = true

# This section overrides default userdata template to pass bottlerocket
# specific user data and pass additional arguments for userdata template rendering
user_data = {
template_file = "${path.module}/userdata.toml"
template_extra_args = {
enable_admin_container = false
enable_control_container = true
aws_region = data.aws_region.current.name
}
}
# example of k8s/kubelet configuration via additional_userdata
pre_userdata = <<EOT
[settings.kubernetes.node-labels]
ingress = "allowed"
EOT
}
}

tags = {
Example = local.name
GithubRepo = "terraform-aws-eks"
GithubOrg = "terraform-aws-modules"
}
}

# SSM policy for bottlerocket control container access
# https://github.com/bottlerocket-os/bottlerocket/blob/develop/QUICKSTART-EKS.md#enabling-ssm
resource "aws_iam_role_policy_attachment" "ssm" {
role = module.eks.worker_iam_role_name
policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
}

################################################################################
# Kubernetes provider configuration
################################################################################

data "aws_eks_cluster" "cluster" {
name = module.eks.cluster_id
}

data "aws_eks_cluster_auth" "cluster" {
name = module.eks.cluster_id
}

provider "kubernetes" {
host = data.aws_eks_cluster.cluster.endpoint
cluster_ca_certificate = base64decode(data.aws_eks_cluster.cluster.certificate_authority[0].data)
token = data.aws_eks_cluster_auth.cluster.token
}

################################################################################
# Supporting Resources
################################################################################

data "aws_region" "current" {}

data "aws_ami" "bottlerocket_ami" {
most_recent = true
owners = ["amazon"]

filter {
name = "name"
values = ["bottlerocket-aws-k8s-${local.cluster_version}-x86_64-*"]
}
}

resource "tls_private_key" "nodes" {
algorithm = "RSA"
}

resource "aws_key_pair" "nodes" {
key_name = "bottlerocket-nodes-${random_string.suffix.result}"
public_key = tls_private_key.nodes.public_key_openssh
}

################################################################################
# Supporting Resources
################################################################################

data "aws_availability_zones" "available" {
}

resource "random_string" "suffix" {
length = 8
special = false
}

module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "~> 3.0"

name = local.name
cidr = "10.0.0.0/16"
azs = data.aws_availability_zones.available.names
private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
public_subnets = ["10.0.4.0/24", "10.0.5.0/24", "10.0.6.0/24"]
enable_nat_gateway = true
single_nat_gateway = true
enable_dns_hostnames = true

public_subnet_tags = {
"kubernetes.io/cluster/${local.name}" = "shared"
"kubernetes.io/role/elb" = "1"
}

private_subnet_tags = {
"kubernetes.io/cluster/${local.name}" = "shared"
"kubernetes.io/role/internal-elb" = "1"
}

tags = {
Example = local.name
GithubRepo = "terraform-aws-eks"
GithubOrg = "terraform-aws-modules"
}
}
24 changes: 24 additions & 0 deletions examples/managed_bottlerocket_node_group/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
output "cluster_endpoint" {
description = "Endpoint for EKS control plane."
value = module.eks.cluster_endpoint
}

output "cluster_security_group_id" {
description = "Security group ids attached to the cluster control plane."
value = module.eks.cluster_security_group_id
}

output "kubectl_config" {
description = "kubectl config as generated by the module."
value = module.eks.kubeconfig
}

output "config_map_aws_auth" {
description = "A kubernetes configuration to authenticate to this EKS cluster."
value = module.eks.config_map_aws_auth
}

output "node_groups" {
description = "Outputs from node groups"
value = module.eks.node_groups
}
30 changes: 30 additions & 0 deletions examples/managed_bottlerocket_node_group/userdata.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# https://github.com/bottlerocket-os/bottlerocket/blob/develop/README.md#description-of-settings
[settings.kubernetes]
api-server = "${cluster_endpoint}"
cluster-certificate = "${cluster_auth_base64}"
cluster-name = "${cluster_name}"
${pre_userdata}

[settings.kubernetes.node-labels]
"eks.amazonaws.com/capacityType" = "${capacity_type}"
%{ for label, value in {for pair in [ for entry in split(",", append_labels) : split("=", entry) ] : pair[0] => pair[1] if length(pair) == 2 } ~}
"${label}" = "${value}"
%{ endfor ~}

# Hardening based on https://github.com/bottlerocket-os/bottlerocket/blob/develop/SECURITY_GUIDANCE.md

# Enable kernel lockdown in "integrity" mode.
# This prevents modifications to the running kernel, even by privileged users.
[settings.kernel]
lockdown = "integrity"

# The admin host container provides SSH access and runs with "superpowers".
# It is disabled by default, but can be disabled explicitly.
[settings.host-containers.admin]
enabled = ${enable_admin_container}

# The control host container provides out-of-band access via SSM.
# It is enabled by default, and can be disabled if you do not expect to use SSM.
# This could leave you with no way to access the API and change settings on an existing node!
[settings.host-containers.control]
enabled = ${enable_control_container}
Empty file.
11 changes: 11 additions & 0 deletions examples/managed_bottlerocket_node_group/versions.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
terraform {
required_version = ">= 0.13.1"

required_providers {
aws = ">= 3.56.0"
local = ">= 1.4"
random = ">= 2.1"
kubernetes = "~> 2.0"
tls = ">= 2.0"
}
}

0 comments on commit 35948f9

Please sign in to comment.