在Linux服务器上使用 Docker安装ElasticSearch集群。
安装Docker和安装Docker Compose
安装Docker略。
由于是部署伪集群,以及需要安装kibana
,因此还需要安装Docker-Compose
。Docker-Compose
负责实现对Docker
容器集群的快速编排。
Docker-Compose
项目是由Python
编写的,而pip
是Python
包管理工具,该工具提供了对Python
包的查找、下载、安装、卸载的功能。因此,安装Docker-Compose
之前,需要先安装Python
环境,以及安装pip
,再通过pip
安装Docker-Compose
。
我其实并不懂
Python
,但是知其然知其所以然,还是要了解一下,为什么要使用pip
安装Docker-Compose
的。
使用yum
安装pip
yum -y install python-pip
使用pip
安装docker-compose
pip install docker-compose
这是我从网上找的一篇博客介绍的docker-compose
的安装教程,可能这篇博客是很早以前写的,因此并不能安装成功。我跟着提示弄了大概一个多小时,过程就略过了。原因是python
版本太低,需要使用yum
安装新版本的python
和pip
。我升级到3.4
版本之后还是提示版本过低,安装不了。
RuntimeError: Python 3.5 or later is required
提示需要python3.5
或更高的版本。根据提示,我又卸载了3.4
版本,重新安装了3.6
版本。
## 安装EPEL和IUS软件源
yum -y install epel-release
yum -y install https://centos7.iuscommunity.org/ius-release.rpm
## 安装python和pip
yum -y install python36u
yum -y install python36u-pip
关于3.6
版本的安装,可以参考这篇博客:Centos7 通过yum安装python3,及virtualenv基本使用。
查看python3.6
是否安装成功
[root@wujiuye01 data]# ls -la /usr/bin/python*
lrwxrwxrwx. 1 root root 7 Oct 8 17:14 /usr/bin/python -> python2
lrwxrwxrwx. 1 root root 9 Oct 8 17:14 /usr/bin/python2 -> python2.7
-rwxr-xr-x. 1 root root 7216 Aug 7 2019 /usr/bin/python2.7
lrwxrwxrwx 1 root root 9 Mar 8 16:39 /usr/bin/python3 -> python3.6
-rwxr-xr-x 2 root root 11408 Aug 8 2019 /usr/bin/python3.6
....
pip
对应也是3.6
版本
[root@wujiuye01 data]# ls -la /usr/bin/pip*
-rwxr-xr-x 1 root root 223 Mar 8 16:28 /usr/bin/pip
-rwxr-xr-x 1 root root 224 Mar 8 15:57 /usr/bin/pip2
-rwxr-xr-x 1 root root 224 Mar 8 15:57 /usr/bin/pip2.7
lrwxrwxrwx 1 root root 9 Mar 8 16:39 /usr/bin/pip-3 -> ./pip-3.6 #软链接
lrwxrwxrwx 1 root root 8 Mar 8 16:39 /usr/bin/pip-3.6 -> ./pip3.6 #软链接
-rwxr-xr-x 1 root root 407 Aug 8 2019 /usr/bin/pip3.6
因为我只是想安装docker-compose
,就不想改pip
软链接到pip3.6
了,而是直接使用pip3.6
安装。
pip-3.6 install docker-compose
如果想要卸载docker-compose
,也是很简单。
pip-3.6 uninstall docker-compose
编写docker-compose.yml
Docker-Compose
的工程配置文件默认为docker-compose.yml
。我需要启动一个cerebro
服务容器、一个kibana
服务容器、两个elasticsearch
服务容器,因此docker-compose.yml
的配置如下。
来源于:https://github.com/onebirdrocks/geektime-ELK,稍有改动:
version: '2.2'
services:
# cerebro
cerebro:
image: lmenezes/cerebro:0.8.3
container_name: cerebro
ports:
- "9000:9000"
command:
- -Dhosts.0.host=http://【外网访问的es集群的ip或域名】:9200
networks:
- wjy-es-net
# kibana
kibana:
image: docker.elastic.co/kibana/kibana:7.1.0
container_name: kibana
environment:
- I18N_LOCALE=zh-CN
- XPACK_GRAPH_ENABLED=true
- TIMELION_ENABLED=true
- XPACK_MONITORING_COLLECTION_ENABLED="true"
ports:
- "5601:5601"
networks:
- wjy-es-net
# elasticsearch节点1
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:7.1.0
container_name: es-node-01
environment:
- cluster.name=wjy-es-stu-cluster
- node.name=es-node-01
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
- discovery.seed_hosts=es-node-01,es-node-02
- cluster.initial_master_nodes=es-node-01,es-node-02
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- "/data/docker/es7cluster/es-node1-data:/usr/share/elasticsearch/data"
ports:
- "9200:9200"
networks:
- wjy-es-net
# elasticsearch节点2
elasticsearch2:
image: docker.elastic.co/elasticsearch/elasticsearch:7.1.0
container_name: es-node-02
environment:
- cluster.name=wjy-es-stu-cluster
- node.name=es-node-02
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
- discovery.seed_hosts=es-node-01,es-node-02
- cluster.initial_master_nodes=es-node-01,es-node-02
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- "/data/docker/es7cluster/es-node2-data:/usr/share/elasticsearch/data"
networks:
- wjy-es-net
networks:
wjy-es-net:
driver: bridge
关于docker-compose.yml
配置文件:
version
:指定docker-compose.yml
的版本。services
:多个容器集合,它有多个子集,该子集是自定义的容器。volumes
:定义了卷信息,提供给services
中的具体容器使用。networks
:定义了网络信息,提供给services
中的具体容器使用。
让服务后台运行,并查询容器启动情况
docker-compose
相关命令:
# 启动
docker-compose up
# 后台启动
docker-compose up -d
# 停止
docker-compose down
# 停止容器并且移除数据
docker-compose down -v
第一次执行docker-compose up
会很久,因为需要从远程拉取镜像文件,大概又是一个多小时。
可能出现问题一:
es7_01 | "stacktrace": ["org.elasticsearch.bootstrap.StartupException: ElasticsearchException[failed to bind service]; nested: AccessDeniedException[/usr/share/elasticsearch/data/nodes];",
......
"Caused by: java.nio.file.AccessDeniedException: /usr/share/elasticsearch/data/nodes",
.....
容器卷本地目录没有权限访问,需要给目录添加写权限。
可能出现问题二:
es_node_02 | ERROR: [1] bootstrap checks failed
es_node_02 | [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]
elasticsearch
用户拥有的内存权限太小,至少需要262144
;
## 切换到root用户,执行命令:
sysctl -w vm.max_map_count=262144
使用docker-compose up -d
启动服务,让所有容器能够后台运行。使用docker
命令查询容器。
[root@wujiuye01 es7cluster]# docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
04f51ce794f9 docker.elastic.co/kibana/kibana:7.1.0 "/usr/local/bin/kiba…" 8 minutes ago Up 3 minutes 0.0.0.0:5601->5601/tcp kibana
ad50d72184d6 lmenezes/cerebro:0.8.3 "/opt/cerebro/bin/ce…" 8 minutes ago Up 3 minutes 0.0.0.0:9000->9000/tcp cerebro
ea3c3e0aee7d docker.elastic.co/elasticsearch/elasticsearch:7.1.0 "/usr/local/bin/dock…" 8 minutes ago Up 3 minutes 9200/tcp, 9300/tcp es-node-02
a14d52910fe6 docker.elastic.co/elasticsearch/elasticsearch:7.1.0 "/usr/local/bin/dock…" 8 minutes ago Up 3 minutes 0.0.0.0:9200->9200/tcp, 9300/tcp es-node-01
访问
服务器安全组记得开放相应的端口。
- #### ElasticSearch
http://【ip或域名】:9200
- #### Cerebro
http://【ip或域名】:9000
- #### Kibana
http://【ip或域名】:5601
后记
docker-compose.yml
配置文件中,只配置了第一个ES
节点的端口,第二个节点并没有配置端口,而是使用默认端口9300
。这个docker-compose.yml
文件我是从github
找来的,当时我就有个疑问,就是第二个ES
节点是怎么加入到集群的?
我们熟悉的微服务框架dubbo
、消息中间件kafka
等都是基于一个第三方服务实现注册发现的,如使用zookeeper
。在dubbo
中,其实还提供了一个基于广播的注册中心,dubbo
的使用入门例子就是用的广播注册中心。而ES
的集群发现则是使用其内置的发现模块。
ES
集群发现机制有两种,分别是Zen Discovery
和EC2 discovery
。其中zen discovery
是ES
默认使用的内置发现模块,它提供了多播和单播两种发现方式。
使用组播(多播),我们只需要在每个节点配置好集群名称、节点名称。节点会根据ES
自定义的服务发现协议去按照多播的方式来寻找网络上配置在同样集群内的节点。
虽然组播仍然作为插件提供,但不应该在生产环境使用。
单播发现需要一个主机列表充作路由列表。这些主机可以是主机名称也可以是IP地址,在每次ping
的时候主机名称会相应地被解析为对应的ip
地址。
在7.x
之前的版本,配置参数为discovery.zen.ping.unicast.hosts
,Zen Discovery的官方文档中描述:
hosts
配置多个需要用逗号隔开,每一项都是host:port
,如果只有host
,则默认端口号为9300
。7.1
版本的配置参数为:discovery.seed_hosts
。
单播发现是使用传输(transport
)模块实现的,就不是使用UDP
协议了。传输(transport
)模块用于集群内节点之间的内部通信。ES
集群内部,从一个节点到另一个节点的每个调用都使用传输模块。
最后介绍一下组播的实现,以此了解为什么ES
默认禁用组播方式,以及dubbo
的基于广播实现的注册中心为什么只能适用于本地测试。
public class MulticastSocketMain {
/**
* 接收
*/
public void startRevice() throws IOException {
// 组播地址
InetAddress boradcastAddrss = InetAddress.getByName("239.255.255.255");
// 创建MulticastSocket对象
MulticastSocket mSocket = new MulticastSocket(3006);
// 将该MulticastSocket加入到组播
mSocket.joinGroup(boradcastAddrss);
// 设置本MulticastSocket发送的数据报会被回送到自身
// true表示不会回送(本机测试需要设置为false)
mSocket.setLoopbackMode(false);
// 创建相关的DatagramPacket,用于接受数据
byte[] inBuff = new byte[1024];
DatagramPacket inPacket = new DatagramPacket(inBuff, inBuff.length);
while (!Thread.interrupted()) {
// 等待接收数据
mSocket.receive(inPacket);
String recevieMsgStr = new String(inBuff, 0, inPacket.getLength());
System.out.println("接收到广播消息:" + recevieMsgStr);
}
}
/**
* 发送
*/
public void startSend() throws IOException {
// 组播地址
InetAddress boradcastAddrss = InetAddress.getByName("239.255.255.255");
// 创建MulticastSocket对象
MulticastSocket mSocket = new MulticastSocket(3006);
// 将该MulticastSocket加入到组播地址中
mSocket.joinGroup(boradcastAddrss);
// 设置本MulticastSocket发送的数据报会被回送到自身
// true表示不会回送(本机测试需要设置为false)
mSocket.setLoopbackMode(false);
// 创建用于发送数据的DatagramPacket
byte[] inBuff = new byte[1024];
DatagramPacket outPacket = new DatagramPacket(inBuff, inBuff.length, boradcastAddrss, 3006);
// 从控制台读取一行字符串发送
Scanner sc = new Scanner(System.in);
while (sc.hasNextLine()) {
byte[] outBuff = sc.nextLine().getBytes();
outPacket.setData(outBuff);
// 发送数据
mSocket.send(outPacket);
}
}
public static void main(String[] args) throws IOException {
MulticastSocketSendMain multicastSocketSendMain = new MulticastSocketSendMain();
// 接收
new Thread() {
@Override
public void run() {
try {
multicastSocketSendMain.startRevice();
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
// 发送
new Thread() {
@Override
public void run() {
try {
multicastSocketSendMain.startSend();
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
}
此demo
要运行需要配置VM参数:
-Djava.net.preferIPv4Stack=true
IPV4
的广播地址范围是: 224.0.0.0 - 239.255.255.255
,dubbo
的广播注册中心使用的是239.255.255.255,
所以例子中我就使用239.255.255.255做测试了。
如果将上面例子MulticastSocketMain
启动多个进程,那么在任意一个接收者上发送消息其它进程都能接收到。想看测试结果,可将上面代码复制下来运行。
如果当前是线上环境,我突然启动一个服务,但并不想加入到集群中,但是节点启动就发广播,线上的服务接收到广播就认为你要新增节点了。这样得到的结果就是一个节点意外的加入到了生产环境,仅仅是因为一个错误的组播信号。
因此ES
默认被配置为使用单播发现,以防止节点无意中加入集群。