15分鐘搞定使用 Docker 搭建 ELK 環境

前言:本文將聊聊如何使用 Docker 搭建 ELK (Elasticsearch、Logstash、Kibana)。

文章將分兩個部分對搭建進行介紹,用於開發測試以及一般分析需求的環境,以及彈性擴容後可以用於一般生產的環境。

因為藉助於方便的 Docker,完整操作時間不超過 15 分鐘,如果你對 Docker 還不熟悉,可以瀏覽之前的文章。

寫在前面

為了方便搭建,我們使用 https://github.com/deviantony/docker-elk 這個開源項目,這個項目維護了 ELK 技術棧最近的三個版本,也就是 7.x、6.x、5.x ,本文將使用最新版本。

用於開發測試的基礎環境使用一臺1c2g的虛擬機即可,當然機器資源越多我們的服務運行效率也會越高、相同時間內數據處理能力也就越大。而用於一般生產環境建議根據自己具體情況給予更多資源。

先聊聊測試環境搭建。

測試開發環境

使用 Git Clone 命令將項目下載到所需要的位置。

<code>git clone https://github.com/deviantony/docker-elk.git /app/docker-elk
Cloning into '/app/docker-elk'...
remote: Enumerating objects: 1729, done.
remote: Total 1729 (delta 0), reused 0 (delta 0), pack-reused 1729


Receiving objects: 100% (1729/1729), 410.25 KiB | 11.00 KiB/s, done.
Resolving deltas: 100% (705/705), done./<code>

在啟動項目前,我們先了解下基礎的目錄結構。

<code>├── docker-compose.yml
├── docker-stack.yml
├── elasticsearch
│ ├── config
│ │ └── elasticsearch.yml
│ └── Dockerfile
├── extensions
│ ├── apm-server
│ ├── app-search
│ ├── curator
│ ├── logspout
├── kibana
│ ├── config
│ │ └── kibana.yml
│ └── Dockerfile
├── LICENSE
├── logstash
│ ├── config
│ │ └── logstash.yml
│ ├── Dockerfile
│ └── pipeline
│ └── logstash.conf
└── README.md/<code>

可以清楚看到,項目主要使用根目錄的 docker-compose.yml 作為啟動配置,並在首次啟動時,構建相關服務的容器鏡像。

瞭解了項目工作方式後,可以使用 docker-compose up 來啟動項目。

<code>docker-compose up
Creating network "docker-elk_elk" with driver "bridge"
Creating volume "docker-elk_elasticsearch" with default driver
Building elasticsearch
Step 1/2 : ARG ELK_VERSION
Step 2/2 : FROM docker.elastic.co/elasticsearch/elasticsearch:${ELK_VERSION}
7.6.2: Pulling from elasticsearch/elasticsearch
c808caf183b6: Downloading [==> ] 3.736MB/85.21MB


d6caf8e15a64: Downloading [===================> ] 13.69MB/34.71MB
b0ba5f324e82: Download complete
d7e8c1e99b9a: Downloading [=> ] 11.71MB/321.6MB
85c4d6c81438: Waiting
3119218fac98: Waiting
914accf214bb: Waiting
...
Creating docker-elk_elasticsearch_1 ... done
Creating docker-elk_logstash_1 ... done
Creating docker-elk_kibana_1 ... done
Attaching to docker-elk_elasticsearch_1, docker-elk_logstash_1, docker-elk_kibana_1
logstash_1 | OpenJDK 64-Bit Server VM warning: Option UseConcMarkSweepGC was deprecated in version 9.0 and will likely be removed in a future release.
elasticsearch_1 | Created elasticsearch keystore in /usr/share/elasticsearch/config
logstash_1 | WARNING: An illegal reflective access operation has occurred
logstash_1 | WARNING: Illegal reflective access by com.headius.backport9.modules.Modules (file:/usr/share/logstash/logstash-core/lib/jars/jruby-complete-9.2.9.0.jar) to method sun.nio.ch.NativeThread.signal(long)
logstash_1 | WARNING: Please consider reporting this to the maintainers of com.headius.backport9.modules.Modules
logstash_1 | WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
logstash_1 | WARNING: All illegal access operations will be denied in a future release
elasticsearch_1 | OpenJDK 64-Bit Server VM warning: Option UseConcMarkSweepGC was deprecated in version 9.0 and will likely be removed in a future release.
elasticsearch_1 | {"type": "server", "timestamp": "2020-05-03T03:47:40,483Z", "level": "INFO", "component": "o.e.e.NodeEnvironment", "cluster.name": "docker-cluster", "node.name": "0d05db8360df", "message": "using [1] data paths, mounts [[/usr/share/elasticsearch/data (/dev/sda2)]], net usable_space [83.6gb], net total_space [97.9gb], types [ext4]" }
elasticsearch_1 | {"type": "server", "timestamp": "2020-05-03T03:47:40,493Z", "level": "INFO", "component": "o.e.e.NodeEnvironment", "cluster.name": "docker-cluster", "node.name": "0d05db8360df", "message": "heap size [247.5mb], compressed ordinary object pointers [true]" }
kibana_1 | {"type":"log","@timestamp":"2020-05-03T03:47:40Z","tags":["info","plugins-service"],"pid":6,"message":"Plugin \"case\" is disabled."}/<code>

啟動過程中的日誌會類似上面這樣,因為首次啟動需要從官網鏡像倉庫中下載相關鏡像,所以會慢一些。當你看到終端輸出類似上面的日誌時,說明服務已經啟動完畢。

為了驗證,我們可以使用瀏覽器或者 curl 等工具訪問機器地址加端口號 9200,並使用默認用戶名 elastic 和默認密碼 changeme 來訪問 Elasticsearch HTTP 端口,如果一切正常,你將看到類似下面的結果。

<code>{
"name" : "0d05db8360df",
"cluster_name" : "docker-cluster",
"cluster_uuid" : "Mq2EZX59TqW7ysGx7Y-jIw",
"version" : {


"number" : "7.6.2",
"build_flavor" : "default",
"build_type" : "docker",
"build_hash" : "ef48eb35cf30adf4db14086e8aabd07ef6fb113f",
"build_date" : "2020-03-26T06:34:37.794943Z",
"build_snapshot" : false,
"lucene_version" : "8.4.0",
"minimum_wire_compatibility_version" : "6.8.0",
"minimum_index_compatibility_version" : "6.0.0-beta1"
},
"tagline" : "You Know, for Search"
}/<code>

現在不著急訪問 Kibana ,我們繼續進行配置調整。

重置內建用戶密碼

使用 docker-compose exec -T elasticsearch bin/elasticsearch-setup-passwords auto --batch 命令對服務默認的賬戶進行默認密碼重置。

<code>docker-compose exec -T elasticsearch bin/elasticsearch-setup-passwords auto --batch

Changed password for user apm_system
PASSWORD apm_system = YkELBJGOT6AxqsPqsi7I

Changed password for user kibana
PASSWORD kibana = FxRwjm5KRYvHhGEnYTM9

Changed password for user logstash_system
PASSWORD logstash_system = A4f5VOfjVWSdi0KAZWGu

Changed password for user beats_system
PASSWORD beats_system = QnW8xxhnn7LMlA7vuI7B

Changed password for user remote_monitoring_user
PASSWORD remote_monitoring_user = OvjEGR13wjkOkIbWqaEM

Changed password for user elastic
PASSWORD elastic = PGevNMuv7PhVnaYg7vJw/<code>

將密碼妥善保存後,我們需要將 docker-compose.yml 配置文件中的 elasticsearch 服務的 ELASTIC_PASSWORD 去掉,這樣可以確保服務啟動只使用我們剛剛重置後的密碼(keystore)。以及需要對 kibana 、 logstash 配置文件中的信息進行替換,將文件中的

elastic 用戶的密碼進行更新,相關文件我們在開篇的目錄結構中有提過,暫時先修改下面三個文件就可以了:

需要注意的是, logstash pipeline 需要一個高權限賬號,當前測試開發過程中,可以使用上面重置後的 elastic 賬號和密碼,如果是生產使用可以參考官方文檔 Configuring Security in Logstash 進行操作,分配一個新的專用賬號。

在配置修改完畢後,我們執行 docker-compose restart 重啟相關服務。

<code>docker-compose restart
Restarting docker-elk_kibana_1 ... done
Restarting docker-elk_logstash_1 ... done
Restarting docker-elk_elasticsearch_1 ... done/<code>

如果日誌中沒有出現任何 401 或者訪問拒絕的內容,說明服務一切正常。

使用 Kibana 控制檯

啟動之後,我們使用瀏覽器訪問服務器IP+端口5601,打開 kibana 控制檯。

使用elastic 賬號和密碼登錄後,就能夠看到 Kibana 的界面了,如果第一次使用,會看到歡迎界面。

在登陸之後,第一次使用,可以考慮導入示例數據,來幫助瞭解 Kibana 的基礎功能。

接下來就是自由探索的過程了

關閉付費組件(別忘記了)

打開設置界面,選擇 Elasticsearch 模塊中的 License Management ,可以看到默認軟件會啟動為期一個月的高級功能試用。

在 官方訂閱 頁面,我們可以看到官方支持的訂閱類型,一般來說,如果沒有特殊需求,使用基礎版本就好。

如果你想要了解軟件當前運行狀態,除了登陸機器,查看宿主機和容器狀態外,在監控界面,我們也可以方便快捷的看到單節點中各個服務的運行狀態和資源佔用。

選擇“Revert to Basic license”,選擇回退到基礎版本,可以看到整個界面都簡潔了不少,至此如果不付費的話,就可以安心合法的使用軟件了。

當然,你也可以在 elasticsearch.yml 配置文件中的 xpack.license.self_generated.type 修改為 basic 來禁用 X-Pack 相關功能。

<code>xpack.license.self_generated.type: basic/<code>

對接各種軟件/系統進行日誌收集,以及定製你的可視化界面或者 API 我們後面有機會再聊,接下來繼續聊聊,如何進一步搭建配置 ELK 。

修改自官方示例的生產環境

生產環境的基礎要求是高可用性,常規實現方案中見的比較多的是“多副本/實例”,多機器,多機架,甚至多區域部署。

本文我們先聊聊最簡單的多實例。

前置準備

如果想讓生產環境中使用 Docker 運行 ELK,有一些必備的系統設置必不可少。

首先調整 vm.max_map_count 的數值,至少調整到 262144 以上。在 /etc/sysctl.conf 添加下面的內容即可。

<code>vm.max_map_count = 262144

sysctl -w vm.max_map_count=262144/<code>

然後調整 ulimits 以及 nprocedit,因為我們使用容器運行 ELK 相關應用,所以直接修改 compose 配置文件中的 ES 配置就可以了:

<code>ulimits:
memlock:
soft: -1
hard: -1/<code>

我們繼續調整,關閉內存交換,同樣修改 compose 配置文件中的 ES 配置即可:

<code>environment:
bootstrap.memory_lock: "true"
複製代碼/<code>

Java 堆大小同樣需要調整,默認的數值如下,在生產環境中太小了,更詳細的內容可以參考這裡。

<code>environment:
ES_JAVA_OPTS: "-Xmx1g -Xms1g"/<code>

如果你真實使用在生產環節,務必開啟 TLS 和密碼認證,此處為了不額外擴展篇幅(以及懶得申請通配符證書/配置自簽名)先使用關閉安全配置的方式忽略這個設置 : )

修改配置支持多實例

官方多實例方案(這篇官方指引),採取在 compose 中定義三個不同的服務,然後使用第一個服務作為 Master 對外暴露服務,我們先以該方案為基礎,並進行一些調整。

首先創建服務所需要的數據目錄,並賦予所需要的權限。

<code>mkdir -p data/{es01,es02,es03}
chmod g+rwx data/*
chgrp 0 data/*/<code>

之前在單節點中,我們掛載的數據使用的是容器的數據卷方案,在這裡,我們可以考慮使用性能更好的文件映射替換之前的方案,當然也可以配合儲存插件使用:

<code>volumes:
- ./elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml:ro
- ./data:/usr/share/elasticsearch/data:rw/<code>

考慮到多實例之間配置幾乎一致,並且如果要單獨維護太過囉嗦,我們可以將 elasticsearch.yml 內的配置使用環境變量的方式寫在 compose 配置文件中:

<code>environment:
cluster.name: "docker-cluster"
network.host: "0.0.0.0"
bootstrap.memory_lock: "true"
xpack.license.self_generated.type: "basic"
xpack.security.enabled: "false"
xpack.monitoring.collection.enabled: "true"
ES_JAVA_OPTS: "-Xmx1g -Xms1g"/<code>

此外,因為涉及到多個節點組網,所以這裡需要額外指定這些實例的節點名稱等信息:

<code>version: "3.2"

services:
elasticsearch01:
environment:
node.name: "es01"
discovery.seed_hosts: "es02,es03"
cluster.initial_master_nodes: "es01,es02,es03"

elasticsearch02:
environment:
node.name: "es02"
discovery.seed_hosts: "es01,es03"
cluster.initial_master_nodes: "es01,es02,es03"

elasticsearch03:
environment:
node.name: "es03"
discovery.seed_hosts: "es01,es02"
cluster.initial_master_nodes: "es01,es02,es03"/<code>

最後,按照官網的推薦的模式,讓其中一臺機器支持對外暴露端口,與外部進行數據交換即可。

<code>ports:
- 9200:9200
- 9300:9300/<code>

到這裡多實例就配置完成了。

更新 Logstash 配置

logstash 需要更新的有兩處,一處是要讓服務在 剛剛定義的 elasticsearch 實例啟動之後再啟動,另外可以將配置以相同方式改寫,方便後續維護。

<code>logstash:
volumes:
- ./logstash/config/logstash.yml:/usr/share/logstash/config/logstash.yml:ro
- ./logstash/pipeline:/usr/share/logstash/pipeline:ro
depends_on:
- elasticsearch01
- elasticsearch02
- elasticsearch03/<code>

接著需要更新 logstash/config/logstash.yml 配置中的 xpack.monitoring.elasticsearch.host 信息,確保啟動不會出現問題。

<code>xpack.monitoring.elasticsearch.hosts: [ "http://es01:9200" ]/<code>

以及 logstash/pipeline/logstash.conf 配置中的 output. elasticsearch 信息為 hosts => "es01:9200"。

更新 Kibana 配置

需要更新的地方有三處,兩處同 Logstash ,額外還有一處是指定 ELASTICSEARCH_URL 地址為我們暴露服務的 elasticsearch 實例的地址。

<code>kibana:
volumes:
- ./kibana/config/kibana.yml:/usr/share/kibana/config/kibana.yml:ro
ports:
- "5601:5601"
depends_on:
- elasticsearch01
- elasticsearch02
- elasticsearch03
environment:
- ELASTICSEARCH_URL=http://es01:9200
- xpack.security.enabled=false/<code>

以及需要額外更新 kibana/config/kibana.yml 配置中的 elasticsearch.hosts 字段信息:

<code>elasticsearch.hosts: [ "http://es01:9200" ]/<code>

完整配置文件

上述配置完成內容如下:

<code>version: "3.2"


services:
elasticsearch01:
image: docker.elastic.co/elasticsearch/elasticsearch:7.6.2
container_name: es01
volumes:
- ./data/es01:/usr/share/elasticsearch/data:rw
ports:
- 9200:9200
- 9300:9300
environment:
node.name: "es01"
cluster.name: "docker-cluster"
network.host: "0.0.0.0"
discovery.seed_hosts: "es02,es03"
cluster.initial_master_nodes: "es01,es02,es03"
bootstrap.memory_lock: "true"
xpack.license.self_generated.type: "basic"
xpack.security.enabled: "false"
xpack.monitoring.collection.enabled: "true"
ES_JAVA_OPTS: "-Xmx1g -Xms1g"
ulimits:
memlock:
soft: -1
hard: -1
networks:
- elk

elasticsearch02:
image: docker.elastic.co/elasticsearch/elasticsearch:7.6.2
container_name: es02
volumes:
- ./data/es02:/usr/share/elasticsearch/data:rw
environment:
node.name: "es02"
cluster.name: "docker-cluster"
network.host: "0.0.0.0"
discovery.seed_hosts: "es01,es03"
cluster.initial_master_nodes: "es01,es02,es03"
bootstrap.memory_lock: "true"
xpack.license.self_generated.type: "basic"
xpack.security.enabled: "false"
xpack.monitoring.collection.enabled: "true"
ES_JAVA_OPTS: "-Xmx1g -Xms1g"
ulimits:
memlock:
soft: -1
hard: -1
networks:
- elk

elasticsearch03:
image: docker.elastic.co/elasticsearch/elasticsearch:7.6.2
container_name: es03
volumes:
- ./data/es03:/usr/share/elasticsearch/data:rw
environment:
node.name: "es03"
cluster.name: "docker-cluster"
network.host: "0.0.0.0"
discovery.seed_hosts: "es01,es02"
cluster.initial_master_nodes: "es01,es02,es03"
bootstrap.memory_lock: "true"
xpack.license.self_generated.type: "basic"
xpack.security.enabled: "false"
xpack.monitoring.collection.enabled: "true"
ES_JAVA_OPTS: "-Xmx1g -Xms1g"
ulimits:
memlock:
soft: -1
hard: -1
networks:
- elk

logstash:
build:
context: logstash/
args:
ELK_VERSION: $ELK_VERSION
volumes:
- ./logstash/config/logstash.yml:/usr/share/logstash/config/logstash.yml:ro
- ./logstash/pipeline:/usr/share/logstash/pipeline:ro
ports:
- "5000:5000/tcp"
- "5000:5000/udp"
- "9600:9600"
environment:
LS_JAVA_OPTS: "-Xmx1g -Xms1g"
networks:
- elk
depends_on:
- elasticsearch01
- elasticsearch02
- elasticsearch03

kibana:
build:
context: kibana/
args:
ELK_VERSION: $ELK_VERSION
volumes:

- ./kibana/config/kibana.yml:/usr/share/kibana/config/kibana.yml:ro
ports:
- "5601:5601"
networks:
- elk
depends_on:
- elasticsearch01
- elasticsearch02
- elasticsearch03
environment:
- ELASTICSEARCH_URL=http://es01:9200
- xpack.security.enabled=false

networks:
elk:
driver: bridge/<code>

其實如果你全部使用官方鏡像,而不做二次定製,比如安裝插件的話,那麼都改為官方鏡像名稱即可。

啟動服務之後,打開 kibana 可以看到多實例的 ELK 環境就配置完畢了。

至此,使用 Docker 搭建 ELK 環境的步驟就全部完成!感謝閱讀,希望對你有所幫助喲