一覧に戻る
Containers

Amazon EKS クラスター構成

Amazon EKS + Fargate プロファイルによるサーバーレス Kubernetes 環境を構築します。AWS Load Balancer Controller 用の IRSA(IAM Roles for Service Accounts)設定と ECR リポジトリを含み、ALB Ingress による外部公開に対応します。

構成要素 (AWS Services):

EKSFargateECRALBVPCIAM

構築される主要リソース (15種):

EC2 Subnet4
EC2 SubnetRouteTableAssociation4
IAM Role3
EC2 RouteTable2
EC2 Route2
EKS FargateProfile2
EC2 VPC1
EC2 InternetGateway1
EC2 VPCGatewayAttachment1
EC2 EIP1
EC2 NatGateway1
EC2 SecurityGroup1
EKS Cluster1
ECR Repository1
Logs LogGroup1

アーキテクチャ図 (Architecture Diagram)

クリックで拡大表示
Amazon EKS クラスター構成 アーキテクチャ図

AWS CLI でのデプロイ例

AWS CLIを使用してCloudFormationスタックをデプロイする場合は、以下のコマンドを実行します。

aws cloudformation deploy \
  --template-file eks-cluster.yaml \
  --stack-name eks-cluster-stack \
  --capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM
eks-cluster.yaml
DL
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Amazon EKS Cluster with Fargate, ALB Ingress Controller (AWS Load Balancer Controller), and ECR'

Parameters:
  Environment:
    Type: String
    Default: dev
    AllowedValues: [dev, prod]
  KubernetesVersion:
    Type: String
    Default: '1.32'
    Description: EKS Kubernetes version

Resources:
  # VPC
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsHostnames: true
      EnableDnsSupport: true
      Tags:
        - Key: Name
          Value: !Sub 'eks-vpc-${Environment}'

  PublicSubnetOne:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.0.0/24
      AvailabilityZone: !Select [0, !GetAZs '']
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: !Sub 'eks-public-1-${Environment}'
        - Key: kubernetes.io/role/elb
          Value: '1'

  PublicSubnetTwo:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.1.0/24
      AvailabilityZone: !Select [1, !GetAZs '']
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: !Sub 'eks-public-2-${Environment}'
        - Key: kubernetes.io/role/elb
          Value: '1'

  PrivateSubnetOne:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.2.0/24
      AvailabilityZone: !Select [0, !GetAZs '']
      Tags:
        - Key: Name
          Value: !Sub 'eks-private-1-${Environment}'
        - Key: kubernetes.io/role/internal-elb
          Value: '1'

  PrivateSubnetTwo:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.3.0/24
      AvailabilityZone: !Select [1, !GetAZs '']
      Tags:
        - Key: Name
          Value: !Sub 'eks-private-2-${Environment}'
        - Key: kubernetes.io/role/internal-elb
          Value: '1'

  InternetGateway:
    Type: AWS::EC2::InternetGateway

  GatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref InternetGateway

  NatGatewayEIP:
    Type: AWS::EC2::EIP
    DependsOn: GatewayAttachment
    Properties:
      Domain: vpc

  NatGateway:
    Type: AWS::EC2::NatGateway
    Properties:
      AllocationId: !GetAtt NatGatewayEIP.AllocationId
      SubnetId: !Ref PublicSubnetOne

  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC

  PublicRoute:
    Type: AWS::EC2::Route
    DependsOn: GatewayAttachment
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway

  PublicSubnetOneAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnetOne
      RouteTableId: !Ref PublicRouteTable

  PublicSubnetTwoAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnetTwo
      RouteTableId: !Ref PublicRouteTable

  PrivateRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC

  PrivateRoute:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PrivateRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId: !Ref NatGateway

  PrivateSubnetOneAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnetOne
      RouteTableId: !Ref PrivateRouteTable

  PrivateSubnetTwoAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnetTwo
      RouteTableId: !Ref PrivateRouteTable

  # Security Groups
  ClusterSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: EKS cluster security group
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub 'eks-cluster-sg-${Environment}'

  # IAM Role for EKS Cluster
  EKSClusterRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: eks.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonEKSClusterPolicy

  # EKS Cluster
  EKSCluster:
    Type: AWS::EKS::Cluster
    Properties:
      Name: !Sub 'eks-cluster-${Environment}'
      Version: !Ref KubernetesVersion
      RoleArn: !GetAtt EKSClusterRole.Arn
      ResourcesVpcConfig:
        SubnetIds:
          - !Ref PublicSubnetOne
          - !Ref PublicSubnetTwo
          - !Ref PrivateSubnetOne
          - !Ref PrivateSubnetTwo
        SecurityGroupIds:
          - !Ref ClusterSecurityGroup
        EndpointPublicAccess: true
        EndpointPrivateAccess: true
      Logging:
        ClusterLogging:
          EnabledTypes:
            - Type: api
            - Type: audit
            - Type: authenticator
            - Type: controllerManager
            - Type: scheduler
      Tags:
        - Key: Environment
          Value: !Ref Environment

  # Fargate Profile for system pods
  FargateProfileSystem:
    Type: AWS::EKS::FargateProfile
    Properties:
      ClusterName: !Ref EKSCluster
      FargateProfileName: !Sub 'fargate-system-${Environment}'
      PodExecutionRoleArn: !GetAtt FargatePodExecutionRole.Arn
      Subnets:
        - !Ref PrivateSubnetOne
        - !Ref PrivateSubnetTwo
      Selectors:
        - Namespace: kube-system
        - Namespace: default

  # Fargate Profile for application pods
  FargateProfileApp:
    Type: AWS::EKS::FargateProfile
    Properties:
      ClusterName: !Ref EKSCluster
      FargateProfileName: !Sub 'fargate-app-${Environment}'
      PodExecutionRoleArn: !GetAtt FargatePodExecutionRole.Arn
      Subnets:
        - !Ref PrivateSubnetOne
        - !Ref PrivateSubnetTwo
      Selectors:
        - Namespace: app
          Labels:
            environment: !Ref Environment

  # IAM Role for Fargate Pod Execution
  FargatePodExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: eks-fargate-pods.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonEKSFargatePodExecutionRolePolicy

  # ECR Repository
  ECRRepository:
    Type: AWS::ECR::Repository
    Properties:
      ImageScanningConfiguration:
        ScanOnPush: true
      EncryptionConfiguration:
        EncryptionType: KMS
      LifecyclePolicy:
        LifecyclePolicyText: |
          {
            "rules": [{
              "rulePriority": 1,
              "description": "Keep last 10 images",
              "selection": {
                "tagStatus": "any",
                "countType": "imageCountMoreThan",
                "countNumber": 10
              },
              "action": { "type": "expire" }
            }]
          }
      Tags:
        - Key: Environment
          Value: !Ref Environment

  # OIDC Provider for IRSA (IAM Roles for Service Accounts)
  # Note: OIDCProvider requires the cluster OIDC issuer URL.
  # After cluster creation, retrieve it with:
  #   aws eks describe-cluster --name <cluster-name> --query "cluster.identity.oidc.issuer"
  # Then create the OIDC provider via:
  #   eksctl utils associate-iam-oidc-provider --cluster <cluster-name> --approve

  # IAM Role for AWS Load Balancer Controller (IRSA)
  # The AWS Load Balancer Controller replaces the legacy ALB Ingress Controller.
  # It is installed via Helm after cluster creation and uses IRSA for permissions.
  AWSLoadBalancerControllerRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub 'AmazonEKSLoadBalancerControllerRole-${Environment}'
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Federated: !Sub 'arn:aws:iam::${AWS::AccountId}:oidc-provider/oidc.eks.${AWS::Region}.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE'
            Action: sts:AssumeRoleWithWebIdentity
            Condition:
              StringEquals:
                'oidc.eks.${AWS::Region}.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE:sub': 'system:serviceaccount:kube-system:aws-load-balancer-controller'
                'oidc.eks.${AWS::Region}.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE:aud': 'sts.amazonaws.com'
      Policies:
        - PolicyName: AWSLoadBalancerControllerPolicy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - ec2:DescribeAccountAttributes
                  - ec2:DescribeAddresses
                  - ec2:DescribeAvailabilityZones
                  - ec2:DescribeInternetGateways
                  - ec2:DescribeVpcs
                  - ec2:DescribeSubnets
                  - ec2:DescribeSecurityGroups
                  - ec2:DescribeInstances
                  - ec2:DescribeNetworkInterfaces
                  - ec2:DescribeTags
                  - ec2:GetCoipPoolUsage
                  - ec2:DescribeCoipPools
                  - elasticloadbalancing:DescribeLoadBalancers
                  - elasticloadbalancing:DescribeLoadBalancerAttributes
                  - elasticloadbalancing:DescribeListeners
                  - elasticloadbalancing:DescribeListenerCertificates
                  - elasticloadbalancing:DescribeSSLPolicies
                  - elasticloadbalancing:DescribeRules
                  - elasticloadbalancing:DescribeTargetGroups
                  - elasticloadbalancing:DescribeTargetGroupAttributes
                  - elasticloadbalancing:DescribeTargetHealth
                  - elasticloadbalancing:DescribeTags
                Resource: '*'
              - Effect: Allow
                Action:
                  - cognito-idp:DescribeUserPoolClient
                  - acm:ListCertificates
                  - acm:DescribeCertificate
                  - iam:ListServerCertificates
                  - iam:GetServerCertificate
                  - waf-regional:GetWebACL
                  - waf-regional:GetWebACLForResource
                  - waf-regional:AssociateWebACL
                  - waf-regional:DisassociateWebACL
                  - wafv2:GetWebACL
                  - wafv2:GetWebACLForResource
                  - wafv2:AssociateWebACL
                  - wafv2:DisassociateWebACL
                  - shield:GetSubscriptionState
                  - shield:DescribeProtection
                  - shield:CreateProtection
                  - shield:DeleteProtection
                Resource: '*'
              - Effect: Allow
                Action:
                  - ec2:AuthorizeSecurityGroupIngress
                  - ec2:RevokeSecurityGroupIngress
                  - ec2:CreateSecurityGroup
                  - ec2:CreateTags
                  - ec2:DeleteTags
                  - ec2:DeleteSecurityGroup
                  - ec2:DescribeSecurityGroupRules
                  - ec2:ModifySecurityGroupRules
                  - ec2:RevokeSecurityGroupEgress
                Resource: '*'
              - Effect: Allow
                Action:
                  - elasticloadbalancing:CreateLoadBalancer
                  - elasticloadbalancing:CreateTargetGroup
                  - elasticloadbalancing:CreateListener
                  - elasticloadbalancing:DeleteListener
                  - elasticloadbalancing:CreateRule
                  - elasticloadbalancing:DeleteRule
                  - elasticloadbalancing:AddTags
                  - elasticloadbalancing:RemoveTags
                  - elasticloadbalancing:ModifyLoadBalancerAttributes
                  - elasticloadbalancing:SetIpAddressType
                  - elasticloadbalancing:SetSecurityGroups
                  - elasticloadbalancing:SetSubnets
                  - elasticloadbalancing:DeleteLoadBalancer
                  - elasticloadbalancing:ModifyTargetGroup
                  - elasticloadbalancing:ModifyTargetGroupAttributes
                  - elasticloadbalancing:DeleteTargetGroup
                  - elasticloadbalancing:RegisterTargets
                  - elasticloadbalancing:DeregisterTargets
                  - elasticloadbalancing:SetWebAcl
                  - elasticloadbalancing:ModifyListener
                  - elasticloadbalancing:AddListenerCertificates
                  - elasticloadbalancing:RemoveListenerCertificates
                  - elasticloadbalancing:ModifyRule
                Resource: '*'

  # CloudWatch Log Group for EKS
  EKSLogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: !Sub '/aws/eks/${EKSCluster}/cluster'
      RetentionInDays: 7

Outputs:
  ClusterName:
    Description: EKS Cluster name
    Value: !Ref EKSCluster
    Export:
      Name: !Sub '${AWS::StackName}-ClusterName'

  ClusterArn:
    Description: EKS Cluster ARN
    Value: !GetAtt EKSCluster.Arn
    Export:
      Name: !Sub '${AWS::StackName}-ClusterArn'

  ClusterEndpoint:
    Description: EKS Cluster API endpoint
    Value: !GetAtt EKSCluster.Endpoint
    Export:
      Name: !Sub '${AWS::StackName}-ClusterEndpoint'

  ECRRepositoryUri:
    Description: ECR Repository URI
    Value: !Sub '${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${ECRRepository}'
    Export:
      Name: !Sub '${AWS::StackName}-ECRRepositoryUri'

  FargatePodExecutionRoleArn:
    Description: Fargate Pod Execution Role ARN
    Value: !GetAtt FargatePodExecutionRole.Arn
    Export:
      Name: !Sub '${AWS::StackName}-FargatePodExecutionRoleArn'

  LoadBalancerControllerRoleArn:
    Description: IAM Role ARN for AWS Load Balancer Controller (IRSA)
    Value: !GetAtt AWSLoadBalancerControllerRole.Arn
    Export:
      Name: !Sub '${AWS::StackName}-LBControllerRoleArn'