【Golang 实战 ELK 日志系统全流程教程(三):ElasticSearch和kibanna环境搭建】
Golang 实战 ELK 日志系统全流程教程(三):Elasticsearch 和 Kibana 环境搭建
前两篇把 Go 侧日志怎么打、日志字段大概怎么设计捋了一遍以后,接下来就绕不开 ELK 里最先要跑起来的两个东西:
Elasticsearch:存日志、查日志
Kibana:看日志、筛日志、做一点简单分析
我一开始搭这个环境时犯过一个挺典型的错误:上来就想把 Elasticsearch、Kibana、Logstash、Filebeat 全部塞进一个 compose 文件里。
看起来很完整,实际一旦启动失败,排查会很痛苦。到底是 ES 没起来?还是 Kibana 连不上?还是 Logstash pipeline 写错?还是 Beat 采集路径不对?日志一堆,问题反而看不清。
所以这篇先只做一件事:把 Elasticsearch 和 Kibana 稳稳跑起来,并且手动写入一条 Go 应用日志,确认 Kibana 能查到。
先说版本:不要用 latest
Elastic 这套东西最怕“版本随缘”。
我写这篇时是 2026-05-28,Elastic 官方 Docker 文档当前示例已经是 9.4.1。但真实项目里我不建议写 latest,原因很简单:今天能跑,不代表下周同一份 compose 还能用同样的方式跑。
这里统一固定版本:
Elasticsearch:9.4.1
Kibana:9.4.1
Kibana 和 Elasticsearch 尽量保持同一个大版本、同一个小版本。它们本来就是一套栈里的组件,版本错开以后,经常不是直接报一个很好懂的错误,而是在启动、认证、API 兼容上给你一点小惊喜。
这篇是本地开发环境,所以我会先关闭安全认证:
xpack.security.enabled=false
这不是生产建议。生产环境要启用认证、TLS、账号权限、审计等配置。但学习 Go 日志链路时,第一阶段先把“日志能写进去、Kibana 能查出来”跑通,认知负担会小很多。
目录准备
我习惯把 ELK 环境单独放一个目录:
mkdir go-elk-demo
cd go-elk-demo
目录最后大概长这样:
go-elk-demo
├── .env
└── docker-compose.yml
写 .env
.env 里只放版本号:
STACK_VERSION=9.4.1
这样后面升级版本时,不用在 compose 文件里到处改。
写 docker-compose.yml
下面这个 compose 是我本地学习日志系统时比较常用的最小版本:
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION}
container_name: go-elk-elasticsearch
environment:
- node.name=es01
- cluster.name=go-elk-demo
- discovery.type=single-node
- bootstrap.memory_lock=true
- xpack.security.enabled=false
- ES_JAVA_OPTS=-Xms1g -Xmx1g
ulimits:
memlock:
soft: -1
hard: -1
ports:
- "9200:9200"
- "9300:9300"
volumes:
- es-data:/usr/share/elasticsearch/data
healthcheck:
test: ["CMD-SHELL", "curl -fsS http://localhost:9200 >/dev/null || exit 1"]
interval: 10s
timeout: 5s
retries: 12
kibana:
image: docker.elastic.co/kibana/kibana:${STACK_VERSION}
container_name: go-elk-kibana
environment:
- SERVER_NAME=kibana
- ELASTICSEARCH_HOSTS=http://elasticsearch:9200
ports:
- "5601:5601"
depends_on:
elasticsearch:
condition: service_healthy
volumes:
es-data:
几个配置我单独说一下,不然很容易照抄完了不知道为什么这么写。
discovery.type=single-node 是告诉 Elasticsearch:我现在就是单节点开发环境,不要再等别的节点加入集群。
ES_JAVA_OPTS=-Xms1g -Xmx1g 是限制 JVM 堆内存。ES 很吃内存,本地机器如果还开着 IDE、浏览器、数据库,别一上来就给太大。
xpack.security.enabled=false 是为了本地教程先绕过账号密码和证书。等后面日志链路通了,再单独补安全配置更清楚。
ELASTICSEARCH_HOSTS=http://elasticsearch:9200 这里的 elasticsearch 不是本机域名,而是 Docker Compose 内部服务名。Kibana 在容器网络里访问 ES,要走服务名,不是 localhost。
这个地方我以前就写错过。Kibana 容器里的 localhost 指的是 Kibana 自己,不是宿主机,也不是 Elasticsearch 容器。

启动环境
执行:
docker compose up -d
看容器状态:
docker compose ps
正常情况下会看到两个容器都在运行:
go-elk-elasticsearch running
go-elk-kibana running

如果 Kibana 还在启动,不要急。Kibana 第一次起来会比较慢,尤其是机器内存不太宽裕的时候。
可以看日志:
docker logs -f go-elk-elasticsearch
docker logs -f go-elk-kibana
验证 Elasticsearch
访问:
curl http://localhost:9200
Windows PowerShell 里建议写成:
curl.exe http://localhost:9200
因为 PowerShell 里的 curl 很多时候是 Invoke-WebRequest 的别名,输出格式和 Linux/macOS 下不一样。
正常会返回类似这样的 JSON:
{
"name": "es01",
"cluster_name": "go-elk-demo",
"version": {
"number": "9.4.1"
},
"tagline": "You Know, for Search"
}
这一步很关键。不要 Elasticsearch 还没验证,就直接去开 Kibana。否则 Kibana 页面打不开时,你不知道是 Kibana 自己的问题,还是后面的 ES 根本没活。

验证 Kibana
浏览器打开:
http://localhost:5601
因为我们本地关闭了安全认证,所以这里不需要输入 elastic 用户密码。
如果页面一直转圈,先看 Kibana 日志:
docker logs -f go-elk-kibana
我比较关注这几类信息:
Kibana is now available
Unable to retrieve version information from Elasticsearch nodes
connect ECONNREFUSED
第一种说明 Kibana 基本好了。
后两种大概率是 Kibana 连不上 Elasticsearch。优先检查 ELASTICSEARCH_HOSTS,再检查 ES 容器健康状态。
手动写入一条 Go 应用日志
环境起来以后,不要急着接 Go 代码。先手动写一条日志进去。
curl -X POST "http://localhost:9200/go-app-log-000001/_doc" \
-H "Content-Type: application/json" \
-d '{
"@timestamp": "2026-05-28T10:30:00+08:00",
"service_name": "order-api",
"env": "dev",
"level": "INFO",
"trace_id": "trace-20260528-0001",
"span_id": "span-001",
"message": "create order success",
"method": "POST",
"path": "/api/orders",
"status": 200,
"cost_ms": 37,
"user_id": 10001
}'
PowerShell 可以这样写,少一点转义折磨:
$body = @{
"@timestamp" = "2026-05-28T10:30:00+08:00"
service_name = "order-api"
env = "dev"
level = "INFO"
trace_id = "trace-20260528-0001"
span_id = "span-001"
message = "create order success"
method = "POST"
path = "/api/orders"
status = 200
cost_ms = 37
user_id = 10001
} | ConvertTo-Json
Invoke-RestMethod `
-Method Post `
-Uri "http://localhost:9200/go-app-log-000001/_doc" `
-ContentType "application/json" `
-Body $body
返回里看到 result: created,说明写入成功。
再查一下:
curl "http://localhost:9200/go-app-log-000001/_search?pretty"
如果能看到刚才那条日志,Elasticsearch 这一侧就没问题。

在 Kibana 里创建 Data View
接下来去 Kibana 看这条日志。
打开 Kibana 后,进入:
Stack Management -> Data Views -> Create data view
填:
Name: go-app-log
Index pattern: go-app-log-*
Timestamp field: @timestamp
保存后,进入:
Discover
选择 go-app-log 这个 Data View,把时间范围调大一点,比如 Last 7 days 或者手动覆盖到日志时间。

这里有个小坑:如果你插入的 @timestamp 是一个很早或者很晚的时间,而 Kibana 默认只看最近 15 分钟,你会以为日志没写进去。
我第一次用 Kibana 查日志时就被这个时间范围坑过。ES 里 _search 明明查得到,Kibana 里就是空。后来才发现不是索引问题,也不是 Data View 问题,就是右上角时间范围太窄。

先别急着上 Logstash
到这里,我们已经完成了一个最小闭环:
Elasticsearch 已启动
Kibana 已启动
能手动写入日志
能在 Kibana 查到日志
这个闭环看起来简单,但它很重要。
因为后面接 Go 服务、Filebeat、Logstash 时,只要日志没出现,就可以分段排查:
Go 程序有没有输出日志文件?
Filebeat 有没有采集到?
Logstash 有没有收到?
Logstash 有没有写入 Elasticsearch?
Elasticsearch 里有没有索引?
Kibana 的 Data View 和时间范围对不对?
如果一上来就把所有组件混在一起,排查路径会变成一锅粥。
本地常见坑
1. Elasticsearch 容器启动后立刻退出
先看日志:
docker logs go-elk-elasticsearch
Linux 机器上比较常见的是 vm.max_map_count 太小。可以临时设置:
sudo sysctl -w vm.max_map_count=262144
如果是 Docker Desktop,通常要看 Docker Desktop 给 Linux VM 分配的资源。ES 内存不够时,表现也可能是启动慢、卡住、容器被杀。
2. Kibana 报连不上 Elasticsearch
重点看这个配置:
ELASTICSEARCH_HOSTS=http://elasticsearch:9200
在 compose 网络里,Kibana 访问 ES 用服务名 elasticsearch。
不要写:
ELASTICSEARCH_HOSTS=http://localhost:9200
除非你非常清楚自己在做什么。容器里的 localhost 不是宿主机的 localhost。
3. Kibana Discover 里看不到日志
按这个顺序查:
curl "http://localhost:9200/_cat/indices?v"
curl "http://localhost:9200/go-app-log-000001/_search?pretty"
如果 ES 能查到,Kibana 看不到,优先检查:
Data View 是否匹配 go-app-log-*
时间字段是不是 @timestamp
右上角时间范围是否覆盖日志时间
很多时候问题不在写入,而在 Kibana 默认时间范围。
4. 端口被占用
9200 和 5601 都是常见端口。
如果启动时报端口占用,可以先看本机端口:
netstat -ano | findstr :9200
netstat -ano | findstr :5601
或者直接改 compose 里的宿主机端口:
ports:
- "19200:9200"
这样宿主机访问就是:
http://localhost:19200
容器内部还是 9200,不要把 Kibana 的 ELASTICSEARCH_HOSTS 也跟着改乱。
停止和清理
停止:
docker compose down
如果想把数据卷也删掉,重新来一遍:
docker compose down -v
注意,-v 会删除 Elasticsearch 里的数据。学习环境无所谓,项目环境别手滑。
这一篇先到这里
这一篇没有接 Go 代码,也没有上 Logstash。
我更想先把前面弄稳:Elasticsearch 能存,Kibana 能看,索引和时间字段能对上。后面真正接 Go 日志时,我们就不用再怀疑底层环境是不是坏的,可以把精力放到日志格式、trace_id、采集链路和字段映射上。
下一篇就可以开始做 Go 应用日志输出,然后考虑到底是:
Go -> 日志文件 -> Filebeat -> Elasticsearch
还是:
Go -> 日志文件 -> Filebeat -> Logstash -> Elasticsearch
我个人更倾向先从 Filebeat 直写 ES 开始,链路短,排错快。等字段清洗、脱敏、复杂路由需求出现,再把 Logstash 加进来。
参考资料
更多推荐

所有评论(0)