LoginSignup
6
5

More than 3 years have passed since last update.

EKSでクラスタを作成した後にやるべきこと

Last updated at Posted at 2019-10-19

概要

  • AWSのマネージドKubernetesサービスであるEKSでクラスタを作成した後、アプリケーションを稼働させる前にセットアップしておくべきツールをまとめました

セットアップするもの

kube2iam

  • Pod単位でIAM Roleを付与できるツール

AWS ALB Ingress Controller

  • Ingressリソースを作成するためのコントローラー

External DNS

  • Ingressリソースの作成時に構築されるLoad BalancerのDNS名を自動的にRoute53に登録してくれる

Container Insights

  • Podのログやリソースの情報をCloudWatchで見れるようにする

Clustor Autoscaler

  • そのまんまClustor Autoscaler
    • Worker Nodeのオートスケーラー

前提

  • EKSのクラスタ、及びそれに紐付くWorker Nodeが稼働している

kube2iam

  • 稼働しているPod単位でIAM Roleを付与できるようになる
  • このようなツールを使わない場合、Podに権限を付与する場合は以下の2通りの方法がある

    1. PodにIAM Userのクレデンシャルを埋め込む(Configファイルや環境変数など)
    2. 稼働しているEC2のIAM Roleに必要なPolicyを付与する
  • 1の場合はPodもしくは必要なロール単位でIAM Userを作成する必要があり、なおかつ安全のためSecretリソースを作成する必要がある

  • 2の場合は対象のEC2上で稼働し得るPodで必要な全てのPolicyを付与する必要があり、セキュリティ的によろしくない(例えば、1つのPodがS3にアクセスする必要がある場合、そのEC2上で稼働している全てのPodにS3へアクセスできるPolicyが付与されてしまう)

  • これらの問題解決や手間を省いてくれるツールが今回導入するkube2iam

  • 同様のツールでkiamというものもあるが、kiamはServerというコンポーネントをMaster Nodeで動かすことを前提としているため、EKSでは使えない

構築

kube2iam-sa.yaml

  • ServiceAccountとClusterRoleを作成し、それらを基にClusterRoleBindingを作成

kube2iam-ds.yaml

  • kube2iamとしての処理を行うPodがDaemonsetとしてデプロイされる
  • kube2iam-sa.yamlで作成したServiceAccountがアタッチされる

  • 以下のようにデプロイ

$ kubectl apply -f kube2iam-sa.yaml
$ kubectl apply -f kube2iam-ds.yaml

使用方法

  • PodにアタッチするIAM Roleを作成
    • ここでは以下のようなRoleを作成

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "sts:AssumeRole"
      ],
      "Effect": "Allow",
      "Resource": "*"
    }
  ]
}
  • 作成したIAM RoleのTrust RelationshipにStatementを追加
    • 追加しているのは2つ目のStatement
    • Principal.AWSにはWorker Nodeに付与されているIAM Roleを指定する
  • これによりWorker NodeがAssume Roleによってセッション情報を取得できるようになる
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": "ec2.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    },
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::123456789012:role/kubernetes-worker-role"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
  • マニフェストファイルの編集
    • Deploymentの場合はspec.template.metadata.annotationsにKeyをiam.amazonaws.com/role、ValueをIAM Roleのarnとして記載する
    • 以下の例では、nginx-deploymentから作成されるPodにはsample-roleというIAM Roleが付与される
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 3
  template:
    metadata:
      annotations:
        iam.amazonaws.com/role: sample-role
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.9.1
        ports:
        - containerPort: 80

参考

AWS ALB Ingress Controller

  • EKSにIngressリソースを作成するためのコントーローラーを作成
  • Ingressコントローラーにもいくつか種類があるが、ここでは公式ドキュメントで紹介されているALB Ingress Controllerを採用

構築

ここでの手順は、kube2iamのセットアップが完了していることが前提となっています

  • IAM Policy作成
    • Ingress Controllerに付与するIAM Roleを作成する前に、そのRoleにアタッチするIAM Policyを作成
    • 以下のようなPolicyを作成
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "acm:DescribeCertificate",
        "acm:ListCertificates",
        "acm:GetCertificate"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "ec2:AuthorizeSecurityGroupIngress",
        "ec2:CreateSecurityGroup",
        "ec2:CreateTags",
        "ec2:DeleteTags",
        "ec2:DeleteSecurityGroup",
        "ec2:DescribeInstances",
        "ec2:DescribeInstanceStatus",
        "ec2:DescribeSecurityGroups",
        "ec2:DescribeSubnets",
        "ec2:DescribeTags",
        "ec2:DescribeVpcs",
        "ec2:ModifyInstanceAttribute",
        "ec2:ModifyNetworkInterfaceAttribute",
        "ec2:RevokeSecurityGroupIngress"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "elasticloadbalancing:AddTags",
        "elasticloadbalancing:CreateListener",
        "elasticloadbalancing:CreateLoadBalancer",
        "elasticloadbalancing:CreateRule",
        "elasticloadbalancing:CreateTargetGroup",
        "elasticloadbalancing:DeleteListener",
        "elasticloadbalancing:DeleteLoadBalancer",
        "elasticloadbalancing:DeleteRule",
        "elasticloadbalancing:DeleteTargetGroup",
        "elasticloadbalancing:DeregisterTargets",
        "elasticloadbalancing:DescribeListeners",
        "elasticloadbalancing:DescribeLoadBalancers",
        "elasticloadbalancing:DescribeLoadBalancerAttributes",
        "elasticloadbalancing:DescribeRules",
        "elasticloadbalancing:DescribeSSLPolicies",
        "elasticloadbalancing:DescribeTags",
        "elasticloadbalancing:DescribeTargetGroups",
        "elasticloadbalancing:DescribeTargetGroupAttributes",
        "elasticloadbalancing:DescribeTargetHealth",
        "elasticloadbalancing:ModifyListener",
        "elasticloadbalancing:ModifyLoadBalancerAttributes",
        "elasticloadbalancing:ModifyRule",
        "elasticloadbalancing:ModifyTargetGroup",
        "elasticloadbalancing:ModifyTargetGroupAttributes",
        "elasticloadbalancing:RegisterTargets",
        "elasticloadbalancing:RemoveTags",
        "elasticloadbalancing:SetIpAddressType",
        "elasticloadbalancing:SetSecurityGroups",
        "elasticloadbalancing:SetSubnets",
        "elasticloadbalancing:SetWebACL"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "iam:GetServerCertificate",
        "iam:ListServerCertificates"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "waf-regional:GetWebACLForResource",
        "waf-regional:GetWebACL",
        "waf-regional:AssociateWebACL",
        "waf-regional:DisassociateWebACL"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "tag:GetResources",
        "tag:TagResources"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "waf:GetWebACL"
      ],
      "Resource": "*"
    }
  ]
}
  • IAM Role作成
    • 先ほど作成したIAM PolicyをアタッチしたIAM Roleを作成
    • Trust relationshipにStatementを追加する(kube2iamの章を参照)
  • ServiceAccount、ClusterRole、ClusterRoleBindingを作成
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.1.2/docs/examples/rbac-role.yaml
$ kubectl apply -f alb-ingress-controller.yaml
  • サブネットにタグを付与
    • AWS ALB Ingress Controllerから検知されるよう、Public Subnetに以下2つのTagを付与
      • kubernetes.io/role/alb-ingress:(ブランク)
      • kubernetes.io/role/elb:1 ## Ingressリソースのマニフェストファイル修正
  • Ingressリソースを作成する際は、マニフェストファイルのannotationsに以下を追記
  • 以下一例
annotations:
    kubernetes.io/ingress.class: alb
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS":443}]'
    alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:ap-northeast-1:XXXXXXXXXXXXX:certificate/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX
    alb.ingress.kubernetes.io/actions.[ingressで指定するserviceName]: '{"Type": "redirect", "RedirectConfig": { "Protocol": "HTTPS", "Port": "443", "StatusCode": "HTTP_301"}}'
    alb.ingress.kubernetes.io/waf-acl-id: XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX
    alb.ingress.kubernetes.io/security-groups: sg-XXXXXXXXXXXXXXXX
  • alb.ingress.kubernetes.io/listen-ports
    • LoadBalancerで受け付けるプロトコルを指定
    • HTTPのトラッフィクをHTTPSにリダイレクトさせたい場合も、上記のようにHTTPとHTTPSどちらも指定する
  • alb.ingress.kubernetes.io/certificate-arn
    • HTTPSのトラフィックを受け付ける場合は、Certificate Managerで作成した証明書のarnを記載する
  • alb.ingress.kubernetes.io/actions.[ingressで指定するserviceName]
    • HTTPのトラフィックをHTTPSにリダイレクトさせる場合に必要
    • この際、Ingressリソースのマニフェストファイルにも変更が必要になる
    • spec.rules.http.pathsの一番上にpathを追記
      • 上から優先順位をつけてLoadBalancerのruleに適用されるため
    • これによりLoadBalancerのruleにリダイレクトが追加される
- path: /*
  backend:
    serviceName: [annotationで指定したserviceName]
    servicePort: use-annotation
  • alb.ingress.kubernetes.io/waf-acl-id

    • LoadBalancerにWAFをアタッチする場合、ACLのIDを記載
  • alb.ingress.kubernetes.io/security-groups

    • LoadBalancerにアタッチするSecurity Groupを指定
    • 何も指定しないと自動でSecurity Groupが作成されるが、基本的に指定することを推奨
      • 自動で作成されたSecurity GroupはNetwork Interfaceにアタッチされるが、アタッチできるSecurity Groupの上限数は5、申請しても最大で16個まで。作成するIngressリソース数が限られていることが事前に分かっている場合には不要かもしれないが、稼働させたアプリが増えた際などのエラーを防ぐためにも指定しておいた方がベター。
      • また、事前に作成したSecurity Groupを指定した場合には、Worker NodeのSecurity GroupのInboundで、このSecurity Groupからの通信を許可しておく必要がある。
        • これをしないとHealth Checkが通らなくなる、、、
  • 他のAnnotationはここで確認できる

参考

External DNS

  • Ingressのデプロイが検知されると自動的にRoute53へドメインの登録を行ってくれる

IAM Policy作成

  • External DNSに付与するRoleにアタッチするためのIAM Policyを作成
  • 以下のようなPolicyを作成
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "route53:ChangeResourceRecordSets"
            ],
            "Resource": [
                "arn:aws:route53:::hostedzone/*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "route53:ListHostedZones",
                "route53:ListResourceRecordSets"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}

IAM Role作成

  • 先ほど作成したIAM PolicyをアタッチしたIAM Roleを作成
  • Trust relationshipにStatementを追加(kube2iamの章を参照)

マニフェストファイル作成

  • 以下のファイルを作成
  • 修正点は2点
    • Deploymentのspec.templete.metadata.annotations.iam.amazonaws.com/roleに先ほど作成したExternal DNS用のIAM RoleのArnを指定する
    • Deploymentのspec.templete.spec.containers.argsのdomain-filterに使用するドメイン(XXXX.com)を指定
apiVersion: v1
kind: ServiceAccount
metadata:
  name: external-dns
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
  name: external-dns
rules:
  - apiGroups:
      - ""
    resources:
      - "services"
    verbs:
      - "get"
      - "watch"
      - "list"
  - apiGroups:
      - ""
    resources:
      - "pods"
    verbs:
      - "get"
      - "watch"
      - "list"
  - apiGroups:
      - "extensions"
    resources:
      - "ingresses"
    verbs:
      - "get"
      - "watch"
      - "list"
  - apiGroups:
      - ""
    resources:
      - "nodes"
    verbs:
      - "list"
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: external-dns-viewer
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: external-dns
subjects:
- kind: ServiceAccount
  name: external-dns
  namespace: kube-system
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: external-dns
  namespace: kube-system
spec:
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: external-dns
      annotations:
        iam.amazonaws.com/role: route53-externaldns
    spec:
      serviceAccountName: external-dns
      containers:
      - name: external-dns
        image: registry.opensource.zalan.do/teapot/external-dns:v0.5.9
        args:
        - --source=service
        - --source=ingress
        - --domain-filter=XXXX.com
        - --provider=aws
        - --policy=sync
        - --registry=txt
        - --txt-owner-id=prod
  • 同じホストを複数のクラスタで共有する場合、--txt-owner-idはクラスタ毎に異なる値を設定する
    • 同じidが使われていると、どのクラスタで作成されたものか判断がつかず、誤削除されてしまう

参考

Container Insights

IAM Role作成

  • CloudWatchAgentServerPolicy(AWSのデフォルトで作成されているPolicy)をアタッチしたIAM Roleを作成
  • Trust relationshipにStatementを追加(kube2iamの章を参照)

CloudWatchエージェントのセットアップ

  • Namespaceの作成
$ curl -O https://s3.amazonaws.com/cloudwatch-agent-k8s-yamls/kubernetes-monitoring/cloudwatch-namespace.yaml
$ kubectl apply -f cloudwatch-namespace.yaml
  • ServiceAccountの作成
$ curl -O https://s3.amazonaws.com/cloudwatch-agent-k8s-yamls/kubernetes-monitoring/cwagent-serviceaccount.yaml
$ kubectl apply -f cwagent-serviceaccount.yaml
  • ConfigMap作成
    • ファイル内の{{cluster-name}}を対象のクラスタ名に変更
$ curl -O https://s3.amazonaws.com/cloudwatch-agent-k8s-yamls/kubernetes-monitoring/cwagent-configmap.yaml
$ kubectl apply -f cwagent-configmap.yaml
  • CloudWatch エージェントをデプロイ
    • ファイル内のspec.template.metadata.annotationsにiam.amazonaws.com/roleを追記して、事前に作成したIAM Role名を記載する
$ curl -O https://s3.amazonaws.com/cloudwatch-agent-k8s-yamls/kubernetes-monitoring/cwagent-daemonset.yaml
$ kubectl apply -f cwagent-daemonset.yaml
  • 確認
    • CloudWatch MetricsでContinerInsightsというメトリクスが作成されている

FluentDのセットアップ

  • FluendDのインストール
    • CloudWatch エージェントの際と同じようにfluentd.ymlにIAM Roleのannotationを追記しておく
$ curl -O https://s3.amazonaws.com/cloudwatch-agent-k8s-yamls/fluentd/fluentd.yml
$ kubectl create configmap cluster-info \
--from-literal=cluster.name=[cluster_name] \
--from-literal=logs.region=[region_name] -n amazon-cloudwatch
$ kubectl apply -f fluentd.yml
  • 確認
    • CloudWatch Logsで以下のロググループが3つ作成されている
      • /aws/containerinsights/Cluster_Name/application
      • /aws/containerinsights/Cluster_Name/host
      • /aws/containerinsights/Cluster_Name/dataplane

参考

Clustor Autoscaler

  • EC2のAutoScalingGroupに紐づいてオートスケールが行われる
  • StatusがPendingのPodが存在することがトリガーになる

IAM Polocy作成

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "autoscaling:DescribeAutoScalingGroups",
                "autoscaling:DescribeAutoScalingInstances",
                "autoscaling:DescribeLaunchConfigurations",
                "autoscaling:DescribeTags",
                "autoscaling:SetDesiredCapacity",
                "autoscaling:TerminateInstanceInAutoScalingGroup",
                "ec2:DescribeLaunchTemplateVersions"
            ],
            "Resource": "*"
        }
    ]
}

IAM Role作成

  • 先ほど作成したPolicyがアタッチされたRoleを作成
  • Trust relationshipにStatementを追加(kube2iamの章を参照)

デプロイ

  • マニフェストファイルを取得
    • マニフェストファイルに明示的にAutoScalingGroupの名前を記載する方法もあるが、ここでは自動的にAutoScalingGroupを検知する方法(autodiscover)を採用する
    • AutoScalingGroupのタグで判別される
$ wget https://raw.githubusercontent.com/kubernetes/autoscaler/master/cluster-autoscaler/cloudprovider/aws/examples/cluster-autoscaler-autodiscover.yaml
  • Deploymentのspec.template.spec.containers.command内の--node-group-auto-discovery末尾のクラスタ名を対象のものに書き換える
command:
    - ./cluster-autoscaler
    - --v=4
    - --stderrthreshold=info
    - --cloud-provider=aws
    - --skip-nodes-with-local-storage=false
    - --expander=least-waste
    - --node-group-auto-discovery=asg:tag=k8s.io/cluster-autoscaler/enabled,k8s.io/cluster-autoscaler/<YOUR CLUSTER NAME>
  • Deploymentのspec.template.metadata.annotationsに先ほど作成したRoleのarnを記載する
  • オートスケールさせるAutoScalingGroupのタグに以下のキーを追加(バリューは空でOK)

    • k8s.io/cluster-autoscaler/enabled
    • k8s.io/cluster-autoscaler/[クラスタ名]
  • デプロイ

$ kubectl apply -f cluster-autoscaler-autodiscover.yaml

確認

  • レプリカ数を適当な数に設定する
$ kubectl create deployment autoscaler-demo --image=nginx
$ kubectl scale deployment autoscaler-demo --replicas=100
  • Nodeが増えていればセットアップ完了!

参考

6
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5