Kubenetes 容器日志收集方案
应用日志收集痛点
业务无要求:
日志格式无要求
,可以是json序列化也可以是logback格式,对日志是否格式化/归一化格式无要求;
日志文件名无要求
,可以是application.log、access.log; 只是需要规范认证后缀,以 .log/.txt/.lo
;
对业务要求:
1.业务日志轮转能力
-业务日志Node节点上
a.默认保留最近7份,最新2份明文保留,最久5份tar.gz压缩保留;
b.如果node节点磁盘总可用度小于15%,将减少默认保留分数;
-业务云端中心化保留N天
2.业务日志自定义输出
container 自定义日志写入到$(LOG_MOUNT_PATH)目录中
spec:
containers:
- env:
- name: POD_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.name
- name: NAMESPACE
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
- name: LOG_MOUNT_PATH
value: "/app/log/"
image: tomcat
name: tomcat
volumeMounts:
- mountPath: $(LOG_MOUNT_PATH)
name: datalog
subPathExpr: $(NAMESPACE)/$(POD_NAME)
volumes:
- hostPath:
path: /data/log
type: ""
name: datalog
日志轮转
- 无日志轮转应用:如python、php、C/C++,sae支持外部轮转;
- 有日志轮转医用:如java(logback, log4j2)、golang;支持内部轮转;
日志采集
- 自定义日志:可以根据日志文件路径挂载的Volume,找到相应在节点的文件进行采集。并同时自动将Pod上的Env/Annotation/Label加入到日志里作为元信息
- 标准输出日志:自动自动发现并采集
容器CSI存储介质对比
存储介质
Kubernetes 从 1.12-1.30 被使用出差日志的存储介质,分为4类:
- emptyDir/gitRepo
- hostPath/Local
- volume(cephfs、glusterfs、NFS、openebs)
- 云厂商存储(awsEBS、NAS、AzureDisk)
日志落盘模式
Pod里不仅仅是输出stdout,还包括日志文件,就需要考虑到挂载日志文件到节点上,同时采用DaemonSet部署的Agent也需要挂载相同的目录,否则采用容器化部署的Agent无法查看到相应的文件,更无法采集。
emtpyDir
emtpyDir的生命周期跟随Pod,Pod销毁后其中存储的日志也会消失。
优点:使用简单,不同Pod都使用自己的emtpyDir,有一定的隔离性。 缺点:日志如果采集不及时,在Pod消耗后,存在丢失的可能性。 使用emptyDir挂载的日志文件,一般在节点的路径如下:
/var/lib/kubelet/pods/${pod.UID}/volumes/kubernetes.io~empty-dir/${volumeName}
hostPath
生命周期和Pod无关,Pod迁移或者销毁,日志文件还保留在现有磁盘上。
优点:生命周期和Pod无关,即使Pod销毁,日志文件依然在节点磁盘上,假设Agent没有采集日志,仍然可以找到日志文件 缺点:默认无隔离性,需要控制挂载的日志路径;另外,Pod迁移节点后,残留的日志文件长期积累容易占据磁盘,同时日志占据的磁盘无法控制使用的配额 为了解决隔离性,避免多个Pod打印日志到相同的路径和文件中,我们需要使用 subPathExpr 字段从 Downward API 环境变量构造 subPath 目录名。 该 VolumeSubpathEnvExpansion 功能从 Kubernetes1.15 开始默认开启,在1.17 GA。可参考 feature-gates 和 using-subpath-expanded-environment。
使用subPathExpr
的示例如下所示:
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx
name: nginx
namespace: default
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- env:
- name: POD_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.name
- name: NAMESPACE
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
image: nginx
name: nginx
resources: {}
volumeMounts:
- mountPath: /data/log
name: datalog
subPathExpr: $(NAMESPACE)/$(POD_NAME)
volumes:
- hostPath:
path: /data/log
type: ""
name: datalog
Pv
Pv的访问模式包括:
- ReadWriteOnce(RWO):读写权限,并且只能被单个Node挂载。
- ReadOnlyMany(ROX):只读权限,允许被多个Node挂载。
- ReadWriteMany(RWX):读写权限,允许被多个Node挂载。
对于大部分的业务来说,都是Deployment无状态部署,需要挂载同一个Pv共享;对于一些中间件等有状态服务,一般会使用StatefulSet部署,每个Pod会使用独立的Pv。
优点:存储日志不容易丢失; 缺点:有一定的使用和运维复杂度;多个Pod共享同一个Pv时存在隔离性问题;很多的日志Agent对采集云盘上的日志文件支持不够成熟,可能存在一些隐患; 在Node上找到使用Pv挂载的对应日志文件,但是Pv根据不同的底层实现,在Node上的路径会有一定的区别。
总结
- 大部分主流的开源Agent,只对容器Stdout有部分支持,比如支持采集的时候统一加上一些K8s相关元信息;
- Agent采集 不能保证数据100%及时,通过落盘再采集方式 做IO缓冲;
- HostPath是上云节点业务感知最小方式;
- 最终态,是提高网络传输可靠性和稳定性,减少落盘空间大小(以网络IO换磁盘IO);
应用日志现状假设
应用日志:混在标准输出stdout 和 错误输出stderr中情况
- 非容器化:
- 标准输出到系统回收站 2>&1 1>/dev/null
- 标准输出到文件 2>&1 &>filename
- 容器化方式: 标准输出stdout和错误输出stderr,到 /var
kubelet每个节点上运行的进程来管理日志轮换。
containerLogMaxSize
- 它定义容器日志文件在轮换之前的最大大小。例如:“5Mi”或“256Ki”。默认值:“10Mi”。containerLogMaxFiles
- 指定每个容器可以存在的最大容器日志文件数量。默认值:5 对于 docker ce 引擎:/etc/docker/daemon.json
{
"log-driver": "local",
"log-opts": {
"max-size": "10m",
"max-file": "10"
}
}
对于非 docker ce引擎:只能通过kubelet 做日志轮转
为了轮转方式统一,统一使用 kubelet 做日志轮转
应用日志:输出local文件,无format和日志轮转能力
- 非容器化方式:
- 写到规划好的/data盘下的一个目录中,再做日志轮转。核心在于日志保存和轮转;
- 容器化方式:通过外挂hostPath 或者 外挂卷实现日志本地化存储;
- 通过DaemonSet/CrobJob对规范下的日志目录(/data/log//<pod.name>/xxxx)进行 日志轮转:
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: app-logrotate
spec:
schedule: "*/1 * * * *"
concurrencyPolicy: Forbid
jobTemplate:
spec:
completions: 5 # Number of nodes
parallelism: 5 # Number of nodes
template:
metadata:
labels:
app.kubernetes.io/name: app-logrotate
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app.kubernetes.io/name
operator: In
values:
- app-logrotate
topologyKey: kubernetes.io/hostname
containers:
- name: logrotate
image: docker.io/kicm/logrotate
volumeMounts:
- name: logrotate-conf
mountPath: /etc/logrotate.d
readOnly: true
- name: app-logs
mountPath: /var/log/app
volumes:
- name: logrotate-conf
configMap:
name: logrotate-config
- name: app-logs
hostpath:
path: /data/log/
type: Directory
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: logrotate
namespace: kube-system
spec:
template:
metadata:
labels:
k8s-app: logrotate
spec:
dnsPolicy: Default
containers:
- name: logrotate
image: docker.io/kicm/logrotate
resources:
limits:
memory: 10Mi
requests:
cpu: 10m
memory: 10Mi
env:
- name: LOGROTATE_ARGS
value: -v
volumeMounts:
- name: logrotate-conf
mountPath: /etc/logrotate.d
readOnly: true
- name: app-logs
mountPath: /var/log/app
terminationGracePeriodSeconds: 30
volumes:
- name: logrotate-conf
configMap:
name: logrotate-config
- name: app-logs
hostpath:
path: /data/log/
type: Directory
---
apiVersion: v1
kind: ConfigMap
metadata:
name: logrotate-config
data:
my_logs.conf: |
/var/log/app/*/*/*.log {
daily
maxsize 500M
rotate 7
missingok
notifempty
compress
delaycompress
dateformat -%Y%m%d_%H%M%S
create
su
}
为了解决隔离性,避免多个Pod打印日志到相同的路径和文件中,我们需要使用 subPathExpr 字段从 Downward API 环境变量构造 subPath 目录名。
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx
name: nginx
namespace: default
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- env:
- name: POD_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.name
- name: NAMESPACE
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
image: nginx
name: nginx
resources: {}
volumeMounts:
- mountPath: /data/log
name: datalog
subPathExpr: $(NAMESPACE)/$(POD_NAME)
volumes:
- hostPath:
path: /data/log
type: ""
name: datalog
总结
应用日志轮转
:使用DaemonSet/CrobJob对日志轮转;应用日志采集
:/data/log/$(NAMESPACE)/$(POD_NAME)/xxx.log 进行收集,并将日志自动添加pod label
应用日志:输出local文件,并且分类型。包括不限于accesslog、application.log和crash.log, 并且也有日志轮转能力
和上面类似
日志采集架构设计方案
日志采集范畴
- 业务容器日志:容器标准输出 和 容器日志采集
- PaaS Addon组件日志: 包括 coredns、metrics-server、kube-state-metrics等
- PaaS平台组件 日志采集 和 聚合: 包括: etcd、kube-controller-manager、kube-apiserver、kube-scheduler 的 标准输出和文件
- Linux系统日志: /var/log/message 、/var/log/yum.log 等
日志采集架构
业务监控日志
- 支持pod 自定义日志、标准输出日志采集,并主动管理上pod元数据
- agent支持多住户采集,不同租户id,写入不同loki index
- agent支持部分pipeline改写能力
- 支持checkpoint机制,断点续传
- 不依赖日志是否序列化
业务大数据日志
- agent支持数据采集 多写出源;
- 支持sink loki、外部es和外部kafka能力;
「如果这篇文章对你有用,请随意打赏」
如果这篇文章对你有用,请随意打赏
使用微信扫描二维码完成支付