在k8s上部署efk日志采集系统
a.elasticsearch
先使用命令获取es的arm版镜像,这里使用的es是7.3.2版本的
docker pull gagara/elasticsearch-oss-arm64:7.3.2
通过:
git clone https://github.com/kubernetes/kubernetes.git
下载代码,然后切换tag,切换到和k8s版本一致的tag v1.16.0
git checkout v1.16.0
然后进入上述目录的es-image目录下(目录为kubernetes/cluster/addons/fluentd-elasticsearch/),
修改Dockerfile文件中使用的es镜像为 gagara/elasticsearch-oss-arm64:7.3.2
之后就可以构建镜像了
docker build -t elasticsearch-arm64:7.3.2 .
b.fluentd
进入fluentd-es-image目录,然后
docker build -t fluentd-arm64:7.3.2 .
c. kibana
拉取kibana的arm版镜像,版本需要和es对应
docker pull gagara/kibana-oss-arm64:7.3.2
切换到之前下载的项目的 kubernetes/cluster/addons/fluentd-elasticsearch/目录下依次构建
a.es
修改es-statefulset.yaml文件下 containers: image标签下使用的镜像为在之前步骤构建的镜像,然后修改resources标签下限制的cpu和内存大小,建议按需求改大一点
然后使用如下命令构建
kubectl apply -f es-statefulset.yaml
创建service
kubectl apply -f es-service.yaml
b. fluentd
修改fluentd-es-ds.yaml文件下 containers: image标签下的镜像名为之前构建的镜像,然后修改第二个
volumes:hostPath:path值为/data/docker/containers(- name: varlibdockercontainers标签下的)
执行
kubectl apply -f fluentd-es-ds.yaml
清空fluentd-es-configmap.yaml文件,然后添加如下内容
kind: ConfigMap
apiVersion: v1
metadata:
name: fluentd-es-config-v0.2.0
namespace: kube-system
labels:
addonmanager.kubernetes.io/mode: Reconcile
data:
containers.input.conf: >-
# This configuration file for Fluentd / td-agent is used
# to watch changes to Docker log files. The kubelet creates symlinks that
# capture the pod name, namespace, container name & Docker container ID
# to the docker logs for pods in the /var/log/containers directory on the
host.
# If running this fluentd configuration in a Docker container, the /var/log
# directory should be mounted in the container.
#
# These logs are then submitted to Elasticsearch which assumes the
# installation of the fluent-plugin-elasticsearch & the
# fluent-plugin-kubernetes_metadata_filter plugins.
# See https://github.com/uken/fluent-plugin-elasticsearch &
# https://github.com/fabric8io/fluent-plugin-kubernetes_metadata_filter for
# more information about the plugins.
#
# Example
# =======
# A line in the Docker log file might look like this JSON:
#
# {"log":"2014/09/25 21:15:03 Got request with path wombat\n",
# "stream":"stderr",
# "time":"2014-09-25T21:15:03.499185026Z"}
#
# The time_format specification below makes sure we properly
# parse the time format produced by Docker. This will be
# submitted to Elasticsearch and should appear like:
# $ curl 'http://elasticsearch-logging:9200/_search?pretty'
# ...
# {
# "_index" : "logstash-2014.09.25",
# "_type" : "fluentd",
# "_id" : "VBrbor2QTuGpsQyTCdfzqA",
# "_score" : 1.0,
# "_source":{"log":"2014/09/25 22:45:50 Got request with path
wombat\n",
# "stream":"stderr","tag":"docker.container.all",
# "@timestamp":"2014-09-25T22:45:50+00:00"}
# },
# ...
#
# The Kubernetes fluentd plugin is used to write the Kubernetes metadata to
the log
# record & add labels to the log record if properly configured. This enables
users
# to filter & search logs on any metadata.
# For example a Docker container's logs might be in the directory:
#
#
/var/lib/docker/containers/997599971ee6366d4a5920d25b79286ad45ff37a74494f262e3bc98d909d0a7b
#
# and in the file:
#
# 997599971ee6366d4a5920d25b79286ad45ff37a74494f262e3bc98d909d0a7b-json.log
#
# where 997599971ee6... is the Docker ID of the running container.
# The Kubernetes kubelet makes a symbolic link to this file on the host
machine
# in the /var/log/containers directory which includes the pod name and the
Kubernetes
# container name:
#
#
synthetic-logger-0.25lps-pod_default_synth-lgr-997599971ee6366d4a5920d25b79286ad45ff37a74494f262e3bc98d909d0a7b.log
# ->
#
/var/lib/docker/containers/997599971ee6366d4a5920d25b79286ad45ff37a74494f262e3bc98d909d0a7b/997599971ee6366d4a5920d25b79286ad45ff37a74494f262e3bc98d909d0a7b-json.log
#
# The /var/log directory on the host is mapped to the /var/log directory in
the container
# running this instance of Fluentd and we end up collecting the file:
#
#
/var/log/containers/synthetic-logger-0.25lps-pod_default_synth-lgr-997599971ee6366d4a5920d25b79286ad45ff37a74494f262e3bc98d909d0a7b.log
#
# This results in the tag:
#
#
var.log.containers.synthetic-logger-0.25lps-pod_default_synth-lgr-997599971ee6366d4a5920d25b79286ad45ff37a74494f262e3bc98d909d0a7b.log
#
# The Kubernetes fluentd plugin is used to extract the namespace, pod name &
container name
# which are added to the log message as a kubernetes field object & the
Docker container ID
# is also added under the docker field object.
# The final tag is:
#
#
kubernetes.var.log.containers.synthetic-logger-0.25lps-pod_default_synth-lgr-997599971ee6366d4a5920d25b79286ad45ff37a74494f262e3bc98d909d0a7b.log
#
# And the final log record look like:
#
# {
# "log":"2014/09/25 21:15:03 Got request with path wombat\n",
# "stream":"stderr",
# "time":"2014-09-25T21:15:03.499185026Z",
# "kubernetes": {
# "namespace": "default",
# "pod_name": "synthetic-logger-0.25lps-pod",
# "container_name": "synth-lgr"
# },
# "docker": {
# "container_id":
"997599971ee6366d4a5920d25b79286ad45ff37a74494f262e3bc98d909d0a7b"
# }
# }
#
# This makes it easier for users to search for logs by pod name or by
# the name of the Kubernetes container regardless of how many times the
# Kubernetes pod has been restarted (resulting in a several Docker container
IDs).
# Json Log Example:
# {"log":"[info:2016-02-16T16:04:05.930-08:00] Some log text
here\n","stream":"stdout","time":"2016-02-17T00:04:05.931087621Z"}
# CRI Log Example:
# 2016-02-17T00:04:05.931087621Z stdout F
[info:2016-02-16T16:04:05.930-08:00] Some log text here
# Detect exceptions in the log output and forward them as one log entry.
@id raw.kubernetes
@type detect_exceptions
remove_tag_prefix raw
message log
stream stream
multiline_flush_interval 5
max_bytes 500000
max_lines 1000
# Concatenate multi-line logs
@id filter_concat
@type concat
key message
multiline_end_regexp /\n$/
separator ""
# Enriches records with Kubernetes metadata
@id filter_kubernetes_metadata
@type kubernetes_metadata
# Fixes json fields in Elasticsearch
@id filter_parser
@type parser
key_name log
reserve_data true
remove_key_name_field true
@type multi_format
format json
format none
forward.input.conf: |-
# Takes the messages sent over TCP
monitoring.conf: |-
# Prometheus Exporter Plugin
# input plugin that exports metrics
# input plugin that collects metrics from MonitorAgent
# input plugin that collects metrics for output plugin
# input plugin that collects metrics for in_tail plugin
output.conf: |-
@id elasticsearch
@type elasticsearch
@log_level info
type_name _doc
include_tag_key true
host elasticsearch-logging
port 9200
logstash_format true
@type file
path /var/log/fluentd-buffers/kubernetes.system.buffer
flush_mode interval
retry_type exponential_backoff
flush_thread_count 2
flush_interval 5s
retry_forever
retry_max_interval 30
chunk_limit_size 2M
total_limit_size 500M
overflow_action block
system.conf: |-
root_dir /tmp/fluentd-buffers/
system.input.conf: >-
# Example:
# 2015-12-21 23:17:22,066 [salt.state ][INFO ] Completed state
[net.ipv4.ip_forward] at time 23:17:22.066081
# Example:
# Dec 21 23:17:22 gke-foo-1-1-4b5cbd14-node-4eoj startupscript: Finished
running startup script /var/run/google.startup.script
# Examples:
# time="2016-02-04T06:51:03.053580605Z" level=info msg="GET
/containers/json"
# time="2016-02-04T07:53:57.505612354Z" level=error msg="HTTP Error" err="No
such image: -f" statusCode=404
# TODO(random-liu): Remove this after cri container runtime rolls out.
# Example:
# 2016/02/04 06:52:38 filePurge: successfully removed file
/var/etcd/data/member/wal/00000000000006d0-00000000010a23d1.wal
# Multi-line parsing is required for all the kube logs because very large
log
# statements, such as those that include entire object bodies, get split
into
# multiple lines by glog.
# Example:
# I0204 07:32:30.020537 3368 server.go:1048] POST /stats/container/:
(13.972191ms) 200 [[Go-http-client/1.1] 10.244.1.3:40537]
使用以下命令创建configmap
kubectl apply -f fluentd-es-configmap.yam
c.kibana
修改kibana-deployment.yaml文件下的containers: image 标签为之前创建的kibana镜像
然后修改 kibana-service.yaml文件,在spec标签下添加 type: NodePort 标签
之前使用如下命令创建
kubectl apply -f kibana-deployment.yaml
kubectl apply -f kibana-service.yaml
然后进入k8s,进入kube-system命名空间。查看创建的es,fluentd和kibana开头的组件是否创建正常。
然后进入service,查看kibana-service查看端口
这个便是kibanaservice暴露出来的端口号26920,通过 任意k8s计算节点ip:26920便可以访问kibana。
比如 http://xxxx.xxx.xxx.xxx:26920/,之后点击discover找到 logstash*的索引便可以查看容器的日志
由于日志太多,索引增长很快,需要定期删除,不然磁盘容量不够。
先创建一个shell脚本 vi rotate.sh
粘贴以下内容
#!/bin/bash
#--------------------------------------------------
# Rotate the indices in elastic of the EFK deployment
#
# @author: gjmzj
# @usage: ./rotator.sh [ ...]
# @repo: https://github.com/kubeasz/mirrorepo/es-index-rotator
# @ref: https://github.com/easzlab/kubeasz/tree/master/manifests/efk/es-index-rotator/rotator.yaml
set -o nounset
set -o errexit
set -o xtrace
[[ "$#" -gt 1 && $1 =~ ^[1-9][0-9]{0,2}$ ]] || \
{ echo 'Usage: ./rotator.sh [ ...]'; exit 1; }
max_days_of_log="$1"
echo -e "\n[INFO] rotate job starts, try to keep $max_days_of_log days of logs."
curl -s elasticsearch-logging:9200/_cat/indices > /tmp/indices || \
{ echo "[ERROR] Can not connect to elastic!"; exit 1; }
for index_prefix in "${@:2}";do
cat /tmp/indices|grep "$index_prefix"|wc -l > /tmp/lines
curr_days_of_log=$(cat /tmp/lines)
curr_days_of_log=$((${curr_days_of_log}-2))
if [[ "$max_days_of_log" -gt "$curr_days_of_log" ]];then
echo "[WARN] No need to rotate the ES indices: $index_prefix-*!"
else
first_day=$(date -d "$max_days_of_log days ago" +'%Y.%m.%d')
cat /tmp/indices|grep "$index_prefix"|cut -d' ' -f3|sed "s/$index_prefix-//g"|sed "s/-/\./g" > /tmp/index
rotate=$(cat /tmp/index|sort|sed -n "1,/$first_day/"p)
for day in $rotate;do
curl -s -X DELETE "elasticsearch-logging:9200/$index_prefix-$day"
day=$(echo $day|sed 's/\./-/g')
curl -s -X DELETE "elasticsearch-logging:9200/$index_prefix-$day"
done
echo -e "\n[INFO] Success to rotate the ES indices: $index_prefix-*!"
fi
done
创建一个Dockerfile文件,粘贴以下内容:
FROM alpine:3.9
COPY rotate.sh /bin/rotate.sh
RUN echo "===> Installing essential tools..." && \
apk --update add bash curl coreutils && \
echo "===> Cleaning up cache..." && \
rm -rf /var/cache/apk/* && \
chmod +x /bin/rotate.sh
CMD ["/bin/rotate.sh"]
然后构建镜像
docker build -t es-index-rotator:1 .
然后创建 es-index-rotator.yaml文件
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: es-index-rotator
namespace: kube-system
spec:
# 每天1点3分执行
schedule: "3 1 */1 * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: es-index-rotator
image: es-index-rotator:1
# 保留最近7天日志
command:
- /bin/rotate.sh
- "7"
- "logstash" # fluented 默认创建的index形如'logstash-2020.01.01'
restartPolicy: OnFailure
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 2
failedJobsHistoryLimit: 1
其中containers:command 下的7就是表示删除几天前的日志 ,可以自行修改,(可以写个一天测试)
然后构建到k8s
kubectl apply -f es-index-rotator.yaml
进入k8s中的cron job