Kubernetes和EFK

我们使用Kubernetes作为微服务架构的基础,在我们的系统中每个微服务都有多个副本,每个副本的数量以及所在的Node都是可变的。因此对于日志需要集中化管理,在使用Kubernetes之前,我们的系统使用ELK(Elasticsearch+Logstash+Kibana)实现日志的聚集、查询和展现。由于Kubernetes推荐使用Fluentd,所以我们尝试使用EFK(Elasticsearch+Fluentd+Kibana)作为我们的日志集中管理组件。

Kubernetes官方文档Logging and Monitoring Cluster Activity中给出了在Node上通过Logging Agent将日志收集到Logging Backend中的架构方案,如下图:

Using a node logging agent

其中Logging Agent推荐使用Fluentd,Logging Backend推荐使用Elasticsearch和Kibana。

准备镜像

Kubernetes已经给了Logging Agent For Elasticsearch的部署参考,我们从其中的 fluentd-es-ds.yaml, es-controller.yaml, kibana-controller.yaml中可以看出我们需要如下三个Docker镜像:

1gcr.io/google_containers/fluentd-elasticsearch:1.22
2gcr.io/google_containers/elasticsearch:v2.4.1-2
3gcr.io/google_containers/kibana:v4.6.1-1

由于某些的原因,我们从gcr.io/google_containers上pull镜像会遇到一些麻烦,这里我们做一些准备工作,到这里查看gcr.io的host,并配置到各个Node的hosts中。

测试Node到grc连接:

1curl https://gcr.io/v1

并可在某个Node上测试pull这些镜像:

1docker pull gcr.io/google_containers/fluentd-elasticsearch:1.22
2docker pull gcr.io/google_containers/elasticsearch:v2.4.1-2
3docker pull gcr.io/google_containers/kibana:v4.6.1-1

以DaemonSet形式启动Fluentd

Fluentd需要作为Logging Agent的形式在每个Node启动,因此DaemonSet是最好的选择。

1wget https://raw.githubusercontent.com/kubernetes/kubernetes/master/cluster/addons/fluentd-elasticsearch/fluentd-es-ds.yaml

接下来创建DaemonSet时出错了:

1kubectl create -f fluentd-es-ds.yaml
2error: error validating "fluentd-es-ds.yaml": error validating data: found invalid field tolerations for v1.PodSpec; if you choose to ignore these errors, turn validation off with --validate=false

修改fluentd-es-ds.yaml,注释掉下面的几行:

1      nodeSelector:
2        beta.kubernetes.io/fluentd-ds-ready: "true"
3      tolerations:
4      - key : "node.alpha.kubernetes.io/ismaster"
5        effect: "NoSchedule"

这下创建成功了:

1kubectl create -f fluentd-es-ds.yaml
2daemonset "fluentd-es-v1.22" created

查看创建结果:

1 kubectl get ds --namespace=kube-system -l k8s-app=fluentd-es
2NAME               DESIRED   CURRENT   READY     NODE-SELECTOR   AGE
3fluentd-es-v1.22   3         3         3         <none>          1m
1kubectl get pod --namespace=kube-system -l k8s-app=fluentd-es -o wide
2NAME                     READY     STATUS    RESTARTS   AGE       IP             NODE
3fluentd-es-v1.22-38x88   1/1       Running   0          3m        10.244.3.102   cent1
4fluentd-es-v1.22-5579j   1/1       Running   0          3m        10.244.2.17    cent2
5fluentd-es-v1.22-5sd4b   1/1       Running   0          3m        10.244.0.158   cent0

可以看出fluentd的DaemonSet正常创建,同时在集群的每个Node上启动了一个Pod。

启动Elasticsearch

1wget https://raw.githubusercontent.com/kubernetes/kubernetes/master/cluster/addons/fluentd-elasticsearch/es-service.yaml
2wget https://raw.githubusercontent.com/kubernetes/kubernetes/master/cluster/addons/fluentd-elasticsearch/es-controller.yaml

创建ES的RC和Service:

1kubectl create -f es-controller.yaml
2replicationcontroller "elasticsearch-logging-v1" created
3
4kubectl create -f es-service.yaml
5service "elasticsearch-logging" created

查看创建的Service和Pod:

 1kubectl get svc --namespace=kube-system -l k8s-app=elasticsearch-logging -o wide
 2NAME                    CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE       SELECTOR
 3elasticsearch-logging   10.97.140.122   <none>        9200/TCP   1m        k8s-app=elasticsearch-logging
 4
 5
 6kubectl get rc --namespace=kube-system -l k8s-app=elasticsearch-logging
 7NAME                       DESIRED   CURRENT   READY     AGE
 8elasticsearch-logging-v1   2         2         2         2m
 9
10
11kubectl get pod --namespace=kube-system -l k8s-app=elasticsearch-logging -o wide
12NAME                             READY     STATUS    RESTARTS   AGE       IP             NODE
13elasticsearch-logging-v1-67v53   1/1       Running   0          3m        10.244.3.103   cent1
14elasticsearch-logging-v1-sn8h9   1/1       Running   0          3m        10.244.2.18    cent2

启动Kibana

1wget https://raw.githubusercontent.com/kubernetes/kubernetes/master/cluster/addons/fluentd-elasticsearch/kibana-controller.yaml
2wget https://raw.githubusercontent.com/kubernetes/kubernetes/master/cluster/addons/fluentd-elasticsearch/kibana-service.yaml
1kubectl create -f kibana-controller.yaml
2kubectl create -f kibana-service.yaml

查看创建的Service和Pod:

 1kubectl get svc --namespace=kube-system -l k8s-app=kibana-logging -o wide
 2NAME             CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE       SELECTOR
 3kibana-logging   10.110.251.77   <none>        5601/TCP   1m        k8s-app=kibana-logging
 4
 5
 6kubectl get deploy --namespace=kube-system -l k8s-app=kibana-logging
 7NAME             DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
 8kibana-logging   1         1         1            1           1m
 9
10
11kubectl get pod --namespace=kube-system -l k8s-app=kibana-logging -o wide
12NAME                              READY     STATUS    RESTARTS   AGE       IP            NODE
13kibana-logging-1918083406-6cq9n   1/1       Running   0          1m        10.244.2.19   cent2

查看Kibana服务的地址:

1kubectl cluster-info
2Kibana is running at http://localhost:8080/api/v1/proxy/namespaces/kube-system/services/kibana-logging

看到Kibana服务只在Master Node的localhost好用,下面我们kubectl proxy代理api server:

1kubectl proxy --port=8011 --address=192.168.61.100 --accept-hosts='^192\.168\.61\.*'
2Starting to serve on 192.168.61.100:8011

使用下面的地址访问Kibana:

1http://192.168.61.100:8011/api/v1/proxy/namespaces/kube-system/services/kibana-logging

创建index后,就可以在Kibana中查看到Kubernetes集群中的日志了:

最后

Kubernetes官方EFK的部署参考中,Elasticsearch挂载的Volume是emptyDir。

 1  template:
 2    metadata:
 3      labels:
 4        k8s-app: elasticsearch-logging
 5        version: v1
 6        kubernetes.io/cluster-service: "true"
 7    spec:
 8      containers:
 9      - image: gcr.io/google_containers/elasticsearch:v2.4.1-2
10        name: elasticsearch-logging
11        resources:
12          # need more cpu upon initialization, therefore burstable class
13          limits:
14            cpu: 1000m
15          requests:
16            cpu: 100m
17        ports:
18        - containerPort: 9200
19          name: db
20          protocol: TCP
21        - containerPort: 9300
22          name: transport
23          protocol: TCP
24        volumeMounts:
25        - name: es-persistent-storage
26          mountPath: /data
27        env:
28        - name: "NAMESPACE"
29          valueFrom:
30            fieldRef:
31              fieldPath: metadata.namespace
32      volumes:
33      - name: es-persistent-storage
34        emptyDir: {}

因此官方的部署参考仅可用于试验,实际部署到生产环境时需要使用Persistent Volume。

参考