Kubernetes入門

複数ホスト間でもコンテナな環境を統合的に管理することができるKubernetesについて、以下の構成でまとめました。

  • アーキテクチャ
  • リソース種類
  • マニフェストの設定
  • kubectlの使用方法
  • トラブルシューティング
  • 監視(Prometheus+Grafana)
  • EKS固有

Architecture

Components

大きく以下のコンポーネントで構成

  • Control Plane
    • kube-apiserver : Kubernetes APIを受けるAPI Server
    • etcd : 全クラスターのデータを保存する一貫性と高可用性を備えたKVS
    • kube-scheduler : 新たに作成されて、未割り当て状態のノードを監視し、それらをkube-apiserverにリクエストを送ってスケジューリング
    • kube-controller-manager : プロセス制御。Node controller, Replication controller, Endpoints controller, Service Account & Token controllersを含む
    • cloud-controller-manager : クラウド固有の制御ロジックを埋め込み、クラウドプロバイダーAPIとクラスターを関連付け
  • Node
    • kubelet : Pod上でコンテナの起動や停止を管理
    • kube-proxy : Serviceリソースが作られた際にClusteIPやNodePort宛のトラフィックがPodに転送
    • Container Runtime : コンテナを稼働させるソフトウェア。Docker, containerd, CRI-O等

各コンポーネント詳細については、Kubernetes Components を参照

Diagram

Kubernetesのアーキテクチャ

(Reference) Kubernetes Components

Resources

Overview

リソースは大きく以下の5種類。詳細はConceptsを参照。

  • Workloads : クラスター上にコンテナを起動させるのに利用するリソース
    • Pod
    • ReplicaSet
    • Deployment
    • StatefulSet
    • Job
    • CronJob
  • Discovery & LB : クラスター上のコンテナに対するエンドポイントの提供やラベルに一致するコンテナのディスカバリーに利用されるリソース
    • Service : L4ロードバランシング
      • ClusterIP
      • NodePort
      • LoadBalancer
      • Headless
      • ExternalName
    • Ingress : L7ロードバランシング
  • Config & Storage : コンテナに対して設定ファイル、パスワードなどの機密情報などをインジェクトしたり、永続化ボリュームを提供したりするためのリソース
    • Secret
    • ConfigMap
    • PersistentVolumeClaim
  • Cluster : セキュリティ周りの設定やクォータの設定等、クラスターの挙動を制御するリソース
    • Node
    • NameSpace
    • PersistentVolume
    • ResourceQuota
    • ServiceAccount
    • Role
    • ClusterRole
    • RoleBinding
    • ClusterRoleBinding
    • NetworkPolicy
  • Metadata : クラスター上にコンテナを起動させるのに利用するリソース
    • LimitRange
    • HorizontalPodAutoscaler
    • PodDisruptionBudget
    • CustomResourceDefinition

(参考) Kubernetes完全ガイド

Example

Workloads

PodがWorkloadsリソースの最小単位となります。Podのマニフェストファイルの例は以下のようになります。

apiVersion: v1
kind: Pod
metadata:
  name: pod-mywebsite
spec:
  containers:
    - name: mywebsite-container
      image: mywebsite:latest
      imagePullPolicy: IfNotPresent

それに対してReplicaSetによりPodのレプリカが作成され、指定した数のPodを維持し続けるようにします。 spec.template,spec.containersでPod定義を行います。

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: replicaset-mywebsite
spec:
  replicas: 3
  selector:
    matchLabels:
      app: mywebsite
  template:
    metadata:
      labels:
        app: mywebsite
    spec:
      containers:
        - name: mywebsite-container
          image: mywebsite:latest
          imagePullPolicy: IfNotPresent

そして、Deploymentが複数のReplicaSetを管理することで、ローリングアップデートやロールバック等を実現します。 spec以下でReplicaSetの定義を行い、spec.template.spec.containers以下でPod定義を行います。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deployment-mywebsite
spec:
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 0
      maxSurge: 3
  replicas: 3
  selector:
    matchLabels:
      app: mywebsite
  template:
    metadata:
      labels:
        app: mywebsite
    spec:
      containers:
        - name: mywebsite-container
          image: mywebsite:latest
          imagePullPolicy: IfNotPresent

ReplicaSetで起動したインスタンスに対してリクエストを割り振るには、Serviceリソースでロードバランサーの作成を行い、こちらのエンドポイントに対してアクセスすることで可能です。

実際にEKSでKubernetesのクラスターの作成を行い、Auto Scalingで起動したインスタンスをNLBでリクエストを受けるような構成の組み方は以下を参照ください。

EKSを利用してKubernetesでSpring MVCをデプロイ(NLB + Auto Scaling)

Serviceリソース、Secretリソース、Deploymentリソースを使用します。マニフェストファイルのみの概要を説明すると大きく以下の3つに別れます。

  1. NLBの設定
  2. 機密情報の受け渡し設定
  3. コンテナ設定

NLBの設定のマニフェストファイルについては以下のようになります。

  • service-nlb.yaml
apiVersion: v1
kind: Service
metadata:
  name: mywebsite-service
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-type: nlb
    service.beta.kubernetes.io/aws-load-balancer-ssl-cert: "arn:aws:acm:us-west-2:xxxxxxxxxxxx:certificate/c97dad88-731f-4cd0-939c-1565e7db1c6d"
    service.beta.kubernetes.io/aws-load-balancer-backend-protocol: "http"
    service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "https"

spec:
  type: LoadBalancer
  selector:
    app: mywebsite
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 80
    - name: https
      protocol: TCP
      port: 443
      targetPort: 80

機密情報の受け渡し設定のためのマニフェストファイルについては以下のようになります。YAMLファイルとして作成する場合は、Pod上から呼び出す名前の変数名に対してBase64でエンコーディングした値を設定することがポイントとなります。この例では、サンプルのエンドポイントに対してBase64でエンコードしたものを記載していますが、実際にはデコードはかなり容易なため管理には注意ください。

  • secret-mywebsite.yaml
apiVersion: v1
kind: Secret
metadata:
  name: mywebsite-secret
data:
  dbhost: amRiYzpteXNxbDovL3h4eHh4eHh4eHgueXl5eXl5eXl5eS51cy13ZXN0LTIucmRzLmFtYXpvbmF3cy5jb206MzMwNi9teXdlYnNpdGU=
  dbuser: c2FtcGxldXNlcg==
  dbpassword: VGVzdDEyMzQ=
  cachehost: enp6enp6enp6ei5hYWFhYWEubmcuMDAwMS51c3cyLmNhY2hlLmFtYXpvbmF3cy5jb20=

PodがWorkloadsリソースの最小単位となります。それに対してReplicaSetによりPodのレプリカが作成され、指定した数のPodを維持し続けるようにします。そして、Deploymentが複数のReplicaSetを管理することで、ローリングアップデートやロールバック等を実現します。

Pod定義部分のenv以下でアプリケーションから読み込む環境変数名と先ほどSecretで指定した変数名と関連付けます。Secretリソースの機能を使用せずに直接値を指定する場合は、valueFrom:の代わりにvalue:で目的の値を指定します。

  • deployment-mywebiste.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deployment-mywebsite
spec:
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 0
      maxSurge: 3
  replicas: 3
  selector:
    matchLabels:
      app: mywebsite
  template:
    metadata:
      labels:
        app: mywebsite
    spec:
      containers:
        - name: mywebsite-container
          image: xxxxxxxxxxxx.dkr.ecr.us-west-2.amazonaws.com/mywebsite:v1
          ports:
            - containerPort: 80
          env:
          - name: DBHOST
            valueFrom:
              secretKeyRef:
                name: mywebsite-secret
                key: dbhost
          - name: DBUSER
            valueFrom:
              secretKeyRef:
                name: mywebsite-secret
                key: dbuser
          - name: DBPASSWORD
            valueFrom:
              secretKeyRef:
                name: mywebsite-secret
                key: dbpassword
          - name: CACHEHOST
            valueFrom:
              secretKeyRef:
                name: mywebsite-secret
                key: cachehost
          resources:
            requests:
              memory: 512Mi
              cpu: 250m
            limits:
              memory: 4096Mi
              cpu: 1000m

Kind

YAMLファイル中のkindで指定するオブジェクトの種類一覧

  • Binding
  • ComponentStatus
  • ConfigMap
  • Endpoints
  • Event
  • LimitRange
  • Namespace
  • Node
  • PersistentVolume
  • Pod
  • PodTemplate
  • ResourceQuota
  • Secret
  • ServiceAccount
  • Service
  • APIService
  • ControllerRevision
  • DaemonSet
  • Deployment
  • ReplicaSet
  • StatefulSet
  • TokenReview
  • SubjectAccessReview
  • CronJob
  • Job
  • Lease
  • ENIConfig
  • Event
  • DaemonSet
  • Deployment
  • Ingress
  • NetworkPolicy
  • PodSecurityPolicy
  • ReplicaSet
  • Ingress
  • NetworkPolicy
  • RuntimeClass
  • PodDisruptionBudget
  • PodSecurityPolicy
  • ClusterRoleBinding
  • ClusterRole
  • RoleBinding
  • Role
  • PriorityClass
  • CSIDriver
  • CSINode
  • StorageClass
  • VolumeAttachment

kubectl api-resources

kubectlからAPIを通して操作できるKubernetesのリソース一覧 (kubectl Version: 1.18.2)

$ kubectl api-resources
NAME                              SHORTNAMES   APIGROUP                       NAMESPACED   KIND
bindings                                                                      true         Binding
componentstatuses                 cs                                          false        ComponentStatus
configmaps                        cm                                          true         ConfigMap
endpoints                         ep                                          true         Endpoints
events                            ev                                          true         Event
limitranges                       limits                                      true         LimitRange
namespaces                        ns                                          false        Namespace
nodes                             no                                          false        Node
persistentvolumeclaims            pvc                                         true         PersistentVolumeClaim
persistentvolumes                 pv                                          false        PersistentVolume
pods                              po                                          true         Pod
podtemplates                                                                  true         PodTemplate
replicationcontrollers            rc                                          true         ReplicationController
resourcequotas                    quota                                       true         ResourceQuota
secrets                                                                       true         Secret
serviceaccounts                   sa                                          true         ServiceAccount
services                          svc                                         true         Service
mutatingwebhookconfigurations                  admissionregistration.k8s.io   false        MutatingWebhookConfiguration
validatingwebhookconfigurations                admissionregistration.k8s.io   false        ValidatingWebhookConfiguration
customresourcedefinitions         crd,crds     apiextensions.k8s.io           false        CustomResourceDefinition
apiservices                                    apiregistration.k8s.io         false        APIService
controllerrevisions                            apps                           true         ControllerRevision
daemonsets                        ds           apps                           true         DaemonSet
deployments                       deploy       apps                           true         Deployment
replicasets                       rs           apps                           true         ReplicaSet
statefulsets                      sts          apps                           true         StatefulSet
tokenreviews                                   authentication.k8s.io          false        TokenReview
localsubjectaccessreviews                      authorization.k8s.io           true         LocalSubjectAccessReview
selfsubjectaccessreviews                       authorization.k8s.io           false        SelfSubjectAccessReview
selfsubjectrulesreviews                        authorization.k8s.io           false        SelfSubjectRulesReview
subjectaccessreviews                           authorization.k8s.io           false        SubjectAccessReview
horizontalpodautoscalers          hpa          autoscaling                    true         HorizontalPodAutoscaler
cronjobs                          cj           batch                          true         CronJob
jobs                                           batch                          true         Job
certificatesigningrequests        csr          certificates.k8s.io            false        CertificateSigningRequest
leases                                         coordination.k8s.io            true         Lease
eniconfigs                                     crd.k8s.amazonaws.com          false        ENIConfig
events                            ev           events.k8s.io                  true         Event
daemonsets                        ds           extensions                     true         DaemonSet
deployments                       deploy       extensions                     true         Deployment
ingresses                         ing          extensions                     true         Ingress
networkpolicies                   netpol       extensions                     true         NetworkPolicy
podsecuritypolicies               psp          extensions                     false        PodSecurityPolicy
replicasets                       rs           extensions                     true         ReplicaSet
ingresses                         ing          networking.k8s.io              true         Ingress
networkpolicies                   netpol       networking.k8s.io              true         NetworkPolicy
runtimeclasses                                 node.k8s.io                    false        RuntimeClass
poddisruptionbudgets              pdb          policy                         true         PodDisruptionBudget
podsecuritypolicies               psp          policy                         false        PodSecurityPolicy
clusterrolebindings                            rbac.authorization.k8s.io      false        ClusterRoleBinding
clusterroles                                   rbac.authorization.k8s.io      false        ClusterRole
rolebindings                                   rbac.authorization.k8s.io      true         RoleBinding
roles                                          rbac.authorization.k8s.io      true         Role
priorityclasses                   pc           scheduling.k8s.io              false        PriorityClass
csidrivers                                     storage.k8s.io                 false        CSIDriver
csinodes                                       storage.k8s.io                 false        CSINode
storageclasses                    sc           storage.k8s.io                 false        StorageClass
volumeattachments                              storage.k8s.io                 false        VolumeAttachment

KubernetesのapiVersion

マニフェスト中のapiVersionは、[APIGROUP]/<[APIVERSION]の形式で記載します。[APIGROUP]はkubectl api-resourcesコマンドの結果で各種リソースがどのAPIグループに対応するか確認できます。APIグループが空欄の場合はコアグループに属し、[APIVERSION]のみの形式となります。

$ kubectl api-versions  
admissionregistration.k8s.io/v1beta1
apiextensions.k8s.io/v1beta1
apiregistration.k8s.io/v1
apiregistration.k8s.io/v1beta1
apps/v1
apps/v1beta1
apps/v1beta2
authentication.k8s.io/v1
authentication.k8s.io/v1beta1
authorization.k8s.io/v1
authorization.k8s.io/v1beta1
autoscaling/v1
autoscaling/v2beta1
autoscaling/v2beta2
batch/v1
batch/v1beta1
certificates.k8s.io/v1beta1
coordination.k8s.io/v1
coordination.k8s.io/v1beta1
crd.k8s.amazonaws.com/v1alpha1
events.k8s.io/v1beta1
extensions/v1beta1
networking.k8s.io/v1
networking.k8s.io/v1beta1
node.k8s.io/v1beta1
policy/v1beta1
rbac.authorization.k8s.io/v1
rbac.authorization.k8s.io/v1beta1
scheduling.k8s.io/v1
scheduling.k8s.io/v1beta1
storage.k8s.io/v1
storage.k8s.io/v1beta1
v1

(参考) Kubernetesの apiVersion に何を書けばいいか

kubectl

Use case

ローカルからコンテナで稼働しているサービスにアクセス

ローカルマシンのポートからDeployment,Service,Podへポートフォワード。kubectl proxy はローカルマシンのポートとAPIサーバーのポートをポートフォワードするためのもの。

$ sudo kubectl port-forward pod-mywebsite 80:80

シェルを取得

$ kubectl exec -it pod-mywebsite -- /bin/bash
root@pod-mywebsite:/usr/local/tomcat# 

クラスターの切り替え

コンテキストに登録されているクラスター一覧の取得

$ kubectl config get-contexts
CURRENT   NAME                                       CLUSTER                                 AUTHINFO                                   NAMESPACE
*         docker-desktop                             docker-desktop                          docker-desktop                             
          docker-for-desktop                         docker-desktop                          docker-desktop                             
          me@mywebsite-cluster.us-west-2.eksctl.io   mywebsite-cluster.us-west-2.eksctl.io   me@mywebsite-cluster.us-west-2.eksctl.io 

現在のコンテキストを確認

$ kubectl config current-context
me@mywebsite-cluster.us-west-2.eksctl.io

コンテキストの切り替え

$ kubectl config use-context docker-desktop
Switched to context "docker-desktop".
$ kubectl config current-context           
docker-desktop

Others

  • 全namespaceの詳細を把握

-Aで全namespaceの情報、-o wideオプションでより詳細に情報表示

$ kubectl get all -A -o wide
  • Podのログ確認

コンテナから標準出力された内容を確認できます。

$ kubectl logs pod-mywebsite
  • 直近1時間のイベント確認
$ kubectl get events -A
  • リソースの詳細表示

以下の形式でリソースの詳細を確認できます。例えば、Podの場合、kubectl describe pods deployment-mywebsite-68b6fbcd95-bvjr9コマンドのように実行することでイベントを含めた詳細情報を確認できます。

$ kubectl describe <RESOURCE_TYPE> <RESOURCE_NAME>

Useful Links

Get Started

Reference

Cheetsheet

Troubleshooting

  • 共通

    • 以下のコマンドの結果
      • Podのリスト取得
        • kubectl get pods -A -o wide
      • 全Pod情報の詳細取得
        • kubectl describe pods -A
      • 全リソース情報取得
        • kubectl get "$(kubectl api-resources --namespaced=true --verbs=list -o name | tr "\n" "," | sed -e 's/,$//')" -A
      • ワーカーノードのリスト取得
        • kubectl get nodes -o wide
      • 全ワーカーノード情報の詳細取得
        • kubectl describe node s
  • kubectlの接続性の調査 : デバッグレベルを上げてHTTPレイヤーのレベルで確認

    • kubectl get pods --v=9
  • ワーカーノードの接続性の調査

    • kubeletログ
      • sudo journalctl -u kubelet > kubelet.log
    • Dockerログ
      • journalctl -u docker > docker.log
    • /var/log/messages
  • Amazon VPC CNI PluginのL-IPAMDの動作の調査

    • CNI Log Collection Toolより生成した/var/log/aws-routed-eni/aws-cni-support.tar.gz
    • kubeletログ
      • sudo journalctl -u kubelet > kubelet.log
  • RBAC認証テーブルの調査 : IAMユーザーとKubernetesのRBACの関連付けを管理

    • kubectlコマンドの実行に失敗するマシンにて以下のコマンドの結果
      • aws sts get-caller-identity
    • 管理者IAMエンティティを使用して以下のコマンドの結果
      • kubectl describe configmap -n kube-system aws-auth
  • Podの調査

    • Pod のログ
      • kubectl logs <Pod name>
    • 終了した Pod のログ
      • kubectl logs <Pod name> -p
  • (EKS) Control Planeのログ

    • Kubernetes API server component logs (api)
    • Audit (audit)
    • Authenticator (authenticator)
    • Controller manager (controllerManager)
    • Scheduler (scheduler)
  • その他確認事項

    • マニフェストYAMLファイル
    • Helmチャート

(参照) Amazon EKS control plane logging

Podが起動しない

  • コンテナログ
    • アプリケーション側に問題がある場合
    • アプリケーションから標準出力したログ
    • kubectl logs コマンド
  • Kubernetesの設定やリソース設定に問題がある場合
    • kubectl describe コマンド
  • コンテナのシェル上で確認
    • 起動したアプリケーションが停止することによるPodの実行停止を避けるために、アプリケーションのENTRYPOINTを上書きして一時的にコンテナを立ち上げ
    • kubectl run --image=nginx:1.12 --restart=Never --rm -it sample-debug --command -- /bin/sh

ログ収集

ワーカーノード上で以下を実行

$ curl -O https://raw.githubusercontent.com/awslabs/amazon-eks-ami/master/log-collector-script/linux/eks-log-collector.sh
$ sudo bash eks-log-collector.sh

一応、CNI ログ収集ツールというのもあるが、基本的にEKS Log Collectorを使用

Useful Links

設計

リソース設計

eksctlコマンドでは、Control Planeに加えて、オプション次第でワーカーノードやVPC環境の作成を行います。

VPC環境は別途CloudFormationやTerraformで管理する場合やマニュアルでカスタマイズした環境を使用する場合にはkubectlとは別に作成するといった対応が可能です。 ワーカーノードを別個管理する場合、--without-nodegroupオプションを指定してノードグループを作成せずにEKSクラスターを作成し、eks create nodegroupコマンドでノードグループの作成を行います。

「eksctl」コマンドの使い方 (応用編)

マニフェスト設計

マニフェストファイルは1つのファイルに複数のリソースを記述することもできます。その場合、上から順に実行されます。途中で文法エラーなどの問題が発生した場合にはそれ以降のリソースは適用されません。

kubectl apply -f ./ -R コマンドとすることで複数のマニフェストファイルを一つのコマンドで適用することもできます。その場合、ファイル名の順に適用されるため、インデックス番号等をつけておくことで順番制御できます。  1つのマニフェストファイルでエラーが発生しても他のマニフェストファイルは実行されます。

リソース間の制御や厳密な実行順序制御をする必要がある場合は、複数のリソースを一つのマニフェストファイルに分けていただき、設定ファイルやパスワードなどConfigMapやSecretリソースなど共通で利用するものはマニフェストファイルを分割するといった形で対応します。 1つのディレクトリで一括管理することや、サブディレクトリごとに管理、もしくはマイクロサービス毎に管理するなど管理体制に合わせて管理方法をわけることもできます。

モニタリング

Container Insightsの導入

用意されたコマンド1つで、CloudWatchエージェントとFluentdをDaemonSetによってPodをサイドカーとして配置することで導入します。

メトリクスとログをCloudWatchに送信できるようにするために、EC2にアタッチされているIAMロールを確認し、こちらにCloudWatchAgentServerPolicyのポリシーをアタッチします。例えば、eksctl-mywebsite-cluster-nodegrou-NodeInstanceRole-XXXXXXXXXXXXのような名前のIAMロールになります。

mywebsite-clusterというクラスター名で、us-west-2のリージョンを使用している場合は、以下のように実行することで導入準備完了です。これはmetric_name{"tag"="value"[,...]} valueのようなPrometheusの形式となります。

$ curl https://raw.githubusercontent.com/aws-samples/amazon-cloudwatch-container-insights/latest/k8s-deployment-manifest-templates/deployment-mode/daemonset/container-insights-monitoring/quickstart/cwagent-fluentd-quickstart.yaml | sed "s/{{cluster_name}}/mywebsite-cluster/;s/{{region_name}}/us-west-2/" | kubectl apply -f -
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 15552  100 15552    0     0  14685      0  0:00:01  0:00:01 --:--:-- 14685
namespace/amazon-cloudwatch created
serviceaccount/cloudwatch-agent created
clusterrole.rbac.authorization.k8s.io/cloudwatch-agent-role created
clusterrolebinding.rbac.authorization.k8s.io/cloudwatch-agent-role-binding created
configmap/cwagentconfig created
daemonset.apps/cloudwatch-agent created
configmap/cluster-info created
serviceaccount/fluentd created
clusterrole.rbac.authorization.k8s.io/fluentd-role created
clusterrolebinding.rbac.authorization.k8s.io/fluentd-role-binding created
configmap/fluentd-config created
daemonset.apps/fluentd-cloudwatch created

Amazon EKS での Container Insights のクイックスタートセットアップ

Control PlaneのメトリクスをPrometheusでグラフ表示

APIサーバーに対して、/metricsのパスにHTTP APIでメトリクスの生データを参照することができます。

$ kubectl get --raw /metrics
# HELP APIServiceOpenAPIAggregationControllerQueue1_adds (Deprecated) Total number of adds handled by workqueue: APIServiceOpenAPIAggregationControllerQueue1
# TYPE APIServiceOpenAPIAggregationControllerQueue1_adds counter
APIServiceOpenAPIAggregationControllerQueue1_adds 1.231392e+06
# HELP APIServiceOpenAPIAggregationControllerQueue1_depth (Deprecated) Current depth of workqueue: APIServiceOpenAPIAggregationControllerQueue1
# TYPE APIServiceOpenAPIAggregationControllerQueue1_depth gauge
APIServiceOpenAPIAggregationControllerQueue1_depth 0
# HELP APIServiceOpenAPIAggregationControllerQueue1_longest_running_processor_microseconds (Deprecated) How many microseconds has the longest running processor for APIServiceOpenAPIAggregationControllerQueue1 been running.
# TYPE APIServiceOpenAPIAggregationControllerQueue1_longest_running_processor_microseconds gauge
APIServiceOpenAPIAggregationControllerQueue1_longest_running_processor_microseconds 0
# HELP APIServiceOpenAPIAggregationControllerQueue1_queue_latency (Deprecated) How long an item stays in workqueueAPIServiceOpenAPIAggregationControllerQueue1 before being requested.
# TYPE APIServiceOpenAPIAggregationControllerQueue1_queue_latency summary
APIServiceOpenAPIAggregationControllerQueue1_queue_latency{quantile="0.5"} 52
APIServiceOpenAPIAggregationControllerQueue1_queue_latency{quantile="0.9"} 86
APIServiceOpenAPIAggregationControllerQueue1_queue_latency{quantile="0.99"} 101
APIServiceOpenAPIAggregationControllerQueue1_queue_latency_sum 5.6469144e+07
APIServiceOpenAPIAggregationControllerQueue1_queue_latency_count 1.231392e+06
:

Helmを使用するため、インストールしていない場合、Amazon EKS での Helm の使用等参照して利用できるようにしておきます。

MacOSの場合、Homebrewでインストールできます。

$ brew install helm

brew install コマンド実行後、バージョン確認できます。

$ helm version
version.BuildInfo{Version:"v3.2.1", GitCommit:"fe51cd1e31e6a202cba7dead9552a6d418ded79a", GitTreeState:"clean", GoVersion:"go1.13.10"}

Helmのバージョン3には自動でstableレポジトリがインストールされないため、stableレポジトリを追加します。 (参照) (Optional) Set Up Sample Containerized Workloads for Prometheus Metric Testing, Quickstart Guide

$ helm repo add stable https://kubernetes-charts.storage.googleapis.com/

Prometheusをインストールします。

$ helm install prometheus stable/prometheus \
    --namespace prometheus \
    --set alertmanager.persistentVolume.storageClass="gp2",server.persistentVolume.storageClass="gp2"

Deploymentをポートフォワーディングします。

$ kubectl --namespace=prometheus port-forward deploy/prometheus-server 9090

Podをポートフォワーディングすることでも問題ありません。

$ export POD_NAME=$(kubectl get pods --namespace prometheus -l "app=prometheus,component=pushgateway" -o jsonpath="{.items[0].metadata.name}")
$ kubectl --namespace prometheus port-forward $POD_NAME 9091

http://localhost:9090 にアクセスすることで、Prometheusの画面を見ることができます。

"- insert metric at cursor -"から対象のメトリクスを選択して、"Execute"を選択します。すると、Consoleタブ上に各要素のログが出力されます。 Graphタブに切り替えることでグラフとして見ることができます。

(参照)Prometheus を使用したプレーンメトリクスのコントロール

Prometheus + Grafanaの連携

$ kubectl create namespace grafana
$ helm install grafana stable/grafana \
    --namespace grafana \
    --set persistence.storageClassName="gp2" \
    --set adminPassword='EKS!sAWSome' \
    --set datasources."datasources\.yaml".apiVersion=1 \
    --set datasources."datasources\.yaml".datasources[0].name=Prometheus \
    --set datasources."datasources\.yaml".datasources[0].type=prometheus \
    --set datasources."datasources\.yaml".datasources[0].url=http://prometheus-server.prometheus.svc.cluster.local \
    --set datasources."datasources\.yaml".datasources[0].access=proxy \
    --set datasources."datasources\.yaml".datasources[0].isDefault=true \
    --set service.type=LoadBalancer

ユーザー名はAdmin、パスワードは以下のコマンドの出力

$ kubectl get secret --namespace grafana grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo

アクセス先のELBが出力されます。

$ kubectl get svc --namespace grafana grafana
NAME      TYPE           CLUSTER-IP      EXTERNAL-IP                                                               PORT(S)        AGE
grafana   LoadBalancer   172.20.213.53   xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.us-west-2.elb.amazonaws.com   80:31399/TCP   3m36s

Kubernetes cluster monitoring (via Prometheus)のダッシュボードを表示できるようにします。

  1. PrometheusからのデータをGrafanaに取り込むために、画面右側の"+"マークを選択
  2. "Import"を選択
  3. Grafana.com Dashboardに"9135"を入力して"Load"
  4. Folderとして"General"、prometheusの項目に"Prometheus"を選択して"Import"を選択。

同様にして、9144を入れることでKubernetes pod monitoringをインストールできます。  7279を入れることでCoreDNSのダッシュボードをインポートできます。

Container InsightsによるPrometheusメトリクスのモニタリング(Beta版)

こちらはBeta版の機能となりますので、利用の際には十分に理解の上で実施ください。

EC2にアタッチされている、例えば、eksctl-mywebsite-cluster-nodegrou-NodeInstanceRole-XXXXXXXXXXXXのような名前のIAMロールを確認し、CloudWatchAgentServerPolicyのポリシーをアタッチしていなければアタッチする。

以下を実行するのみ。

$ kubectl apply -f https://raw.githubusercontent.com/aws-samples/amazon-cloudwatch-container-insights/prometheus-beta/k8s-deployment-manifest-templates/deployment-mode/service/cwagent-prometheus/prometheus-eks.yaml

以下のようにPodが稼働していることを確認できます。

$ kubectl get pod -l "app=cwagent-prometheus" -n amazon-cloudwatch
NAME                                  READY   STATUS    RESTARTS   AGE
cwagent-prometheus-75dfcd47d7-jqm2h   1/1     Running   0          52m

CloudWatchエージェントで他のワークロードからメトリクスを取得するために、prometheus-eks.yamlをダウンロードしてきて、追加で取得するメトリクスの設定を記載します。

$ curl -O https://raw.githubusercontent.com/aws-samples/amazon-cloudwatch-container-insights/prometheus-beta/k8s-deployment-manifest-templates/deployment-mode/service/cwagent-prometheus/prometheus-eks.yaml

logs.metrics_collected.prometheus.emf_processor.metric_declaration[]以下に以下を追記します。

{
    "source_labels": ["Service"],
    "label_matcher": "(.*node-exporter.*|.*kube-dns.*)",
    "dimensions": [["Service","Namespace"]],
    "metric_selectors": ["^coredns_dns_request_type_count_total$"]
}

元からあったリソースは削除して編集後の内容を適用します。

$ kubectl delete deployment cwagent-prometheus -n amazon-cloudwatch
$ kubectl apply -f prometheus-eks.yaml

JMX Exporter等を利用することで、Container InsightsがJVMやTomcatなどからもPrometheusのメトリクスを取得できるようになります。

JMX Exporterのエージェントファイルをダウンロードしてきます。

$ cd /Path/To/作成しているwarのアプリケーションやDockerfileを配置しているディレクトリ]
$ curl https://repo1.maven.org/maven2/io/prometheus/jmx/jmx_prometheus_javaagent/0.12.0/jmx_prometheus_javaagent-0.12.0.jar -o jmx_prometheus_javaagent-0.12.0.jar

JAVA_OPTSの環境変数の設定を行います。

$ vim setenv.sh
  • setenv.sh
export JAVA_OPTS="-javaagent:/opt/jmx_exporter/jmx_prometheus_javaagent-0.12.0.jar=9404:/opt/jmx_exporter/config.yaml $JAVA_OPTS"

JMX Exporterの設定ファイルを作成します。ここでは、ドキュメントの例をそのまま使用していますが、詳細はJMX ExporterのREADMEを参照

$ vim config.yaml
  • config.yaml
lowercaseOutputName: true
lowercaseOutputLabelNames: true

rules:
- pattern: 'java.lang<type=OperatingSystem><>(FreePhysicalMemorySize|TotalPhysicalMemorySize|FreeSwapSpaceSize|TotalSwapSpaceSize|SystemCpuLoad|ProcessCpuLoad|OpenFileDescriptorCount|AvailableProcessors)'
  name: java_lang_OperatingSystem_$1
  type: GAUGE

- pattern: 'java.lang<type=Threading><>(TotalStartedThreadCount|ThreadCount)'
  name: java_lang_threading_$1
  type: GAUGE

- pattern: 'Catalina<type=GlobalRequestProcessor, name=\"(\w+-\w+)-(\d+)\"><>(\w+)'
  name: catalina_globalrequestprocessor_$3_total
  labels:
    port: "$2"
    protocol: "$1"
  help: Catalina global $3
  type: COUNTER

- pattern: 'Catalina<j2eeType=Servlet, WebModule=//([-a-zA-Z0-9+&@#/%?=~_|!:.,;]*[-a-zA-Z0-9+&@#/%=~_|]), name=([-a-zA-Z0-9+/$%~_-|!.]*), J2EEApplication=none, J2EEServer=none><>(requestCount|maxTime|processingTime|errorCount)'
  name: catalina_servlet_$3_total
  labels:
    module: "$1"
    servlet: "$2"
  help: Catalina servlet $3 total
  type: COUNTER

- pattern: 'Catalina<type=ThreadPool, name="(\w+-\w+)-(\d+)"><>(currentThreadCount|currentThreadsBusy|keepAliveCount|pollerThreadCount|connectionCount)'
  name: catalina_threadpool_$3
  labels:
    port: "$2"
    protocol: "$1"
  help: Catalina threadpool $3
  type: GAUGE

- pattern: 'Catalina<type=Manager, host=([-a-zA-Z0-9+&@#/%?=~_|!:.,;]*[-a-zA-Z0-9+&@#/%=~_|]), context=([-a-zA-Z0-9+/$%~_-|!.]*)><>(processingTime|sessionCounter|rejectedSessions|expiredSessions)'
  name: catalina_session_$3_total
  labels:
    context: "$2"
    host: "$1"
  help: Catalina session $3 total
  type: COUNTER

- pattern: ".*"

次にwarファイルをTomcatで稼働させていたWebアプリケーションのDockerfileの編集を行います。

元のDockerfileは以下の内容でした。

FROM tomcat:9.0.34-jdk11
MAINTAINER "Shogo Hayashi <goodheaven700@gmail.com>"

ADD hayashier-website-0.0.1-SNAPSHOT.war /usr/local/tomcat/webapps/
COPY conf/server.xml  /usr/local/tomcat/conf/server.xml

EXPOSE 80

CMD ["catalina.sh", "run"] 

こちらに以下の4行を追加します。

RUN mkdir -p /opt/jmx_exporter
COPY ./jmx_prometheus_javaagent-0.12.0.jar /opt/jmx_exporter
COPY ./config.yaml /opt/jmx_exporter
COPY ./setenv.sh /usr/local/tomcat/bin
RUN chmod  o+x /usr/local/tomcat/bin/setenv.sh

変更後のDockerfileは以下の内容になります。

FROM tomcat:9.0.34-jdk11
MAINTAINER "Shogo Hayashi <goodheaven700@gmail.com>"

RUN mkdir -p /opt/jmx_exporter
COPY ./jmx_prometheus_javaagent-0.12.0.jar /opt/jmx_exporter
COPY ./config.yaml /opt/jmx_exporter
COPY ./setenv.sh /usr/local/tomcat/bin
RUN chmod  o+x /usr/local/tomcat/bin/setenv.sh

ADD hayashier-website-0.0.1-SNAPSHOT.war /usr/local/tomcat/webapps/
COPY conf/server.xml  /usr/local/tomcat/conf/server.xml

EXPOSE 80

CMD ["catalina.sh", "run"] 

上記内容からDockerイメージを作成して、Kubernetesのクラスターにデプロイします。

すると、以下のようにPodに対して9404番ポートにアクセスすることで、Prometheus形式のメトリクスが取得できるようになっていることを確認できます。

$ kubectl exec deployment-mywebsite-5d65c64459-2tplt -n default -- curl -s http://localhost:9404
# HELP jmx_config_reload_failure_total Number of times configuration have failed to be reloaded.
# TYPE jmx_config_reload_failure_total counter
jmx_config_reload_failure_total 0.0
# HELP process_cpu_seconds_total Total user and system CPU time spent in seconds.
# TYPE process_cpu_seconds_total counter
process_cpu_seconds_total 47.62
# HELP process_start_time_seconds Start time of the process since unix epoch in seconds.
# TYPE process_start_time_seconds gauge
process_start_time_seconds 1.589036278583E9
# HELP process_open_fds Number of open file descriptors.
# TYPE process_open_fds gauge
process_open_fds 65.0
# HELP process_max_fds Maximum number of open file descriptors.
# TYPE process_max_fds gauge
process_max_fds 65536.0
# HELP process_virtual_memory_bytes Virtual memory size in bytes.
# TYPE process_virtual_memory_bytes gauge
process_virtual_memory_bytes 3.753336832E9
# HELP process_resident_memory_bytes Resident memory size in bytes.
# TYPE process_resident_memory_bytes gauge
process_resident_memory_bytes 2.59690496E8
# HELP jvm_gc_collection_seconds Time spent in a given JVM garbage collector in seconds.
# TYPE jvm_gc_collection_seconds summary
jvm_gc_collection_seconds_count{gc="Copy",} 258.0
jvm_gc_collection_seconds_sum{gc="Copy",} 0.842
jvm_gc_collection_seconds_count{gc="MarkSweepCompact",} 10.0
jvm_gc_collection_seconds_sum{gc="MarkSweepCompact",} 0.811
:

この9494番ポートはprometheus-configのConfigMapで定義されています。

$ kubectl describe configmap prometheus-config -n amazon-cloudwatch
Name:         prometheus-config
Namespace:    amazon-cloudwatch
Labels:       <none>
Annotations:  
Data
====
prometheus.yaml:
----
global:
  scrape_interval: 1m
  scrape_timeout: 10s
scrape_configs:
:
- job_name: 'kubernetes-pod-jmx'
  sample_limit: 10000
  metrics_path: /metrics
  kubernetes_sd_configs:
  - role: pod
  relabel_configs:
  - source_labels: [__address__]
    action: keep
    regex: '.*:9404$'
  - action: labelmap
    regex: __meta_kubernetes_pod_label_(.+)
  - action: replace
    source_labels:
    - __meta_kubernetes_namespace
    target_label: Namespace
  - source_labels: [__meta_kubernetes_pod_name]
    action: replace
    target_label: pod_name
  - action: replace
    source_labels:
    - __meta_kubernetes_pod_container_name
    target_label: container_name
  - action: replace
    source_labels:
    - __meta_kubernetes_pod_controller_name
    target_label: pod_controller_name
  - action: replace
    source_labels:
    - __meta_kubernetes_pod_controller_kind
    target_label: pod_controller_kind
  - action: replace
    source_labels:
    - __meta_kubernetes_pod_phase
    target_label: pod_phase

Events:  <none>

また、Podの定義にPrometheusのサービスディスカバリー用のアノテーションを追加します。

  • prometheus.io/scrape
    • Podをスクレーピングの対象にするか
  • prometheus.io/port
    • Prometheusメトリクスを取得できるポート
  • prometheus.io/path
    • Prometheusメトリクスが/metricsのパスで取得できない場合に取得

例えば、Deploymentリソースを使用している場合、以下のように定義します。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deployment-mywebsite
spec:
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 0
      maxSurge: 3
  replicas: 3
  selector:
    matchLabels:
      app: mywebsite
  template:
    metadata:
      labels:
        app: mywebsite
      annotations:
        prometheus.io/scrape: 'true'
        prometheus.io/port: '9404'
    spec:
      containers:
        - name: mywebsite-container
          image: 745403317212.dkr.ecr.us-west-2.amazonaws.com/mywebsite:v10
          ports:
            - containerPort: 80

GrafanaにKubernetes JMX Dashboardを追加します。前述の要領で11131を追加して読み込むことで監視可能です。

EKS

ConfigMap

$ kubectl get configmap -A
NAMESPACE     NAME                                 DATA   AGE
kube-system   aws-auth                             1      6d1h
kube-system   coredns                              1      6d1h
kube-system   eks-certificates-controller          0      6d1h
kube-system   extension-apiserver-authentication   6      6d1h
kube-system   kube-proxy                           1      6d1h
kube-system   kube-proxy-config                    1      6d1h
  • aws-authはkube-systemのnamespaceに属するConfigMapでIAMエンティティをRBACを関連付け。EKSクラスターにアクセス可能なIAMユーザーやIAMロールの追加に使用 クラスターのユーザーまたは IAM ロールの管理

    • IAMユーザーやIAMロールにsystem:mastersのグループに追加することで管理者権限を付与
    • ConfigMap中で以下に対応付けを記載します。
      • IAMユーザー : mapUsers
      • IAMロール : mapRoles
    $ kubectl describe configmap -n kube-system aws-auth  
    Name:         aws-auth
    Namespace:    kube-system
    Labels:       <none>
    Annotations:  <none>
    
    Data
    ====
    mapRoles:
    ----
    - groups:
    - system:bootstrappers
    - system:nodes
    rolearn: arn:aws:iam::xxxxxxxxxxxx:role/eksctl-mywebsite-cluster-nodegrou-NodeInstanceRole-HAM9LC2CTOK7
    username: system:node:{{EC2PrivateDNSName}}
    
    Events:  <none>
    

<!-- eks-certificates-controllerはkubeletの証明書の承認とローテーションを処理するKubernetesのController

$ kubectl describe configmap -n kube-system eks-certificates-controller
Name:         eks-certificates-controller
Namespace:    kube-system
Labels:       <none>
Annotations:  control-plane.alpha.kubernetes.io/leader:
                {"holderIdentity":"ip-172-16-56-176.us-west-2.compute.internal","leaseDurationSeconds":30,"acquireTime":"2020-05-02T09:38:48Z","renewTime"...

Data
====
Events:  <none>

-->

DaemonSet

$ kubectl get daemonset -A
NAMESPACE     NAME         DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
kube-system   aws-node     3         3         3       3            3           <none>          6d1h
kube-system   kube-proxy   3         3         3       3            3           <none>          6d1h
  • aws-nodeはkube-systemのnamespaceに属し、Podを起動し、Amazon VPC CNI PluginというNetworking Pluginが呼び出される。

    • Amazon VPC CNI Pluginは以下の2つで構成
      • CNI Plugin
        • ホストネットワークの接続 (例: インターフェイスと仮想イーサネットペアの設定) とPod名前空間への正しいインターフェイスの関連付け
      • L-IPAMD (Local IP Address Managed Daemon)
        • インスタンスへの Elastic Network Interface の接続
        • Elastic Network Interface へのセカンダリ IP アドレスの割り当て
        • スケジュールされた際に Kubernetes ポッドに割り当てるために各ノードにおける IP アドレスの「ウォームプール」の維持
    $ kubectl describe daemonset -n kube-system aws-node
    Name:           aws-node
    Selector:       k8s-app=aws-node
    Node-Selector:  <none>
    Labels:         k8s-app=aws-node
    Annotations:    deprecated.daemonset.template.generation: 1
    Desired Number of Nodes Scheduled: 3
    Current Number of Nodes Scheduled: 3
    Number of Nodes Scheduled with Up-to-date Pods: 3
    Number of Nodes Scheduled with Available Pods: 3
    Number of Nodes Misscheduled: 0
    Pods Status:  3 Running / 0 Waiting / 0 Succeeded / 0 Failed
    Pod Template:
    Labels:           k8s-app=aws-node
    Service Account:  aws-node
    Containers:
    aws-node:
        Image:      602401143452.dkr.ecr.us-west-2.amazonaws.com/amazon-k8s-cni:v1.5.7
        Port:       61678/TCP
        Host Port:  61678/TCP
        Requests:
        cpu:  10m
        Environment:
        AWS_VPC_K8S_CNI_LOGLEVEL:  DEBUG
        MY_NODE_NAME:               (v1:spec.nodeName)
        Mounts:
        /host/etc/cni/net.d from cni-net-dir (rw)
        /host/opt/cni/bin from cni-bin-dir (rw)
        /host/var/log from log-dir (rw)
        /var/run/docker.sock from dockersock (rw)
    Volumes:
    cni-bin-dir:
        Type:          HostPath (bare host directory volume)
        Path:          /opt/cni/bin
        HostPathType:  
    cni-net-dir:
        Type:          HostPath (bare host directory volume)
        Path:          /etc/cni/net.d
        HostPathType:  
    log-dir:
        Type:          HostPath (bare host directory volume)
        Path:          /var/log
        HostPathType:  
    dockersock:
        Type:               HostPath (bare host directory volume)
        Path:               /var/run/docker.sock
        HostPathType:       
    Priority Class Name:  system-node-critical
    Events:                 <none>
    

CNI

  • コンテナにおけるネットワークインターフェイスを構成するプラグイン
  • 種類
    • Calico : レイヤー3の仮想ネットワークを構成可能
    • Cilium : 負荷分散、プロトコルのフィルタリングが可能
    • CNI-Genie : 複数NICに異なるプラグインを割り当て、同時利用が可能
    • Contiv : ポリシーベースの管理、ACL、QoS
    • Infoblox : 複数のrktホストに対応
    • Linen : 仮想スイッチを作成し、VXLANを構成可能
    • Multus : 複数のCNIプラグインのグループ化が可能
    • Nuage : オーバーレイネットワークを提供。Mesos, Kubernetes, OpenShiftに対応
    • Romana : フラットなL2,L3に対応
    • Silk : L3オーバーレイネットワークを提供
    • Weave : オーバーレイネットワークを提供

(参考) Docker実践ガイド 第2版

Kubernetes Dashboard

Kubernetes Dashboardではメトリクスサーバーを使用するためデプロイ。

$ kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.3.6/components.yaml
$ kubectl get deployment metrics-server -n kube-system

Dashboardのデプロイ

$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-beta8/aio/deploy/recommended.yaml

Dashboardへのユーザーのアクセス制限があるため、eks-admin サービスアカウントおよびクラスターロールバインディングを作成して、管理者レベルのアクセス権限による接続をします。

$ vim eks-admin-service-account.yaml
$ kubectl apply -f eks-admin-service-account.yaml
  • eks-admin-service-account.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: eks-admin
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: eks-admin
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: eks-admin
  namespace: kube-system

認証のためのトークンを取得します。

/ kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep eks-admin | awk '{print $1}')
Name:         eks-admin-token-hxs4v
Namespace:    kube-system
Labels:       <none>
Annotations:  kubernetes.io/service-account.name: eks-admin
              kubernetes.io/service-account.uid: 9895322a-3609-431f-af9c-c5b875b02a4b

Type:  kubernetes.io/service-account-token

Data
====
ca.crt:     1025 bytes
namespace:  11 bytes
token: <here is token>

プロキシでローカルからブラウザでアクセスできるようにします。

$ kubectl proxy

以下のURLにアクセスします。

  • http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/#!/login

認証方法でKubeconfigとTokenが選択できますので、Tokenを選択肢、先程取得したトークンを貼り付けて、サインインします。

(参考) チュートリアル: Kubernetes ダッシュボード (ウェブ UI) のデプロイ

Addon

Links

GitHub

Best Practice

Architecture

Get Started

<!--

ノウハウブログ

モニタリング

-->

My Twitter & RSS

Leave a Reply

Your email address will not be published. Required fields are marked *