00 收集日志的目的

日志的职责是记录离散事件,通过这些记录事后分析出程序的行为,譬如曾经调用过什么方法,曾经操作过哪些数据,等等。打印日志被认为是程序中最简单的工作之一,它无可或缺却不太被重视,调试问题时常有人会说 当初这里记得打点日志就好了 😵,可见这就是一项举手之劳的任务🙋。

输出日志的确很容易,但收集和分析日志却可能会很复杂,尤其随着容器化技术的迅猛发展,凭借 Docker 高效的部署和扩容的特点,一台计算机就可以同时使用多个容器,轻松地模拟出复杂的微服务架构。

这时,面对成千上万的节点,面对迅速滚动的事件信息,面对 TB 级别的日志数据,传输与收集都并不简单。对大多数程序员来说,分析日志也许就是最常遇见也最有实践性和可行性的大数据系统了。

本文就是让你快速了解并上手实践,🎯 如何使用 ELK 高效搭建一个用于收集和分析 Docker 日志的日志管理系统 🎯

在这里插入图片描述

01 安装Docker环境

1.1 Ubuntu18.04 安装 Docker

Docker 的安装方式有很多,这里展示一种只用 C-V 操作的方式,方便偷懒 😛 😜 😝

其他系统的 Docker CE 的安装方式可以自己参考 官方文档

如果你还不是很了解 Docker 的基础概念和使用方法的话,也可以参考笔者之前写的博文 Docker 安装部署与基础操作 期待 一键三连 👍 💬 ⭐️

# 更新Apt源
sudo apt-get update
# 安装依赖包
sudo apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common
# 添加 Docker 的 GPG 密钥
curl -fsSL http://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add - # 阿里云
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - # 官方 
# 验证您现在是否拥有带有指纹的密钥
sudo apt-key fingerprint 0EBFCD88
# 设置稳定版仓库
sudo add-apt-repository "deb [arch=amd64] http://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable" # 阿里云源
sudo add-apt-repository  "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs)  stable" # 官方源
# 安装Docker-CE
sudo apt-get update
sudo apt-get -y install docker-ce
# 启动docker
sudo systemctl enable docker
sudo systemctl start docker
# docker配置国内镜像源
sudo vim /etc/docker/daemon.json
{"registry-mirrors":["http://registry.docker-cn.com"]} # 在daemon.json文件中添加镜像源
# 重新加载daemon文件
sudo systemctl daemon-reload
# 重启docker服务
sudo systemctl restart docker
# 查看是否配置成功
sudo docker info

1.2 Docker 安装 Nginx 镜像

我们还是以收集 Nginx 日志为示例,所以第一步我们需要使用 Docker 安装 Nginx

如果你还不了解 ELK 日志管理是什么东东❓欢迎参考笔者之前写的博文 ELK 简介与安装使用 期待 一键三连 👍 💬 ⭐️

如果你还不了解 Nginx 日志是啥样子❓ 不清楚使用 ELK 收集 Nginx 的方式❓ 那就又到了广告时间啦,欢迎参考笔者之前写的博文 ELK 收集 Nginx 日志 期待 一键三连 👍 💬 ⭐️

# 查看Nginx镜像可用版本
docker search nginx 
# 拉取最新版的 Nginx 镜像
docker pull nginx:latest
# 查看本地镜像,查看是否已成功安装了 Nginx
docker images
# 运行容器
docker run --name nginx-docker -p 8080:80 -d nginx

运行容器命令run的参数说明:

  • –name nginx-test:容器名称。
  • -p 8080:80: 端口进行映射,将本地 8080 端口映射到容器内部的 80 端口。
  • -d nginx: 设置容器在在后台一直运行。

运行成功之后,可以在本地使用浏览器访问8080号端口,验证Nginx是否启动成功http://localhost:8080

1.3 查看 Docker 镜像的日志文件

和直接本地安装软件一样,使用 Docker 镜像安装软件的日志被记录在 Docker 的指定目录中/var/lib/docker/containers/,在对应镜像 ID 目录下保存该镜像的日志

以 Nginx 镜像为例,查看 Docker 中 Nginx 的日志文件

# 进入Docker镜像目录
cd /var/lib/docker/containers/
# 进入指定镜像(通过镜像ID识别)目录
cd 1cf162f8275bf1e3332c8864c923b722d433f6aa0a724cbd19c03c22c1375691
# 查看日志
tail -f 1cf162f8275bf1e3332c8864c923b722d433f6aa0a724cbd19c03c22c1375691-json.log 
# 得到如下输出结果,以Json格式保存的日志数据
{"log":"/docker-entrypoint.sh: Configuration complete; ready for start up\n","stream":"stdout","time":"2021-08-02T08:48:32.073222187Z"}
{"log":"2021/08/02 08:48:32 [notice] 1#1: using the \"epoll\" event method\n","stream":"stderr","time":"2021-08-02T08:48:32.087638853Z"}
{"log":"2021/08/02 08:48:32 [notice] 1#1: nginx/1.21.1\n","stream":"stderr","time":"2021-08-02T08:48:32.087953162Z"}
{"log":"2021/08/02 08:48:32 [notice] 1#1: built by gcc 8.3.0 (Debian 8.3.0-6) \n","stream":"stderr","time":"2021-08-02T08:48:32.087971584Z"}
{"log":"2021/08/02 08:48:32 [notice] 1#1: OS: Linux 4.15.0-151-generic\n","stream":"stderr","time":"2021-08-02T08:48:32.087977404Z"}
{"log":"2021/08/02 08:48:32 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576\n","stream":"stderr","time":"2021-08-02T08:48:32.08806543Z"}
{"log":"2021/08/02 08:48:32 [notice] 1#1: start worker processes\n","stream":"stderr","time":"2021-08-02T08:48:32.088352968Z"}

02 Filebeat 根据容器 ID 收集 Docker 日志

使用 Filebeat 采集日志其实就是一个配置工作 让他知道到哪个目录或文件中去找 👀 日志内容就可以了

为 Filebeat 的输入添加 docker 类型的日志收集配置如下

# 输入配置
filebeat.inputs:
- type: docker # docker类型
    containers.ids:
      - '1cf162f8275bf1e3332c8864c923b722d433f6aa0a724cbd19c03c22c1375691'

setup.kibana:
  host: "172.16.255.131:5601"

# 输出配置
output.elasticsearch:
  hosts: ["172.16.255.131:9200"]
  index: "docker-nginx-access-%{[agent.version]}-%{+yyyy.MM}"

# 模板配置
setup.template.name: "docker"
setup.template.pattern: "docker-*"
setup.template.enabled: false
setup.template.overwrite: true

03 Filebeat 收集多个 Docker 容器日志

打一个算什么,要的是能打一群❗️

使用 ELK 收集多个容器日志的配置方式也很简单

3.1 启动多个容器

先启动多个容器,本测试中启动两个 Nginx 镜像如下

# 列出当前Docker中的容器
docker ps
# 从容器创建一个新的镜像
docker commit nginx-docker nginx:v2
# 查看新创建的镜像
root@master:/etc/filebeat$ docker images
REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
nginx        v2        2ecdbbcdc6d7   24 seconds ago   133MB
nginx        latest    08b152afcfae   11 days ago      133MB
# 启动该镜像
docker run --name nginx-v2 -p 8081:80 -d nginx:v2
# 查看启动的镜像
root@master:/etc/filebeat$ docker ps
CONTAINER ID   IMAGE      COMMAND                  CREATED          STATUS          PORTS                                   NAMES
0a8f97993dc6   nginx:v2   "/docker-entrypoint.…"   37 seconds ago   Up 36 seconds   0.0.0.0:8081->80/tcp, :::8081->80/tcp   nginx-v2
1cf162f8275b   nginx      "/docker-entrypoint.…"   4 hours ago      Up 4 hours      0.0.0.0:8080->80/tcp, :::8080->80/tcp   nginx-docker

3.2 配置 Filebeat 进行多容器日志收集

当Docker中存在多个容器时,采用依据容器ID的方式进行日志采集会带来很多问题:

  • 容器的数量很多时需要添加多个容器ID,容器日志收集过于复杂
  • 容器会被删除,如果容器被删除,配置在Filebeat中的容器ID变得冗余

多个Docker容器收集Filebeat配置官方文档:官方文档

# Docker类型输入配置
- type: docker
  combine_partial: true
  containers:
    path: "/var/lib/docker/containers"
    # stream: "stdout" # 只收集正常日志 stderr标识错误日志
    ids:
      - "*"
    tags: ["docker"]

output.elasticsearch:
  hosts: ["172.16.255.131:9200"]
  indices:
      - index: "nginx-access-%{[agent.version]}-%{+yyyy.MM}"
        when.contains:
            tags: "access"
      - index: "nginx-error-%{[agent.version]}-%{+yyyy.MM}"
        when.contains:
            tags: "error"
     # 添加如下索引配置
      - index: "docker-%{[agent.version]}-%{+yyyy.MM}"
        when.contains:
            tags: "docker"

04 根据服务类型收集多个 Docker 容器日志

不仅能释放范围攻击,精准打击也不在话下 🎯 🎯 🎯

下面就介绍怎么根据服务类型来收集容器日志

4.1 直接配置 Filebeat 收集多容器日志的缺陷

使用 03 节中的多容器日志收集的方法,将所有Docker容器的日志都统一收集在同一个索引中存储;这样可能带来无法区分不同服务类型容器日志的问题,本节考虑将Docker容器中不同服务类型的日志收集区分开。

📌一种思路:📌 和区分 Nginx 正常日志和错误日志一样,通过在采集的日志条目中的字段进行区分不同类型的日志,但是需要手动设置

其实收集的日志本质上来说还是文件,而这个日志是以容器ID-json.log命名存放在默认目录下的Json格式的文件,但是每个容器的ID都是不一样的,所以为了区分不同服务运行的不同容器,可以使用容器编排工具 docker-compose 通过给容器添加 labels标签进行区分。

以此为基础,Filebeat 把容器当作普通 Json 格式来解析并传输到 ES 中。

4.2 安装与使用 docker-compose

如果你在问什么是 docker-compose❓ 那就又到了广告时间啦,欢迎参考笔者之前写的博文 Docker Compose 容器编排基础使用 期待 一键三连 👍 💬 ⭐️

安装 docker-compose

这里使用 pip 安装 docker-compose

# 安装下载 pip
apt install python3-pip -y
pip3 install pip -U
# 更新库
apt-get update
# 升级 pip
pip install --upgrade pip
# 安装docker-compose
pip install docker-compose
# 检查是否安装成功
docker-compose -version

编排 docker-compose

编写 docker-compose,用两个Nginx模拟两个服务一个nginx服务一个db服务。创建配置文件 docker-compose.yml

root@master:/home/wang$ vim docker-compose.yml

在文件中编写如下内容

version: '3'
# 定义一个服务组,服务中包含哪些容器
services:
    nginx:
        # 容器名称
        image: nginx:v2 
        # 设置labels
        labels:
            service: nginx
        # logging设置增加labels.service
        logging:
            options:
                labels: "services"
        ports:            
            - "8081:80"

    db:
        image: nginx:latest
        # 设置labels
        labels:
            service: db
        # logging设置增加labels.service
        logging:
            options:
                labels: "services"
        ports:            
            - "8082:80"

启动 docker-compose

首先,关闭原先的容器并删除,因为他们会占用端口号

docker stop nginx-v2
docker stop nginx-docker
docker rm nginx-v2
docker rm nginx-docker
# 查看是否已经删除
docker ps -a

打开一个新窗口,启动 docker-compose,因为他是前台启动

docker-compose up

查看docker-compose根据编排创建的容器

root@master:/home/wang$ docker ps -a
CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS          PORTS                                   NAMES
a02e09d7d62d   nginx:latest   "/docker-entrypoint.…"   5 minutes ago    Up 5 minutes    0.0.0.0:8082->80/tcp, :::8082->80/tcp   wang_db_1
b8705e247a70   nginx:v2       "/docker-entrypoint.…"   19 minutes ago   Up 19 minutes   0.0.0.0:8081->80/tcp, :::8081->80/tcp   wang_nginx_1

查看docker中Nginx镜像的日志可以看出,日志内容根据编排增加了labels标签

在这里插入图片描述

4.3 配置 Filebeat 分服务收集 Docker 容器日志

使用容器编排工具 docker-compose 编排容器之后,可以看到 Docker 容器产生的日志中增加了labels标签,在Filbeat中根据此标签区分不同服务。

另外值得注意的是,在本地保存的日志中可用于区分服务的标签com_docker_compose_serviceservice上有多级标签,完整标签为container.labels.com_docker_compose_servicecontainer.labels.service

进一步的说,可以看到 Dokcer容器日志的在本地保存时是以 Json 格式保存的,所以直接可以把他当成普通日志的方式,和收集 Nginx、Tomcat 等一样,采用type: log的方式去收集 Docker 日志。

所以 Filebeat 的容器收集输入配置可以如下形式:

# ------------------------Docker-Services--------------------------------
- type: log
  enabled: true
  paths:
    - /var/lib/docker/containers/*/*-json.log # 通配符*匹配容器ID,达到收集所有容器日志的目的
  # type为log所以需要加上下面两行Json解析配置,否则日志被当成纯文本处理 
  json.keys_under_root: true
  json.overwrite_keys: true

本测试还是基于 03 节中的容器日志收集配置为基础,对 Filebeat 增加配置如下

# 输入配置 保留原先配置不进行改变
- type: docker
  combine_partial: true
  containers:
    path: "/var/lib/docker/containers"
    # stream: "stdout" # 只收集正常日志 stderr标识错误日志
    ids:
      - "*"

# 输出配置
# ---------------------------- Elasticsearch Output ----------------------------
output.elasticsearch:
  hosts: ["172.16.255.131:9200"]
  indices:
      - index: "docker-%{[agent.version]}-%{+yyyy.MM}"
        when.contains:
            tags: "docker"
      # 增加如下几行索引配置,通过label标签判别不同服务
      - index: "docker-nginx-%{[agent.version]}-%{+yyyy.MM}"
        when.contains:
            container.labels.service: "nginx" # nginx服务日志
      - index: "docker-db-%{[agent.version]}-%{+yyyy.MM}"
        when.contains:
            container.labels.service: "db" # db服务日志

配置完成后重新启动 Filebeat,并在本地浏览器中访问8081和8082两个Nginx容器的端口,刷新页面向服务发送请求产生日志

systemctl restart filebeat
# 浏览器访问
http://172.16.255.131:8081
http://172.16.255.131:8081

使用 ES-head 查看容器日志被分服务收集如下图所示

在这里插入图片描述

4.4 配置 Filebeat 进一步区分不同容器服务的错误日志和正常日志

在 4.3 节成功分服务采集容器日志的基础上,进一步考虑将同一个服务的正常日志和错误日志区分开并分别存储。如下图所示,容器日志中stream标签的内容区分了正常日志 stdout 和错误日志 stderr

在这里插入图片描述

为了在容器服务区分的基础上实现日志类型的区分,Filebeat 的输出配置中需要对索引配置进行多个条件限定,and关系的条件只需要写在一起即可,对 Filebeat 输出配置如下

# 输出配置
# ---------------------------- Elasticsearch Output ----------------------------
output.elasticsearch:
  hosts: ["172.16.255.131:9200"]
  indices:
      - index: "docker-nginx-access-%{[agent.version]}-%{+yyyy.MM}"
        when.contains:
            container.labels.service: "nginx"
            stream: "stdout" # 进一步区分日志类型
      - index: "docker-db-access%{[agent.version]}-%{+yyyy.MM}"
        when.contains:
            container.labels.service: "db"
            stream: "stdout"
      - index: "docker-nginx-error-%{[agent.version]}-%{+yyyy.MM}"
        when.contains:
            container.labels.service: "nginx"
            stream: "stderr"
      - index: "docker-db-error-%{[agent.version]}-%{+yyyy.MM}"
        when.contains:
            container.labels.service: "db"
            stream: "stderr"

配置完成后删除之前的docker索引并重新启动 Filebeat,然后在本地浏览器中访问8081和8082两个Nginx容器的端口,刷新页面向服务发送请求产生日志

systemctl restart filebeat
# 浏览器访问
http://172.16.255.131:8081
http://172.16.255.131:8081

使用ES-head查看容器日志被分服务分类型收集如下图所示

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

参考资料

Ubuntu18.04安装docker

Docker安装Nginx

Docker 官方文档

Filebeat 官方文档

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐