作者:Eddie Mitchell
随着 Elastic Stack 多年来的发展和功能集的增加,在本地开始或尝试概念验证 (POC) 的复杂性也越来越高。 虽然 Elastic Cloud 仍然是开始使用 Elastic 最快、最简单的方式,但对本地开发和测试的需求仍然非常丰富。 作为开发人员,我们被吸引到快速设置和快速开发而无需付出太多努力。 没有什么比 Docker 更能快速设置和 POC 了——这就是我们将专注于开始构建整个 Elastic Stack 以供你本地享受的内容。
在这个由两部分组成的系列的第一部分中,我们将深入探讨由 Elasticsearch、Logstash、Kibana 和 Beats (ELK-B) 组成的标准 Elastic Stack 的组件配置,我们可以立即开始开发。
在第二部分中,我们将增强我们的基本配置并添加许多不同的功能来支持我们不断发展的堆栈,例如 APM、代理、队列、集成和企业搜索。 我们还将考虑在我们新的本地环境中对这些进行检测,以用于开发和 POC 目的。
对于那些以前经历过其中一些的人,欢迎你来到太长不需要阅读并前往存储库获取文件。
作为先决条件,需要安装和配置带有 Docker-Compose 的 Docker 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 和示例密钥仅用于演示目的。 即使是你当地的 POC 需求,也应该更改这些内容。
正如你在这里看到的,我们分别为 Elasticsearch 和 Kibana 指定了端口 9200 和 5601。 这也是你可以从 “basic” 许可类型更改为 “trial” 许可类型以测试其他功能的地方。
我们在这里使用 STACK_VERSION 环境变量,以便将其传递给 docker-compose.yml 文件中的每个服务(容器)。 使用 Docker 时,选择硬编码版本号而不是使用 :latest 标签之类的东西是保持对环境的积极控制的好方法。 对于 Elastic Stack 的组件,不支持 :latest 标签,我们需要版本号来拉取镜像。
设置和 Elasticsearch 节点
入门时经常遇到的第一个麻烦是安全配置。 从 8.0 开始,默认情况下启用安全性。 因此,我们需要确保通过使用 “setup” 节点来建立证书来正确设置证书 CA。 启用安全性是一种推荐做法,不应禁用,即使在 POC 环境中也是如此。
docker-compose.yml (‘setup’ container)
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 的顶部,我们设置了组合版本,然后是将在我们的不同容器中使用的 volume 和默认网络配置。
我们还看到我们正在建立一个标有 “setup” 的容器,其中包含一些 bash 魔法来指定我们的集群节点。 这允许我们调用 elasticsearch-certutil,以 yml 格式传递服务器名称以创建 CA 证书和节点证书。 如果你希望堆栈中有多个 Elasticsearch 节点,你可以在此处添加服务器名称以允许创建证书。
注意:在以后的文章中,我们将采用推荐的使用密钥库(keystore)保密的方法,但现在,这将使我们能够启动并运行集群。
这个设置容器将首先启动,等待 es01 容器上线,然后使用我们的环境变量在我们的集群中设置我们想要的密码。 我们还将所有证书保存到 “certs” 卷,以便所有其他容器都可以访问它们。
由于 setup 容器依赖于 es01 容器,让我们快速看一下下一个配置,以便我们可以同时启动它们:
docker-compose.yml (‘es01’ container)
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 证书和节点证书。
你还会注意到,我们通过指定将 Elasticsearch 数据存储在容器外部的卷中 - esdata01:/usr/share/elasticsearch/data 这样做的两个主要原因是性能和数据持久性。 如果我们将数据目录留在容器内,我们会看到 Elasticsearch 节点的性能显着下降,并且在我们需要更改 docker-compose 文件中的容器配置时随时丢失数据。
有了这两个配置,我们就可以执行我们的第一个 docker-compose up 命令。
docker-compose up
Docker Compose 技巧
如果你是 Docker Compose 的新手,或者你已经有一段时间没有记住一些命令,那么让我们快速回顾一下你在这次练习中想要了解的主要命令。
你将希望在终端中运行所有这些命令,同时在你的 docker-compose.yml 文件所在的同一文件夹中。 我的示例文件夹:
让我们来看看这些命令。
命令 | 描述 |
---|---|
docker-compose up | 创建并启动 docker-compose.yml 中的所有容器 |
docker-compse down | 停止所有容器并删除与 docker-compose.yml 相关的任何网络。 保持创建的 Voluesm 完好无损,并允许生成的数据在环境构建之间持续存在 |
docker-compse down -v | 与上面相同,除了还会删除所有已创建的卷。 这非常适合“重新开始” |
docker-compose start | 如果容器存在但已停止,这将启动所有容器 |
docker-compose down | 停止所有容器并保持环境完好无损。 如果你在运行的终端中,那么 “CTRL+C” 也会退出并停止所有容器 |
现在,让我们运行 `docker-compose up`。
此时,如果语法正确,Docker 将开始下载所有镜像并构建 docker-compose.yml 文件中列出的环境。 这可能需要几分钟,具体取决于你的互联网速度。 如果你想在 Docker Desktop 之外查看图像,你始终可以在官方 Elastic Docker Hub 中找到它们。
虚拟内存配置错误故障排除
首次启动 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"}
这里的关键是最大虚拟内存区域 vm.max_map_count [65530] 太低,至少增加到 [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 命令。
请记住,安装容器将在完成生成证书和密码后故意退出。
到目前为止一切顺利,但让我们测试一下。
我们可以使用命令将 ca.crt 从 es01-1 容器中复制出来。 请记住,容器集的名称基于运行 docker-compose.yml 的文件夹。 例如,我的目录是“elasticstack_docker”,因此,根据上面的屏幕截图,我的命令如下所示:
docker cp elasticstack_docker-es01-1:/usr/share/elasticsearch/config/certs/ca/ca.crt /tmp/.
下载证书后,运行 curl 命令查询 Elasticsearch 节点:
curl --cacert /tmp/ca.crt -u elastic:changeme https://localhost:9200
成功!
请注意,我们正在使用 localhost:9200 访问 Elasticsearch。 这要归功于端口,它已通过 docker-compose.yml 的端口部分指定。 此设置将容器上的端口映射到主机上的端口,并允许流量通过你的机器并进入指定该端口的 docker 容器。
Kibana
对于 Kibana 配置,我们将使用之前的证书输出。 我们还将指定此节点不会启动,直到它看到上面的 Elasticsearch 节点已启动并正确运行。
docker-compose.yml (‘kibana’ container)
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,配置文件使用 bind mounts。 文件的绑定挂载将在容器内保留与它们在主机系统上相同的权限和所有权。 确保设置权限,使文件可读,理想情况下,容器用户不可写。 否则你将在容器中收到错误消息。 删除主机上的写入权限可能就足够了。
docker-compose.yml (‘metricbeat01’ container)
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
在这里,我们以只读方式将有关进程、文件系统和 docker 守护进程的主机信息公开给 Metricbeat 容器。 这使 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 并导航到 Stack Monitoring 以查看情况。
不要忘记设置开箱即用的规则!
Metricbeat 还配置为通过 /var/run/docker.sock 监控容器的主机。检查 Elastic 可观察性允许你查看来自主机的指标。
Filebeat
现在集群稳定并使用 Metricbeat 进行监控,让我们看看用于日志摄取的 Filebeat。 在这里,我们的 Filebeat 将以两种不同的方式使用:
docker-compose.yml (‘filebeat01’ container)
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 Observability 中为你的自定义日志测试日志流查看器,你可以轻松地将任何具有 .log 扩展名的文件放入 /filebeat_ingest_data/,日志将被读入默认的 Filebeat 数据流。
除此之外,我们还在 /var/lib/docker/containers 和 /var/run/docker.sock 中映射,结合 filebeat.autodiscover 部分和基于提示的自动发现,允许 Filebeat 提取所有容器的日志 . 这些日志也可以在上面提到的日志流查看器中找到。
Logstash
我们最终要实现的容器就是 Logstash。
docker-compose.yml (‘logstash01’ container)
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 的启动和运行,如果你导航回 Cluster Monitoring,你将看到 Logstash 被监控,以及 Elasticsearch 日志的一些指标和链接。
结论
本系列的第 1 部分介绍了一个完整的活动集群,其中监控和摄取是我们堆栈的基础。 这将作为你本地的游乐场来测试 Elastic 生态系统的一些功能。
请继续关注第二部分! 我们将深入优化这个基础,同时设置附加功能,例如 APM 服务器、Elastic Agents、Elastic integrations 和企业搜索。 我们还将部署和测试一个应用程序,你可以使用其中的一些部分进行检测。
GitHub 上提供了此处讨论的所有文件以及一些示例数据,以便为 Filebeat 和 Logstash 提取。
额外资源:
- Running Elasticsearch on Docker
- Running Kibana on Docker
- Running Metricbeat on Docker
- Running Filebeat on Docker
- Running Logstash on Docker