开始使用 Elastic Stack 和 Docker Compose:第 1 部分

blog-thumb-charts-laptop.png

随着 Elastic Stack 多年来的发展和功能集的增加,在本地开始使用或者尝试概念验证 (POC) 的复杂性也在增加。尽管 Elastic Cloud 仍然是开始使用 Elastic 的最快、最简单的方式,但对本地开发和测试的需求仍然非常大。作为开发人员,我们都喜欢快速设置以及低投入高产出的快速开发。没有什么比 Docker 更能快速设置和概念验证了 — 这就是我们将重点关注的,以便让您开始构建整个 Elastic Stack,享受在本地开发的乐趣。

这个系列博文分为两部分,在第一部分中,我们将深入探讨如何配置由 Elasticsearch、Logstash、Kibana 和 Beats (ELK-B) 组成的标准 Elastic Stack 的组件,我们可以在标准 Elastic Stack 上立即开始开发。

在第二部分中,我们将增强基本配置,并添加许多不同的功能,为我们不断发展的堆栈提供支持,如 APM、Agent、Fleet、集成和企业搜索。我们还将考虑在新的本地环境中利用这些功能进行开发和概念验证。

对于那些以前有过一些这方面经验的人,欢迎前往 TL;DR,然后前往存储库获取文件

作为先决条件,您需要安装和配置带有 Docker-ComposeDocker Desktop 或 Docker Engine。在本教程中,我们将使用 Docker Desktop。

我们将重点介绍这些 Docker 容器中的 Elasticsearch 和 Kibana。然而,我们将利用 Metricbeat 为我们提供一些集群方面的见解,并利用 Filebeat 和 Logstash 了解一些采集方面的基础知识。

文件结构

首先,我们来概述一下文件结构。

├── .env

├── docker-compose.yml

├── filebeat.yml

├── logstash.conf

└── metricbeat.yml

我们先从简单的开始着手。Elasticsearch 和 Kibana 将能够从 docker-compose 文件开始,而 Filebeat、Metricbeat 和 Logstash 都需要从 yml 文件进行额外配置。

环境文件

接下来,我们将定义通过 .env 文件传递给 docker-compose 的变量。这些参数将帮助我们建立端口、内存限制、组件版本等。

.env

# Project namespace (defaults to the current folder name if not set)
#COMPOSE_PROJECT_NAME=myproject


# Password for the 'elastic' user (at least 6 characters)
ELASTIC_PASSWORD=changeme


# Password for the 'kibana_system' user (at least 6 characters)
KIBANA_PASSWORD=changeme


# Version of Elastic products
STACK_VERSION=8.7.1


# Set the cluster name
CLUSTER_NAME=docker-cluster


# Set to 'basic' or 'trial' to automatically start the 30-day trial
LICENSE=basic
#LICENSE=trial


# Port to expose Elasticsearch HTTP API to the host
ES_PORT=9200


# Port to expose Kibana to the host
KIBANA_PORT=5601


# Increase or decrease based on the available host memory (in bytes)
ES_MEM_LIMIT=1073741824
KB_MEM_LIMIT=1073741824
LS_MEM_LIMIT=1073741824


# SAMPLE Predefined Key only to be used in POC environments
ENCRYPTION_KEY=c34d38b3a14956121ff2170e5030b471551370178f43e5626eec58b04a30fae2

请注意,所有密码和示例密钥的占位符单词“changeme”仅用于演示目的。即使是在进行本地概念验证时,也应该对其进行更改。

正如您在这里所看到的,我们分别为 Elasticsearch 和 Kibana 指定了端口 9200 和 5601。您也可以在这里将许可证类型从“basic”更改为“trial”,以测试其他功能。

我们在这里使用了“STACK_VERSION”环境变量,以便将其传递给 docker-compose.yml 文件中的每个服务(容器)。使用 Docker 时,选择对版本号进行硬编码而不是使用像 :latest 标记之类的内容,可以保持对环境的积极控制。对于 Elastic Stack 的组件,不支持 :latest 标记,我们需要版本号来拉取映像。

Setup 和 Elasticsearch 节点

开始使用时经常遇到的一些麻烦之一是安全性配置。从 8.0 起,默认情况下启用安全性。因此,我们需要利用“setup”节点来建立证书,从而确保正确设置证书 CA。建议启用安全性,即使在概念验证环境中也不应禁用。

docker-compose.yml(“setup”容器)

version: "3.8"


volumes:
 certs:
   driver: local
 esdata01:
   driver: local
 kibanadata:
   driver: local
 metricbeatdata01:
   driver: local
 filebeatdata01:
   driver: local
 logstashdata01:
   driver: local


networks:
 default:
   name: elastic
   external: false


services:
 setup:
   image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION}
   volumes:
     - certs:/usr/share/elasticsearch/config/certs
   user: "0"
   command: >
     bash -c '
       if [ x${ELASTIC_PASSWORD} == x ]; then
         echo "Set the ELASTIC_PASSWORD environment variable in the .env file";
         exit 1;
       elif [ x${KIBANA_PASSWORD} == x ]; then
         echo "Set the KIBANA_PASSWORD environment variable in the .env file";
         exit 1;
       fi;
       if [ ! -f config/certs/ca.zip ]; then
         echo "Creating CA";
         bin/elasticsearch-certutil ca --silent --pem -out config/certs/ca.zip;
         unzip config/certs/ca.zip -d config/certs;
       fi;
       if [ ! -f config/certs/certs.zip ]; then
         echo "Creating certs";
         echo -ne \
         "instances:\n"\
         "  - name: es01\n"\
         "    dns:\n"\
         "      - es01\n"\
         "      - localhost\n"\
         "    ip:\n"\
         "      - 127.0.0.1\n"\
         "  - name: kibana\n"\
         "    dns:\n"\
         "      - kibana\n"\
         "      - localhost\n"\
         "    ip:\n"\
         "      - 127.0.0.1\n"\
         > config/certs/instances.yml;
         bin/elasticsearch-certutil cert --silent --pem -out config/certs/certs.zip --in config/certs/instances.yml --ca-cert config/certs/ca/ca.crt --ca-key config/certs/ca/ca.key;
         unzip config/certs/certs.zip -d config/certs;
       fi;
       echo "Setting file permissions"
       chown -R root:root config/certs;
       find . -type d -exec chmod 750 \{\} \;;
       find . -type f -exec chmod 640 \{\} \;;
       echo "Waiting for Elasticsearch availability";
       until curl -s --cacert config/certs/ca/ca.crt https://es01:9200 | grep -q "missing authentication credentials"; do sleep 30; done;
       echo "Setting kibana_system password";
       until curl -s -X POST --cacert config/certs/ca/ca.crt -u "elastic:${ELASTIC_PASSWORD}" -H "Content-Type: application/json" https://es01:9200/_security/user/kibana_system/_password -d "{\"password\":\"${KIBANA_PASSWORD}\"}" | grep -q "^{}"; do sleep 10; done;
       echo "All done!";
     '
   healthcheck:
     test: ["CMD-SHELL", "[ -f config/certs/es01/es01.crt ]"]
     interval: 1s
     timeout: 5s
     retries: 120

docker-compose.yml 的顶部,我们设置了 compose 版本,然后设置了将在不同容器中使用的卷和默认网络配置。

我们还看到,我们使用一些 bash magic 来建立一个名为“setup”的容器,以指定我们的集群节点。这样我们将可以调用 elasticsearch-certutil,以 yml 格式传递服务器名称,从而创建 CA 证书和节点证书。如果您希望堆栈中有多个 Elasticsearch 节点,可以在这里添加服务器名称以允许创建证书。

注意:在以后的某篇博文中,我们将采用推荐的方法,使用密钥库来保存密码,但目前上述方法可帮助我们启动和运行集群。

这个 setup 容器将首先启动,等待 ES01 容器联机,然后使用我们的环境变量在集群中设置我们想要的密码。我们还会将所有证书保存到“certs”卷,以便所有其他容器都可以访问这些证书。

由于 Setup 容器依赖于 ES01 容器,让我们快速查看下一个配置,以便我们可以启动这两个容器:

docker-compose.yml(“es01”容器)

 es01:
   depends_on:
     setup:
       condition: service_healthy
   image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION}
   labels:
     co.elastic.logs/module: elasticsearch
   volumes:
     - certs:/usr/share/elasticsearch/config/certs
     - esdata01:/usr/share/elasticsearch/data
   ports:
     - ${ES_PORT}:9200
   environment:
     - node.name=es01
     - cluster.name=${CLUSTER_NAME}
     - discovery.type=single-node
     - ELASTIC_PASSWORD=${ELASTIC_PASSWORD}
     - bootstrap.memory_lock=true
     - xpack.security.enabled=true
     - xpack.security.http.ssl.enabled=true
     - xpack.security.http.ssl.key=certs/es01/es01.key
     - xpack.security.http.ssl.certificate=certs/es01/es01.crt
     - xpack.security.http.ssl.certificate_authorities=certs/ca/ca.crt
     - xpack.security.transport.ssl.enabled=true
     - xpack.security.transport.ssl.key=certs/es01/es01.key
     - xpack.security.transport.ssl.certificate=certs/es01/es01.crt
     - xpack.security.transport.ssl.certificate_authorities=certs/ca/ca.crt
     - xpack.security.transport.ssl.verification_mode=certificate
     - xpack.license.self_generated.type=${LICENSE}
   mem_limit: ${ES_MEM_LIMIT}
   ulimits:
     memlock:
       soft: -1
       hard: -1
   healthcheck:
     test:
       [
         "CMD-SHELL",
         "curl -s --cacert config/certs/ca/ca.crt https://localhost:9200 | grep -q 'missing authentication credentials'",
       ]
     interval: 10s
     timeout: 10s
     retries: 120

这将是我们用于测试的 Elasticsearch 的单节点集群。

请注意,我们将使用生成的 CA 证书和节点证书。

您还会注意到,我们通过指定 - esdata01:/usr/share/elasticsearch/data 将 Elasticsearch 数据存储在容器外部的卷中。这样做主要有两个原因,即性能和数据持久性。如果我们将数据目录留在容器中,我们会发现 Elasticsearch 节点的性能显著下降,并且会在需要更改 docker-compose 文件中容器的配置时丢失数据。

有了这两种配置,我们就可以执行第一个“docker-compose up”命令。

Docker Compose 提示

如果您刚接触 Docker Compose,或者您已经有一段时间无法记住其中的一些命令了,让我们快速回顾一下您在此次探索之旅中需要知道的主要命令。

您将需要在终端中运行所有这些命令,同时还要在 docker-compose.yml 文件所在的同一文件夹中运行。我的示例文件夹:

让我们看一下这些命令。

现在,我们来运行“docker-compose up”。

此时,如果语法正确,Docker 将开始下载所有映像并构建 docker-compose.yml 文件中列出的环境。这可能需要几分钟的时间,具体取决于您的互联网速度。如果您想在 Docker Desktop 外部看到映像,可以在官方 Elastic Docker 中心找到它们。

对虚拟内存配置错误进行故障排查

当首次启动 Elasticsearch 节点时,许多用户会遇到虚拟内存配置方面的问题,并收到错误消息,例如:

{"@timestamp":"2023-04-14T13:16:22.148Z", "log.level":"ERROR", "message":"node validation exception\n[1] bootstrap checks failed. You must address the points described in the following [1] lines before starting Elasticsearch.\nbootstrap check failure [1] of [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]", "ecs.version": "1.2.0","service.name":"ES_ECS","event.dataset":"elasticsearch.server","process.thread.name":"main","log.logger":"org.elasticsearch.bootstrap.Elasticsearch","elasticsearch.node.name":"es01","elasticsearch.cluster.name":"docker-cluster"}

这里的关键点是 max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

最终,需要在容器所在的位置运行命令 sysctl -w vm.max_map_count=262144

如果是 Mac,请查看 Docker for Mac 的这些说明。按照 Docker Desktop 的这些说明进行操作。对于 Linux 用户,请参阅这些说明。对于 Windows 用户,如果您有 Docker Desktop,可以试试这些说明。但是,如果您将 WSLv2 与 Docker Desktop 一起使用,请查看此处

完成后,您可以重新启动 Docker Desktop,然后重试 docker-compose up 命令。

请记住,Setup 容器在生成完证书和密码后会自动退出。

到目前为止一切正常,但我们要测试一下。

我们可以使用一个命令将 ca.crt 从 es01-1 容器中复制出来。请记住,容器集的名称基于从中运行 docker-compose.yml 的文件夹。例如,我的目录是“elasticstack_docker”,因此,根据上面的屏幕截图,我的命令看起来是这样的:

docker cp

elasticstack_docker-es01-1:/usr/share/elasticsearch/config/certs/ca/ca.crt /cn/tmp/.

下载证书后,运行 curl 命令以查询 Elasticsearch 节点:

curl --cacert /cn/tmp/ca.crt -u elastic:changeme https://localhost:9200

成功!

请注意,我们正在使用 localhost:9200 访问 Elasticsearch。这要归功于该端口,它是通过 docker-compose.ymlports 部分指定的。此设置将容器上的端口映射到主机上的端口,并允许流量通过您的机器进入指定了该端口的 Docker 容器。

Kibana

对于 Kibana 配置,我们将使用前面的证书输出。我们还将指定,此节点在看到上面的 Elasticsearch 节点正确启动并运行之后才会启动。

docker-compose.yml(“kibana”容器)

kibana:
   depends_on:
     es01:
       condition: service_healthy
   image: docker.elastic.co/kibana/kibana:${STACK_VERSION}
   labels:
     co.elastic.logs/module: kibana
   volumes:
     - certs:/usr/share/kibana/config/certs
     - kibanadata:/usr/share/kibana/data
   ports:
     - ${KIBANA_PORT}:5601
   environment:
     - SERVERNAME=kibana
     - ELASTICSEARCH_HOSTS=https://es01:9200
     - ELASTICSEARCH_USERNAME=kibana_system
     - ELASTICSEARCH_PASSWORD=${KIBANA_PASSWORD}
     - ELASTICSEARCH_SSL_CERTIFICATEAUTHORITIES=config/certs/ca/ca.crt
     - XPACK_SECURITY_ENCRYPTIONKEY=${ENCRYPTION_KEY}
     - XPACK_ENCRYPTEDSAVEDOBJECTS_ENCRYPTIONKEY=${ENCRYPTION_KEY}
     - XPACK_REPORTING_ENCRYPTIONKEY=${ENCRYPTION_KEY}
   mem_limit: ${KB_MEM_LIMIT}
   healthcheck:
     test:
       [
         "CMD-SHELL",
         "curl -s -I http://localhost:5601 | grep -q 'HTTP/1.1 302 Found'",
       ]
     interval: 10s
     timeout: 10s
     retries: 120

请注意,在“environment”部分中,我们指定了 ELASTICSEARCH_HOSTS=https://es01:9200。我们可以在这里为 ES01 Elasticsearch 容器指定容器名称,因为我们使用的是 Docker 默认网络。所有在 docker-compose.yml 文件开头使用指定的“elastic”网络的容器都将能够正确解析其他容器名称并相互通信。

我们来加载 Kibana,看看我们是否可以访问它。

容器是绿色的。我们现在应该能够访问 http://localhost:5601

使用指定的用户名和密码快速登录应该会让我们直接进入 Kibana 的一个全新实例。好极了!

Metricbeat

现在我们已经启动并运行 Kibana 和 Elasticsearch,并且正在通信,我们来配置 Metricbeat 以帮助我们密切关注情况。这将需要在我们的 docker-compose 文件以及独立的 metricbeat.yml 文件中进行配置。

注意:对于 Logstash、Filebeat 和 Metricbeat,配置文件使用的是绑定挂载。文件绑定挂载将在容器中保留它们在主机系统上拥有的相同权限和所有权。请确保设置权限,以使文件可读,理想情况下,容器的用户不可对文件进行写入。否则,您将在容器中收到一个错误。移除主机上的写入权限就可以了。

docker-compose.yml(“metricbeat01”容器)

 metricbeat01:
   depends_on:
     es01:
       condition: service_healthy
     kibana:
       condition: service_healthy
   image: docker.elastic.co/beats/metricbeat:${STACK_VERSION}
   user: root
   volumes:
     - certs:/usr/share/metricbeat/certs
     - metricbeatdata01:/usr/share/metricbeat/data
     - "./metricbeat.yml:/usr/share/metricbeat/metricbeat.yml:ro"
     - "/var/run/docker.sock:/var/run/docker.sock:ro"
     - "/sys/fs/cgroup:/hostfs/sys/fs/cgroup:ro"
     - "/proc:/hostfs/proc:ro"
     - "/:/hostfs:ro"
   environment:
     - ELASTIC_USER=elastic
     - ELASTIC_PASSWORD=${ELASTIC_PASSWORD}
     - ELASTIC_HOSTS=https://es01:9200
     - KIBANA_HOSTS=http://kibana:5601
     - LOGSTASH_HOSTS=http://logstash01:9600

在这里,我们将以只读方式向 Metricbeat 容器公开有关进程、文件系统和 Docker 守护进程的主机信息。这使 Metricbeat 能够收集要发送到 Elasticsearch 的数据。

metricbeat.yml

metricbeat.config.modules:
 path: ${path.config}/modules.d/*.yml
 reload.enabled: false


metricbeat.modules:
- module: elasticsearch
 xpack.enabled: true
 period: 10s
 hosts: ${ELASTIC_HOSTS}
 ssl.certificate_authorities: "certs/ca/ca.crt"
 ssl.certificate: "certs/es01/es01.crt"
 ssl.key: "certs/es01/es01.key"
 username: ${ELASTIC_USER}
 password: ${ELASTIC_PASSWORD}
 ssl.enabled: true


- module: logstash
 xpack.enabled: true
 period: 10s
 hosts: ${LOGSTASH_HOSTS}


- module: kibana
 metricsets:
   - stats
 period: 10s
 hosts: ${KIBANA_HOSTS}
 username: ${ELASTIC_USER}
 password: ${ELASTIC_PASSWORD}
 xpack.enabled: true


- module: docker
 metricsets:
   - "container"
   - "cpu"
   - "diskio"
   - "healthcheck"
   - "info"
   #- "image"
   - "memory"
   - "network"
 hosts: ["unix:///var/run/docker.sock"]
 period: 10s
 enabled: true


processors:
 - add_host_metadata: ~
 - add_docker_metadata: ~


output.elasticsearch:
 hosts: ${ELASTIC_HOSTS}
 username: ${ELASTIC_USER}
 password: ${ELASTIC_PASSWORD}
 ssl:
   certificate: "certs/es01/es01.crt"
   certificate_authorities: "certs/ca/ca.crt"
   key: "certs/es01/es01.key"

我们的 Metricbeat 取决于 ES01 和 Kibana 节点在启动前是否正常。这里值得注意的配置位于 metricbeat.yml 文件中。我们已经启用了四个模块来收集指标,包括 Elasticsearch、Kibana、Logstash 和 Docker。这意味着,一旦我们验证 Metricbeat 已启动,就可以跳到 Kibana 并导航到“堆栈监测”以了解情况。

别忘了设置开箱即用型规则!

Metricbeat 还被配置为通过 /var/run/docker.sock 监测容器的主机。通过检查 Elastic 可观测性,您可以看到来自主机的指标。

Filebeat

现在,集群已经稳定并通过 Metricbeat 进行监测,接下来,我们看看 Filebeat 以了解日志采集情况。在这里,我们将通过两种不同方式来使用 Filebeat:

docker-compose.yml(“filebeat01”容器)

 filebeat01:
   depends_on:
     es01:
       condition: service_healthy
   image: docker.elastic.co/beats/filebeat:${STACK_VERSION}
   user: root
   volumes:
     - certs:/usr/share/filebeat/certs
     - filebeatdata01:/usr/share/filebeat/data
     - "./filebeat_ingest_data/:/usr/share/filebeat/ingest_data/"
     - "./filebeat.yml:/usr/share/filebeat/filebeat.yml:ro"
     - "/var/lib/docker/containers:/var/lib/docker/containers:ro"
     - "/var/run/docker.sock:/var/run/docker.sock:ro"
   environment:
     - ELASTIC_USER=elastic
     - ELASTIC_PASSWORD=${ELASTIC_PASSWORD}
     - ELASTIC_HOSTS=https://es01:9200
     - KIBANA_HOSTS=http://kibana:5601
     - LOGSTASH_HOSTS=http://logstash01:9600

filebeat.yml

filebeat.inputs:
- type: filestream
 id: default-filestream
 paths:
   - ingest_data/*.log


filebeat.autodiscover:
 providers:
   - type: docker
     hints.enabled: true


processors:
- add_docker_metadata: ~


setup.kibana:
 host: ${KIBANA_HOSTS}
 username: ${ELASTIC_USER}
 password: ${ELASTIC_PASSWORD}


output.elasticsearch:
 hosts: ${ELASTIC_HOSTS}
 username: ${ELASTIC_USER}
 password: ${ELASTIC_PASSWORD}
 ssl.enabled: true
 ssl.certificate_authorities: "certs/ca/ca.crt"

首先,我们设置一个绑定挂载,将文件夹“filebeat_ingest_data”映射到容器中。如果您的主机上没有此文件夹,则会在容器启动时进行创建。如果您想在 Elastic 可观测性中为您的自定义日志测试日志流查看器,可以轻松地将任何扩展名为 .log 的文件放入 /filebeat_ingest_data/ 中,日志将被读取到默认的 Filebeat 数据流中。

除此之外,我们还在 /var/lib/docker/containers/var/run/docker.sock 中进行了映射,它们与 filebeat.autodiscover 部分和基于提示的自动发现相结合,允许 Filebeat 提取所有容器的日志。这些日志也可以在上面提到的日志流查看器中找到。

Logstash

我们要展示的最后一个容器就是 Logstash。

docker-compose.yml(“logstash01”容器)

 logstash01:
   depends_on:
     es01:
       condition: service_healthy
     kibana:
       condition: service_healthy
   image: docker.elastic.co/logstash/logstash:${STACK_VERSION}
   labels:
     co.elastic.logs/module: logstash
   user: root
   volumes:
     - certs:/usr/share/logstash/certs
     - logstashdata01:/usr/share/logstash/data
     - "./logstash_ingest_data/:/usr/share/logstash/ingest_data/"
     - "./logstash.conf:/usr/share/logstash/pipeline/logstash.conf:ro"
   environment:
     - xpack.monitoring.enabled=false
     - ELASTIC_USER=elastic
     - ELASTIC_PASSWORD=${ELASTIC_PASSWORD}
     - ELASTIC_HOSTS=https://es01:9200

logstash.conf

input {
 file {
   #https://www.elastic.co/guide/en/logstash/current/plugins-inputs-file.html
   #default is TAIL which assumes more data will come into the file.
   #change to mode => "read" if the file is a compelte file.  by default, the file will be removed once reading is complete -- backup your files if you need them.
   mode => "tail"
   path => "/usr/share/logstash/ingest_data/*"
 }
}


filter {
}


output {
 elasticsearch {
   index => "logstash-%{+YYYY.MM.dd}"
   hosts=> "${ELASTIC_HOSTS}"
   user=> "${ELASTIC_USER}"
   password=> "${ELASTIC_PASSWORD}"
   cacert=> "certs/ca/ca.crt"
 }
}

Logstash 配置与 Filebeat 配置非常相似。我们将再次使用绑定挂载,并将名为 /logstash_ingest_data/ 的文件夹从主机映射到 Logstash 容器中。在这里,您可以通过修改 logstash.yml 文件来测试其中一些输入插件筛选器插件然后将数据放入 /logstash_ingest_data/ 文件夹中。修改 logstash.yml 文件后,您可能需要重新启动 Logstash 容器。

注意,Logstash 输出索引名称为“logstash-%{+YYYY.MM.dd}”。要查看数据,您需要为“logstash-*”模式创建一个数据视图,如下所示。

现在,随着 Filebeat 和 Logstash 的启动和运行,如果您导航回“集群监测”,将看到 Logstash 受到监测,Elasticsearch 日志的一些指标和链接也受到监测。

结论

本系列博文的第一部分介绍了一个完整的活动集群,其中监测和采集是我们堆栈的基础。这将作为您本地的实际演练,用来测试 Elastic 生态系统的一些功能。

准备好了解更多详情了吗?看看第二部分!我们将深入优化这个基础,同时设置其他功能,如 APM 服务器、Elastic Agent、Elastic 集成和 Elastic Search。我们还部署和测试了一个应用程序,您可以使用其中的一些部分。

本文中讨论的所有文件以及为 Filebeat 和 Logstash 采集的一些示例数据都可以在 GitHub 上获得

观看 Elastic Stack 简介