1.kubernetes
eks
Graviton Vs Intel

'''Summary: Bottlerocket AMI:

Optimized for containers, minimal OS focused on performance.

Comes in x86_64 (Intel/AMD) and arm64 (Graviton) versions.

Best for container-only workloads in EKS.

EKS Optimized AMI:

Based on Amazon Linux 2, optimized for Kubernetes workloads in EKS.

Supports both x86_64 and arm64 versions.

Suitable for more general workloads beyond just containers. cli command - aws ssm get-parameter --region us-east-1 --name "/aws/service/bottlerocket/aws-k8s-1.32/x86_64/latest/image_id" --query Parameter.Value --output text ami-0b6ef2ef3518ddbba aws ssm get-parameter
--region us-east-1
--name "/aws/service/bottlerocket/aws-k8s-1.32/arm64/latest/image_id"
--query "Parameter.Value"
--output text ami-0d6fdf644c07969ee

AWS-Codebuild Container Runtime: AWS CodeBuild offers several standard container runtimes you can choose based on your architecture:

ARM64 (Graviton-based):

aws/codebuild/amazonlinux-aarch64-standard:2.0

aws/codebuild/amazonlinux-aarch64-standard:3.0

x86_64 (Intel/AMD):

aws/codebuild/amazonlinux-x86_64-standard:4.0

aws/codebuild/amazonlinux-x86_64-standard:5.0

aws/codebuild/amazonlinux-x86_64-standard:corretto11

aws/codebuild/amazonlinux-x86_64-standard:corretto8

Dockerfile Changes for Alpine 20: Here's how you can modify the Dockerfile to use Alpine 20 and update the architecture to ARM64 (--platform=linux/arm64):

Dockerfile Copy Edit

Use Alpine 20 as the base image

FROM --platform=linux/arm64 node:18-alpine20 as build

Install build dependencies

RUN apk update && apk add --no-cache build-base gcc autoconf automake zlib-dev libpng-dev vips-dev git > /dev/null 2>&1

ARG NODE_ENV=production ENV NODE_ENV=${NODE_ENV}

WORKDIR /opt/

Copy package.json and package-lock.json

COPY package.json package-lock.json ./

Install global npm packages

RUN npm install -g node-gyp

Set retry timeout and install production dependencies

RUN npm config set fetch-retry-maxtimeout 600000 -g && npm install --only=production ENV PATH /opt/node_modules/.bin:$PATH

WORKDIR /opt/app

Copy application files

COPY . .

Run build command

RUN npm run build

Final image setup

FROM --platform=linux/arm64 node:18-alpine20

RUN apk add --no-cache vips-dev

ARG NODE_ENV=production ENV NODE_ENV=${NODE_ENV}

WORKDIR /opt/

Copy dependencies from the build stage

COPY --from=build /opt/node_modules ./node_modules

WORKDIR /opt/app

Copy the application files from build stage

COPY --from=build /opt/app ./

Update PATH

ENV PATH /opt/node_modules/.bin:$PATH

Set ownership and user

RUN chown -R node:node /opt/app USER node

EXPOSE 1337

CMD ["npm", "run", "start"] Key Changes: Base Image: alpine:20 is used to make the image smaller and more efficient.

ARM64: The --platform=linux/arm64 option ensures compatibility with ARM-based instances like AWS Graviton.

Docker Image: The Dockerfile uses multi-stage builds to minimize the final image size.

Key Takeaways: Bottlerocket AMI is optimized for container workloads and can be used with either x86_64 or arm64 architecture.

EKS Optimized AMI supports a wider range of workloads but is less minimal than Bottlerocket.

''' AWSTemplateFormatVersion: '2010-09-09' Description: 'AWS EKS cluster with default node group and addons' Parameters: environment: Type: String Description: Environment type product: Type: String Description: Product name service: Type: String Default: 'eks' Description: Service name storageSize: Type: Number Default: 80 Description: Node disk size in GB isProdEnv: Type: String Default: "false" AllowedValues: ["true", "false"] Description: Set to true for production-like environments isArm64: Type: String Default: "false" AllowedValues: ["true", "false"] Description: Set to true for ARM64 architecture, false for x86_64 eksVersion: Type: String Default: '1.32' Description: EKS cluster version vpcCniVersion: Type: String Default: v1.19.3-eksbuild.1 kubeProxyVersion: Type: String Default: v1.32.0-eksbuild.2 coreDnsVersion: Type: String Default: v1.11.4-eksbuild.2 ebsCsiVersion: Type: String Default: v1.41.0-eksbuild.1 podIdentityVersion: Type: String Default: v1.3.5-eksbuild.2 Conditions: isProd: !Equals [!Ref isProdEnv, "true"] isArm64Architecture: !Equals [!Ref isArm64, "true"] Mappings: default: dev: minSize: 1 maxSize: 2 desiredSize: 1 prod: minSize: 2 maxSize: 4 desiredSize: 2 Resources: eksClusterRole: Type: 'AWS::IAM::Role' Properties: RoleName: !Sub '${environment}-${product}-${service}-cluster-role' AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: eks.amazonaws.com Action: 'sts:AssumeRole' ManagedPolicyArns: - 'arn:aws:iam::aws:policy/AmazonEKSClusterPolicy' clusterAutoscalerPolicy: Type: 'AWS::IAM::ManagedPolicy' Properties: ManagedPolicyName: !Sub '${environment}-${product}-${service}-autoscaler-policy' PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - 'autoscaling:DescribeAutoScalingGroups' - 'autoscaling:DescribeAutoScalingInstances' - 'autoscaling:DescribeLaunchConfigurations' - 'autoscaling:DescribeTags' - 'autoscaling:SetDesiredCapacity' - 'autoscaling:TerminateInstanceInAutoScalingGroup' - 'ec2:DescribeLaunchTemplateVersions' - 'ec2:DescribeInstances' - 'ec2:DescribeInstanceTypes' - 'ec2:DescribeImages' - 'ec2:GetInstanceTypesFromInstanceRequirements' Resource: '*' workerNodeInstanceRole: Type: 'AWS::IAM::Role' Properties: RoleName: !Sub '${environment}-${product}-${service}-node-role' AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: ec2.amazonaws.com Action: 'sts:AssumeRole' ManagedPolicyArns: - 'arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy' - 'arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy' - 'arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly' - 'arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore' - !Ref clusterAutoscalerPolicy eksSecurityGroup: Type: 'AWS::EC2::SecurityGroup' Properties: GroupDescription: 'Security group for EKS cluster allowing only VPC CIDR' VpcId: !ImportValue 'Fn::Sub': '${environment}-${product}-vpc' SecurityGroupIngress: - IpProtocol: -1 FromPort: 0 ToPort: 65535 CidrIp: 10.94.0.0/16 - IpProtocol: -1 FromPort: 0 ToPort: 65535 CidrIp: 10.95.0.0/16 - IpProtocol: -1 FromPort: 0 ToPort: 65535 CidrIp: 10.96.0.0/16 eksCluster: Type: 'AWS::EKS::Cluster' Properties: Name: !Sub '${environment}-${product}-${service}' Version: !Ref eksVersion RoleArn: !GetAtt eksClusterRole.Arn ResourcesVpcConfig: SecurityGroupIds: - !Ref eksSecurityGroup SubnetIds: - !ImportValue Fn::Sub: '${environment}-${product}-vpc-private-subnet-a' - !ImportValue Fn::Sub: '${environment}-${product}-vpc-private-subnet-b' - !ImportValue Fn::Sub: '${environment}-${product}-vpc-private-subnet-c' EndpointPublicAccess: false EndpointPrivateAccess: true eksNodeGroup: Type: 'AWS::EKS::Nodegroup' DependsOn: eksCluster Properties: ClusterName: !Ref eksCluster NodegroupName: !Sub '${environment}-${product}-${service}-default' NodeRole: !GetAtt workerNodeInstanceRole.Arn ScalingConfig: MinSize: !FindInMap [default, !Ref environment, minSize] MaxSize: !FindInMap [default, !Ref environment, maxSize] DesiredSize: !FindInMap [default, !Ref environment, desiredSize] Subnets: - !ImportValue Fn::Sub: '${environment}-${product}-vpc-private-subnet-a' - !ImportValue Fn::Sub: '${environment}-${product}-vpc-private-subnet-b' - !ImportValue Fn::Sub: '${environment}-${product}-vpc-private-subnet-c' # AMI Type based on CPU architecture AmiType: !If [isArm64Architecture, 'AL2_ARM_64', 'AL2_x86_64'] DiskSize: !Ref storageSize # Instance types based on both environment and CPU architecture InstanceTypes: !If - isProd - !If - isArm64Architecture - [m6g.xlarge, m6gd.large] # Prod + ARM64 - [t3a.xlarge] # Prod + x86_64 - !If - isArm64Architecture - [t4g.medium, t4g.large] # Non-Prod + ARM64 - [m4.large, m5.large, m5a.large, t2.large, t3.large, t3a.large, m5ad.large, m5d.large, m6a.large, m6i.large, m6in.large, m7i.large] # Non-Prod + x86_64 # Capacity type based on environment CapacityType: !If [isProd, 'ON_DEMAND', 'SPOT'] vpcCniAddon: Type: 'AWS::EKS::Addon' DependsOn: eksNodeGroup Properties: AddonName: vpc-cni ClusterName: !Ref eksCluster AddonVersion: !Ref vpcCniVersion ResolveConflicts: PRESERVE kubeProxyAddon: Type: 'AWS::EKS::Addon' DependsOn: eksNodeGroup Properties: AddonName: kube-proxy ClusterName: !Ref eksCluster AddonVersion: !Ref kubeProxyVersion ResolveConflicts: PRESERVE coreDnsAddon: Type: 'AWS::EKS::Addon' DependsOn: eksNodeGroup Properties: AddonName: coredns ClusterName: !Ref eksCluster AddonVersion: !Ref coreDnsVersion ResolveConflicts: PRESERVE ebsCsiDriverRole: Type: 'AWS::IAM::Role' Properties: RoleName: !Sub '${environment}-${product}-${service}-ebs-csi-role' AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: ec2.amazonaws.com Action: 'sts:AssumeRole' ManagedPolicyArns: - 'arn:aws:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy' ebsCsiAddon: Type: 'AWS::EKS::Addon' DependsOn: eksNodeGroup Properties: AddonName: aws-ebs-csi-driver ClusterName: !Ref eksCluster AddonVersion: !Ref ebsCsiVersion ResolveConflicts: PRESERVE ServiceAccountRoleArn: !GetAtt ebsCsiDriverRole.Arn podIdentityAgentAddon: Type: 'AWS::EKS::Addon' DependsOn: eksNodeGroup Properties: AddonName: eks-pod-identity-agent ClusterName: !Ref eksCluster AddonVersion: !Ref podIdentityVersion ResolveConflicts: PRESERVE Outputs: eksClusterEndpoint: Description: 'The endpoint for your EKS Kubernetes API' Value: !GetAtt eksCluster.Endpoint '''