本文記錄使用docker搭建elasticsearch集羣的整個過程(文中使用的2.1.2舉例),過程親測同樣適用於elasticsearch2.x,5.x,後續作者將繼續深入研究es,下一步準備基於此集羣對源生elasticsearch(以下簡稱es)做改造測試。
1、 環境介紹
本文運行環境
ubuntu16.04
+docker17.05
+ 官網上下載的elasticsearch2.1.2
,另外docker環境爲openjdk:8-jre-alpine
。(使用alpine的原因就是沒有太多不必要的組件和命令,docker內部也不需要太多組件)
es源碼下載地址
1.1 ubuntu
$ cat /proc/version
Linux version 4.4.0-46-generic (buildd@lcy01-10) (gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.2) ) #67-Ubuntu SMP Thu Oct 20 15:05:12 UTC 2016
1.2 docker
$ docker -v
Docker version 17.05.0-ce, build 89658be
1.3 elasticsearch(版本忽略)
$ ./elasticsearch -version
Version: 2.1.2, Build: c849dd1/2017-04-24T16:18:17Z, JVM: 1.8.0_101
2、 部署過程中遇到的問題
2.1 主要就是docker的網絡配置,默認是橋接網絡,不知爲何多個node啓動來之後無法互相發現。
解決方案:修改
elasticsearch.yml
配置。
2.2 每次重啓docker實例docker自動會重新分配ip。
未解決。
3、 部署過程
3.1 製作生成es的dockerfile
.
參照dockerfile的git地址,如下圖。
3.2 在es源文件中爲es安裝head
插件。
$ plugin install mobz/elasticsearch-head
3.3 生成es的docker鏡像
鏡像名稱爲
psiitoy/elasticsearch:2.1.2
。
$ docker build -t psiitoy/elasticsearch:2.1.2 .
3.4 查看已有網橋信息。
docker 默認使用
docker0
作爲網橋
$ brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.0242552a7fb0 no vetha061837
3.5 查看網橋對應網段地址。
發現網段爲172.17.0.x
$ ip addr show docker0
4: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:55:2a:7f:b0 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:55ff:fe2a:7fb0/64 scope link
valid_lft forever preferred_lft forever
3.6 修改elasticsearch.yml
配置。
避免docker容器es服務之間無法互相發現導致的腦裂。
參照Elasticsearch部分節點不能發現集羣(腦裂)問題處理
network.host: 0.0.0.0
discovery.zen.ping.multicast.enabled: false
discovery.zen.ping_timeout: 120s
discovery.zen.minimum_master_nodes: 2 #至少要發現集羣可做master的節點數,
client.transport.ping_timeout: 60s
discovery.zen.ping.unicast.hosts: ["172.17.0.2", "172.17.0.3"]
3.7 創建docker容器x5。
docker run 參數介紹:
在使用-v
參數時,代表把本地目錄掛載到鏡像裏,我們可以在本機查看容器中的/usr/share/elasticsearch/logs目錄。
在使用-d
參數時,容器啓動後會進入後臺。
$ docker run -d -v ~/usr/share/elasticsearch/logs:/usr/share/elasticsearch/logs psiitoy/elasticsearch:2.1.2
66ca0270ef44
$ docker run -d -v ~/usr/share/elasticsearch/logs:/usr/share/elasticsearch/logs psiitoy/elasticsearch:2.1.2
ddfbb7ef65bc
3.8 若想進入容器可以執行 docker exec -it $CONTAINER_ID
在使用
-i
參數時,打開STDIN,用於控制檯交互
在使用-t
參數時,分配tty設備,該可以支持終端登錄,默認爲false
$ docker exec -it 66ca0270ef44 /bin/bash
bash-4.3#
3.9 查看集羣狀態
curl http://ip:port/_cat/health?v
,也可以用health?pretty
我們看到集羣有5個節點加入了,實驗成功!
$ curl http://172.17.0.2:9200/_cat/health?v
epoch timestamp cluster status node.total node.data shards pri relo init unassign pending_tasks max_task_wait_time active_shards_percent
1497352537 11:15:37 elasticsearch green 5 5 0 0 0 0 0 0 - 100.0%
3.10 測試一下用客戶端創建索引
創建一個
number_of_shards
爲8,number_of_replicas
爲1 的名叫twitter的index。
參照testClient的git地址
public class ClientTest {
private static Client client = null;//client一定要是單例,單例,單例!不要在應用中構造多個客戶端!
public static void main(String[] args) {
try {
client = getClient("elasticsearch", "172.17.0.3", 9300);//client一定要是單例,單例,單例!不要在應用中構造多個客戶端!
createIndex("twitter", "tweet");
System.out.println("#" + client);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (client != null) {
client.close();
}
}
}
/**
* 創建es client 一定要是單例,單例,單例!不要在應用中構造多個客戶端!
* clusterName:集羣名字
* nodeIp:集羣中節點的ip地址
* nodePort:節點的端口
*
* @return
* @throws UnknownHostException
*/
public static synchronized Client getClient(String clusterName, String nodeIp, int nodePort) throws UnknownHostException {
//設置集羣的名字
Settings settings = Settings.settingsBuilder()
.put("cluster.name", clusterName)
.put("client.transport.sniff", false)
// .put("number_of_shards", 1)
// .put("number_of_replicas", 0)
.build();
//創建集羣client並添加集羣節點地址
Client client = TransportClient.builder().settings(settings).build()
// .addTransportAddress(new InetSocketTransportAddress("192.168.200.195", 9370))
// .addTransportAddress(new InetSocketTransportAddress("192.168.200.196", 9370))
// .addTransportAddress(new InetSocketTransportAddress("192.168.200.197", 9370))
// .addTransportAddress(new InetSocketTransportAddress("192.168.200.198", 9370))
.addTransportAddress(
new InetSocketTransportAddress(InetAddress.getByName(nodeIp),
nodePort));
return client;
}
/**
* 創建索引
* 注意:在生產環節中通知es集羣的owner去創建index
* @param indexName
* @param documentType
* @throws IOException
*/
private static void createIndex(String indexName, String documentType) throws IOException {
final IndicesExistsResponse iRes = client.admin().indices().prepareExists(indexName).execute().actionGet();
if (iRes.isExists()) {
client.admin().indices().prepareDelete(indexName).execute().actionGet();
}
client.admin().indices().prepareCreate(indexName).setSettings(Settings.settingsBuilder().put("number_of_shards", 8).put("number_of_replicas", 1)).execute().actionGet();
XContentBuilder mapping = jsonBuilder()
.startObject()
.startObject(documentType)
// .startObject("_routing").field("path","tid").field("required", "true").endObject()
.startObject("_source").field("enabled", "true").endObject()
.startObject("_all").field("enabled", "false").endObject()
.startObject("properties")
.startObject("user")
.field("store", true)
.field("type", "string")
.field("index", "not_analyzed")
.endObject()
.startObject("message")
.field("store", true)
.field("type","string")
.field("index", "analyzed")
.field("analyzer", "standard")
.endObject()
.startObject("price")
.field("store", true)
.field("type", "float")
.endObject()
.startObject("nv1")
.field("store", true)
.field("type", "integer")
.field("index", "no")
.field("null_value", 0)
.endObject()
.startObject("nv2")
.field("store", true)
.field("type", "integer")
.field("index", "not_analyzed")
.field("null_value", 10)
.endObject()
.startObject("tid")
.field("store", true)
.field("type", "string")
.field("index", "not_analyzed")
.endObject()
// .startObject("location")
// .field("store", true)
// .field("type", "geo_point")
// .field("lat_lon", true)
// .field("geohash", true)
// .field("geohash_prefix", true)
// .field("geohash_precision", 7)
// .endObject()
// .startObject("shape")
// .field("store", true)
// .field("type", "geo_shape")
// .field("geohash", true)
// .field("geohash_prefix", false)
// .field("geohash_precision", 7)
// .endObject()
.startObject("endTime")
.field("type", "date")
.field("store", true)
.field("index", "not_analyzed")
//2015-08-21T08:35:13.890Z
.field("format", "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd'T'HH:mm:ss.SSSZ")
.endObject()
.startObject("date")
.field("type", "date")
// .field("store", true)
// .field("index", "not_analyzed")
//2015-08-21T08:35:13.890Z
// .field("format", "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd'T'HH:mm:ss.SSSZ")
.endObject()
.endObject()
.endObject()
.endObject();
client.admin().indices()
.preparePutMapping(indexName)
.setType(documentType)
.setSource(mapping)
.execute().actionGet();
}
}
3.11 查看head集羣信息,成功了。
3.12 停止並刪除所有docker容器
加
-f
參數強制停止刪除
$ docker rm -f $(docker ps -aq)
b1b17d0f41eb
55d9259ff921
ff4d42575213
66ca0270ef44
ddfbb7ef65bc