{Terraform} Deploying Docker in AWS EKS

 

参考文献: Terraform Up & Running (Yevgeniy Brikman著)

cd
mkdir -p ~/20231121
cd 20231121

 

     
-- 1. k8sモジュール作成

mkdir -p ~/20231121/modules/services/k8s-app

cat <<-'EOF' > ~/20231121/modules/services/k8s-app/variables.tf


variable "name" {
  description ="name"
  type = string
}

variable "image" {
  description = "image"
  type = string
}

variable "container_port" {
  description = "container_port"
  type = number
}

variable "replicas" {
  description = "replicas"
  type = number
}

variable "environment_variables" {
  description = "environment_variables"
  type = map(string)
  default = {}
}

EOF

 

cat <<-'EOF' > ~/20231121/modules/services/k8s-app/main.tf

terraform {
  required_version = ">= 1.0.0, < 2.0.0"
  
  required_providers {
    kubernetes = {
      source = "hashicorp/kubernetes"
      version = "~> 2.0"
    }
  }
}

locals {
  pod_labels = {
    app = var.name
  }
}

resource "kubernetes_deployment" "app" {
  metadata {
    name = var.name
  }
  
  spec {
    replicas = var.replicas
    
    template{
      metadata {
        labels = local.pod_labels
      }
    
      spec {
        container {
          name = var.name
          image = var.image
          
          port {
            container_port = var.container_port
          }
          
          dynamic "env" {
            for_each = var.environment_variables
            content {
              name = env.key
              value = env.value
            }
          }
        }
      }
    }


    selector {
      match_labels = local.pod_labels
    }
  }
}

 


resource "kubernetes_service" "app" {
  metadata {
    name = var.name
  }
  
  spec {
    type = "LoadBalancer"
    port {
      port = 80
      target_port = var.container_port
      protocol = "TCP"
    }
    selector = local.pod_labels
  }
}


EOF

 


cat <<-'EOF' > ~/20231121/modules/services/k8s-app/outputs.tf

locals {
  status = kubernetes_service.app.status
}


output "service_endpoint" {
  value = try(
    "http://${local.status[0]["load_balancer"][0]["ingress"][0]["hostname"]}",
    "(error parsing hostnmame from status)"
  )
  description = "service_endpoint"
}

EOF


-- 2. EKSモジュール作成


mkdir -p ~/20231121/modules/services/eks-cluster


cat <<-'EOF' > ~/20231121/modules/services/eks-cluster/variables.tf


variable "name" {
  description = "name"
  type = string
}

variable "min_size" {
  description = "min_size"
  type = number
}

variable "max_size" {
  description = "max_size"
  type = number
}

variable "desired_size" {
  description = "desired_size"
  type = number
}

variable "instance_types" {
  description = "instance_types"
  type = list(string)
}


EOF

 


cat <<-'EOF' > ~/20231121/modules/services/eks-cluster/main.tf


terraform {
  required_version = "= 1.6.0"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "= 4.17.0"
    }
  }
}


provider "aws" {
  region = "ap-northeast-1"
}


resource "aws_iam_role" "cluster" {
  name = "${var.name}-cluster-role"
  assume_role_policy = data.aws_iam_policy_document.cluster_assume_role.json
}

data "aws_iam_policy_document" "cluster_assume_role" {
  statement {
    effect = "Allow"
    actions = ["sts:AssumeRole"]
    principals {
      type = "Service"
      identifiers = ["eks.amazonaws.com"]
    }
  }
}

resource "aws_iam_role_policy_attachment" "AmazonEKSClusterPolicy" {
  policy_arn = "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy"
  role = aws_iam_role.cluster.name
}

data "aws_vpc" "default" {
  default = true
}

data "aws_subnets" "default" {
  filter {
    name = "vpc-id"
    values = [data.aws_vpc.default.id]
  }
}

resource "aws_eks_cluster" "cluster" {
  name = var.name
  role_arn = aws_iam_role.cluster.arn
  version = "1.28"
  
  vpc_config {
    subnet_ids = data.aws_subnets.default.ids
  }
  
  depends_on = [
    aws_iam_role_policy_attachment.AmazonEKSClusterPolicy
  ]
}


resource "aws_iam_role" "node_group" {
  name = "${var.name}-node-group"
  assume_role_policy = data.aws_iam_policy_document.node_assume_role.json
}

data "aws_iam_policy_document" "node_assume_role" {
  statement {
    effect = "Allow"
    actions = ["sts:AssumeRole"]
    
    principals {
      type = "Service"
      identifiers = ["ec2.amazonaws.com"]
    }
  }
}

resource "aws_iam_role_policy_attachment" "AmazonEKSWorkerNodePolicy" {
  policy_arn ="arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy"
  role = aws_iam_role.node_group.name
}


resource "aws_iam_role_policy_attachment" "AmazonEC2ContainerRegistryReadOnly" {
  policy_arn ="arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly"
  role = aws_iam_role.node_group.name
}

resource "aws_iam_role_policy_attachment" "AmazonEKS_CNI_Policy" {
  policy_arn ="arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy"
  role = aws_iam_role.node_group.name
}


resource "aws_eks_node_group" "nodes" {
  cluster_name = aws_eks_cluster.cluster.name
  node_group_name = var.name
  node_role_arn = aws_iam_role.node_group.arn
  subnet_ids = data.aws_subnets.default.ids
  instance_types = var.instance_types
  
  scaling_config {
    min_size = var.min_size
    max_size = var.max_size
    desired_size = var.desired_size
  }
  
  depends_on = [
    aws_iam_role_policy_attachment.AmazonEKSWorkerNodePolicy,
    aws_iam_role_policy_attachment.AmazonEC2ContainerRegistryReadOnly,
    aws_iam_role_policy_attachment.AmazonEKS_CNI_Policy,
  ]
}


EOF

 

cat <<-'EOF' > ~/20231121/modules/services/eks-cluster/outputs.tf

output "cluster_name" {
  value = aws_eks_cluster.cluster.name
  description = "cluster_name"
}

output "cluster_arn" {
  value = aws_eks_cluster.cluster.arn
  description = "cluster_arn"
}

output "cluster_endpoint" {
  value = aws_eks_cluster.cluster.endpoint
  description = "cluster_endpoint"
}

output "cluster_certificate_authority" {
  value = aws_eks_cluster.cluster.certificate_authority
  description = "cluster_certificate_authority"
}

EOF

 

-- 3. メインモジュール作成


mkdir -p  ~/20231121/examples/kubernetes-eks

cat <<-'EOF' > ~/20231121/examples/kubernetes-eks/main.tf

 

provider "aws" {
  region = "ap-northeast-1"
}

module "eks_cluster" {
  source = "../../modules/services/eks-cluster"
  name = "example-eks-clsuter"
  min_size = 1
  max_size = 2
  desired_size = 1
  
  instance_types = ["t3.small"]
}
  


provider "kubernetes" {
  host = module.eks_cluster.cluster_endpoint
  cluster_ca_certificate = base64decode(
    module.eks_cluster.cluster_certificate_authority[0].data
  )
  token = data.aws_eks_cluster_auth.cluster.token
}

data "aws_eks_cluster_auth" "cluster" {
  name = module.eks_cluster.cluster_name
}

module "simple_webapp" {
  source = "../../modules/services/k8s-app"
  
  name = "simple-webapp"
  image = "training/webapp"
  replicas = 2
  container_port = 5000
  
  environment_variables = {
    PROVIDER = "Terraform"
  }
  
  depends_on = [module.eks_cluster]
}

EOF

cat <<-'EOF' > ~/20231121/examples/kubernetes-eks/variables.tf

output "service_endpoint" {
  value = module.simple_webapp.service_endpoint
  description = "service_endpoint"
}

EOF


-- 4. 動作確認

cd ~/20231121/examples/kubernetes-eks

terraform init
terraform fmt
terraform -version

terraform plan

 


terraform apply -auto-approve


aws eks update-kubeconfig --region ap-northeast-1 --name example-eks-clsuter

kubectl get nodes
kubectl get deployments
kubectl get pods
kubectl get services


terraform destroy -auto-approve