[集羣搭建]記錄使用docker搭建elasticsearch集羣

本文記錄使用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地址,如下圖。

圖 es-dockerfile

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集羣信息,成功了。

圖 es-head-cluster

3.12 停止並刪除所有docker容器

-f參數強制停止刪除

$ docker rm -f $(docker ps -aq)
b1b17d0f41eb
55d9259ff921
ff4d42575213
66ca0270ef44
ddfbb7ef65bc

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章