../../_images/amazon_eks.png

Amazon Elastic Kubernetes Service

Requirements

To install the L7|ESP Helm chart on Amazon Elastic Kubernetes Service (Amazon EKS), you must have:

The kubectl and aws command line tools will be use respectively to programmatically access the Kubernetes cluster and the AWS account. To install the CLI tools, follow the link below and choose the correct operating sytem:

Infrastructure as Code

CloudFormation Template

The latest CloudFormation template is as follows:

CloudFormation template
AWSTemplateFormatVersion: '2010-09-09'
Description: EKS cluster using a VPC with two public subnets

Parameters:
  EKSClusterName:
    Type: String
    Default: ""
    Description: The desired name of your AWS EKS Cluster.
  
  EKSVersion:
    Type: String
    Default: 1.22
    AllowedValues: 
      - 1.16
      - 1.17
      - 1.18
      - 1.21
      - 1.22
    Description: The desired version of your AWS EKS Cluster.
  
  EKSNodeGroupName:
    Type: String
    Default: "NodeGroup01"
    Description: The desired name of your AWS EKS Node Group.
  
  NodeAutoScalingGroupDesiredCapacity:
    Type: Number
    Default: 2
    Description: Number of desired Worker Node.
    # MinValue: 1
    # MaxValue: 5

  NodeAutoScalingGroupMinSize:
    Type: Number
    Default: 1
    Description: Minimum size of Node Group ASG.

  NodeAutoScalingGroupMaxSize:
    Type: Number
    Default: 5
    Description: Maximum size of Node Group ASG. Set to at least 1 greater than NodeAutoScalingGroupDesiredCapacity.

  EKSWorkerNodeInstanceType:
    Type: String
    Default: t2.large
    AllowedValues: [t2.nano, t2.micro, t2.small, t2.medium, t2.large, t2.xlarge, t2.2xlarge,
      t3.nano, t3.micro, t3.small, t3.medium, t3.large, t3.xlarge, t3.2xlarge,
      m4.large, m4.xlarge, m4.2xlarge, m4.4xlarge, m4.10xlarge,
      m5.large, m5.xlarge, m5.2xlarge, m5.4xlarge,
      c5.large, c5.xlarge, c5.2xlarge, c5.4xlarge, c5.9xlarge,
      g3.8xlarge,r5.large, r5.xlarge, r5.2xlarge, r5.4xlarge, r3.12xlarge,
      i3.xlarge, i3.2xlarge, i3.4xlarge, i3.8xlarge,
      d2.xlarge, d2.2xlarge, d2.4xlarge, d2.8xlarge]
    ConstraintDescription: Must be a valid EC2 instance type
    Description: EC2 instance type for the node instances.

  EKSIAMRoleName:
    Type: String
    Default: ""
    Description: The name of the IAM role for the EKS service to assume.
  
  EKSKeyPair:
    Type: "AWS::EC2::KeyPair::KeyName"
    Default: "devopskey"
    Description: The name of Key Pair to etasblish connection with Worker Node.
  
  VpcBlock:
    Type: String
    Default: 10.0.0.0/16
    Description: The CIDR range for the VPC. This should be a valid private (RFC 1918) CIDR range.
    AllowedPattern: (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})
    ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x.

  PublicSubnet01Block:
    Type: String
    Default: 10.0.0.0/24
    Description: CidrBlock for public subnet 01 within the VPC.
    AllowedPattern: (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})
    ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x.

  PublicSubnet02Block:
    Type: String
    Default: 10.0.1.0/24
    Description: CidrBlock for public subnet 02 within the VPC.
    AllowedPattern: (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})
    ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x.

  AvailabilityZonePublicSubnet01:
    Type: CommaDelimitedList<AWS::EC2::AvailabilityZone::Name>
    Default: us-east-1a
    Description: Availability Zone for the Public Subnet 01. 

  AvailabilityZonePublicSubnet02:
    Type: CommaDelimitedList<AWS::EC2::AvailabilityZone::Name>
    Default: us-east-1b
    Description: Availability Zone for the Public Subnet 02.
Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
    -
      Label:
        default: "Worker Network Configuration"
      Parameters:
        - VpcBlock
        - PublicSubnet01Block
        - AvailabilityZonePublicSubnet01
        - PublicSubnet02Block
        - AvailabilityZonePublicSubnet02

    -
      Label:
        default: "EKS Cluster Information"
      Parameters:
        - EKSClusterName
        - EKSVersion
        - EKSNodeGroupName
        - NodeAutoScalingGroupDesiredCapacity
        - EKSWorkerNodeInstanceType
        - EKSIAMRoleName
        - EKSKeyPair
        - NodeAutoScalingGroupMinSize
        - NodeAutoScalingGroupMaxSize

Mappings:
  ServicePrincipals:
    aws-cn:
      ec2: ec2.amazonaws.com.cn
    aws-us-gov:
      ec2: ec2.amazonaws.com
    aws:
      ec2: ec2.amazonaws.com

Resources:
  eksVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: !Ref VpcBlock
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: !Sub '${AWS::StackName}-VPC'
        - Key: Project
          Value: aws-eks

  eksInternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: !Sub '${AWS::StackName}-InternetGateway'
        - Key: Project
          Value: aws-eks
    
  eksVPCGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      InternetGatewayId: !Ref eksInternetGateway
      VpcId: !Ref eksVPC
  
  eksPublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref eksVPC
      Tags:
        - Key: Name
          Value: !Sub '${AWS::StackName}-RouteTable'
        - Key: Project
          Value: aws-eks

  eksPublicRoute:
    DependsOn: eksVPCGatewayAttachment
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref eksPublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref eksInternetGateway

  eksPublicSubnet01:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: !Ref AvailabilityZonePublicSubnet01
      MapPublicIpOnLaunch: true
      CidrBlock:
        Ref: PublicSubnet01Block
      VpcId:
        Ref: eksVPC
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-PublicSubnet01"
        - Key: Project
          Value: aws-eks
    
  eksPublicSubnet02:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: !Ref AvailabilityZonePublicSubnet02
      MapPublicIpOnLaunch: true
      CidrBlock:
        Ref: PublicSubnet02Block
      VpcId:
        Ref: eksVPC
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-PublicSubnet02"
        - Key: Project
          Value: aws-eks
  
  eksPublicSubnet01RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref eksPublicSubnet01
      RouteTableId: !Ref eksPublicRouteTable

  eksPublicSubnet02RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref eksPublicSubnet02
      RouteTableId: !Ref eksPublicRouteTable

  eksSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Cluster communication with worker nodes
      VpcId: !Ref eksVPC
      Tags:
        - Key: Name
          Value: !Sub "${AWS::StackName}-SecurityGroup"
        - Key: Project
          Value: aws-eks

  eksIAMRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service:
              - eks.amazonaws.com
            Action:
            - 'sts:AssumeRole'
      RoleName: !Ref EKSIAMRoleName
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonEKSClusterPolicy

  eksCluster:
    Type: AWS::EKS::Cluster
    Properties:
      Name: !Ref EKSClusterName
      Version: !Ref EKSVersion
      RoleArn:
        "Fn::GetAtt": ["eksIAMRole", "Arn"]
      ResourcesVpcConfig:
        SecurityGroupIds:
          - !Ref eksSecurityGroup
        SubnetIds:
          - !Ref eksPublicSubnet01
          - !Ref eksPublicSubnet02
    DependsOn: [eksIAMRole, eksPublicSubnet01, eksPublicSubnet02, eksSecurityGroup]

  eksNodeInstanceRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - !FindInMap [ServicePrincipals, !Ref "AWS::Partition", ec2]
            Action:
              - "sts:AssumeRole"
      ManagedPolicyArns:
        - !Sub "arn:${AWS::Partition}:iam::aws:policy/AmazonEKSWorkerNodePolicy"
        - !Sub "arn:${AWS::Partition}:iam::aws:policy/AmazonEKS_CNI_Policy"
        - !Sub "arn:${AWS::Partition}:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly"
      Path: /

  eksNodeGroup:
    Type: AWS::EKS::Nodegroup
    Properties:
      ClusterName: !Ref EKSClusterName
      NodeRole: 
        "Fn::GetAtt": ["eksNodeInstanceRole", "Arn"]
      AmiType: AL2_x86_64
      InstanceTypes: 
        - !Ref EKSWorkerNodeInstanceType
      NodegroupName: !Ref EKSNodeGroupName
      RemoteAccess:
        Ec2SshKey: !Ref EKSKeyPair
      ScalingConfig:
        MinSize: !Ref NodeAutoScalingGroupMinSize
        DesiredSize: !Ref NodeAutoScalingGroupDesiredCapacity
        MaxSize: !Ref NodeAutoScalingGroupMaxSize
      Labels:
        Project: aws-eks
      Subnets:
        - !Ref eksPublicSubnet01
        - !Ref eksPublicSubnet02
    DependsOn: [eksCluster, eksNodeInstanceRole]
Outputs:
  SubnetIds:
    Description: Subnets IDs in the eksVPC
    Value: !Join [ ",", [ !Ref eksPublicSubnet01, !Ref eksPublicSubnet02 ] ]
  SecurityGroups:
    Description: Security group for the cluster control plane communication with worker nodes
    Value: !Join [ ",", [ !Ref eksSecurityGroup ] ]
  VpcId:
    Description: The eksVPC Id
    Value: !Ref eksVPC

Parameters

  • EKSClusterName (String) - The desired name of your AWS EKS Cluster.

  • EKSVersion (String) - The desired version of your AWS EKS Cluster. (1.16, 1.17, 1.18, 1.21 - Default: 1.21)

  • EKSNodeGroupName (String) - The desired name of your AWS EKS Node Group. (Default: NodeGroup01)

  • NodeAutoScalingGroupDesiredCapacity (Number) - Number of desired worker nodes. (Default: 2)

  • NodeAutoScalingGroupMinSize (Number) - Minimum size of Node Group ASG. (Default: 1)

  • NodeAutoScalingGroupMaxSize (Number) - Maximum size of Node Group ASG. Set to at least 1 greater than NodeAutoScalingGroupDesiredCapacity. (Default: 5)

  • EKSWorkerNodeInstanceType (String) - EC2 instance type for the node instances. (Default: t2.large)

  • EKSIAMRoleName (String) - Description: The name of the IAM role for the EKS service to assume. (Default: EKSClusterRole)

  • EKSKeyPair (AWS::EC2::KeyPair::KeyName) - The name of Key Pair to etasblish connection with Worker Node. (Default: "devopskey")

  • VpcBlock (String) - The CIDR range for the VPC. This should be a valid private (RFC 1918) CIDR range. (Default: 10.0.0.0/16)

  • PublicSubnet01Block (String) - CidrBlock for public subnet 01 within the VPC. (Default: 10.0.0.0/24)

  • PublicSubnet02Block (String) - CidrBlock for public subnet 02 within the VPC. (Default: 10.0.1.0/24)

  • AvailabilityZonePublicSubnet01 (CommaDelimitedList<AWS::EC2::AvailabilityZone::Name>) - Availability Zone for the Public Subnet 01. (Default: us-east-1a)

  • AvailabilityZonePublicSubnet02 (CommaDelimitedList<AWS::EC2::AvailabilityZone::Name>) - Availability Zone for the Public Subnet 02. (Default: us-east-1b)

Parameters File

Create a parameters.json file for use when deploying the CloudFormation template:

CloudFormation template
[
  {
    "ParameterKey": "NodeAutoScalingGroupDesiredCapacity",
    "ParameterValue": "2"
  },
  {
    "ParameterKey": "EKSNodeGroupName",
    "ParameterValue": "NodeGroup01"
  },
  {
    "ParameterKey": "NodeAutoScalingGroupMinSize",
    "ParameterValue": "1"
  },
  {
    "ParameterKey": "NodeAutoScalingGroupMaxSize",
    "ParameterValue": "5"
  },
  {
    "ParameterKey": "EKSWorkerNodeInstanceType",
    "ParameterValue": "t2.large"
  },
  {
    "ParameterKey": "EKSClusterName",
    "ParameterValue": "l7eksdevops"
  },
  {
    "ParameterKey": "EKSKeyPair",
    "ParameterValue": "devopskey"
  },
  {
    "ParameterKey": "EKSIAMRoleName",
    "ParameterValue": "EKSClusterRoleLatest"  
  }
]

Provisioning

Create a profile for use with AWS CLI:

~$ aws configure --profile <profile>
AWS Access Key ID [None]: AKIAIOSFODNN7EXAMPLE
AWS Secret Access Key [None]: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
Default region name [us-east-1]:
Default output format [None]:

Switch to the correct AWS profile for current shell session:

~$ export AWS_PROFILE=<profile>

Deploy CloudFormation stack:

$ aws cloudformation deploy \
   --stack-name l7esp-example \
   --template-file eks.yml \
   --parameter-overrides file://eks.parameters.json \
   --capabilities CAPABILITY_NAMED_IAM

Validate Resource Creation

Log into the AWS Console and navigate to CloudFormation. Under “Stacks”, validate that the CloudFormation stack was created:

../../_images/cloudformationstack.png

Access the Kubernetes cluster

Use the AWS CLI to download the Kubernetes credentials into your local config:

~$ aws eks update-kubeconfig --name <eks_cluster_name>
Updated context arn:aws:eks:us-east-1:123456789012:cluster/<eks_cluster_name> in /home/<user>/.kube/config

Check that Kubernetes nodes were successfully provisioned and are healthy:

~$ kubectl get nodes
NAME                          STATUS   ROLES   AGE   VERSION
ip-10-0-0-123.ec2.internal    Ready    agent   1h    v1.21.5-eks-9017834
ip-10-0-1-123.ec2.internal    Ready    agent   1h    v1.21.5-eks-9017834

You should see a list of nodes with a Ready status.

Installing L7|ESP Helm chart

To install L7|ESP on the new Kubernetes cluster, see the Helm deployment guide.