前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >部署 Kubernetes 集群日志插件 Fluentd、Elasticsearch、Kibana

部署 Kubernetes 集群日志插件 Fluentd、Elasticsearch、Kibana

作者头像
哎_小羊
发布2018-01-02 14:41:49
7.3K0
发布2018-01-02 14:41:49
举报
文章被收录于专栏:哎_小羊

目录

  • Kubernetes 日志架构介绍
  • 环境、软件准备
  • 启动 Fluentd
  • 启动 Elasticsearch
  • 启动 Kibana
    • 浏览器添加证书
    • RBAC 认证模式介绍

1、Kubernetes 日志架构介绍

对于任何基础架构或者服务系统,日志重要性不言而喻,当然 Kubernetes 也少不了对 Logging 的支持,集群中各个资源以及服务日志如何很好的集中查看并分析,官方给出了 Cluster-level Logging 的架构,其中就提供使用 EFK 框架作为集群日志解决方案。当然 EFK / ELK 在业内也是相对成熟作为日志集中分析平台,ELK 在 Kubernetes 集群中以 Pod 方式运行,丝毫不影响集群中其他 Pod,而且不需要修改其他 Pod 配置,非常方便。

Kubernetes 官网给出的 Cluster-level Logging 参考架构如下:

从图上可以看出,它是采用 Node Logging Agent 的方式,通过在集群每个节点上部署一个 Agent 代理 Pod 服务,收集该 Node 上的日志并 Push 到后端,当然 Logging agent 是以容器方式运行,并且有权限进入该节点上所有服务容器的日志目录。上边提到的 Logging-agent 就可以采用 Fluentd,而 Logging Backend 就可以采用 Elasticsearch,简单理解就是,通过 Fluentd 作为 Logging-agent 收集并 Push 日志到后端 Elasticsearch,最终通过 Kibana 图形化展现出来。

2、环境、软件准备

部署 Fluentd、Elasticsearch、Kibana 到 Kubernetes 集群中,前提我们需要有一个正常运行的集群服务,这里我采用 kubeadm 搭建的 Kubernetes 集群,具体搭建步骤可以参考我上一篇文章 国内使用 kubeadm 在 Centos 7 搭建 Kubernetes 集群 讲述的比较详细,这里就不做演示了。不过还是要说一下的就是国内访问外国网站问题,由于这三个服务所需要的 images 在国外,国内用户可以去 Docker Hub 下载指定版本的镜像替代,下载完成后,通过 docker tag ... 命令修改成指定名称的镜像即可。

本次演示所依赖的各个镜像列表如下:

Image Name

Version

Des ( * 必需)

gcr.io/google_containers/elasticsearch

v2.4.1-1

*

gcr.io/google_containers/kibana

v4.6.1-1

*

gcr.io/google_containers/fluentd-elasticsearch

1.22

*

说明一下,这里我没有使用最新版本的镜像,因为我的 Kubernetes 版本为 v1.6.2,所以我选择了Github kubernetes 下该版本对应的组件,回头再试下更新成最新版本的试试看。

可使用下边脚本,分别替换以上镜像。

代码语言:javascript
复制
#!/bin/bash

images=(
    elasticsearch:v2.4.1-1 
    kibana:v4.6.1-1
    fluentd-elasticsearch:1.22)

for imageName in ${images[@]} ; do
    docker pull docker.io/bigwhite/$imageName
    docker tag docker.io/bigwhite/$imageName gcr.io/google_containers/$imageName 
    docker rmi docker.io/bigwhite/$imageName
done   

3、启动 Fluentd

Fluentd 是以 DaemonSet 的形式运行在 Kubernetes 集群中,这样就可以保证集群中每个 Node 上都会启动一个 Fluentd,我们在 Master 节点创建 Fluented 服务,最终会在各个 Node 上运行,可以通过 Yaml 文件的方式。

代码语言:javascript
复制
$ cd /home/wanyang3/k8s/
$ git clone https://github.com/kubernetes/kubernetes.git
$ git checkout v1.6.2
$ cd cluster/addons/fluentd-elasticsearch
$ ls -l *.yaml
-rw-r--r--. 1 root root 1246 11月  1 16:55 es-controller.yaml
-rw-r--r--. 1 root root  382 11月  1 14:44 es-service.yaml
-rw-r--r--. 1 root root 1626 11月  1 14:46 fluentd-es-ds.yaml
-rw-r--r--. 1 root root  986 11月  1 14:46 kibana-controller.yaml
-rw-r--r--. 1 root root  354 11月  1 14:44 kibana-service.yaml

$ kubectl create -f fluentd-es-ds.yaml

命令创建 Fluentd 后,默认会将启动日志输出到 Node 节点的 /var/log/fluented.log 文件里面去。但是,当我们去 Node 节点上执行 tail -f /var/log/fluented.log 时,却发现提示并没有该文件,难道没启动成功?

首先查看一下 Pod 没有创建,通过 kubectl get pods -n kube-system 命令查看并没有Running 或者 Pendding 中的 fluentd,那就是没有创建成功,这是为啥呢?

接着我们查看下 fluentd-es-ds.yaml 信息

代码语言:javascript
复制
$ kubectl get -f fluentd-es-ds.yaml
NAME               DESIRED   CURRENT   READY     UP-TO-DATE   AVAILABLE   NODE-SELECTOR                              AGE
fluentd-es-v1.22   0         0         0         0            0           beta.kubernetes.io/fluentd-ds-ready=true   1m

通过输出我们可以看到,确实没有启动起来,不过我们发现 NODE-SELECTOR 选项为 beta.kubernetes.io/fluentd-ds-ready=true,这下就明白为什么了,原来 fluentd 只会调度设置了标签 beta.kubernetes.io/fluentd-ds-ready=true 的 Node 节点。

不甘心的我,决定看下我集群中 Node 节点是否有这个标签,

代码语言:javascript
复制
$ kubectl describe nodes node0.localdomain
Name:           node0.localdomain
Role:
Labels:         beta.kubernetes.io/arch=amd64
                beta.kubernetes.io/os=linux
                kubernetes.io/hostname=node0.localdomain
...         

好吧,这下死心了,确实没有这个标签,那就给该 Node 补上这个标签,然后重新运行下 fluentd。

代码语言:javascript
复制
# Node 节点打标签
$ kubectl label node node0.localdomain beta.kubernetes.io/fluentd-ds-ready=true 
# 重新运行 fluentd
$ kubectl apply -f fluentd-es-ds.yaml
# 查看 Pod 是否启动成功
$ kubectl get pods -n kube-system
NAME                                         READY     STATUS    RESTARTS   AGE
fluentd-es-v1.22-4g2zl                       1/1       Running   1          5m
...

好了,这下启动成功了,这下在去看下 Node 节点 /var/log/fluented.log 文件,这下有日志输出啦。

代码语言:javascript
复制
$ tail -f /var/log/fluented.log
2017-11-01 08:37:44 +0000 [info]: reading config file path="/etc/td-agent/td-agent.conf"
2017-11-01 08:37:44 +0000 [info]: starting fluentd-0.12.31
2017-11-01 08:37:44 +0000 [info]: gem 'fluent-mixin-config-placeholders' version '0.4.0'
2017-11-01 08:37:44 +0000 [info]: gem 'fluent-mixin-plaintextformatter' version '0.2.6'
2017-11-01 08:37:44 +0000 [info]: gem 'fluent-plugin-docker_metadata_filter' version '0.1.3'
2017-11-01 08:37:44 +0000 [info]: gem 'fluent-plugin-elasticsearch' version '1.5.0'
2017-11-01 08:37:44 +0000 [info]: gem 'fluent-plugin-kafka' version '0.4.1'
2017-11-01 08:37:44 +0000 [info]: gem 'fluent-plugin-kubernetes_metadata_filter' version '0.24.0'
2017-11-01 08:37:44 +0000 [info]: gem 'fluent-plugin-mongo' version '0.7.16'
2017-11-01 08:37:44 +0000 [info]: gem 'fluent-plugin-rewrite-tag-filter' version '1.5.5'
2017-11-01 08:37:44 +0000 [info]: gem 'fluent-plugin-s3' version '0.8.0'
2017-11-01 08:37:44 +0000 [info]: gem 'fluent-plugin-scribe' version '0.10.14'
2017-11-01 08:37:44 +0000 [info]: gem 'fluent-plugin-td' version '0.10.29'
2017-11-01 08:37:44 +0000 [info]: gem 'fluent-plugin-td-monitoring' version '0.2.2'
2017-11-01 08:37:44 +0000 [info]: gem 'fluent-plugin-webhdfs' version '0.4.2'
2017-11-01 08:37:44 +0000 [info]: gem 'fluentd' version '0.12.31'
2017-11-01 08:37:44 +0000 [info]: adding match pattern="fluent.**" type="null"
...
2017-11-01 08:37:46 +0000 [warn]: /var/log/containers/fluentd-es-v1.22-4g2zl_kube-system_fluentd-es-5632cf09917eda0637a911be6a7bb2738d490216c8f0b56a0f74b4b8c91e191c.log unreadable. It is excluded and would be examined next time.

最后的一行输出又是什么鬼?获取不到容器 fluentd 在 /var/log/containers/fluentd-es-xxxxxx 下的日志输出。果断去该目录 /var/log/containers/ 下看下确实没有任何容器日志文件,好吧,分析觉得很有可能是 Docker 输出日志的位置跟 Fluentd 监听的日志的位置不一致。

代码语言:javascript
复制
$ cat fluentd-es-ds.yaml
...
volumes:
- name: varlog
hostPath:
    path: /var/log
- name: varlibdockercontainers
hostPath:
    path: /var/lib/docker/containers

原来是去 /var/lib/docker/containers/var/log 目录去找日志。我查看那一下机器Docker 的日志驱动配置

代码语言:javascript
复制
$ docker info
...
Logging Driver: journald
Cgroup Driver: systemd
...

原来这个节点 安装的 Docker 默认日志驱动为 journald,那么所有的日志都会通过系统的 journal进行统一处理,输出到 /var/log/messages 下边了。怪不得提示 /var/log/containers/ 下没有任何容器日志文件呢。解决办法就是修改 Docker 的日志驱动为 json-file 方式。

代码语言:javascript
复制
$ vim /etc/sysconfig/docker
增加 OPTIONS='--selinux-enabled --log-driver=json-file --signature-verification=false'

$ systemctl daemon-reload
$ systemctl restart docker

好了,现在去看下 /var/log/containers/fluentd-es-xxxxxx 终于有日志输出了。

代码语言:javascript
复制
2017-11-01 08:49:25 +0000 [info]: reading config file path="/etc/td-agent/td-agent.conf"
2017-11-01 08:49:25 +0000 [info]: starting fluentd-0.12.31
2017-11-01 08:49:25 +0000 [info]: gem 'fluent-mixin-config-placeholders' version '0.4.0'
2017-11-01 08:49:25 +0000 [info]: gem 'fluent-mixin-plaintextformatter' version '0.2.6'
2017-11-01 08:49:25 +0000 [info]: gem 'fluent-plugin-docker_metadata_filter' version '0.1.3'
2017-11-01 08:49:25 +0000 [info]: gem 'fluent-plugin-elasticsearch' version '1.5.0'
2017-11-01 08:49:25 +0000 [info]: gem 'fluent-plugin-kafka' version '0.4.1'
2017-11-01 08:49:25 +0000 [info]: gem 'fluent-plugin-kubernetes_metadata_filter' version '0.24.0'
2017-11-01 08:49:25 +0000 [info]: gem 'fluent-plugin-mongo' version '0.7.16'
2017-11-01 08:49:25 +0000 [info]: gem 'fluent-plugin-rewrite-tag-filter' version '1.5.5'
2017-11-01 08:49:25 +0000 [info]: gem 'fluent-plugin-s3' version '0.8.0'
2017-11-01 08:49:25 +0000 [info]: gem 'fluent-plugin-scribe' version '0.10.14'
2017-11-01 08:49:25 +0000 [info]: gem 'fluent-plugin-td' version '0.10.29'
2017-11-01 08:49:25 +0000 [info]: gem 'fluent-plugin-td-monitoring' version '0.2.2'
2017-11-01 08:49:25 +0000 [info]: gem 'fluent-plugin-webhdfs' version '0.4.2'
2017-11-01 08:49:25 +0000 [info]: gem 'fluentd' version '0.12.31'
2017-11-01 08:49:25 +0000 [info]: adding match pattern="fluent.**" type="null"
...
2017-11-01 08:49:39 +0000 [warn]: suppressed same stacktrace
2017-11-01 08:49:48 +0000 [warn]: temporarily failed to flush the buffer. next_retry=2017-11-01 08:50:03 +0000 error_class="Fluent::ElasticsearchOutput::ConnectionFailure" error="Can not reach Elasticsearch cluster ({:host=>\"elasticsearch-logging\", :port=>9200, :scheme=>\"http\"})!" plugin_id="object:3ff062495470"

这下输出终于正常了,不过最后输出 error="Can not reach Elasticsearch cluster 这个错误,可以先不用管,因为 Elasticsearch 服务我们还没启动呢,连接不上是正常的,下边启动完毕之后,就正常了。

4、启动 Elasticsearch

经过一番折腾,作为 Logging-agent 的 Fluentd 启动好了,现在要启动作为 Logging Backend 的 Elasticsearch 了,Elasticsearch 的主要作用是将日志信息进行分割,建立索引,配合下边 Kibana 展示数据使用。它也是通过 Yaml 文件创建。

代码语言:javascript
复制
$ kubectl create -f es-controller.yaml
$ kubectl create -f es-service.yaml

$ kubectl get pods --all-namespaces -o wide
NAMESPACE     NAME                                   READY     STATUS    RESTARTS   AGE       IP             NODE
kube-system   elasticsearch-logging-v1-1rt61         1/1       Running   0          10s        10.96.2.28     node0.localdomain
kube-system   elasticsearch-logging-v1-gbq8p         1/1       Running   0          10s        10.96.2.29     node0.localdomain
kube-system   fluentd-es-v1.22-4g2zl                 1/1       Running   1          20m        10.96.2.24     node0.localdomain
...

看样子是启动成功了,不放心还是看下日志输出吧!

代码语言:javascript
复制
$ kubectl logs -f pod/elasticsearch-logging-v1-1rt61 -n kube-system
[2017-11-01 08:58:04,774][INFO ][node                     ] [elasticsearch-logging-v1-1rt61] version[2.4.1], pid[13], build[c67dc32/2016-09-27T18:57:55Z]
[2017-11-01 08:58:04,788][INFO ][node                     ] [elasticsearch-logging-v1-1rt61] initializing ...
[2017-11-01 08:58:06,218][INFO ][plugins                  ] [elasticsearch-logging-v1-1rt61] modules [reindex, lang-expression, lang-groovy], plugins [], sites []
[2017-11-01 08:58:06,367][INFO ][env                      ] [elasticsearch-logging-v1-1rt61] using [1] data paths, mounts [[/data (/dev/mapper/cl-root)]], net usable_space [22.4gb], net total_space [32.7gb], spins? [possibly], types [xfs]
[2017-11-01 08:58:06,367][INFO ][env                      ] [elasticsearch-logging-v1-1rt61] heap size [1015.6mb], compressed ordinary object pointers [true]
[2017-11-01 08:58:12,117][INFO ][node                     ] [elasticsearch-logging-v1-1rt61] initialized
[2017-11-01 08:58:12,117][INFO ][node                     ] [elasticsearch-logging-v1-1rt61] starting ...
[2017-11-01 08:58:12,688][INFO ][transport                ] [elasticsearch-logging-v1-1rt61] publish_address {10.96.2.28:9300}, bound_addresses {[::]:9300}
[2017-11-01 08:58:12,706][INFO ][discovery                ] [elasticsearch-logging-v1-1rt61] kubernetes-logging/9bdsRkUYTCKI5DNKGZXmxw
[2017-11-01 08:58:15,828][INFO ][cluster.service          ] [elasticsearch-logging-v1-1rt61] new_master {elasticsearch-logging-v1-1rt61}{9bdsRkUYTCKI5DNKGZXmxw}{10.96.2.28}{10.96.2.28:9300}{master=true}, added {{elasticsearch-logging-v1-gbq8p}{clJyWOTlRx6qn5nHeFEinw}{10.96.2.29}{10.96.2.29:9300}{master=true},}, reason: zen-disco-join(elected_as_master, [1] joins received)
[2017-11-01 08:58:15,948][INFO ][http                     ] [elasticsearch-logging-v1-1rt61] publish_address {10.96.2.28:9200}, bound_addresses {[::]:9200}
[2017-11-01 08:58:15,948][INFO ][node                     ] [elasticsearch-logging-v1-1rt61] started
[2017-11-01 08:58:16,059][INFO ][gateway                  ] [elasticsearch-logging-v1-1rt61] recovered [0] indices into cluster_state
[2017-11-01 08:58:44,750][INFO ][cluster.metadata         ] [elasticsearch-logging-v1-1rt61] [logstash-2017.11.01] creating index, cause [auto(bulk api)], templates [], shards [5]/[1], mappings []
[2017-11-01 08:58:46,296][INFO ][cluster.routing.allocation] [elasticsearch-logging-v1-1rt61] Cluster health status changed from [RED] to [YELLOW] (reason: [shards started [[logstash-2017.11.01][0], [logstash-2017.11.01][0]] ...]).
[2017-11-01 08:58:46,434][INFO ][cluster.metadata         ] [elasticsearch-logging-v1-1rt61] [logstash-2017.11.01] create_mapping [fluentd]
[2017-11-01 08:58:46,578][INFO ][cluster.metadata         ] [elasticsearch-logging-v1-1rt61] [logstash-2017.11.01] update_mapping [fluentd]
[2017-11-01 08:58:46,697][INFO ][cluster.metadata         ] [elasticsearch-logging-v1-1rt61] [logstash-2017.11.01] update_mapping [fluentd]
[2017-11-01 08:58:47,059][INFO ][cluster.routing.allocation] [elasticsearch-logging-v1-1rt61] Cluster health status changed from [YELLOW] to [GREEN] (reason: [shards started [[logstash-2017.11.01][0]] ...]).

[YELLOW] to [GREEN] 了,妥妥没问题了。在去 Node 节点看下上边安装完 Fluentd 最后的 error 如何了。

代码语言:javascript
复制
$ tail -f /var/log/fluented.log
...
2017-11-01 08:58:44 +0000 [info]: Connection opened to Elasticsearch cluster => {:host=>"elasticsearch-logging", :port=>9200, :scheme=>"http"}
2017-11-01 08:58:47 +0000 [warn]: retry succeeded. plugin_id="object:3ff062495470"
2017-11-01 09:00:26 +0000 [info]: following tail of /var/log/containers/kibana-logging-3757371098-dkjsg_kube-system_kibana-logging-e60bec3a2f87ba6d85952bf4d73f301b912cf797b97ca545340a429747c4351a.log

显示连接成功,这一次还挺顺利的哈。接下来该启动 Kibana 服务来图形化查看收集的日志信息了。

5、启动 Kibana

Kibana 是一个开源的分析与可视化平台,与 Elasticsearch 一起使用的,可以用 Kibana 搜索、查看、交互存放在 Elasticsearch 索引里的数据,很直观的在浏览器页面图形化展示出来,非常方便,它也是通过 Yaml 文件创建。

代码语言:javascript
复制
$ kubectl create -f kibana-controller.yaml
$ kubectl create -f kibana-service.yaml

$ kubectl get pods --all-namespaces -o wide
NAMESPACE     NAME                                         READY     STATUS    RESTARTS   AGE       IP             NODE
kube-system   elasticsearch-logging-v1-1rt61               1/1       Running   0          2m        10.96.2.28     node0.localdomain
kube-system   elasticsearch-logging-v1-gbq8p               1/1       Running   0          2m        10.96.2.29     node0.localdomain
kube-system   fluentd-es-v1.22-4g2zl                       1/1       Running   1          22m       10.96.2.24     node0.localdomain
kube-system   kibana-logging-3757371098-dkjsg              1/1       Running   0          8s        10.96.2.30     node0.localdomain

显示启动成功,查看下日志输出,显示需要花费几分钟优化缓存 Kibana 和状态页。

代码语言:javascript
复制
$ kubectl logs -f pod/kibana-logging-3757371098-dkjsg -n kube-system
ELASTICSEARCH_URL=http://elasticsearch-logging:9200
server.basePath: /api/v1/proxy/namespaces/kube-system/services/kibana-logging
{"type":"log","@timestamp":"2017-11-01T09:00:40Z","tags":["info","optimize"],"pid":5,"message":"Optimizing and caching bundles for kibana and statusPage. This may take a few minutes"}

稍等几分钟(有的可能需要更长时间,我的 5 分钟左右),再来查看日志,就显示启动成功了。

代码语言:javascript
复制
$ kubectl logs -f pod/kibana-logging-3757371098-dkjsg -n kube-system
ELASTICSEARCH_URL=http://elasticsearch-logging:9200
server.basePath: /api/v1/proxy/namespaces/kube-system/services/kibana-logging
{"type":"log","@timestamp":"2017-11-01T09:00:40Z","tags":["info","optimize"],"pid":5,"message":"Optimizing and caching bundles for kibana and statusPage. This may take a few minutes"}
{"type":"log","@timestamp":"2017-11-01T09:06:52Z","tags":["info","optimize"],"pid":5,"message":"Optimization of bundles for kibana and statusPage complete in 371.83 seconds"}
{"type":"log","@timestamp":"2017-11-01T09:06:52Z","tags":["status","plugin:kibana@1.0.0","info"],"pid":5,"state":"green","message":"Status changed from uninitialized to green - Ready","prevState":"uninitialized","prevMsg":"uninitialized"}
{"type":"log","@timestamp":"2017-11-01T09:06:53Z","tags":["status","plugin:elasticsearch@1.0.0","info"],"pid":5,"state":"yellow","message":"Status changed from uninitialized to yellow - Waiting for Elasticsearch","prevState":"uninitialized","prevMsg":"uninitialized"}
{"type":"log","@timestamp":"2017-11-01T09:06:53Z","tags":["status","plugin:kbn_vislib_vis_types@1.0.0","info"],"pid":5,"state":"green","message":"Status changed from uninitialized to green - Ready","prevState":"uninitialized","prevMsg":"uninitialized"}
{"type":"log","@timestamp":"2017-11-01T09:06:53Z","tags":["status","plugin:markdown_vis@1.0.0","info"],"pid":5,"state":"green","message":"Status changed from uninitialized to green - Ready","prevState":"uninitialized","prevMsg":"uninitialized"}
{"type":"log","@timestamp":"2017-11-01T09:06:53Z","tags":["status","plugin:metric_vis@1.0.0","info"],"pid":5,"state":"green","message":"Status changed from uninitialized to green - Ready","prevState":"uninitialized","prevMsg":"uninitialized"}
{"type":"log","@timestamp":"2017-11-01T09:06:53Z","tags":["status","plugin:spyModes@1.0.0","info"],"pid":5,"state":"green","message":"Status changed from uninitialized to green - Ready","prevState":"uninitialized","prevMsg":"uninitialized"}
{"type":"log","@timestamp":"2017-11-01T09:06:53Z","tags":["status","plugin:statusPage@1.0.0","info"],"pid":5,"state":"green","message":"Status changed from uninitialized to green - Ready","prevState":"uninitialized","prevMsg":"uninitialized"}
{"type":"log","@timestamp":"2017-11-01T09:06:53Z","tags":["status","plugin:table_vis@1.0.0","info"],"pid":5,"state":"green","message":"Status changed from uninitialized to green - Ready","prevState":"uninitialized","prevMsg":"uninitialized"}
{"type":"log","@timestamp":"2017-11-01T09:06:53Z","tags":["listening","info"],"pid":5,"message":"Server running at http://0.0.0.0:5601"}
{"type":"log","@timestamp":"2017-11-01T09:06:59Z","tags":["status","plugin:elasticsearch@1.0.0","info"],"pid":5,"state":"yellow","message":"Status changed from yellow to yellow - No existing Kibana index found","prevState":"yellow","prevMsg":"Waiting for Elasticsearch"}
{"type":"log","@timestamp":"2017-11-01T09:07:08Z","tags":["status","plugin:elasticsearch@1.0.0","info"],"pid":5,"state":"green","message":"Status changed from yellow to green - Kibana index ready","prevState":"yellow","prevMsg":"No existing Kibana index found"}

又看到熟悉的 yellow to green 了,妥妥没问题。不过后边同时显示 "prevMsg":"No existing Kibana index found",这个没啥影响,初次启动,Kibana 没有默认给我们创建好索引,我们可以到 Kibana Web 页面去设置索引。但是如何获取 Kibana 服务访问地址呢?可以通过获取 cluster-info 查看

代码语言:javascript
复制
$ kubectl cluster-info
Kubernetes master is running at https://10.236.65.76:6443
Elasticsearch is running at https://10.236.65.76:6443/api/v1/proxy/namespaces/kube-system/services/elasticsearch-logging
Heapster is running at https://10.236.65.76:6443/api/v1/proxy/namespaces/kube-system/services/heapster
Kibana is running at https://10.236.65.76:6443/api/v1/proxy/namespaces/kube-system/services/kibana-logging
KubeDNS is running at https://10.236.65.76:6443/api/v1/proxy/namespaces/kube-system/services/kube-dns
monitoring-grafana is running at https://10.236.65.76:6443/api/v1/proxy/namespaces/kube-system/services/monitoring-grafana
monitoring-influxdb is running at https://10.236.65.76:6443/api/v1/proxy/namespaces/kube-system/services/monitoring-influxdb

也就是 https://<api_server_ip>:<api_server_ secure_port>/api/v1/proxy/namespaces/kube-system/services/kibana-logging 这个访问地址,不过当我们满心欢喜的将这个地址在浏览器中打开时,并没有显示出来页面,而是显示:

这个主要是因为访问地址为 Https,但是没有导入 Kubernetes 证书所致。然而 Kubernetes 证书从哪里得来呢?有两种方式,一种是自己生成然后拷贝到各个机器上,配置 Kubernetes 使用,并导入到浏览器中,另一种使用现成的证书,下边说一下如何导入现成的证书到浏览器中。

使用 kubeadm 安装的 Kubernetes 集群,默认会生成一系列证书供 kubelet 使用,默认生成证书到 /etc/kubernetes/pki/ 目录。

代码语言:javascript
复制
$ /etc/kubernetes/pki/
总用量 48
-rw-r--r--. 1 root root 1237 10月 30 10:19 apiserver.crt
-rw-------. 1 root root 1675 10月 30 10:19 apiserver.key
-rw-r--r--. 1 root root 1099 10月 30 10:19 apiserver-kubelet-client.crt
-rw-------. 1 root root 1679 10月 30 10:19 apiserver-kubelet-client.key
-rw-r--r--. 1 root root 1025 10月 30 10:19 ca.crt
-rw-------. 1 root root 1675 10月 30 10:19 ca.key
-rw-r--r--. 1 root root 1025 10月 30 10:19 front-proxy-ca.crt
-rw-------. 1 root root 1679 10月 30 10:19 front-proxy-ca.key
-rw-r--r--. 1 root root 1050 10月 30 10:19 front-proxy-client.crt
-rw-------. 1 root root 1675 10月 30 10:19 front-proxy-client.key
-rw-------. 1 root root 1675 10月 30 10:19 sa.key
-rw-------. 1 root root  451 10月 30 10:19 sa.pub

这里每个证书和对应的 key 都有不同的用处,我们可以从 kubelet 进程中可以看到这些证书在启动时已经指定加载进去了。

代码语言:javascript
复制
$ ps -ef | grep kubelet
root      2045     1  1 11月02 ?      00:31:53 /usr/bin/kubelet --kubeconfig=/etc/kubernetes/kubelet.conf --require-kubeconfig=true --pod-manifest-path=/etc/kubernetes/manifests --allow-privileged=true --network-plugin=cni --cni-conf-dir=/etc/cni/net.d --cni-bin-dir=/opt/cni/bin --cluster-dns=10.96.0.10 --cluster-domain=cluster.local --authorization-mode=Webhook --client-ca-file=/etc/kubernetes/pki/ca.crt --cgroup-driver=systemd
root      5139  5126  1 08:50 ?        00:05:33 kube-controller-manager --use-service-account-credentials=true --kubeconfig=/etc/kubernetes/controller-manager.conf --root-ca-file=/etc/kubernetes/pki/ca.crt --service-account-private-key-file=/etc/kubernetes/pki/sa.key --cluster-signing-key-file=/etc/kubernetes/pki/ca.key --address=127.0.0.1 --insecure-experimental-approve-all-kubelet-csrs-for-group=system:bootstrappers --controllers=*,bootstrapsigner,tokencleaner --cluster-signing-cert-file=/etc/kubernetes/pki/ca.crt --leader-elect=true --allocate-node-cidrs=true --cluster-cidr=10.96.0.0/12
root      5704  5692  0 08:52 ?        00:03:24 kube-apiserver --kubelet-client-key=/etc/kubernetes/pki/apiserver-kubelet-client.key --secure-port=6443 --storage-backend=etcd3 --requestheader-allowed-names=front-proxy-client --admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,ResourceQuota,DefaultTolerationSeconds --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname --requestheader-group-headers=X-Remote-Group --requestheader-extra-headers-prefix=X-Remote-Extra- --service-cluster-ip-range=10.96.0.0/12 --service-account-key-file=/etc/kubernetes/pki/sa.pub --client-ca-file=/etc/kubernetes/pki/ca.crt --tls-cert-file=/etc/kubernetes/pki/apiserver.crt --allow-privileged=true --requestheader-username-headers=X-Remote-User --kubelet-client-certificate=/etc/kubernetes/pki/apiserver-kubelet-client.crt --requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.crt --tls-private-key-file=/etc/kubernetes/pki/apiserver.key --insecure-port=0 --experimental-bootstrap-token-auth=true --authorization-mode=RBAC --advertise-address=10.236.65.76 --etcd-servers=http://127.0.0.1:2379
root     29063 28044  0 14:51 pts/2    00:00:00 grep --color=auto kubelet

这里我们主要看一下 kube-apiserver,毕竟我们大部分操作都是需要请求它来完成,格式化一下:

代码语言:javascript
复制
kube-apiserver --kubelet-client-key=/etc/kubernetes/pki/apiserver-kubelet-client.key 
--secure-port=6443 
--storage-backend=etcd3 
--requestheader-allowed-names=front-proxy-client 
--admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,ResourceQuota,DefaultTolerationSeconds 
--kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname 
--requestheader-group-headers=X-Remote-Group 
--requestheader-extra-headers-prefix=X-Remote-Extra- 
--service-cluster-ip-range=10.96.0.0/12 
--service-account-key-file=/etc/kubernetes/pki/sa.pub 
--client-ca-file=/etc/kubernetes/pki/ca.crt 
--tls-cert-file=/etc/kubernetes/pki/apiserver.crt 
--allow-privileged=true 
--requestheader-username-headers=X-Remote-User 
--kubelet-client-certificate=/etc/kubernetes/pki/apiserver-kubelet-client.crt --requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.crt 
--tls-private-key-file=/etc/kubernetes/pki/apiserver.key 
--insecure-port=0 
--experimental-bootstrap-token-auth=true 
--authorization-mode=RBAC 
--advertise-address=10.236.65.76 
--etcd-servers=http://127.0.0.1:2379

从上边可以看出默认开启的是 secure-port 的方式,以及一系列的证书。其中客户端证书 --client-ca-file=/etc/kubernetes/pki/ca.crt 就是我们需要的证书。下边演示下在 Mac 上如何将 ca.crt 证书导入到浏览器中。

5.1 浏览器添加证书

打开 应用程序 —> 实用工具 —> 钥匙串访问,点击 “+” 选择 ca.crt 证书。

不过添加的 Kubernetes 证书,显示此根证书不被信任,可以点击右键 “显示简介”,弹框中点击 “信任”,在使用此证书时这一栏选择 “始终信任” 即可。

此时,重新打开浏览器,或者刷新浏览器,就正常了。

好了,https 证书的问题解决了,这下应该可以了吧。在次打开 https://<api_server_ip>:<api_server_ secure_port>/api/v1/proxy/namespaces/kube-system/services/kibana-logging 这个访问地址,还是没有显示 Kibana 页面,而是显示:

代码语言:javascript
复制
User "system:anonymous" cannot proxy services in the namespace "kube-system".

OMG,这又是为啥。。。原来 Kubernetes 从 v1.6 开始,默认的认证模式变成了 RBAC 方式了,从上边 --authorization-mode=RBAC 也可以看出,那 RBAC 模式又是个啥?

5.2 RBAC 认证模式介绍

从官网文档 RBAC Support in Kubernetes 中的一张图片可以窥探 RBAC 究竟。

从图中我们可以看出 RBAC 中对各个角色进行绑定授权操作。也就是 Role 为 pod-reader 拥有对 Pod 的 get 和 list 权限,然后通过 RoleBinding 操作将该 Role 类型授权给 User、Group 和 ServiceAccount。也就是说,我们在创建 Pod 时,要通过 RoleBinding 操作将具有特定权限的 Role 授权给该 Pod 创建的 User、Group 或 ServiceAccount。我们可以在最新官网 kubernetes-dashboard 1.7 的 Yaml 文件中得到验证。

代码语言:javascript
复制
# kubernetes-dashboard.yaml
# ------------------- Dashboard Service Account ------------------- #

apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard
  namespace: kube-system

---
# ------------------- Dashboard Role & Role Binding ------------------- #

kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: kubernetes-dashboard-minimal
  namespace: kube-system
rules:
  # Allow Dashboard to create and watch for changes of 'kubernetes-dashboard-key-holder' secret.
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["create", "watch"]
- apiGroups: [""]
  resources: ["secrets"]
  # Allow Dashboard to get, update and delete 'kubernetes-dashboard-key-holder' secret.
  resourceNames: ["kubernetes-dashboard-key-holder", "kubernetes-dashboard-certs"]
  verbs: ["get", "update", "delete"]
  # Allow Dashboard to get metrics from heapster.
- apiGroups: [""]
  resources: ["services"]
  resourceNames: ["heapster"]
  verbs: ["proxy"]

---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:
  name: kubernetes-dashboard-minimal
  namespace: kube-system
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: kubernetes-dashboard-minimal
subjects:
- kind: ServiceAccount
  name: kubernetes-dashboard
  namespace: kube-system

---

从 Yaml 描述文件中大体可以看出,首先创建了一个 kubernetes-dashboard 的 ServiceAccount,然后创建一个 kubernetes-dashboard-minimal 的 Dashboard Role,最后通过 RoleBinding 将 Role:ubernetes-dashboard-minimal 授权给 ServiceAccount:kubernetes-dashboard,而且他们至始至终都在同一个命令空间下 namespace: kube-system。这样就可以完成 RBAC 的认证过程。

同时 Kubernetes API Server 还更新了一个 –anonymous-auth 选项,允许匿名请求访问 secure port,就像我上边访问地址报错一样,属于匿名请求。这样的匿名请求的 username 默认为 “system:anonymous”, 归属的组默认为 “system:unauthenticated”,所以当我们请求上边命名空间为 kube-system 的服务时,是肯定访问不了的。

好吧,原因找到了,还扯了这么多,到底该如何解决这个问题呢?有三种方法解决。

一、修改 Yaml 文件,为 Kibana 创建符合 RBAC 的配置。可以参考上边 kubernetes-dashboard.yaml 方式配置。

二、使用非安全端口访问 kube-apiserver,也即使用 insecure-port 方式访问,这种方式没有任何安全限制。使用该方式需要修改 kubelet apiserver 配置文件 /etc/kubernetes/manifests/kube-apiserver.yaml,指定 insecure-bind-addressinsecure-port

代码语言:javascript
复制
$ vim /etc/kubernetes/manifests/kube-apiserver.yaml
...
spec:
  containers:
  - command:
    ...
    - --insecure-bind-address=0.0.0.0 
    - --insecure-port=8080
    ...

配置完成后,就可以通过 http://10.236.65.76:8080/api/v1/proxy/namespaces/kube-system/services/kibana-logging 地址访问了,当然这种方式不安全的哈。

三、使用 kubectl proxy 创建代理。这种方式是最简单的,不需要修改 kubelet 配置,只需要启动代理即可。

代码语言:javascript
复制
$ kubectl proxy --address='10.236.65.76' --port=8085 --accept-hosts='^*$'

执行完毕,就可以通过 http://10.236.65.76:8085/api/v1/proxy/namespaces/kube-system/services/kibana-logging 地址访问了。

好了,现在 Kibana 页面也成功打开了,我们需要创建一个索引,解决日志中 "prevMsg":"No existing Kibana index found" 的问题。 点击导航栏 “Setting” -> “Configure an index pattern”,选中 “Index contains time-based events” 选项,“Index name or pattern” 默认为 logstash-* 即可,“Time-field name” 默认 @timestamp,最后点击 “Create” 即可完成索引创建。

稍等一段时间,就可以看到有日志展示出来啦!如上图所示。不过默认显示的栏目只有 Time 和 _source,这看着很不直观,我们可以点开下边任何一个日志记录,将 Table 展示左侧列,有需要添加到展示栏的项,点击右侧类似打开的书的图标,就可以展示了。这里我选择了关键性栏目,如:kubernetes.container_namekubernetes.hostkubernetes.namespace_namelog,这下看起来是不是就直观了很多。

好了,服务都启动起来了,最后我们要验证一下是否集群中 Pod 发生变化时,日志能够实时发送过来。这里简单的启动一个 Pod,我们可以从 Dashboard 中创建一个部署,以示区别我们同时为这个部署指定到一个新的 Namespace 下,还以之前的 redis 为例,指定命名空间为 my-kube,看下启动完毕,在 Kibana 上能否看到对应的日志信息吧。

码字太多了。。。这个就不演示如何在 Dashboard 上创建这个 redis 实例了。看下通过日志收集并分析,最终呈现到 Kibana 上的图吧!证明是可以实时获取到的!

好了,Kibana 其他功能的用法,我还没研究完,等研究后在补充吧!

参考资料

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017-11-06 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器镜像服务
容器镜像服务(Tencent Container Registry,TCR)为您提供安全独享、高性能的容器镜像托管分发服务。您可同时在全球多个地域创建独享实例,以实现容器镜像的就近拉取,降低拉取时间,节约带宽成本。TCR 提供细颗粒度的权限管理及访问控制,保障您的数据安全。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档