👏

Terraformを使って、AWS EKS(Kubernetes)クラスターを構築しALB経由でアクセスする

2023/02/25に公開

内容

Terraformを使って、AWS EKSのKubernetesクラスターを作成します。
また、そのEKSクラスター内で実行されているPodにALB経由でアクセスできるようにします。

準備

Terraformでネットワークを作成する

まずはKubernetesクラスターが動作するネットワークをTerraformで作成していきます。

module "vpc" {
  source = "terraform-aws-modules/vpc/aws"

  name                 = "eks-vpc"
  cidr                 = "10.0.0.0/16"
  enable_dns_hostnames = true

  azs             = ["ap-northeast-1a", "ap-northeast-1c", "ap-northeast-1d"]
  public_subnets  = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
  private_subnets = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]

  enable_nat_gateway = true
  single_nat_gateway  = true

  # これがないと後ほど作成するALBが自動で作成されません。
  public_subnet_tags = {
    "kubernetes.io/role/elb" = 1
  }

  tags = {
    Terraform   = "true",
    Environment = terraform.workspace
  }
}

PublicサブネットとPrivateサブネットを持つ、VPCを作成しました。

EKSクラスターを立ち上げる

今回はFargate Profileを使ったEKSクラスターを作成していきます。
※( https://github.com/terraform-aws-modules/terraform-aws-eks/tree/master/examples/fargate_profile )こちらの公式モジュールのexampleを元に必要な箇所だけ修正しました。

module "eks" {
  source = "terraform-aws-modules/eks/aws"
  version = "~> 19.0"

  cluster_name                   = "main-eks"
  cluster_version                = "1.25"
  cluster_endpoint_public_access = true

  cluster_addons = {
    kube-proxy = {}
    vpc-cni    = {}
    coredns = {
      configuration_values = jsonencode({
        computeType = "Fargate"
      })
    }
  }

  vpc_id                   = module.vpc.vpc_id
  subnet_ids               = module.vpc.private_subnets
  control_plane_subnet_ids = module.vpc.intra_subnets

  create_cluster_security_group = false
  create_node_security_group    = false

  fargate_profile_defaults = {
    iam_role_additional_policies = {
      additional = aws_iam_policy.additional.arn
    }
  }

  fargate_profiles = merge(
    {
      apps = {
        name = "apps"
        selectors = [
          {
            namespace = "apps"
          },
        ]
        subnet_ids = module.vpc.private_subnets
      }
    },
    { for i in range(3) :
      "kube-system-${i}" => {
        selectors = [
          { namespace = "kube-system" }
        ]
        subnet_ids = [element(module.vpc.private_subnets, i)]
      }
    }
  )
}

resource "aws_iam_policy" "additional" {
  name = "iam-eks-additional"

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = [
          "ec2:Describe*",
        ]
        Effect   = "Allow"
        Resource = "*"
      },
    ]
  })
}

これで、Kubernetesクラスターとそのクラスターが動作するVPCネットワークが完成しました。

EKSクラスターにNginxポッドを作成する

Contextを設定する

EKSクラスターが立ち上がったので、ローカルのターミナルからそのクラスターを操作できるように、Contextの設定を行います。

$ aws eks --region ap-northeast-1 update-kubeconfig --name "main-eks"

Namespaceを作成する

Fargate Profileによって、apps namespaceにPod等を配置するように設定しています。そのため、apps namespaceを作成します。

$ kubectl create ns apps
kubenamespace/apps created

Nginx Podを作成し、exposeする

次に、apps namespaceに対して、nginx Podを作成し、そのPodをexposeします。

$ kubectl run test-pod -n apps --image=nginx:latest
pod/test-pod created

$ kubectl expose pod test-pod --port=80 --target-port=80 -n apps
service/test-pod exposed

$ kubectl get all -n apps
NAME           READY   STATUS    RESTARTS   AGE
pod/test-pod   1/1     Running   0          3m7s

NAME               TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
service/test-pod   ClusterIP   172.20.38.47   <none>        80/TCP    38s

ALB経由でアクセスする

ネットワークとKubernetesクラスターが立ち上がり、そのクラスター内にPodを立てることもできたのでs、そのPodに対して、ALB経由でアクセスできるようにします。
※( https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/aws-load-balancer-controller.html )公式チュートリアルを参考にしています。

ALB IngressをKubernetesクラスターから作成できるように、ServiceAccountを作成する

まずは、ALBをKubernetesクラスターから作成できるように、ServiceAccountを作成します。

Policyの作成

AWS APIを呼び出すことが出来るALB用のIAMポリシーを作成します。

$ curl -O https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.4.4/docs/install/iam_policy.json
$ aws iam create-policy --policy-name AWSLoadBalancerControllerIAMPolicy --policy-document file://iam_policy.json

ClusterにServiceAccountを作成する

次に、今作成したPolicyをアタッチしたKubernetes Service Accountを作成します。

$ eksctl create iamserviceaccount \
  --cluster=main-eks \
  --namespace=kube-system \
  --name=aws-load-balancer-controller \
  --role-name AmazonEKSLoadBalancerControllerRole \
  --attach-policy-arn=arn:aws:iam::<AWS Account ID>:policy/AWSLoadBalancerControllerIAMPolicy \
  --approve

AWS Account IDの部分はご自分のAWSアカウントのIDに変更してください。

$ kubectl describe sa aws-load-balancer-controller -n kube-system
Name:                aws-load-balancer-controller
Namespace:           kube-system
Labels:              app.kubernetes.io/managed-by=eksctl
Annotations:         eks.amazonaws.com/role-arn: arn:aws:iam::1111111111:role/AmazonEKSLoadBalancerControllerRole
Image pull secrets:  <none>
Mountable secrets:   <none>
Tokens:              <none>
Events:              <none>

正常にServiceAccountがクラスター内に作成されました。

HELMを使ってALBをデプロイする

HELMを使って、AWS Load Balancer Controllerをインストールする

$ helm repo add eks https://aws.github.io/eks-charts
$ helm repo update
$ helm install aws-load-balancer-controller eks/aws-load-balancer-controller \
  -n kube-system \
  --set clusterName=main-eks \
  --set region=ap-northeast-1 \
  --set serviceAccount.create=false \
  --set vpcId=<VPC ID> \
  --set serviceAccount.name=aws-load-balancer-controller 

# コントローラが正常にインストールされているかを確認する
$ kubectl get deployment -n kube-system aws-load-balancer-controller
NAME                           READY   UP-TO-DATE   AVAILABLE   AGE
aws-load-balancer-controller   2/2     2            2           4m49s

VPC IDの部分はご自分のAWSVPCのIDに変更してください。

これで、 ALBを作成するためのAnnotationを付与したIngressを作成すれば、KubernetesがALBを自動でセットアップしてくれる準備が整いました。最後に、Ingressを作成し、NginxPodにトラフィックを流します。

Ingressを作成し、nginx Podに接続する

最後に、Ingressを作成し、ALBを作成します。以下のyamlファイルを kubectl apply ingress.yaml して、Kubernetesクラスターに適用します。

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  namespace: apps
  name: ingress
  annotations:
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
spec:
  ingressClassName: alb
  rules:
    - http:
        paths:
        - path: /
          pathType: Prefix
          backend:
            service:
              name: test-pod
              port:
                number: 80

しばらくすると、

$ kubectl apply ingress.yaml
$ kubectl get ingress -n apps
NAMESPACE   NAME      CLASS   HOSTS   ADDRESS                                PORTS   AGE
apps        ingress   alb     *       ....ap-northeast-1.elb.amazonaws.com   80      4m12s

といった具合に自動付与されたDNS名が表示されるので、そのDNSにアクセスするとnginxの初期画面が表示されます!

$ curl ....ap-northeast-1.elb.amazonaws.com
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

これで、EKSクラスターをTerraformで作成して、ALBを使ってクラスター内で動作するPodにアクセスすることができました!

note

勉強法やキャリア構築法など、エンジニアに役立つ記事をnoteで配信しています。

https://note.com/ring_belle/membership

Discussion