目次
概要
EFKを用いてログの収集とUIを提供する。 必要な機能は、以下の通り。
- コンテナのログの収集
- 収集したログのUI
今回使うのは、EFK(Elastic Search, Fluentd, Kibana)とよばれるソフトウェアスタック。 FluentdでログをElasticSearchに送り、KibanaでElasticSearchのログを可視化する。 これらをKubernetesのリソースとして構築する。
準備
ロギングコンポーネントを配置するノードがk8s-monitoring-01
とk8s-monitoring-02
なので、これらにlabelを付与する。
kubectl label node k8s-monitoring-01 role=monitoring
kubectl label node k8s-monitoring-02 role=monitoring
続いて、ロギング用ネームスペースの作成。
kubectl create ns kube-logging
Elastic Searchのインストール
Elastic SearchはStatefulSetとしてインストールする。 GithubにあるAddonと公式のDockerを使ったデプロイを参考にすすめていく。
まず、StatefulSetに使用するPersistenetVolumeの作成を行う。
# elastic-pv.yml
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-elastic0-pv
spec:
capacity:
storage: 100Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
nfs:
server: 192.168.1.50
path: /mnt/nfs/pv/elastic0
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-elastic1-pv
spec:
capacity:
storage: 100Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
nfs:
server: 192.168.1.50
path: /mnt/nfs/pv/elastic1
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-elastic2-pv
spec:
capacity:
storage: 100Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
nfs:
server: 192.168.1.50
path: /mnt/nfs/pv/elastic2
上記を読み込んでPVを作成。
kubectl apply -f elastic-pv.yml
作成が完了すると下記のようにPVがAvailable
で表示される。
$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
nfs-elastic0-pv 100Gi RWO Recycle Available 1m
nfs-elastic1-pv 100Gi RWO Recycle Available 1m
nfs-elastic2-pv 100Gi RWO Recycle Available 1m
続いて、StatefulSetの設定ファイルを作成する。 大枠はaddonのものを使用し、イメージはElasticSearchの公式を用いる。
# elastic-statefulset.yml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: elasticsearch-logging
namespace: kube-logging
labels:
k8s-app: elasticsearch-logging
version: v6.6.0
kubernetes.io/cluster-service: "true"
spec:
serviceName: elasticsearch
replicas: 3
selector:
matchLabels:
k8s-app: elasticsearch-logging
version: v6.6.0
template:
metadata:
labels:
k8s-app: elasticsearch-logging
version: v6.6.0
kubernetes.io/cluster-service: "true"
spec:
nodeSelector:
role: monitoring
containers:
- name: elasticsearch-logging
image: docker.elastic.co/elasticsearch/elasticsearch-oss:6.6.0
resources:
limits:
cpu: 1000m
requests:
cpu: 100m
ports:
- containerPort: 9200
name: db
protocol: TCP
- containerPort: 9300
name: transport
protocol: TCP
volumeMounts:
- name: data
mountPath: /usr/share/elasticsearch/data
env:
- name: cluster.name
value: elasticsearch-cluster
- name: node.name
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: discovery.zen.ping.unicast.hosts
value: "elasticsearch-logging-0.elasticsearch,elasticsearch-logging-1.elasticsearch,elasticsearch-logging-2.elasticsearch"
- name: discovery.zen.minimum_master_nodes
value: "2"
- name: ES_JAVA_OPTS
value: "-Xms1g -Xmx1g"
initContainers:
- image: alpine:3.6
command: ["/sbin/sysctl", "-w", "vm.max_map_count=262144"]
name: elasticsearch-logging-init-vm-map-count
securityContext:
privileged: true
- image: alpine:3.6
command: ["sh", "-c", "ulimit -n 65536"]
name: elasticsearch-logging-init-ulimit
securityContext:
privileged: true
volumeClaimTemplates:
- metadata:
name: data
labels:
app: elasticsearch
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 100Gi
変更点は以下の通り。
- ServiceAccountに関する設定は今回必要ないので削除
- デプロイ先をmonitoringノードのみにするためnodeSelectorを使用
- イメージを公式のものに変更
- データ用ディレクトリはPVを使うように変更
- 必要な初期設定をenvとして追加している。メモリの割当などは環境に合わせて要件等
クラスタを構築する際にDNSを使っているので、この名前で解決できるようにHeadless Service
を用いる。
詳しくは、公式を参照。
ざっくり、ClusterIPは割当せず、各PodへのアクセスへのDNSを設定するよとのこと。
# elastic-service.yml
apiVersion: v1
kind: Service
metadata:
name: elasticsearch
namespace: kube-logging
labels:
k8s-app: elasticsearch-logging
kubernetes.io/cluster-service: "true"
kubernetes.io/name: "Elasticsearch"
spec:
selector:
k8s-app: elasticsearch-logging
clusterIP: None
ports:
- port: 9200
name: db
- port: 9300
name: transport
実際に、上記の設定を読み込んでいく。 まず、Serviceの作成。
kubectl apply -f elastic-service.yml
作成されたサービスの確認。
$ kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
elasticsearch ClusterIP None <none> 9200/TCP,9300/TCP 11d
ClusterIPが割り当てられていないことがわかる。 続いて、Statefulsetのインストール。
kubectl apply -f elastic-statefulset.yml
デプロイされたPodの確認。
$ kubectl get pod -o wide -l k8s-app=elasticsearch-logging
NAME READY STATUS RESTARTS AGE IP NODE
elasticsearch-logging-0 1/1 Running 0 2m 10.244.5.14 k8s-monitoring-01
elasticsearch-logging-1 1/1 Running 0 1m 10.244.6.9 k8s-monitoring-02
elasticsearch-logging-2 1/1 Running 0 9s 10.244.5.15 k8s-monitoring-01
PVCの確認もしておく。
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
data-elasticsearch-logging-0 Bound nfs-elastic2-pv 100Gi RWO 3m
data-elasticsearch-logging-1 Bound nfs-elastic1-pv 100Gi RWO 2m
data-elasticsearch-logging-2 Bound nfs-elastic0-pv 100Gi RWO 56s
以上で、ElasticSearchのインストールは終了なので、実際に動作しているかを確認する。
kubectl -n kube-logging port-forward elasticsearch-logging-0 9200:9200
他のターミナル画面でhttp://localhost:9200/_cluster/state?prettyにアクセスするとクラスタ内のノードがみれる。 以下は例。
$ curl 'http://localhost:9200/_cluster/state?pretty'
{
"cluster_name" : "elasticsearch-cluster",
"compressed_size_in_bytes" : 13960,
"cluster_uuid" : "wsPB_NqrSrS7P2UvoriLKA",
"version" : 123,
"state_uuid" : "0xjuNhJYTESMEGPD8skLZA",
"master_node" : "g7EyGIaDQKKNWhoa3-4gLA",
"blocks" : { },
"nodes" : {
"JCDeUXEvSJ6dXbwmM3FkQg" : {
"name" : "elasticsearch-logging-2",
"ephemeral_id" : "n5HDGjdCQbmsrl0k1hu3cg",
"transport_address" : "10.244.5.15:9300",
"attributes" : { }
},
"gpYF9LvpR9yw_BqlBCKQ6Q" : {
"name" : "elasticsearch-logging-1",
"ephemeral_id" : "GkV5sG0CTcek7JWiRW1VOQ",
"transport_address" : "10.244.6.9:9300",
"attributes" : { }
},
"g7EyGIaDQKKNWhoa3-4gLA" : {
"name" : "elasticsearch-logging-0",
"ephemeral_id" : "ang23sJ5TDaxJoQv0TIscQ",
"transport_address" : "10.244.5.14:9300",
"attributes" : { }
}
},
<snip>
Kibanaのインストール
ElasticSearchのインストールが完了したので、Kibanaをインストールする。 同様にAddonのファイルを参考にして作る。
今回インストールするのは、DeploymentとService。 Deploymentの設定ファイルから作っていく。
# kibana-deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: kibana-logging
namespace: kube-logging
labels:
k8s-app: kibana-logging
kubernetes.io/cluster-service: "true"
spec:
replicas: 1
selector:
matchLabels:
k8s-app: kibana-logging
template:
metadata:
labels:
k8s-app: kibana-logging
spec:
nodeSelector:
role: monitoring
containers:
- name: kibana-logging
image: docker.elastic.co/kibana/kibana-oss:6.6.0
resources:
limits:
cpu: 1000m
requests:
cpu: 100m
env:
- name: ELASTICSEARCH_URL
value: http://elasticsearch:9200
ports:
- containerPort: 5601
name: ui
protocol: TCP
変更点は以下の通り。
- Addonの設定を削除
- ノードセレクタでmonitoringノードを指定
続いて、Serviceの設定ファイルを作る。
# kibana-service.yml
apiVersion: v1
kind: Service
metadata:
name: kibana-logging
namespace: kube-logging
labels:
k8s-app: kibana-logging
kubernetes.io/cluster-service: "true"
kubernetes.io/name: "Kibana"
spec:
ports:
- port: 5601
protocol: TCP
targetPort: ui
selector:
k8s-app: kibana-logging
type: NodePort
変更点はtype。外部からアクセスできるようにNodePort
に変更
上記をデプロイ。
kubectl apply -f ./kibana-deployment.yml
kubectl apply -f ./kibana-service.yml
デプロイしたら確認。Podから。
$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE
kibana-logging-78d76f68c9-sdx4d 1/1 Running 0 1m 10.244.6.10 k8s-monitoring-02
サービスも確認。
$ kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
elasticsearch ClusterIP None <none> 9200/TCP,9300/TCP 11d
kibana-logging NodePort 10.98.101.139 <none> 5601:32339/TCP 5s
続いて、NodeのIPとNodeのPortを使ってアクセスする。上記の例だとポートは32339を使う。 実際にアクセスできると下記のようなKibanaのページが見れる。
Fluentdのインストール
公式を参考に作る。 ベージによると設定のファイルがGithubにあるので、ありがたく使わせていただく。 使用するのはRBACを含んだコンフィグファイル。
ただし、いくつか変更を加える。
- namespaceの名前
- 認証の削除
上記変更を加えると下記の通り。
# fluentd.yaml
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: fluentd
namespace: kube-logging
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: fluentd
rules:
- apiGroups:
- ""
resources:
- pods
- namespaces
verbs:
- get
- list
- watch
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: fluentd
roleRef:
kind: ClusterRole
name: fluentd
apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
name: fluentd
namespace: kube-logging
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd
namespace: kube-logging
labels:
k8s-app: fluentd-logging
version: v1
kubernetes.io/cluster-service: "true"
spec:
selector:
matchLabels:
k8s-app: fluentd-logging
template:
metadata:
labels:
k8s-app: fluentd-logging
version: v1
kubernetes.io/cluster-service: "true"
spec:
serviceAccount: fluentd
serviceAccountName: fluentd
tolerations:
- key: node-role.kubernetes.io/master
effect: NoSchedule
containers:
- name: fluentd
image: fluent/fluentd-kubernetes-daemonset:elasticsearch
env:
- name: FLUENT_ELASTICSEARCH_HOST
value: "elasticsearch"
- name: FLUENT_ELASTICSEARCH_PORT
value: "9200"
- name: FLUENT_ELASTICSEARCH_SCHEME
value: "http"
- name: FLUENT_UID
value: "0"
resources:
limits:
memory: 200Mi
requests:
cpu: 100m
memory: 200Mi
volumeMounts:
- name: varlog
mountPath: /var/log
- name: varlibdockercontainers
mountPath: /var/lib/docker/containers
readOnly: true
terminationGracePeriodSeconds: 30
volumes:
- name: varlog
hostPath:
path: /var/log
- name: varlibdockercontainers
hostPath:
path: /var/lib/docker/containers
デプロイする。
kubectl apply -f ./fluentd.yaml
作成されたPodの確認。
$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE
elasticsearch-logging-0 1/1 Running 0 33m 10.244.5.14 k8s-monitoring-01
elasticsearch-logging-1 1/1 Running 0 32m 10.244.6.9 k8s-monitoring-02
elasticsearch-logging-2 1/1 Running 0 30m 10.244.5.15 k8s-monitoring-01
fluentd-7cl2p 1/1 Running 0 30s 10.244.4.9 k8s-worker-02
fluentd-8kr77 1/1 Running 0 30s 10.244.0.15 k8s-master-01
fluentd-bg5k4 1/1 Running 0 30s 10.244.2.8 k8s-master-03
fluentd-htjnj 1/1 Running 0 30s 10.244.8.10 k8s-lb-02
fluentd-rglz5 1/1 Running 0 30s 10.244.7.16 k8s-lb-01
fluentd-rtl9s 1/1 Running 0 30s 10.244.5.19 k8s-monitoring-01
fluentd-rxkbh 1/1 Running 0 30s 10.244.6.13 k8s-monitoring-02
fluentd-szn79 1/1 Running 0 30s 10.244.3.11 k8s-worker-01
fluentd-wwjkb 1/1 Running 0 30s 10.244.1.6 k8s-master-02
kibana-logging-589cc9bbf7-kc9w9 1/1 Running 0 12m 10.244.5.16 k8s-monitoring-01
$ kubectl get daemonset
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
fluentd 9 9 9 9 9 <none> 33s
実際にelasticsearchに接続されていると、Kibanaからログが見れるようになる。
Discoverをクリックして、index patternを作成する。
この画面でlogstash-*
を入力して次へ。
次では、@timestamp
を時間のフィールドとして設定すると、次にまたDiscoverをクリックすると集められたログが以下のように見えるようになる。