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
(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ロードバランシング
- Service : L4ロードバランシング
- 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つに別れます。
- NLBの設定
- 機密情報の受け渡し設定
- コンテナ設定
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 nodes
- Podのリスト取得
- 以下のコマンドの結果
-
kubectlの接続性の調査 : デバッグレベルを上げてHTTPレイヤーのレベルで確認
kubectl get pods --v=9
-
ワーカーノードの接続性の調査
- kubeletログ
sudo journalctl -u kubelet > kubelet.log
- Dockerログ
journalctl -u docker > docker.log
/var/log/messages
- kubeletログ
-
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
- kubectlコマンドの実行に失敗するマシンにて以下のコマンドの結果
-
Podの調査
- Pod のログ
kubectl logs <Pod name>
- 終了した Pod のログ
kubectl logs <Pod name> -p
- Pod のログ
-
(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
-
Kubernetes
-
EKS
-
IAM
-
Amazon VPC CNI Plugin
設計
リソース設計
eksctlコマンドでは、Control Planeに加えて、オプション次第でワーカーノードやVPC環境の作成を行います。
VPC環境は別途CloudFormationやTerraformで管理する場合やマニュアルでカスタマイズした環境を使用する場合にはkubectlとは別に作成するといった対応が可能です。
ワーカーノードを別個管理する場合、--without-nodegroupオプションを指定してノードグループを作成せずにEKSクラスターを作成し、eks create nodegroup
コマンドでノードグループの作成を行います。
マニフェスト設計
マニフェストファイルは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)のダッシュボードを表示できるようにします。
- PrometheusからのデータをGrafanaに取り込むために、画面右側の"+"マークを選択
- "Import"を選択
- Grafana.com Dashboardに"9135"を入力して"Load"
- 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
- Container Insights Prometheus Metrics Monitoring
- Configuring the CloudWatch Agent for Prometheus Monitoring
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 アドレスの「ウォームプール」の維持
- CNI Plugin
$ 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>
- Amazon VPC CNI Pluginは以下の2つで構成
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
- Kubernetes
- Kubernetes SIGs
- CoreDNS
- CNI
- Weaveworks
- Amazon Web Services
- Amazon Web Services - Labs
- AWS Samples
- Atlassian
- Tools
Best Practice
Architecture
Get Started
<!--
ノウハウブログ
モニタリング
-->