Kubernetes 日志收集与监控实战指南
1. 引言
在 Kubernetes 环境中,日志收集和监控是 DevOps 人员必须关注的重要方面,它们能帮助我们了解系统的稳定性和状态。本文将详细介绍如何收集应用程序日志、处理 Kubernetes 日志、处理 etcd 日志以及监控主节点和工作节点。
2. 收集应用程序日志
在管理应用程序时,日志收集和分析是跟踪应用程序状态的重要日常工作。但在 Docker/Kubernetes 环境中,由于日志文件位于容器内部,从容器外部访问它们并不容易。此外,如果应用程序有多个 Pod,很难追踪问题发生在哪个 Pod 中。为了解决这个问题,可以使用集中式日志收集平台,如 ELK(Elasticsearch、Logstash 和 Kibana)。
2.1 准备 Elasticsearch 服务器
首先,需要准备 Elasticsearch 服务器。可以使用 curl 命令下载 Kubernetes 源文件中提供的 YAML 文件来设置 Elasticsearch:
# curl -L -O https://github.com/kubernetes/kubernetes/releases/download/v1.1.4/kubernetes.tar.gz
# tar zxf kubernetes.tar.gz
# cd kubernetes/examples/elasticsearch/
# ls
es-rc.yaml es-svc.yaml production_cluster README.md service-account.yaml
然后创建 ServiceAccount、Elasticsearch 复制控制器和服务:
# kubectl create -f service-account.yaml
serviceaccount "elasticsearch" created
# kubectl create -f es-rc.yaml --validate=false
replicationcontroller "es" created
# kubectl create -f es-svc.yaml
service "elasticsearch" created
可以通过 Kubernetes 服务访问 Elasticsearch 接口:
# kubectl get service
NAME CLUSTER_IP EXTERNAL_IP PORT(S) SELECTOR AGE
elasticsearch 192.168.45.152 9200/TCP,9300/TCP component=elasticsearch 9s
kubernetes 192.168.0.1 <none> 443/TCP <none> 110d
# curl http://192.168.45.152:9200/
{
"status" : 200,
"name" : "Wallflower",
"cluster_name" : "myesdb",
"version" : {
"number" : "1.7.1",
"build_hash" : "b88f43fc40b0bcd7f173a1f9ee2e97816de80b19",
"build_timestamp" : "2015-07-29T09:54:16Z",
"build_snapshot" : false,
"lucene_version" : "4.10.4"
},
"tagline" : "You Know, for Search"
}
2.2 准备示例应用程序
使用一个 Python Flask 程序作为示例应用程序:
# cat entry.py
from flask import Flask, request
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello World!"
@app.route("/addition/<int:x>/<int:y>")
def add(x, y):
return "%d" % (x+y)
if __name__ == "__main__":
app.run(host='0.0.0.0')
2.3 使用 Logstash 发送日志到 Elasticsearch
Logstash 可以将应用程序日志从纯文本格式转换为 Elasticsearch(JSON)格式。Logstash 需要一个配置文件来指定 Elasticsearch 的 IP 地址和端口号:
# cat logstash.conf.temp
input {
stdin {}
}
filter {
grok {
match => {
"message" => "%{IPORHOST:clientip} %{HTTPDUSER:ident} %{USER:auth} \[%{DATA:timestamp}\] \"(?:%{WORD:verb} %{NOTSPACE:request}(?: HTTP/%{NUMBER:httpversion})?|%{DATA:rawrequest})\" %{NUMBER:response} (?:%{NUMBER:bytes}|-)"
}
}
}
output {
elasticsearch {
hosts => ["_ES_IP_:_ES_PORT_"]
index => "mycalc-access"
}
stdout { codec => rubydebug }
}
启动脚本会读取环境变量,并替换占位符以设置真实的 IP 和端口号:
#!/bin/sh
TEMPLATE="logstash.conf.temp"
LOGSTASH="logstash-2.2.2/bin/logstash"
cat $TEMPLATE | sed "s/_ES_IP_/$ELASTICSEARCH_SERVICE_HOST/g" | sed "s/_ES_PORT_/$ELASTICSEARCH_SERVICE_PORT/g" > logstash.conf
python entry.py 2>&1 | $LOGSTASH -f logstash.conf
2.4 构建 Docker 镜像
使用 Dockerfile 构建示例应用程序的 Docker 镜像:
FROM ubuntu:14.04
# Update packages
RUN apt-get update -y
# Install Python Setuptools
RUN apt-get install -y python-setuptools git telnet curl openjdk-7-jre
# Install pip
RUN easy_install pip
# Bundle app source
ADD . /src
WORKDIR /src
# Download LogStash
RUN curl -L -O https://download.elastic.co/logstash/logstash/logstash-2.2.2.tar.gz
RUN tar -zxf logstash-2.2.2.tar.gz
# Add and install Python modules
RUN pip install Flask
# Expose
EXPOSE 5000
# Run
CMD ["./startup.sh"]
使用 docker build 命令构建镜像并上传到 Docker Hub:
# docker build -t hidetosaito/my-calc-elk .
# docker login
Username: hidetosaito
Password:
Email: hideto.saito@yahoo.com
# docker push hidetosaito/my-calc-elk
2.5 创建 Kubernetes 复制控制器和服务
使用 YAML 文件创建 Kubernetes 复制控制器和服务:
# cat my-calc-elk.yaml
apiVersion: v1
kind: ReplicationController
metadata:
name: my-calc-elk-rc
spec:
replicas: 2
selector:
app: my-calc-elk
template:
metadata:
labels:
app: my-calc-elk
spec:
containers:
- name: my-calc-elk
image: hidetosaito/my-calc-elk
---
apiVersion: v1
kind: Service
metadata:
name: my-calc-elk-service
spec:
ports:
- protocol: TCP
port: 5000
type: ClusterIP
selector:
app: my-calc-elk
使用 kubectl 命令创建复制控制器和服务:
# kubectl create -f my-calc-elk.yaml
replicationcontroller "my-calc-elk-rc" created
service "my-calc-elk-service" created
检查 Kubernetes 服务以找到应用程序的 IP 地址,并使用 curl 命令访问应用程序:
# kubectl get service
NAME CLUSTER_IP EXTERNAL_IP PORT(S) SELECTOR AGE
elasticsearch 192.168.101.143 9200/TCP,9300/TCP component=elasticsearch 15h
kubernetes 192.168.0.1 <none> 443/TCP <none> 19h
my-calc-elk-service 192.168.121.63 <none> 5000/TCP app=my-calc-elk 39s
# curl http://192.168.121.63:5000/
Hello World!
# curl http://192.168.121.63:5000/addition/3/5
8
2.6 使用 Kibana 可视化日志
Kibana 是 Elasticsearch 的可视化工具。下载 Kibana 并指定 Elasticsearch 的 IP 地址和端口号来启动 Kibana:
# curl -O https://download.elastic.co/kibana/kibana/kibana-4.1.6-linux-x64.tar.gz
# tar -zxf kibana-4.1.6-linux-x64.tar.gz
# kubectl get services
NAME CLUSTER_IP EXTERNAL_IP PORT(S) SELECTOR AGE
elasticsearch 192.168.101.143 9200/TCP,9300/TCP component=elasticsearch 19h
kubernetes 192.168.0.1 <none> 443/TCP <none> 23h
# sed -i -e "s/localhost/192.168.101.143/g" kibana-4.1.6-linux-x64/config/kibana.yml
# kibana-4.1.6-linux-x64/bin/kibana
3. 处理 Kubernetes 日志
Kubernetes 主节点上有三个守护进程:API 服务器、调度器和控制器管理器,对应的日志文件位于 /var/log 文件夹下:
| 主节点守护进程 | 日志文件 | 描述 |
| — | — | — |
| API 服务器 | apiserver.log | API 调用日志 |
| 调度器 | k8s-scheduler.log | 容器调度事件的调度器数据日志 |
| 控制器管理器 | controller-manager.log | 与控制器管理器相关的事件或问题日志 |
节点上有一个 kubelet 进程来处理容器操作并向主节点报告,其日志文件为 kubelet.log。此外,主节点和节点上还有一个 kube-proxy.log 文件来记录网络连接问题。
3.1 准备工作
使用 ELK 作为集中式日志平台来收集 Kubernetes 日志。在收集日志之前,了解日志的数据结构很重要,日志格式如下:
<日志级别><日期> <时间戳> <指示符> <源文件>:<行号>] <日志内容>
例如:
E0328 00:46:50.870875 3189 reflector.go:227] pkg/proxy/config/api.go:60: Failed to watch *api.Endpoints: too old resource version: 45128 (45135)
通过日志文件中每行的首字符可以知道日志的严重程度:
- D: DEBUG
- I: INFO
- W: WARN
- E: ERROR
- F: FATAL
3.2 收集日志
使用 Logstash 的 grok 过滤器来处理日志。首先创建一个自定义模式文件:
# cat ./patterns/k8s
LOGLEVEL [DEFIW]
DATE [0-9]{4}
K8SLOGLEVEL %{LOGLEVEL:level}%{DATE}
然后创建 Logstash 配置文件:
# cat apiserver.conf
input {
file {
path => "/var/log/k8s-apiserver.log"
}
}
filter {
grok {
patterns_dir => ["./patterns"]
match => { "message" => "%{K8SLOGLEVEL} %{TIME} %{NUMBER} %{PROG:program}:%{POSINT:line}] %{GREEDYDATA:message}" }
}
}
output {
elasticsearch {
hosts => ["_ES_IP_:_ES_PORT_"]
index => "k8s-apiserver"
}
stdout { codec => rubydebug }
}
启动 Logstash:
# bin/logstash -f apiserver.conf
4. 处理 etcd 日志
etcd 是 Kubernetes 数据存储,对于保存 Kubernetes 资源信息至关重要。如果 Pod 信息丢失,将无法在系统中识别它。
4.1 准备工作
在收集 etcd 日志之前,需要准备 ELK 服务器。如果 etcd 服务器是 Kubernetes 集群之外的独立机器,需要暴露 Elasticsearch 的 Kubernetes 服务:
# cat es-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: elasticsearch
labels:
component: elasticsearch
spec:
type: LoadBalancer
selector:
component: elasticsearch
ports:
- name: http
port: 9200
nodePort: 30000
protocol: TCP
- name: transport
port: 9300
protocol: TCP
4.2 收集日志
etcd 日志文件位于 /var/log/etcd.log,日志格式如下:
<日期> <时间> <子包>: <日志内容>
例如:
2016/04/4 08:43:51 etcdserver: starting server... [version: 2.1.1, cluster version: to_be_decided]
创建 Logstash 配置文件:
# cat etcd.conf
input {
file {
path => "/var/log/etcd.log"
}
}
filter {
grok {
match => {
"message" => "%{DATA:date} %{TIME:time} %{PROG:subpackage}: %{GREEDYDATA:message}"
}
}
}
output {
elasticsearch {
hosts => ["<ELASTIC_SERVICE_IP>:<EXPOSE_PORT>"]
index => "etcd-log"
}
stdout { codec => rubydebug }
}
启动 Logstash:
# ./bin/logstash -f etcd.conf
5. 监控主节点和工作节点
监控工具可以帮助我们了解工作节点和 Pod 的资源消耗情况,提高资源利用率。
5.1 准备工作
在 Kubernetes 系统中设置监控集群之前,需要完成两个主要前提条件:
- 更新到最新版本的二进制文件,确保集群具有稳定和强大的功能。
- 设置 DNS 服务器,Kubernetes DNS 服务器可以减少安装类似集群的 Pod 的步骤和依赖。
更新 Kubernetes 到最新版本 1.2.1 的步骤如下:
1. 停止所有 Kubernetes 服务:
service <KUBERNETES_DAEMON> stop
- 下载最新的 tarball 文件:
# cd /tmp && wget https://storage.googleapis.com/kubernetes-release/release/v1.2.1/kubernetes.tar.gz
- 解压文件:
# tar -xvf /tmp/kubernetes.tar.gz -C /opt/
# cd /opt && tar -xvf /opt/kubernetes/server/kubernetes-server-linux-amd64.tar.gz
- 复制新文件并覆盖旧文件:
# cd /opt/kubernetes/server/bin/
# cp kubectl hypercube kube-apiserver kube-controller-manager kube-scheduler kube-proxy /usr/local/bin # 主节点
# cp kubelet kube-proxy /usr/local/bin # 工作节点
- 启动系统服务并验证版本:
# kubectl version
设置 DNS 服务器的步骤如下:
1. 使用官方模板启动 DNS 服务器:
# cd /opt/kubernetes/cluster/addons/dns
# cp skydns-rc.yaml.in skydns-rc.yaml
# cp skydns-svc.yaml.in skydns-svc.yaml
替换模板中的变量:
| 输入变量 | 替换值 | 示例 |
| — | — | — |
| {{ pillar[‘dns_domain’] }} | 集群的域名 | k8s.local |
| {{ pillar[‘dns_replicas’] }} | 复制控制器的副本数量 | 1 |
| {{ pillar[‘dns_server’] }} | DNS 服务器的私有 IP | 192.168.0.2 |
修改 skydns-rc.yaml 文件中的 master URL:
# cat skydns-rc.yaml
...
- name: kube2sky
image: gcr.io/google_containers/kube2sky:1.14
resources:
limits:
cpu: 100m
memory: 200Mi
requests:
cpu: 100m
memory: 50Mi
livenessProbe:
httpGet:
path: /healthz
port: 8080
scheme: HTTP
initialDelaySeconds: 60
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 5
readinessProbe:
httpGet:
path: /readiness
port: 8081
scheme: HTTP
initialDelaySeconds: 30
timeoutSeconds: 5
args:
# command = "/kube2sky"
- --domain=k8s.local
- --kube-master-url=<MASTER_ENDPOINT_URL>:<EXPOSED_PORT>
...
创建资源:
# kubectl create -f skydns-svc.yaml
# kubectl create -f skydns-rc.yaml
-
在 kubelet 中启用 Kubernetes DNS:
对于 init 服务守护进程:
# cat /etc/init.d/kubernetes-node
...
# Start daemon.
echo $"Starting kubelet: "
daemon $kubelet_prog \
--api_servers=<MASTER_ENDPOINT_URL>:<EXPOSED_PORT> \
--v=2 \
--cluster-dns=192.168.0.2 \
--cluster-domain=k8s.local \
--address=0.0.0.0 \
--enable_server \
--hostname_override=${hostname} \
> ${logfile}-kubelet.log 2>&1 &
...
对于 systemd 服务:
# cat /etc/kubernetes/kubelet
...
# Add your own!
KUBELET_ARGS="--cluster-dns=192.168.0.2 --cluster-domain=k8s.local"
重启 kubelet 服务。
5.2 安装监控集群
使用 Heapster 作为资源使用情况收集和分析工具,结合 influxDB 进行存储和 Grafana 作为前端仪表盘。
1. 检查监控集群的目录:
# cd /opt/kubernetes/cluster/addons/cluster-monitoring/influxdb && ls
grafana-service.yaml heapster-service.yaml influxdb-service.yaml
heapster-controller.yaml influxdb-grafana-controller.yaml
- 保留大部分服务模板的默认设置,但暴露 Grafana 服务:
# cat heapster-service.yaml
apiVersion: v1
kind: Service
metadata:
name: monitoring-grafana
namespace: kube-system
labels:
kubernetes.io/cluster-service: "true"
kubernetes.io/name: "Grafana"
spec:
type: NodePort
ports:
- port: 80
nodePort: 30000
targetPort: 3000
selector:
k8s-app: influxGrafana
- 修改 Heapster 和 influxDB-Grafana 的复制控制器模板:
# cat influxdb-grafana-controller.yaml
...
- image: gcr.io/google_containers/heapster_grafana:v2.6.0-2
name: grafana
env:
resources:
# keep request = limit to keep this container in guaranteed class
limits:
cpu: 100m
memory: 100Mi
requests:
cpu: 100m
memory: 100Mi
env:
# This variable is required to setup templates in Grafana.
- name: INFLUXDB_SERVICE_URL
value: http://monitoring-influxdb.kube-system:8086
- name: GF_AUTH_BASIC_ENABLED
value: "false"
- name: GF_AUTH_ANONYMOUS_ENABLED
value: "true"
- name: GF_AUTH_ANONYMOUS_ORG_ROLE
value: Admin
- name: GF_SERVER_ROOT_URL
value: /
...
# cat heapster-controller.yaml
...
containers:
- image: gcr.io/google_containers/heapster:v1.0.2
name: heapster
resources:
limits:
cpu: 100m
memory: 200Mi
requests:
cpu: 100m
memory: 200Mi
command:
- /heapster
- --source=kubernetes:<MASTER_ENDPOINT_URL>:<EXPOSED_PORT>?inClusterConfig=false
- --sink=influxdb:http://monitoring-influxdb.kube-system:8086
- --metric_resolution=60s
...
- 创建资源:
# kubectl create -f influxdb-service.yaml
# kubectl create -f grafana-service.yaml
# kubectl create -f heapster-service.yaml
# kubectl create -f influxdb-grafana-controller.yaml
# kubectl create -f heapster-controller.yaml
- 检查 Kubernetes 资源:
# kubectl get svc --namespace=kube-system
# kubectl get pod --namespace=kube-system
5.3 介绍 Grafana 仪表盘
Grafana 仪表盘默认有两个面板:Cluster 和 Pods。Cluster 面板显示节点的资源利用率,Pods 面板显示每个 Pod 的资源使用情况。
创建一个新的指标来监控 Pod 的步骤如下:
1. 进入 Pods 仪表盘,点击底部的 ADD ROW,选择添加图形面板。
2. 给面板命名,例如 CPU Rate。
3. 设置查询参数:
- FROM: cpu/usage_rate
- WHERE: type = pod_container
- AND: namespace_name=$namespace, pod_name= $podname
- GROUP BY: tag(container_name)
- ALIAS BY: $tag_container_name
4. 点击顶部的图标保存面板。
通过以上步骤,我们可以实现应用程序日志收集、Kubernetes 日志处理、etcd 日志收集以及主节点和工作节点的监控。这些操作可以帮助我们更好地了解系统的运行状态,及时发现和解决问题。
Kubernetes 日志收集与监控实战指南(续)
6. 整体流程梳理
为了更清晰地理解整个日志收集与监控的流程,我们可以用 mermaid 流程图来概括:
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px;
A([开始]):::startend --> B(准备工作):::process
B --> C(收集应用程序日志):::process
B --> D(处理Kubernetes日志):::process
B --> E(处理etcd日志):::process
B --> F(监控主节点和工作节点):::process
C --> G(ELK平台存储):::process
D --> G
E --> G
F --> H(Heapster收集资源信息):::process
H --> I(influxDB存储):::process
I --> J(Grafana可视化):::process
J --> K([结束]):::startend
这个流程图展示了从准备工作开始,分别进行应用程序日志收集、Kubernetes 日志处理、etcd 日志处理和节点监控,然后将日志统一存储到 ELK 平台,监控信息通过 Heapster 收集后存储到 influxDB,最后由 Grafana 进行可视化展示的完整流程。
7. 常见问题及解决方法
在实际操作过程中,可能会遇到一些常见问题,以下是一些问题及对应的解决方法:
| 问题描述 | 可能原因 | 解决方法 |
|---|---|---|
| Logstash 无法连接到 Elasticsearch | Elasticsearch 服务未启动、网络问题、配置文件中的 IP 或端口错误 | 检查 Elasticsearch 服务状态,确保网络连通,核对 Logstash 配置文件中的 IP 和端口 |
| Grafana 无法显示数据 | influxDB 数据存储问题、Grafana 配置错误 | 检查 influxDB 中是否有数据,核对 Grafana 中数据源的配置 |
| Kubernetes 日志收集不完整 | Logstash 配置错误、日志文件权限问题 | 检查 Logstash 配置文件,确保日志文件有正确的读取权限 |
8. 最佳实践建议
为了更好地实现日志收集和监控,以下是一些最佳实践建议:
-
定期清理日志
:随着时间的推移,日志文件会占用大量的磁盘空间。定期清理过期的日志可以避免磁盘空间不足的问题。可以使用 cron 任务来实现定期清理,例如:
0 2 * * * find /var/log -type f -mtime +7 -delete
这个 cron 任务会在每天凌晨 2 点删除 /var/log 目录下 7 天前的日志文件。
-
设置合理的监控指标
:根据实际需求设置监控指标,避免监控过多不必要的指标导致资源浪费。例如,对于 CPU 使用率,可以设置一个合理的阈值,当超过阈值时触发警报。
-
备份重要数据
:定期备份 Elasticsearch 和 influxDB 中的数据,以防止数据丢失。可以使用官方提供的备份工具或脚本来实现。
9. 总结
通过本文的介绍,我们详细了解了在 Kubernetes 环境中进行日志收集和监控的方法。从收集应用程序日志到处理 Kubernetes 日志和 etcd 日志,再到监控主节点和工作节点,每个步骤都有其重要性和操作细节。
使用 ELK 平台可以实现集中式的日志收集和存储,方便后续的分析和查询。Heapster、influxDB 和 Grafana 的组合则为我们提供了强大的监控和可视化功能,帮助我们更好地了解系统的资源使用情况。
在实际应用中,我们可以根据具体的需求和场景对这些方法进行调整和优化,以确保系统的稳定性和可靠性。同时,不断关注 Kubernetes 和相关工具的更新,学习新的功能和特性,将有助于我们更好地应对各种挑战。
希望本文能为你在 Kubernetes 日志收集和监控方面提供有价值的参考,让你能够更加高效地管理和维护 Kubernetes 集群。
超级会员免费看
3万+

被折叠的 条评论
为什么被折叠?



