Docker 最佳实战:Docker 部署单节点 ElasticSearch 实战
2024 年云原生运维实战文档 99 篇原创计划 第 015 篇 |Docker 最佳实战「2024」系列 第 010 篇
你好,欢迎来到运维有术。
今天分享的内容是 Docker 最佳实战「2024」 系列文档中的 Docker 部署单节点 ElasticSearch 实战。
本文将详细介绍如何用 Docker 容器及 Docker Compose 部署单节点 ElasticSearch,并配置基于 x-pack 的认证和 TLS 加密。
实战服务器配置 (架构 1:1 复刻小规模生产环境,配置略有不同)
主机名 | IP | CPU(核) | 内存(GB) | 系统盘(GB) | 数据盘(GB) | 用途 |
---|---|---|---|---|---|---|
docker-node-1 | 192.168.9.81 | 4 | 16 | 40 | 100 | Docker 节点 1 |
docker-node-2 | 192.168.9.82 | 4 | 16 | 40 | 100 | Docker 节点 2 |
docker-node-3 | 192.168.9.83 | 4 | 16 | 40 | 100 | Docker 节点 3 |
合计 | 3 | 12 | 48 | 120 | 300 |
实战环境涉及软件版本信息
- 操作系统:openEuler 22.03 LTS SP3
- Docker:24.0.7
- ElasticSearch:7.17.20
1. 前置条件
- 配置系统内核参数
bash
echo "vm.max_map_count=262144" >> /etc/sysctl.conf
sysctl -w vm.max_map_count=262144
- 准备密码
本文所有涉及密码的配置,均使用通用密码 PleaseChangeMe。
生产环境,请用密码生成器生成20位以上 不带特殊符号只包含大小写字母和数字混合组成的密码。
2. 准备前置数据
2.1 创建数据目录
bash
mkdir -p /data/containers/elasticsearch/{data,plugins,logs}
chown 1000:0 /data/containers/elasticsearch/{data,logs}
mkdir -p /data/containers/elasticsearch/config/certs
2.2 创建 ElasticSearch 自定义配置文件
实现 ElasticSearch 服务自定义配置有两种方案:
- Docker-compose 中设置环境变量
- 编写 elasticsearch.yml 配置文件,挂载到容器配置文件目录
本文选择第二种,编辑 elasticsearch.yml
配置文件,挂载到容器 /usr/share/elasticsearch/config
目录的方案。
创建配置文件,vi /data/containers/elasticsearch/config/elasticsearch.yml
yaml
# 基本配置
cluster.name: es-cluster
discovery.type: single-node
network.host: 0.0.0.0
http.port: 9200
# 启用 xpack 及 TLS
xpack.security.enabled: true
xpack.security.transport.ssl.enabled: true
# 证书配置
xpack.security.transport.ssl.keystore.type: PKCS12
xpack.security.transport.ssl.truststore.type: PKCS12
xpack.security.transport.ssl.verification_mode: certificate
xpack.security.transport.ssl.keystore.path: certs/elastic-certificates.p12
xpack.security.transport.ssl.truststore.path: certs/elastic-certificates.p12
#xpack.security.transport.ssl.keystore.password: PleaseChangeMe
#xpack.security.transport.ssl.truststore.password: PleaseChangeMe
# 其他配置
# 禁用 geoip
ingest.geoip.downloader.enabled: false
# 启用审计
xpack.security.audit.enabled: true
2.3 创建 CA 文件
- 执行下面的命令生成 CA 文件
bash
cd /data/containers/elasticsearch
docker run -it --rm \
-v ./config/certs:/usr/share/elasticsearch/config/certs \
elasticsearch:7.17.20 \
bin/elasticsearch-certutil ca --out config/certs/elastic-stack-ca.p12 --pass "PleaseChangeMe"
说明:
- --pass 生产环境一定要替换成自己的密码
正确执行后,输出结果如下:
vbnet
[root@docker-node-1 elasticsearch]# docker run -it --rm \
> -v ./config/certs:/usr/share/elasticsearch/config/certs \
> elasticsearch:7.17.20 \
> bin/elasticsearch-certutil ca --out config/certs/elastic-stack-ca.p12 --pass "PleaseChangeMe"
This tool assists you in the generation of X.509 certificates and certificate
signing requests for use with SSL/TLS in the Elastic stack.
The 'ca' mode generates a new 'certificate authority'
This will create a new X.509 certificate and private key that can be used
to sign certificate when running in 'cert' mode.
Use the 'ca-dn' option if you wish to configure the 'distinguished name'
of the certificate authority
By default the 'ca' mode produces a single PKCS#12 output file which holds:
* The CA certificate
* The CA's private key
If you elect to generate PEM format certificates (the -pem option), then the output will
be a zip file containing individual files for the CA certificate and private key
- 查看是否生成证书
arduino
[root@docker-node-1 elasticsearch]# ls config/certs/
elastic-stack-ca.p12
2.4 创建 elastic-certificates.p12 证书
- 执行下面的命令创建 elastic-certificates.p12 证书
arduino
docker run -it --rm \
-v ./config/certs:/usr/share/elasticsearch/config/certs \
elasticsearch:7.17.20 \
bin/elasticsearch-certutil cert --silent --ca config/certs/elastic-stack-ca.p12 --out config/certs/elastic-certificates.p12 --ca-pass "PleaseChangeMe" --pass "PleaseChangeMe"
说明:
- --ca-pass CA 证书的密码
- --pass p12 证书的密码
正确执行后,输出结果如下:
bash
[root@docker-node-1 elasticsearch]# docker run -it --rm \
> -v ./config/certs:/usr/share/elasticsearch/config/certs \
> elasticsearch:7.17.20 \
> bin/elasticsearch-certutil cert --silent --ca config/certs/elastic-stack-ca.p12 --out config/certs/elastic-certificates.p12 --ca-pass "PleaseChangeMe" --pass "PleaseChangeMe"
[root@docker-node-1 elasticsearch]# ls config/certs/
elastic-certificates.p12 elastic-stack-ca.p12
- 配置证书文件权限
bash
chown -R 1000.0 config/certs/
2.5 生成加密的 keystore 文件
默认情况下,Elasticsearch 自动生成用于安全设置的密钥存储库文件elasticsearch.keystore
。
该文件的用途是存储需要加密的 key/value 配置数据。但是该文件默认只是被简单的模糊(obfuscated)处理,并没有加密。用命令 elasticsearch-keystore list
可以轻松读取到文件内容。生产环境建议做加密处理。
- 执行下面的命令创建
elasticsearch.keystore
文件
bash
docker run -it --rm \
-v ./config:/usr/share/elasticsearch/config \
elasticsearch:7.17.20 \
bin/elasticsearch-keystore create -p
正确执行后,输出结果如下:
bash
[root@docker-node-1 elasticsearch]# docker run -it --rm \
> -v ./config:/usr/share/elasticsearch/config \
> elasticsearch:7.17.20 \
> bin/elasticsearch-keystore create -p
Enter new password for the elasticsearch keystore (empty for no password):
Enter same password again:
Created elasticsearch keystore in /usr/share/elasticsearch/config/elasticsearch.keystore
[root@docker-node-1 elasticsearch]# ls config/
certs elasticsearch.keystore elasticsearch.yml
注意: 命令执行过程中,需按提示输入两次密码
- 添加 p12 证书的密码配置添加到 keystore 文件
bash
# keystore.secure_password
docker run -it --rm \
-v ./config:/usr/share/elasticsearch/config \
elasticsearch:7.17.20 \
bin/elasticsearch-keystore add xpack.security.transport.ssl.keystore.secure_password
# truststore.secure_password
docker run -it --rm \
-v ./config:/usr/share/elasticsearch/config \
elasticsearch:7.17.20 \
bin/elasticsearch-keystore add xpack.security.transport.ssl.truststore.secure_password
正确执行后,输出结果如下:
bash
# 正确执行没有任何输出
[root@docker-node-1 elasticsearch]# docker run -it --rm \
> -v ./config:/usr/share/elasticsearch/config \
> elasticsearch:7.17.20 \
> bin/elasticsearch-keystore add xpack.security.transport.ssl.keystore.secure_password
Enter password for the elasticsearch keystore :
Enter value for xpack.security.transport.ssl.keystore.secure_password:
[root@docker-node-1 elasticsearch]# docker run -it --rm \
> -v ./config:/usr/share/elasticsearch/config \
> elasticsearch:7.17.20 \
> bin/elasticsearch-keystore add xpack.security.transport.ssl.truststore.secure_password
Enter password for the elasticsearch keystore :
Enter value for xpack.security.transport.ssl.truststore.secure_password:
注意:
- 命令执行过程中,请按提示输入两次密码
- 第一次密码是
elasticsearch.keystore
文件的密码,第二次密码是secure_password
的密码
- 验证 elasticsearch.keystore 是否加密
ruby
docker run -it --rm \
-v ./config/:/usr/share/elasticsearch/config \
elasticsearch:7.17.20 \
bin/elasticsearch-keystore list
正确执行后,输出结果如下:
ruby
[root@docker-node-1 elasticsearch]# docker run -it --rm \
> -v ./config/:/usr/share/elasticsearch/config \
> elasticsearch:7.17.20 \
> bin/elasticsearch-keystore list
Enter password for the elasticsearch keystore :
keystore.seed
xpack.security.transport.ssl.keystore.secure_password
xpack.security.transport.ssl.truststore.secure_password
注意: 提示 Enter password for the elasticsearch keystore : 输入正确的密码后显示文件内容,说明文件已经加密。
3. 安装部署 ElasticSearch
3.1 创建 docker-compose.yml 文件
创建配置文件,vi /data/containers/elasticsearch/docker-compose.yml
yaml
name: 'elasticsearch'
services:
elasticsearch:
restart: always
image: elasticsearch:7.17.20
container_name: es-single
ulimits:
nproc: 65535
memlock:
soft: -1
hard: -1
environment:
- TZ=Asia/Shanghai
- ES_JAVA_OPTS=-Xms2048m -Xmx2048m
- KEYSTORE_PASSWORD=PleaseChangeMe
volumes:
- ./data:/usr/share/elasticsearch/data
- ./plugins:/usr/share/elasticsearch/plugins
- ./logs:/usr/share/elasticsearch/logs
- ./config/certs/:/usr/share/elasticsearch/config/certs
- ./config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml
- ./config/elasticsearch.keystore:/usr/share/elasticsearch/config/elasticsearch.keystore
networks:
- app-tier
ports:
- 9200:9200
- 9300:9300
networks:
app-tier:
name: app-tier
driver: bridge
#external: true
#ipam:
# config:
# - subnet: 172.22.1.0/24
说明:
- ES_JAVA_OPTS 需根据服务器实际配置调整 JAVA_OPTS 配置
- KEYSTORE_PASSWORD 必须跟生成加密的 elasticsearch.keystore 文件时使用的密码一致,否则 ES 启动会失败
- ipam 配置了 app-tier 的网络地址,本文注释了,生产环境建议合理规划配置。
- external: true , 同一台服务器其他服务已经创建网络
app-tier
时,创建 elasticsearch 服务时会报错,可以启用这个参数。
3.2 创建并启动 ElasticSearch 服务
- 启动服务
bash
cd /data/containers/elasticsearch
docker compose up -d
- 正确执行后,输出结果如下
ini
[root@docker-node-1 elasticsearch]# docker compose up -d
[+] Running 1/2
⠸ Network app-tier Created 0.4s
✔ Container es-single Started
3.3 验证容器状态
- 查看 ElasticSearch 容器状态
bash
[root@docker-node-1 elasticsearch]# docker compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
es-single elasticsearch:7.17.20 "/bin/tini -- /usr/l..." elasticsearch 16 seconds ago Up Less than a second 0.0.0.0:9200->9200/tcp, :::9200->9200/tcp, 0.0.0.0:9300->9300/tcp, :::9300->9300/tcp
- 查看 ElasticSearch 服务日志
bash
# 通过日志查看 elasticsearch 是否有异常,结果略
docker compose logs -f
4. 密码配置
4.1 为保留用户自动生成初始密码
执行下面的命令:
arduino
docker exec -it es-single bin/elasticsearch-setup-passwords auto
正确执行后,输出结果如下:
ini
[root@docker-node-1 elasticsearch]# docker exec -it es-single bin/elasticsearch-setup-passwords auto
Enter password for the elasticsearch keystore :
Initiating the setup of passwords for reserved users elastic,apm_system,kibana,kibana_system,logstash_system,beats_system,remote_monitoring_user.
The passwords will be randomly generated and printed to the console.
Please confirm that you would like to continue [y/N]y
Changed password for user apm_system
PASSWORD apm_system = dFeUZ5kSgq3Gh4GNVZSJ
Changed password for user kibana_system
PASSWORD kibana_system = YUuHRRQ9NX7ZbdGj40hY
Changed password for user kibana
PASSWORD kibana = YUuHRRQ9NX7ZbdGj40hY
Changed password for user logstash_system
PASSWORD logstash_system = oCqLt1l1ZWCB9eWkKoMS
Changed password for user beats_system
PASSWORD beats_system = iMGY5hLUJBCBHPUrBm2k
Changed password for user remote_monitoring_user
PASSWORD remote_monitoring_user = 7YJ8pTA1fIiTJEGKcHIT
Changed password for user elastic
PASSWORD elastic = Uhfiv3zGRvGsNN58shT0
说明:
- 命令执行时需要输入
elasticsearch keystore
文件的密码- 请记录并妥善保存自动生成的密码
4.2 创建自定义管理员用户
创建一个自定义的管理员用户用于日常管理。
执行下面的命令:
bash
docker exec -it es-single bin/elasticsearch-users useradd elasticadmin -p PleaseChangeMe -r superuser
5. 验证测试 ElasticSearch
5.1 命令行查看集群节点
执行下面的命令:
ini
curl -X GET -u elasticadmin "localhost:9200/_cat/nodes?v=true&pretty"
正确执行后,输出结果如下:
sql
[root@docker-node-1 elasticsearch]# curl -X GET -u elasticadmin "localhost:9200/_cat/nodes?v=true&pretty"
Enter host password for user 'elasticadmin':
ip heap.percent ram.percent cpu load_1m load_5m load_15m node.role master name
172.20.0.2 16 45 0 0.04 0.14 0.34 cdfhilmrstw * 5e53c312d114
说明: 按提示输入用户
elasticadmin
的密码。
6. 常见问题
6.1 问题1
vbnet
es-single | {"type": "server", "timestamp": "2024-05-07T10:00:22,991+08:00", "level": "ERROR", "component": "o.e.i.g.GeoIpDownloader", "cluster.name": "es-cluster", "node.name": "163ac8cb28d7", "message": "exception during geoip databases update", "cluster.uuid": "BenkNlbKQ3a7IiqU5shtOw", "node.id": "iu7VycUqTXyXbsjSGpotVw" ,
es-single | "stacktrace": ["java.net.UnknownHostException: geoip.elastic.co",
es-single | "at sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:567) ~[?:?]",
es-single | "at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:327) ~[?:?]",
es-single | "at java.net.Socket.connect(Socket.java:751) ~[?:?]",
es-single | "at sun.security.ssl.SSLSocketImpl.connect(SSLSocketImpl.java:304) ~[?:?]",
es-single | "at sun.net.NetworkClient.doConnect(NetworkClient.java:178) ~[?:?]",
es-single | "at sun.net.www.http.HttpClient.openServer(HttpClient.java:531) ~[?:?]",
es-single | "at sun.net.www.http.HttpClient.openServer(HttpClient.java:636) ~[?:?]",
es-single | "at sun.net.www.protocol.https.HttpsClient.<init>(HttpsClient.java:264) ~[?:?]",
es-single | "at sun.net.www.protocol.https.HttpsClient.New(HttpsClient.java:377) ~[?:?]",
es-single | "at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.getNewHttpClient(AbstractDelegateHttpsURLConnection.java:193) ~[?:?]",
es-single | "at sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1237) ~[?:?]",
es-single | "at sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:1123) ~[?:?]",
es-single | "at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:179) ~[?:?]",
es-single | "at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1675) ~[?:?]",
es-single | "at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1599) ~[?:?]",
es-single | "at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:531) ~[?:?]",
es-single | "at sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:307) ~[?:?]",
es-single | "at org.elasticsearch.ingest.geoip.HttpClient.lambda$get$0(HttpClient.java:55) ~[ingest-geoip-7.17.20.jar:7.17.20]",
es-single | "at java.security.AccessController.doPrivileged(AccessController.java:571) ~[?:?]",
es-single | "at org.elasticsearch.ingest.geoip.HttpClient.doPrivileged(HttpClient.java:97) ~[ingest-geoip-7.17.20.jar:7.17.20]",
es-single | "at org.elasticsearch.ingest.geoip.HttpClient.get(HttpClient.java:49) ~[ingest-geoip-7.17.20.jar:7.17.20]",
es-single | "at org.elasticsearch.ingest.geoip.HttpClient.getBytes(HttpClient.java:40) ~[ingest-geoip-7.17.20.jar:7.17.20]",
es-single | "at org.elasticsearch.ingest.geoip.GeoIpDownloader.fetchDatabasesOverview(GeoIpDownloader.java:159) ~[ingest-geoip-7.17.20.jar:7.17.20]",
es-single | "at org.elasticsearch.ingest.geoip.GeoIpDownloader.updateDatabases(GeoIpDownloader.java:147) ~[ingest-geoip-7.17.20.jar:7.17.20]",
es-single | "at org.elasticsearch.ingest.geoip.GeoIpDownloader.runDownloader(GeoIpDownloader.java:284) [ingest-geoip-7.17.20.jar:7.17.20]",
es-single | "at org.elasticsearch.ingest.geoip.GeoIpDownloaderTaskExecutor.nodeOperation(GeoIpDownloaderTaskExecutor.java:100) [ingest-geoip-7.17.20.jar:7.17.20]",
es-single | "at org.elasticsearch.ingest.geoip.GeoIpDownloaderTaskExecutor.nodeOperation(GeoIpDownloaderTaskExecutor.java:46) [ingest-geoip-7.17.20.jar:7.17.20]",
es-single | "at org.elasticsearch.persistent.NodePersistentTasksExecutor$1.doRun(NodePersistentTasksExecutor.java:42) [elasticsearch-7.17.20.jar:7.17.20]",
es-single | "at org.elasticsearch.common.util.concurrent.ThreadContext$ContextPreservingAbstractRunnable.doRun(ThreadContext.java:777) [elasticsearch-7.17.20.jar:7.17.20]",
es-single | "at org.elasticsearch.common.util.concurrent.AbstractRunnable.run(AbstractRunnable.java:26) [elasticsearch-7.17.20.jar:7.17.20]",
es-single | "at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144) [?:?]",
es-single | "at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642) [?:?]",
es-single | "at java.lang.Thread.run(Thread.java:1583) [?:?]"] }
- 解决方案
离线环境未使用 geoip 功能,在 elasticsearch.yml
中添加如下配置禁用 geoip downloader:
yaml
ingest.geoip.downloader.enabled: false
6.2 问题 2
- 问题现象
添加新的管理员用户时报错如下:
bash
[root@1--2--3--1--2--3--0006 elasticsearch]# docker run -it --rm \
> -v ./config:/usr/share/elasticsearch/config \
> elasticsearch:7.17.20 \
> bin/elasticsearch-users useradd elastic -p elasticPWD -r superuser
ERROR: Invalid username [elastic]... Username [elastic] is reserved and may not be used.
- 解决方案
elastic 属于 elasticsearch 内置账户的名字不允许使用。换个用户名即可。
6.3 问题 3
- 问题现象
ElasticSearch 容器启动时报错。
php
es-single | Exception in thread "main" java.lang.IllegalStateException: Keystore passphrase required but none provided.
es-single | at org.elasticsearch.bootstrap.Bootstrap.readPassphrase(Bootstrap.java:305)
es-single | at org.elasticsearch.bootstrap.Bootstrap.loadSecureSettings(Bootstrap.java:261)
es-single | at org.elasticsearch.bootstrap.Bootstrap.loadSecureSettings(Bootstrap.java:247)
es-single | at org.elasticsearch.bootstrap.Bootstrap.init(Bootstrap.java:364)
es-single | at org.elasticsearch.bootstrap.Elasticsearch.init(Elasticsearch.java:169)
es-single | at org.elasticsearch.bootstrap.Elasticsearch.execute(Elasticsearch.java:160)
es-single | at org.elasticsearch.cli.EnvironmentAwareCommand.execute(EnvironmentAwareCommand.java:77)
es-single | at org.elasticsearch.cli.Command.mainWithoutErrorHandling(Command.java:112)
es-single | at org.elasticsearch.cli.Command.main(Command.java:77)
es-single | at org.elasticsearch.bootstrap.Elasticsearch.main(Elasticsearch.java:125)
es-single | at org.elasticsearch.bootstrap.Elasticsearch.main(Elasticsearch.java:80)
- 解决方案
编辑 docker-compose.yml
,在 environment 配置项中加入 KEYSTORE_PASSWORD=PleaseChangeMe
。
以上,就是今天分享的内容,下一期我们会分享如何用 Docker 部署 Kibana 并对接 ElasticSearch 集群。敬请持续关注!!!
免责声明:
- 笔者水平有限,尽管经过多次验证和检查,尽力确保内容的准确性,但仍可能存在疏漏之处。敬请业界专家大佬不吝指教。
- 本文所述内容仅通过实战环境验证测试,读者可学习、借鉴,但严禁直接用于生产环境 。由此引发的任何问题,作者概不负责!
Get 本文实战视频(请注意,文档视频异步发行,请先关注)
如果你喜欢本文,请分享、收藏、点赞、评论! 请持续关注 @运维有术,及时收看更多好文!
欢迎加入 「知识星球|运维有术」 ,获取更多的 KubeSphere、Kubernetes、云原生运维、自动化运维、AI 大模型等实战技能。未来运维生涯始终有我坐在你的副驾。
版权声明
- 所有内容均属于原创,感谢阅读、收藏,转载请联系授权,未经授权不得转载。