#はじめに
この記事は、クラスターにデプロイされたアプリケーションとクラスター自体の本番環境グレードのKubernetesログを設定する2部構成のシリーズのPart1です。 当記事ではロギングバックエンドとしてElasticsearchを使用します。 Elasticsearchのセットアップは、非常にスケーラブルで耐障害性の高いものになります。
# デプロイメントアーキテクチャ
-
Elasticsearch データノードポッドは、安定したネットワークIDを提供するヘッドレスサービスを備えたステートフルセットとしてデプロイされます。
-
Elasticsearch マスターノードポッドは、自動検出に役立つヘッドレスサービスを備えたレプリカセットとしてデプロイされます。
-
Elasticsearch クライアントノードポッドは、R / Wリクエストのデータノードへのアクセスを許可する内部サービスを備えたレプリカセットとしてデプロイされます。
-
KibanaポッドとElasticHQポッドは、Kubernetesクラスターの外部からアクセスできるサービスを備えたレプリカセットとしてデプロイされますが、サブネットワークの内部にはあります(特に必要がない限り、公開されません)。
-
HPA(Horizontal Pod Auto-scaler)がクライアントノードに導入され、高負荷での自動スケーリングが可能になりました。
####覚えておくべき重要なこと:
-
ES_JAVA_OPTS環境変数を設定します。
-
CLUSTER_NAME環境変数を設定します。
-
マスター展開用にNUMBER_OF_MASTERS(スプリットブレインの問題を回避するため)環境変数を設定します。 マスターが3つの場合、2に設定しました。
-
ワーカーノードに障害が発生した場合にHAを確保するために、同様のポッド間で正しいPod-AntiAffinityポリシーを設定します。
これらのサービスをGKEクラスターにデプロイするところから始めましょう。
###マスターノードのデプロイメントとヘッドレスサービス
次のマニフェストをデプロイして、マスターノードとヘッドレスサービスを作成します。
apiVersion: v1
kind: Namespace
metadata:
name: elasticsearch
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: es-master
namespace: elasticsearch
labels:
component: elasticsearch
role: master
spec:
replicas: 3
template:
metadata:
labels:
component: elasticsearch
role: master
spec:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: role
operator: In
values:
- master
topologyKey: kubernetes.io/hostname
initContainers:
- name: init-sysctl
image: busybox:1.27.2
command:
- sysctl
- -w
- vm.max_map_count=262144
securityContext:
privileged: true
containers:
- name: es-master
image: quay.io/pires/docker-elasticsearch-kubernetes:6.2.4
env:
- name: NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: CLUSTER_NAME
value: my-es
- name: NUMBER_OF_MASTERS
value: "2"
- name: NODE_MASTER
value: "true"
- name: NODE_INGEST
value: "false"
- name: NODE_DATA
value: "false"
- name: HTTP_ENABLE
value: "false"
- name: ES_JAVA_OPTS
value: -Xms256m -Xmx256m
- name: PROCESSORS
valueFrom:
resourceFieldRef:
resource: limits.cpu
resources:
limits:
cpu: 2
ports:
- containerPort: 9300
name: transport
volumeMounts:
- name: storage
mountPath: /data
volumes:
- emptyDir:
medium: ""
name: "storage"
---
apiVersion: v1
kind: Service
metadata:
name: elasticsearch-discovery
namespace: elasticsearch
labels:
component: elasticsearch
role: master
spec:
selector:
component: elasticsearch
role: master
ports:
- name: transport
port: 9300
protocol: TCP
clusterIP: None
マスターノードポッドのいずれかのログをたどると、それらの間でマスターが選出されます。 これは、マスターノードポッドがグループのリーダーを選択するときです。 マスターノードのログを追跡すると、新しいデータとクライアントノードがいつ追加されたかがわかります。
root$ kubectl -n elasticsearch logs -f po/es-master-594b58b86c-9jkj2 | grep ClusterApplierService
[2018-10-21T07:41:54,958][INFO ][o.e.c.s.ClusterApplierService] [es-master-594b58b86c-9jkj2] detected_master {es-master-594b58b86c-bj7g7}{1aFT97hQQ7yiaBc2CYShBA}{Q3QzlaG3QGazOwtUl7N75Q}{10.9.126.87}{10.9.126.87:9300}, added {{es-master-594b58b86c-lfpps}{wZQmXr5fSfWisCpOHBhaMg}{50jGPeKLSpO9RU_HhnVJCA}{10.9.124.81}{10.9.124.81:9300},{es-master-594b58b86c-bj7g7}{1aFT97hQQ7yiaBc2CYShBA}{Q3QzlaG3QGazOwtUl7N75Q}{10.9.126.87}{10.9.126.87:9300},}, reason: apply cluster state (from master [master {es-master-594b58b86c-bj7g7}{1aFT97hQQ7yiaBc2CYShBA}{Q3QzlaG3QGazOwtUl7N75Q}{10.9.126.87}{10.9.126.87:9300} committed version [3]])
上記のように、es-master-594b58b86c-bj7g7という名前のes-masterポッドがリーダーとして選出され、他の2つのポッドがクラスターに追加されました。
Elasticsearch-discoveryという名前のヘッドレスサービスは、デフォルトでDockerイメージの環境変数として設定され、ノード間の検出に使用されます。 もちろん、これはオーバーライドできます。
###データノードのデプロイメント
次のマニフェストを使用して、データノードにステートフルセットとヘッドレスサービスをデプロイします。
apiVersion: v1
kind: Namespace
metadata:
name: elasticsearch
---
apiVersion: storage.k8s.io/v1beta1
kind: StorageClass
metadata:
name: fast
provisioner: kubernetes.io/gce-pd
parameters:
type: pd-ssd
fsType: xfs
allowVolumeExpansion: true
---
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
name: es-data
namespace: elasticsearch
labels:
component: elasticsearch
role: data
spec:
serviceName: elasticsearch-data
replicas: 3
template:
metadata:
labels:
component: elasticsearch
role: data
spec:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: role
operator: In
values:
- data
topologyKey: kubernetes.io/hostname
initContainers:
- name: init-sysctl
image: busybox:1.27.2
command:
- sysctl
- -w
- vm.max_map_count=262144
securityContext:
privileged: true
containers:
- name: es-data
image: quay.io/pires/docker-elasticsearch-kubernetes:6.2.4
env:
- name: NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: CLUSTER_NAME
value: my-es
- name: NODE_MASTER
value: "false"
- name: NODE_INGEST
value: "false"
- name: HTTP_ENABLE
value: "false"
- name: ES_JAVA_OPTS
value: -Xms256m -Xmx256m
- name: PROCESSORS
valueFrom:
resourceFieldRef:
resource: limits.cpu
resources:
limits:
cpu: 2
ports:
- containerPort: 9300
name: transport
volumeMounts:
- name: storage
mountPath: /data
volumeClaimTemplates:
- metadata:
name: storage
annotations:
volume.beta.kubernetes.io/storage-class: "fast"
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: fast
resources:
requests:
storage: 10Gi
---
apiVersion: v1
kind: Service
metadata:
name: elasticsearch-data
namespace: elasticsearch
labels:
component: elasticsearch
role: data
spec:
ports:
- port: 9300
name: transport
clusterIP: None
selector:
component: elasticsearch
role: data
データノードの場合のヘッドレスサービスは、ノードに安定したネットワークIDを提供し、ノード間のデータ転送にも役立ちます。
永続ボリュームをポッドに接続する前にフォーマットすることが重要です。 これは、ストレージクラスの作成時にボリュームタイプを指定することで実行できます。 また、その場でボリュームを拡張できるようにフラグを設定することもできます。 詳細については、こちらをご覧ください。
...
parameters:
type: pd-ssd
fsType: xfs
allowVolumeExpansion: true
...
#クライアントノードのデプロイメント
次のマニフェストを使用して、クライアントノードのデプロイメントおよび外部サービスを作成します。
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: es-client
namespace: elasticsearch
labels:
component: elasticsearch
role: client
spec:
replicas: 2
template:
metadata:
labels:
component: elasticsearch
role: client
spec:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: role
operator: In
values:
- client
topologyKey: kubernetes.io/hostname
initContainers:
- name: init-sysctl
image: busybox:1.27.2
command:
- sysctl
- -w
- vm.max_map_count=262144
securityContext:
privileged: true
containers:
- name: es-client
image: quay.io/pires/docker-elasticsearch-kubernetes:6.2.4
env:
- name: NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: CLUSTER_NAME
value: my-es
- name: NODE_MASTER
value: "false"
- name: NODE_DATA
value: "false"
- name: HTTP_ENABLE
value: "true"
- name: ES_JAVA_OPTS
value: -Xms256m -Xmx256m
- name: NETWORK_HOST
value: _site_,_lo_
- name: PROCESSORS
valueFrom:
resourceFieldRef:
resource: limits.cpu
resources:
limits:
cpu: 1
ports:
- containerPort: 9200
name: http
- containerPort: 9300
name: transport
volumeMounts:
- name: storage
mountPath: /data
volumes:
- emptyDir:
medium: ""
name: storage
---
apiVersion: v1
kind: Service
metadata:
name: elasticsearch
namespace: elasticsearch
labels:
component: elasticsearch
role: client
spec:
selector:
component: elasticsearch
role: client
ports:
- name: http
port: 9200
type: LoadBalancer
ここでデプロイされるサービスの目的は、Kubernetesクラスターの外部からESクラスターにアクセスすることですが、それでもサブネットの内部にあります。 アノテーション「cloud.google.com/load-balancer-type:Internal」はこれを保証します。
ただし、ESクラスターへのアプリケーションの読み取り/書き込みがクラスター内にデプロイされている場合は、http://elasticsearch.elasticsearch:9200からElasticsearchサービスにアクセスできます。
すべてのコンポーネントがデプロイされたら、次のことを確認する必要があります。
1.Ubuntuコンテナを使用したKubernetesクラスター内からのElasticsearchデプロイメント。
root$ kubectl run my-shell --rm -i --tty --image ubuntu -- bash
root@my-shell-68974bb7f7-pj9x6:/# curl http://elasticsearch.elasticsearch:9200/_cluster/health?pretty
{
"cluster_name" : "my-es",
"status" : "green",
"timed_out" : false,
"number_of_nodes" : 7,
"number_of_data_nodes" : 2,
"active_primary_shards" : 0,
"active_shards" : 0,
"relocating_shards" : 0,
"initializing_shards" : 0,
"unassigned_shards" : 0,
"delayed_unassigned_shards" : 0,
"number_of_pending_tasks" : 0,
"number_of_in_flight_fetch" : 0,
"task_max_waiting_in_queue_millis" : 0,
"active_shards_percent_as_number" : 100.0
}
-
GCP内部ロードバランサーIP(この場合は10.9.120.8)を使用して、クラスターの外部からElasticsearchをデプロイします。 curl http://10.9.120.8:9200/_cluster/health?pretty
を使用してヘルスをチェックすると、出力は上記と同じになります。 -
ESポッドの非アフィニティルール:
root$ kubectl -n elasticsearch get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
es-client-69b84b46d8-kr7j4 1/1 Running 0 10m 10.8.14.52 gke-cluster1-pool1-d2ef2b34-t6h9
es-client-69b84b46d8-v5pj2 1/1 Running 0 10m 10.8.15.53 gke-cluster1-pool1-42b4fbc4-cncn
es-data-0 1/1 Running 0 12m 10.8.16.58 gke-cluster1-pool1-4cfd808c-kpx1
es-data-1 1/1 Running 0 12m 10.8.15.52 gke-cluster1-pool1-42b4fbc4-cncn
es-master-594b58b86c-9jkj2 1/1 Running 0 18m 10.8.15.51 gke-cluster1-pool1-42b4fbc4-cncn
es-master-594b58b86c-bj7g7 1/1 Running 0 18m 10.8.16.57 gke-cluster1-pool1-4cfd808c-kpx1
es-master-594b58b86c-lfpps 1/1 Running 0 18m 10.8.14.51 gke-cluster1-pool1-d2ef2b34-t6h9
#スケーリングに関する考慮事項
CPUのしきい値に応じて、クライアントノードに自動スケーラーをデプロイできます。 クライアントノードのサンプルHPAは、次のようになります。
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: es-client
namespace: elasticsearch
spec:
maxReplicas: 5
minReplicas: 2
scaleTargetRef:
apiVersion: extensions/v1beta1
kind: Deployment
name: es-client
targetCPUUtilizationPercentage: 80
オートスケーラーが起動するたびに、マスターノードポッドのログを監視することで、新しいクライアントノードポッドがクラスターに追加されるのを監視できます。
データノードポッドの場合、K8ダッシュボードまたはGKEコンソールを使用してレプリカの数を増やすだけです。 新しく作成されたデータノードは自動的にクラスターに追加され、他のノードからのデータの複製を開始します。
マスターノードポッドは、クラスター状態情報のみを格納するため、自動スケーリングは必要ありません。 さらにデータノードを追加する場合は、クラスター内に偶数のマスターノードがないことを確認してください。 また、それに応じて環境変数NUMBER_OF_MASTERSが更新されていることを確認してください。
#Check logs of es-master leader pod
root$ kubectl -n elasticsearch logs po/es-master-594b58b86c-bj7g7 | grep ClusterApplierService
[2018-10-21T07:41:53,731][INFO ][o.e.c.s.ClusterApplierService] [es-master-594b58b86c-bj7g7] new_master {es-master-594b58b86c-bj7g7}{1aFT97hQQ7yiaBc2CYShBA}{Q3QzlaG3QGazOwtUl7N75Q}{10.9.126.87}{10.9.126.87:9300}, added {{es-master-594b58b86c-lfpps}{wZQmXr5fSfWisCpOHBhaMg}{50jGPeKLSpO9RU_HhnVJCA}{10.9.124.81}{10.9.124.81:9300},}, reason: apply cluster state (from master [master {es-master-594b58b86c-bj7g7}{1aFT97hQQ7yiaBc2CYShBA}{Q3QzlaG3QGazOwtUl7N75Q}{10.9.126.87}{10.9.126.87:9300} committed version [1] source [zen-disco-elected-as-master ([1] nodes joined)[{es-master-594b58b86c-lfpps}{wZQmXr5fSfWisCpOHBhaMg}{50jGPeKLSpO9RU_HhnVJCA}{10.9.124.81}{10.9.124.81:9300}]]])
[2018-10-21T07:41:55,162][INFO ][o.e.c.s.ClusterApplierService] [es-master-594b58b86c-bj7g7] added {{es-master-594b58b86c-9jkj2}{x9Prp1VbTq6_kALQVNwIWg}{7NHUSVpuS0mFDTXzAeKRcg}{10.9.125.81}{10.9.125.81:9300},}, reason: apply cluster state (from master [master {es-master-594b58b86c-bj7g7}{1aFT97hQQ7yiaBc2CYShBA}{Q3QzlaG3QGazOwtUl7N75Q}{10.9.126.87}{10.9.126.87:9300} committed version [3] source [zen-disco-node-join[{es-master-594b58b86c-9jkj2}{x9Prp1VbTq6_kALQVNwIWg}{7NHUSVpuS0mFDTXzAeKRcg}{10.9.125.81}{10.9.125.81:9300}]]])
[2018-10-21T07:48:02,485][INFO ][o.e.c.s.ClusterApplierService] [es-master-594b58b86c-bj7g7] added {{es-data-0}{SAOhUiLiRkazskZ_TC6EBQ}{qirmfVJBTjSBQtHZnz-QZw}{10.9.126.88}{10.9.126.88:9300},}, reason: apply cluster state (from master [master {es-master-594b58b86c-bj7g7}{1aFT97hQQ7yiaBc2CYShBA}{Q3QzlaG3QGazOwtUl7N75Q}{10.9.126.87}{10.9.126.87:9300} committed version [4] source [zen-disco-node-join[{es-data-0}{SAOhUiLiRkazskZ_TC6EBQ}{qirmfVJBTjSBQtHZnz-QZw}{10.9.126.88}{10.9.126.88:9300}]]])
[2018-10-21T07:48:21,984][INFO ][o.e.c.s.ClusterApplierService] [es-master-594b58b86c-bj7g7] added {{es-data-1}{fiv5Wh29TRWGPumm5ypJfA}{EXqKGSzIQquRyWRzxIOWhQ}{10.9.125.82}{10.9.125.82:9300},}, reason: apply cluster state (from master [master {es-master-594b58b86c-bj7g7}{1aFT97hQQ7yiaBc2CYShBA}{Q3QzlaG3QGazOwtUl7N75Q}{10.9.126.87}{10.9.126.87:9300} committed version [5] source [zen-disco-node-join[{es-data-1}{fiv5Wh29TRWGPumm5ypJfA}{EXqKGSzIQquRyWRzxIOWhQ}{10.9.125.82}{10.9.125.82:9300}]]])
[2018-10-21T07:50:51,245][INFO ][o.e.c.s.ClusterApplierService] [es-master-594b58b86c-bj7g7] added {{es-client-69b84b46d8-v5pj2}{MMjA_tlTS7ux-UW44i0osg}{rOE4nB_jSmaIQVDZCjP8Rg}{10.9.125.83}{10.9.125.83:9300},}, reason: apply cluster state (from master [master {es-master-594b58b86c-bj7g7}{1aFT97hQQ7yiaBc2CYShBA}{Q3QzlaG3QGazOwtUl7N75Q}{10.9.126.87}{10.9.126.87:9300} committed version [6] source [zen-disco-node-join[{es-client-69b84b46d8-v5pj2}{MMjA_tlTS7ux-UW44i0osg}{rOE4nB_jSmaIQVDZCjP8Rg}{10.9.125.83}{10.9.125.83:9300}]]])
主要なマスターポッドのログには、各ノードがいつクラスターに追加されるかが明確に示されます。 デバッグの問題の場合に非常に役立ちます。
#KibanaとES-HQの導入
KibanaはESデータを視覚化するためのシンプルなツールであり、ES-HQはElasticsearchクラスターの管理と監視に役立ちます。 KibanaとES-HQの展開では、次の点に注意してください。
-
Dockerイメージの環境変数としてES-Clusterの名前を指定する必要があります。
-
Kibana / ES-HQデプロイメントにアクセスするためのサービスは、組織の内部のみです。つまり、パブリックIPは作成されません。 GCP内部ロードバランサーを使用する必要があります。
###Kibanaのデプロイメント
次のマニフェストを使用して、Kibanaのデプロイメントとサービスを作成します。
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: logging
name: kibana
labels:
component: kibana
spec:
replicas: 1
selector:
matchLabels:
component: kibana
template:
metadata:
labels:
component: kibana
spec:
containers:
- name: kibana
image: docker.elastic.co/kibana/kibana-oss:6.2.2
env:
- name: CLUSTER_NAME
value: my-es
- name: ELASTICSEARCH_URL
value: http://elasticsearch.elasticsearch:9200
resources:
limits:
cpu: 200m
requests:
cpu: 100m
ports:
- containerPort: 5601
name: http
---
apiVersion: v1
kind: Service
metadata:
namespace: logging
name: kibana
annotations:
cloud.google.com/load-balancer-type: "Internal"
labels:
component: kibana
spec:
selector:
component: kibana
ports:
- name: http
port: 5601
type: LoadBalancer
###ES-HQのデプロイメント
次のマニフェストを使用して、ES-HQの展開とサービスを作成します。
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: es-hq
namespace: elasticsearch
labels:
component: elasticsearch
role: hq
spec:
replicas: 1
template:
metadata:
labels:
component: elasticsearch
role: hq
spec:
containers:
- name: es-hq
image: elastichq/elasticsearch-hq:release-v3.4.0
env:
- name: HQ_DEFAULT_URL
value: http://elasticsearch:9200
resources:
limits:
cpu: 0.5
ports:
- containerPort: 5000
name: http
---
apiVersion: v1
kind: Service
metadata:
name: hq
namespace: elasticsearch
labels:
component: elasticsearch
role: hq
spec:
selector:
component: elasticsearch
role: hq
ports:
- name: http
port: 5000
type: LoadBalancer
新しく作成された内部LoadBalancerを使用して、これら両方のサービスにアクセスできます。
[http:// / app / kibana#/ home?_g =()](http:// / app / kibana#/ home?_g =()
)
にアクセスします。
Kibanaダッシュボード:
[http:// /#!/ clusters / my-es](http:// /#!/ clusters / my-es)にアクセスします。
#まとめ
これで、ロギング用のESバックエンドのデプロイは完了です。 デプロイしたElasticsearchは、他のアプリケーションでも使用できます。 クライアントノードは高負荷時に自動的にスケーリングする必要があり、ステートフルセットのレプリカ数を増やすことでデータノードを追加できます。 また、いくつかのenv変数を微調整する必要がありますが、それは簡単です。 次のブログでは、Elasticsearchバックエンドにログを送信するためのFilebeatDaemonSetのデプロイについて学習します。
こちらの記事がこの記事の続きとなるPart2になります。Part 2 では、Filebeatの構成について詳しく解説していきます。
Elasticsearchはログ監視スペースを支配しますが、MetricFireは時系列の監視を専門としています。デモを予約して、自分に合った監視ソリューションについて直接お問い合わせください。 Part2にご期待ください:)