K8s日志处理

k8s集群的日志方案

Kubernetes 没有为日志数据提供原生存储方案,需要集成现有的日志解决方案到 Kubernetes 集群,首先要介绍一下官方文档对日志架构说明:

节点级日志

容器化应用写入 stdout 和 stderr 的任何数据,都会被容器引擎捕获并被重定向到某个位置。例如,Docker 容器引擎将这两个输出流重定向到 日志驱动 ,该日志驱动在 Kubernetes 中配置为以 json 格式写入文件。

集群级别日志架构

官方文档推荐以下选项:

  • 使用运行在每个节点上的节点级的日志代理。
  • 在应用程序的 pod 中,包含专门记录日志的伴生容器。
  • 在应用程序中将日志直接推送到后台。

使用节点级日志代理

您可以在每个节点上使用 节点级的日志代理 来实现集群级日志记录。日志代理是专门的工具,它会暴露出日志或将日志推送到后台。通常来说,日志代理是一个容器,这个容器可以访问这个节点上所有应用容器的日志目录。

因为日志代理必须在每个节点上运行,所以通常的实现方式为,DaemonSet 副本,manifest pod,或者专用于本地的进程。但是后两种方式已被弃用并且不被推荐。

使用伴生容器和日志代理

您可以通过以下方式之一使用伴生容器:

  • 伴生容器将应用程序日志传送到自己的标准输出。
  • 伴生容器运行一个日志代理,配置该日志代理以便从应用容器收集日志。

从应用中直接暴露日志目录

通过暴露或推送每个应用的日志,您可以实现集群级日志记录;然而,这种日志记录机制的实现已超出 Kubernetes 的范围。

实践

根据我司集群规模用到节点级日志代理就够了,这里使用官方推荐 EFK(Elasticsearch+Fluentd+Kibana) 解决方案,过程中尝试了Fluentd后觉得并不是特别好用(文档、资料、社区活跃都不够),最终选择用 elastic 家族的 Filebeat 替换掉 Fluentd。

目前方案为:

  • Filebeat
  • Elasticsearch
  • Kibana

安装

Elasticsearch:

wget https://raw.githubusercontent.com/kubernetes/kubernetes/release-1.10/cluster/addons/fluentd-elasticsearch/es-service.yaml

kubectl apply -f es-service.yaml

wget https://raw.githubusercontent.com/kubernetes/kubernetes/release-1.10/cluster/addons/fluentd-elasticsearch/es-statefulset.yaml

#修改images为国内,原数据存储方式为emptyDir,修改为网盘

# Elasticsearch deployment itself
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: elasticsearch-logging
  namespace: kube-system
  labels:
    k8s-app: elasticsearch-logging
    version: v5.6.4
    kubernetes.io/cluster-service: "true"
    addonmanager.kubernetes.io/mode: Reconcile
spec:
  serviceName: elasticsearch-logging
  replicas: 2
  selector:
    matchLabels:
      k8s-app: elasticsearch-logging
      version: v5.6.4
  template:
    metadata:
      labels:
        k8s-app: elasticsearch-logging
        version: v5.6.4
        kubernetes.io/cluster-service: "true"
    spec:
      serviceAccountName: elasticsearch-logging
      containers:
      - image: registry.cn-hangzhou.aliyuncs.com/google_containers/elasticsearch:v5.6.4 #国内阿里云镜像
        name: elasticsearch-logging
        resources:
          # need more cpu upon initialization, therefore burstable class
          limits:
            cpu: 1000m
          requests:
            cpu: 100m
        ports:
        - containerPort: 9200
          name: db
          protocol: TCP
        - containerPort: 9300
          name: transport
          protocol: TCP
        volumeMounts:
        - name: elasticsearch-logging
          mountPath: /data
        env:
        - name: "NAMESPACE"
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
      initContainers:
      - image: alpine:3.6
        command: ["/sbin/sysctl", "-w", "vm.max_map_count=262144"]
        name: elasticsearch-logging-init
        securityContext:
          privileged: true
  volumeClaimTemplates: #阿里云盘存储
  - metadata:
      name: "elasticsearch-logging"
    spec:
      accessModes:
      - ReadWriteOnce
      storageClassName: alicloud-disk-efficiency
      resources:
        requests:
          storage: 20Gi

kubectl apply -f es-statefulset.yaml

Filebeat:

wget https://raw.githubusercontent.com/elastic/beats/6.4/deploy/kubernetes/filebeat-kubernetes.yaml

#由于我们安装的es没有权限,清理掉es用户名和密码相关
ConfigMap
  output.elasticsearch:
    hosts: ['${ELASTICSEARCH_HOST:elasticsearch}:${ELASTICSEARCH_PORT:9200}']
    username: ${ELASTICSEARCH_USERNAME}  # 删除
    password: ${ELASTICSEARCH_PASSWORD}  # 删除

DaemonSet 
    env:
        - name: ELASTICSEARCH_HOST
          value: elasticsearch
        - name: ELASTICSEARCH_PORT
          value: "9200"
        - name: ELASTICSEARCH_USERNAME  # 删除
          value: elastic
        - name: ELASTICSEARCH_PASSWORD  # 删除
          value: changeme
        - name: ELASTIC_CLOUD_ID
          value:
        - name: ELASTIC_CLOUD_AUTH
          value:

kubectl apply -f filebeat-kubernetes.yaml

Kibnan:

wget https://raw.githubusercontent.com/kubernetes/kubernetes/release-1.10/cluster/addons/fluentd-elasticsearch/kibana-service.yaml

kubectl apply -f kibana-service.yaml

#添加kibana的ingress
cat>kibana-ingress.yaml<<EOF
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: kibana-logging
  namespace: kube-system
spec:
  rules:
  - host: kibana.domain.com
    http:
      paths:
      - backend:
          serviceName: kibana-logging
          servicePort: 5601
EOF

kubectl apply -f kibana-ingress.yaml

wget https://raw.githubusercontent.com/kubernetes/kubernetes/release-1.10/cluster/addons/fluentd-elasticsearch/kibana-deployment.yaml

#修改 SERVER_BASEPATH 为 ""( 原本是一串地址不知道有什么用,如不修改为“”或者删除,域名是没有办法正常访问的)
          - name: SERVER_BASEPATH
            value: /api/v1/namespaces/kube-system/services/kibana-logging/proxy #修改为 ""

kubectl apply -f kibana-deployment.yaml

使用

安装都完成后访问 kibana.domain.com 查看 kibana,添加 filebeat-* 的 index

访问权限

kibana 目前还是裸奔状态,这样肯定不能在生产环境使用,尝试通过 elastic 的 X-Pack 方式解决并未成功,主要还是官方的Elasticsearch安装文件未对X-Pack支持,而我许久没玩 Elasticsearch 感觉功力不够,最终选择通过为Ingress添加basic-auth认证的方式做权限

安装 htpasswd,创建用户密码

#安装
yum -y install httpd-tools

#产生密码文件
htpasswd -c auth  kibana

New password: 
Re-type new password: 
Adding password for user kibana

创建secret存储密码

kubectl -n <namespace> create secret generic kibana-basic-auth --from-file=auth

修改 Kibnan Ingress

cat>kibana-ingress.yaml<<EOF
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: kibana-logging
  namespace: kube-system
  annotations:
    nginx.ingress.kubernetes.io/auth-type: basic
    nginx.ingress.kubernetes.io/auth-secret: kibana-basic-auth
    nginx.ingress.kubernetes.io/auth-realm: "Authentication Required - kibana"
spec:
  rules:
  - host: kibana.domain.com
    http:
      paths:
      - backend:
          serviceName: kibana-logging
          servicePort: 5601
EOF
kubectl apply -f kibana-ingress.yaml

再访问 kibana.domain.com 就会要求输入用户名和密码拉~~~~

参考文档

上篇Gitlab ci:cd
下篇K8s监控 prometheus Operator