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

Windows node support #139

Merged
merged 15 commits into from
Mar 22, 2023
Merged
Show file tree
Hide file tree
Changes from 11 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
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,7 @@

# vim editor
*.swp

/.terraform.lock.hcl
/.vscode
/examples/complete/.terraform.lock.hcl
46 changes: 42 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -243,19 +243,56 @@ Available targets:
```
<!-- markdownlint-restore -->
<!-- markdownlint-disable -->
## Windows Managed Node groups

Windows managed node-groups have a few pre-requisites.

* Your cluster must contain at least one linux based worker node
* Your EKS Cluster must have the `AmazonEKSVPCResourceController` and `AmazonEKSClusterPolicy` policies attached
* Your cluster must have a config-map called amazon-vpc-cni with the following content

```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: amazon-vpc-cni
namespace: kube-system
data:
enable-windows-ipam: "true"
```

* Windows nodes will automatically be tainted

```yaml
kubernetes_taints = [{
key = "WINDOWS"
value = "true"
effect = "NO_SCHEDULE"
}]
```
* Any pods that target Windows will need to have the following attributes set in their manifest

```yaml
nodeSelector:
kubernetes.io/os: windows
kubernetes.io/arch: amd64
```

https://docs.aws.amazon.com/eks/latest/userguide/windows-support.html
<!-- markdownlint-disable -->
## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 0.14.11 |
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 3.56 |
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 4.48 |
| <a name="requirement_random"></a> [random](#requirement\_random) | >= 2.0 |

## Providers

| Name | Version |
|------|---------|
| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 3.56 |
| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 4.48 |
| <a name="provider_random"></a> [random](#provider\_random) | >= 2.0 |

## Modules
Expand Down Expand Up @@ -294,8 +331,8 @@ Available targets:
| <a name="input_additional_tag_map"></a> [additional\_tag\_map](#input\_additional\_tag\_map) | Additional key-value pairs to add to each map in `tags_as_list_of_maps`. Not added to `tags` or `id`.<br>This is for some rare cases where resources want additional configuration of tags<br>and therefore take a list of maps with tag key, value, and additional configuration. | `map(string)` | `{}` | no |
| <a name="input_after_cluster_joining_userdata"></a> [after\_cluster\_joining\_userdata](#input\_after\_cluster\_joining\_userdata) | Additional `bash` commands to execute on each worker node after joining the EKS cluster (after executing the `bootstrap.sh` script). For more info, see https://kubedex.com/90-days-of-aws-eks-in-production | `list(string)` | `[]` | no |
| <a name="input_ami_image_id"></a> [ami\_image\_id](#input\_ami\_image\_id) | AMI to use. Ignored if `launch_template_id` is supplied. | `list(string)` | `[]` | no |
| <a name="input_ami_release_version"></a> [ami\_release\_version](#input\_ami\_release\_version) | EKS AMI version to use, e.g. For AL2 "1.16.13-20200821" or for bottlerocket "1.2.0-ccf1b754" (no "v"). For AL2 and bottlerocket, it defaults to latest version for Kubernetes version. | `list(string)` | `[]` | no |
| <a name="input_ami_type"></a> [ami\_type](#input\_ami\_type) | Type of Amazon Machine Image (AMI) associated with the EKS Node Group.<br>Defaults to `AL2_x86_64`. Valid values: `AL2_x86_64`, `AL2_x86_64_GPU`, `AL2_ARM_64`, `BOTTLEROCKET_x86_64`, and `BOTTLEROCKET_ARM_64`. | `string` | `"AL2_x86_64"` | no |
| <a name="input_ami_release_version"></a> [ami\_release\_version](#input\_ami\_release\_version) | EKS AMI version to use, e.g. For AL2 "1.16.13-20200821" or for bottlerocket "1.2.0-ccf1b754" (no "v") or for Windows "2023.02.14". For AL2, bottlerocket and Windows, it defaults to latest version for Kubernetes version. | `list(string)` | `[]` | no |
| <a name="input_ami_type"></a> [ami\_type](#input\_ami\_type) | Type of Amazon Machine Image (AMI) associated with the EKS Node Group.<br>Defaults to `AL2_x86_64`. Valid values: `AL2_x86_64, AL2_x86_64_GPU, AL2_ARM_64, CUSTOM, BOTTLEROCKET_ARM_64, BOTTLEROCKET_x86_64, BOTTLEROCKET_ARM_64_NVIDIA, BOTTLEROCKET_x86_64_NVIDIA, WINDOWS_CORE_2019_x86_64, WINDOWS_FULL_2019_x86_64, WINDOWS_CORE_2022_x86_64, WINDOWS_FULL_2022_x86_64`. | `string` | `"AL2_x86_64"` | no |
| <a name="input_associated_security_group_ids"></a> [associated\_security\_group\_ids](#input\_associated\_security\_group\_ids) | A list of IDs of Security Groups to associate the node group with, in addition to the EKS' created security group.<br>These security groups will not be modified. | `list(string)` | `[]` | no |
| <a name="input_attributes"></a> [attributes](#input\_attributes) | ID element. Additional attributes (e.g. `workers` or `cluster`) to add to `id`,<br>in the order they appear in the list. New attributes are appended to the<br>end of the list. The elements of the list are joined by the `delimiter`<br>and treated as a single ID element. | `list(string)` | `[]` | no |
| <a name="input_before_cluster_joining_userdata"></a> [before\_cluster\_joining\_userdata](#input\_before\_cluster\_joining\_userdata) | Additional `bash` commands to execute on each worker node before joining the EKS cluster (before executing the `bootstrap.sh` script). For more info, see https://kubedex.com/90-days-of-aws-eks-in-production | `list(string)` | `[]` | no |
Expand Down Expand Up @@ -366,6 +403,7 @@ Available targets:
| <a name="output_eks_node_group_role_name"></a> [eks\_node\_group\_role\_name](#output\_eks\_node\_group\_role\_name) | Name of the worker nodes IAM role |
| <a name="output_eks_node_group_status"></a> [eks\_node\_group\_status](#output\_eks\_node\_group\_status) | Status of the EKS Node Group |
| <a name="output_eks_node_group_tags_all"></a> [eks\_node\_group\_tags\_all](#output\_eks\_node\_group\_tags\_all) | A map of tags assigned to the resource, including those inherited from the provider default\_tags configuration block. |
| <a name="output_eks_node_group_windows_note"></a> [eks\_node\_group\_windows\_note](#output\_eks\_node\_group\_windows\_note) | Instructions on changes a user needs to follow or script for a windows node group in the event of a custom ami |
<!-- markdownlint-restore -->


Expand Down
1 change: 1 addition & 0 deletions README.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ usage: |2-

include:
- "docs/targets.md"
- "docs/windows.md"
- "docs/terraform.md"

# Contributors to this project
Expand Down
49 changes: 33 additions & 16 deletions ami.tf
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,34 @@
locals {
# "amazon-eks-gpu-node-",
arch_label_map = {
"AL2_x86_64" : "",
"AL2_x86_64_GPU" : "-gpu",
"AL2_ARM_64" : "-arm64",
"BOTTLEROCKET_x86_64" : "x86_64",
"BOTTLEROCKET_ARM_64" : "aarch64"
AL2_x86_64 = "",
AL2_x86_64_GPU = "-gpu",
AL2_ARM_64 = "-arm64",
BOTTLEROCKET_x86_64 = "x86_64",
BOTTLEROCKET_ARM_64 = "aarch64"
BOTTLEROCKET_ARM_64_NVIDIA = "-gpu"
BOTTLEROCKET_x86_64_NVIDIA = "-gpu"
WINDOWS_CORE_2019_x86_64 = ""
WINDOWS_FULL_2019_x86_64 = ""
WINDOWS_CORE_2022_x86_64 = ""
WINDOWS_FULL_2022_x86_64 = ""
}

ami_kind = split("_", var.ami_type)[0]
ami_kind = split("_", var.ami_type)[0] != "WINDOWS" ? split("_", var.ami_type)[0] : format("WINDOWS_%s_%s", split("_", var.ami_type)[1], split("_", var.ami_type)[2])

ami_format = {
# amazon-eks{arch_label}-node-{ami_kubernetes_version}-v{ami_version}
# e.g. amazon-eks-arm64-node-1.21-v20211013
"AL2" : "amazon-eks%s-node-%s"
AL2 = "amazon-eks%s-node-%s"
# bottlerocket-aws-k8s-{ami_kubernetes_version}-{arch_label}-v{ami_version}
# e.g. bottlerocket-aws-k8s-1.21-x86_64-v1.2.0-ccf1b754
"BOTTLEROCKET" : "bottlerocket-aws-k8s-%s-%s-%s"
BOTTLEROCKET = "bottlerocket-aws-k8s-%s-%s-%s"
# Windows_Server-2019-English-Core-EKS_Optimized-{ami_kubernetes_version}-{ami_version}
# e.g. Windows_Server-2019-English-Core-EKS_Optimized-1.23-2022.11.08
WINDOWS_CORE_2019 = "Windows_Server-2019-English-Core-EKS_Optimized-%s-%s"
WINDOWS_FULL_2019 = "Windows_Server-2019-English-Full-EKS_Optimized-%s-%s"
WINDOWS_CORE_2022 = "Windows_Server-2022-English-Core-EKS_Optimized-%s-%s"
WINDOWS_FULL_2022 = "Windows_Server-2022-English-Full-EKS_Optimized-%s-%s"
}

# Kubernetes version priority (first one to be set wins)
Expand All @@ -37,19 +49,24 @@ locals {
# if ami_release_version = "1.21-20211013"
# insert the letter v prior to the ami_version so it becomes 1.21-v20211013
# if not, use the kubernetes version
"AL2" : (length(var.ami_release_version) == 1 ?
replace(var.ami_release_version[0], "/^(\\d+\\.\\d+)\\.\\d+-(\\d+)$/", "$1-v$2") :
"${local.ami_kubernetes_version}-*"),
AL2 = (length(var.ami_release_version) == 1 ? replace(var.ami_release_version[0], "/^(\\d+\\.\\d+)\\.\\d+-(\\d+)$/", "$1-v$2") : "${local.ami_kubernetes_version}-*"),
# if ami_release_version = "1.2.0-ccf1b754"
# prefex the ami release version with the letter v
# prefix the ami release version with the letter v
# if not, use an asterisk
"BOTTLEROCKET" : (length(var.ami_release_version) == 1 ?
format("v%s", var.ami_release_version[0]) : "*"),
BOTTLEROCKET = (length(var.ami_release_version) == 1 ? format("v%s", var.ami_release_version[0]) : "*"),
WINDOWS_CORE_2019 = (length(var.ami_release_version) == 1 ? format("%s", var.ami_release_version[0]) : "*"),
WINDOWS_FULL_2019 = (length(var.ami_release_version) == 1 ? format("%s", var.ami_release_version[0]) : "*"),
WINDOWS_CORE_2022 = (length(var.ami_release_version) == 1 ? format("%s", var.ami_release_version[0]) : "*"),
WINDOWS_FULL_2022 = (length(var.ami_release_version) == 1 ? format("%s", var.ami_release_version[0]) : "*"),
} : {}

ami_regex = local.need_ami_id ? {
"AL2" : format(local.ami_format["AL2"], local.arch_label_map[var.ami_type], local.ami_version_regex[local.ami_kind]),
"BOTTLEROCKET" : format(local.ami_format["BOTTLEROCKET"], local.ami_kubernetes_version, local.arch_label_map[var.ami_type], local.ami_version_regex[local.ami_kind]),
AL2 = format(local.ami_format["AL2"], local.arch_label_map[var.ami_type], local.ami_version_regex[local.ami_kind]),
BOTTLEROCKET = format(local.ami_format["BOTTLEROCKET"], local.ami_kubernetes_version, local.arch_label_map[var.ami_type], local.ami_version_regex[local.ami_kind]),
WINDOWS_CORE_2019 = format(local.ami_format["WINDOWS_CORE_2019"], local.ami_kubernetes_version, local.ami_version_regex[local.ami_kind]),
WINDOWS_FULL_2019 = format(local.ami_format["WINDOWS_FULL_2019"], local.ami_kubernetes_version, local.ami_version_regex[local.ami_kind]),
WINDOWS_CORE_2022 = format(local.ami_format["WINDOWS_CORE_2022"], local.ami_kubernetes_version, local.ami_version_regex[local.ami_kind]),
WINDOWS_FULL_2022 = format(local.ami_format["WINDOWS_FULL_2022"], local.ami_kubernetes_version, local.ami_version_regex[local.ami_kind]),
} : {}
}

Expand Down
9 changes: 5 additions & 4 deletions docs/terraform.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 0.14.11 |
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 3.56 |
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 4.48 |
| <a name="requirement_random"></a> [random](#requirement\_random) | >= 2.0 |

## Providers

| Name | Version |
|------|---------|
| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 3.56 |
| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 4.48 |
| <a name="provider_random"></a> [random](#provider\_random) | >= 2.0 |

## Modules
Expand Down Expand Up @@ -50,8 +50,8 @@
| <a name="input_additional_tag_map"></a> [additional\_tag\_map](#input\_additional\_tag\_map) | Additional key-value pairs to add to each map in `tags_as_list_of_maps`. Not added to `tags` or `id`.<br>This is for some rare cases where resources want additional configuration of tags<br>and therefore take a list of maps with tag key, value, and additional configuration. | `map(string)` | `{}` | no |
| <a name="input_after_cluster_joining_userdata"></a> [after\_cluster\_joining\_userdata](#input\_after\_cluster\_joining\_userdata) | Additional `bash` commands to execute on each worker node after joining the EKS cluster (after executing the `bootstrap.sh` script). For more info, see https://kubedex.com/90-days-of-aws-eks-in-production | `list(string)` | `[]` | no |
| <a name="input_ami_image_id"></a> [ami\_image\_id](#input\_ami\_image\_id) | AMI to use. Ignored if `launch_template_id` is supplied. | `list(string)` | `[]` | no |
| <a name="input_ami_release_version"></a> [ami\_release\_version](#input\_ami\_release\_version) | EKS AMI version to use, e.g. For AL2 "1.16.13-20200821" or for bottlerocket "1.2.0-ccf1b754" (no "v"). For AL2 and bottlerocket, it defaults to latest version for Kubernetes version. | `list(string)` | `[]` | no |
| <a name="input_ami_type"></a> [ami\_type](#input\_ami\_type) | Type of Amazon Machine Image (AMI) associated with the EKS Node Group.<br>Defaults to `AL2_x86_64`. Valid values: `AL2_x86_64`, `AL2_x86_64_GPU`, `AL2_ARM_64`, `BOTTLEROCKET_x86_64`, and `BOTTLEROCKET_ARM_64`. | `string` | `"AL2_x86_64"` | no |
| <a name="input_ami_release_version"></a> [ami\_release\_version](#input\_ami\_release\_version) | EKS AMI version to use, e.g. For AL2 "1.16.13-20200821" or for bottlerocket "1.2.0-ccf1b754" (no "v") or for Windows "2023.02.14". For AL2, bottlerocket and Windows, it defaults to latest version for Kubernetes version. | `list(string)` | `[]` | no |
| <a name="input_ami_type"></a> [ami\_type](#input\_ami\_type) | Type of Amazon Machine Image (AMI) associated with the EKS Node Group.<br>Defaults to `AL2_x86_64`. Valid values: `AL2_x86_64, AL2_x86_64_GPU, AL2_ARM_64, CUSTOM, BOTTLEROCKET_ARM_64, BOTTLEROCKET_x86_64, BOTTLEROCKET_ARM_64_NVIDIA, BOTTLEROCKET_x86_64_NVIDIA, WINDOWS_CORE_2019_x86_64, WINDOWS_FULL_2019_x86_64, WINDOWS_CORE_2022_x86_64, WINDOWS_FULL_2022_x86_64`. | `string` | `"AL2_x86_64"` | no |
| <a name="input_associated_security_group_ids"></a> [associated\_security\_group\_ids](#input\_associated\_security\_group\_ids) | A list of IDs of Security Groups to associate the node group with, in addition to the EKS' created security group.<br>These security groups will not be modified. | `list(string)` | `[]` | no |
| <a name="input_attributes"></a> [attributes](#input\_attributes) | ID element. Additional attributes (e.g. `workers` or `cluster`) to add to `id`,<br>in the order they appear in the list. New attributes are appended to the<br>end of the list. The elements of the list are joined by the `delimiter`<br>and treated as a single ID element. | `list(string)` | `[]` | no |
| <a name="input_before_cluster_joining_userdata"></a> [before\_cluster\_joining\_userdata](#input\_before\_cluster\_joining\_userdata) | Additional `bash` commands to execute on each worker node before joining the EKS cluster (before executing the `bootstrap.sh` script). For more info, see https://kubedex.com/90-days-of-aws-eks-in-production | `list(string)` | `[]` | no |
Expand Down Expand Up @@ -122,4 +122,5 @@
| <a name="output_eks_node_group_role_name"></a> [eks\_node\_group\_role\_name](#output\_eks\_node\_group\_role\_name) | Name of the worker nodes IAM role |
| <a name="output_eks_node_group_status"></a> [eks\_node\_group\_status](#output\_eks\_node\_group\_status) | Status of the EKS Node Group |
| <a name="output_eks_node_group_tags_all"></a> [eks\_node\_group\_tags\_all](#output\_eks\_node\_group\_tags\_all) | A map of tags assigned to the resource, including those inherited from the provider default\_tags configuration block. |
| <a name="output_eks_node_group_windows_note"></a> [eks\_node\_group\_windows\_note](#output\_eks\_node\_group\_windows\_note) | Instructions on changes a user needs to follow or script for a windows node group in the event of a custom ami |
<!-- markdownlint-restore -->
37 changes: 37 additions & 0 deletions docs/windows.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<!-- markdownlint-disable -->
## Windows Managed Node groups

Windows managed node-groups have a few pre-requisites.

* Your cluster must contain at least one linux based worker node
* Your EKS Cluster must have the `AmazonEKSVPCResourceController` and `AmazonEKSClusterPolicy` policies attached
* Your cluster must have a config-map called amazon-vpc-cni with the following content

```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: amazon-vpc-cni
namespace: kube-system
data:
enable-windows-ipam: "true"
```

* Windows nodes will automatically be tainted

```yaml
kubernetes_taints = [{
key = "WINDOWS"
value = "true"
effect = "NO_SCHEDULE"
}]
```
* Any pods that target Windows will need to have the following attributes set in their manifest

```yaml
nodeSelector:
kubernetes.io/os: windows
kubernetes.io/arch: amd64
```

https://docs.aws.amazon.com/eks/latest/userguide/windows-support.html
2 changes: 0 additions & 2 deletions examples/complete/fixtures.us-east-2.tfvars
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ max_size = 3

min_size = 2

disk_size = 20

kubernetes_labels = {
terratest = "true"
}
Expand Down
10 changes: 4 additions & 6 deletions examples/complete/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,9 @@ module "https_sg" {
context = module.label.context
}


module "eks_cluster" {
source = "cloudposse/eks-cluster/aws"
version = "2.4.0"

source = "cloudposse/eks-cluster/aws"
version = "2.4.0"
region = var.region
vpc_id = module.vpc.vpc_id
subnet_ids = module.subnets.public_subnet_ids
Expand All @@ -135,7 +133,7 @@ module "eks_cluster" {
context = module.this.context
}

module "eks_node_group" {
module "eks_nix_node_group" {
source = "../../"

subnet_ids = module.this.enabled ? module.subnets.public_subnet_ids : ["filler_string_for_enabled_is_false"]
Expand All @@ -147,7 +145,7 @@ module "eks_node_group" {
kubernetes_version = [var.kubernetes_version]
kubernetes_labels = merge(var.kubernetes_labels, { attributes = coalesce(join(module.this.delimiter, module.this.attributes), "none") })
kubernetes_taints = var.kubernetes_taints
# disk_size = var.disk_size

ec2_ssh_key_name = var.ec2_ssh_key_name
ssh_access_security_group_ids = [module.ssh_source_access.id]
associated_security_group_ids = [module.ssh_source_access.id, module.https_sg.id]
Expand Down
17 changes: 8 additions & 9 deletions examples/complete/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -60,40 +60,39 @@ output "eks_cluster_managed_security_group_id" {

output "eks_node_group_role_arn" {
description = "ARN of the worker nodes IAM role"
value = module.eks_node_group.eks_node_group_role_arn
value = module.eks_nix_node_group.eks_node_group_role_arn
}

output "eks_node_group_role_name" {
description = "Name of the worker nodes IAM role"
value = module.eks_node_group.eks_node_group_role_name
value = module.eks_nix_node_group.eks_node_group_role_name
}

output "eks_node_group_id" {
description = "EKS Cluster name and EKS Node Group name separated by a colon"
value = module.eks_node_group.eks_node_group_id
value = module.eks_nix_node_group.eks_node_group_id
}

output "eks_node_group_arn" {
description = "Amazon Resource Name (ARN) of the EKS Node Group"
value = module.eks_node_group.eks_node_group_arn
value = module.eks_nix_node_group.eks_node_group_arn
}

output "eks_node_group_resources" {
description = "List of objects containing information about underlying resources of the EKS Node Group"
value = module.eks_node_group.eks_node_group_resources
value = module.eks_nix_node_group.eks_node_group_resources
}

output "eks_node_group_status" {
description = "Status of the EKS Node Group"
value = module.eks_node_group.eks_node_group_status
value = module.eks_nix_node_group.eks_node_group_status
}

output "eks_node_group_cbd_pet_name" {
description = "The pet name of this node group, if this module generated one"
value = module.eks_node_group.eks_node_group_cbd_pet_name
value = module.eks_nix_node_group.eks_node_group_cbd_pet_name
}


output "eks_node_group_launch_template_id" {
value = module.eks_node_group.eks_node_group_launch_template_id
value = module.eks_nix_node_group.eks_node_group_launch_template_id
}
Loading