【實驗級】Docker-Compose搭建單服務器ELK偽集群


本文說明

由於最近在搭ELK的日志系統,為了演示方案搭了個單台服務器的日志系統,就是前一篇文章中所記,其實這些筆記已經整理好久了,一直在解決各種問題就沒有發出來。在演示過程中我提到了兩個方案,其中之一來自於【原創】分布式之elk日志架構的演進一文中的中級版,另一自然是使用日志直接輸出到Kafka.

為了讓這個看起來還不錯的方案落地,領導決定把這些中間件,服務等都虛擬化,做成docker容器,現在仍在試驗階段,所以做了有點不合理的設計,把這些容器都布署在同一台服務器上!為了能實現這種假想式的設計,做了此次嘗試,也為了了解這個集群是否可行性后期拆分參考。大家如果自己電腦內存有16G以上可用的,可以嘗試下這個腳本,話不多說,把之前准備的腳本和文檔發出來,給大家個參考。

本文不包含kafka之前的日志采集部分,這部分可以參考使用本人的LogDemo https://github.com/HellxZ/LogDemo.git

聲明

如果有人擅自使用本文內容放到自己公司生產環境中,出現的所有問題,后果自負,一率與本人無關!

環境准備

  • Debain Stretch 9.9 16G內存
  • Docker 18.09.6
  • Docker-Compose 1.17.1
  • Java 8 及以上

文檔部分

服務器環境准備

1.確認端口號是否有沖突

為了保證環境一致,請仔細查看如下設置是否與當前服務器端口占用有沖突、映射是否有問題

服務名 服務功能說明 容器名 端口號
es-master Elasticsearch主節點,不存數據:防止腦裂問題 es-cluster-master 19200
es-slave1 Elasticsearch從節點1,存數據 es-cluster-slave1 19201
es-slave2 Elasticsearch從節點2,存數據 es-cluster-slave2 19202
es-slave3 Elasticsearch從節點3,存數據 es-cluster-slave3 19203
es-balance Elasticsearch連接節點,不存數據,供Kibana與Logstash連接 es-cluster-balance 19204
kibana Elasticsearch數據可視化前端 kibana 15601
zookeeper 分布式協調中間件,用於Kafka集群的master節點的選取 zookeeper 12181
kafka1 Kafka節點,作業務緩沖存,保證服務可靠性、數據不易丟失 kafka1 9091
kafka2 同上 kafka2 9092
kafka3 同上 kafka3 9093
kafka-manager 管理kafka集群的前端,可以查看集群健康狀態等 kafka-manager 19000
logstash1 Logstash節點,日志數據消費、日志分詞、轉儲到Elasticsearch集群 logstash-1 9601
logstash2 同上 logstash-2 9602
logstash3 同上 logstash-3 9603

這里邊占用的端口號均為宿主機的,為了防止出現沖突,前邊加1都做了處理,如果仍有沖突,請聯系我

2.確定docker與docker-compose安裝

安裝docker與配置國內鏡像請參閱CentOS安裝Docker-ce並配置國內鏡像

sudo docker -v #查看docker版本,如果正常說明docker已經安裝,可以參考把當前登錄用戶加入docker組,來去除sudo

Docker默認使用root用戶權限才能執行,如果想使用普通用戶執行docker還不想用sudo,可以使用如下命令

sudo usermod -aG docker 要使用的用戶名 && newgrp docker

安裝docker-compose

sudo curl -L "https://github.com/docker/compose/releases/download/1.24.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

sudo chmod +x /usr/local/bin/docker-compose #賦執行權限

查看docker-compose是否安裝

docker-compose -v #查看docker-compose版本

3./etc/hosts修改

由於Kafka需要進行域名映射,而我們使用服務的時候很有可能是內網,所以,這里我們通過修改hosts配置文件,來達到局域網內其它服務的訪問

sudo vim /etc/hosts
#追加如下內容
#kafka hosts
本機ip	kafka1
本機ip	kafka2
本機ip	kafka3

其中本機ip是當前主機的內網ip,如果微服務與其它服務不在同一台服務器,我們還需要配置nginx使用stream監聽指定端口, IP也變成了外網的ip,此條待測

4.Centos7修改systemd的配置文件

vim /etc/systemd/system.conf
#添加以下內容
DefaultLimitNOFILE=65536
DefaultLimitNPROC=32000
DefaultLimitMEMLOCK=infinity

修改此處的目的在於需要對Elasticsearch內存進行限制,在systemd管理下如果不設置elasticsearch的限制,有很大可能出現內存溢出與服務器宕機

5.減少swap分區的使用與生產環境es配置

sudo echo "vm.swappiness=0" >> /etc/sysctl.conf #追加盡少使用swap配置
grep vm.max_map_count /etc/sysctl.conf #查看內存權限大小,如果低於262144,需要設置為最小262144
sudo sysctl -p #使配置文件立即生效

減少swap分區使用,而不是禁用,此方式可以使elasticsearch與kafka的性能保持穩定

配置文件准備

配置文件這些放在文章末尾的腳本部分里了,參考目錄結構,創建相同結構的相同內容的配置文件,按下方配置文件的修改即可。

1.復制elk-docker配置文件夾到當前用戶有讀寫權限的目錄中

復制elk-docker文件夾到啟動docker用戶可訪問的目錄

sudo chown -R 當前用戶:當前用戶組 elk-docker  #賦權訪問

2.修改文件夾下的logstash/config下的兩個文件內容

如你所見,此文件夾下有logstash.conf 與logstash.yml兩個文件,下邊分別進行修改

修改logstash.yml文件

修改xpack.monitoring.elasticsearch.hosts中的ip為當前內網ip

修改logstash.conf文件

找到output/elasticsearch下的hosts,把這個ip地址也改成當前內網ip

3..env文件的使用

為了便於運維和實施,在與此文檔同級的目錄下有一個配置文件名為.env,這個文件是通過運維實施人員修改配置之用,下邊對里邊需要用到的參數一一說明

  • HOST_IP: 設置宿主機內網ip,為kibana提供連接,需要改
  • ES_JVM_OPTS: 每個Elasticsearch實例的jvm啟動參數,可指定啟動內存與最大內存,默認-Xms256m -Xmx256m,可以不改,但不能再改小了
  • ES_MASTER_DATA_DIR:Elasticsearch master節點的數據目錄
  • ES_SLAVE1_DATA_DIR:Elasticsearch slave1節點的數據目錄
  • ES_SLAVE2_DATA_DIR:Elasticsearch slave2節點的數據目錄
  • ES_SLAVE3_DATA_DIR:Elasticsearch slave3節點的數據目錄
  • ES_BALANCE_DATA_DIR:Elasticsearch balance節點的數據目錄
  • LOGSTASH_CONFIG_DIR: Logstash的配置文件目錄,無需改

上邊提到的ES開頭變量的指向的是宿主機目錄,如果自行指定,雖然啟動集群時自動創建目錄,但是無法正確訪問的,原因是創建這些文件夾的是root用戶,而es使用的是啟動docker的賬戶,當然了,如果都是在root用戶下執行自然沒問題,可以使用ls -alh查看,不推薦在正式環境中直接使用root用戶

啟動集群服務

啟動前請確保es的數據目錄可以被docker用戶訪問,正確創建

sudo docker-compose up -d #項目后台啟動,沒有報錯,正確輸出多個服務

docker&docker-compose常用命令

#查看各服務日志
docker logs -f 容器名或容器id
#查看當前運行中的容器
docker ps
#關閉docker-compose所有服務
cd docker-compose.yml所在的目錄
docker-compose down #關閉該文件中定義的所有服務 並 移除集群的虛擬網卡
#強制刪除所有容器,無論是開着的還是已經關閉的
docker rm -f $(docker ps -qa)
#進入正在運行的容器中
docker exec -it 容器名或容器id bash   #使用bash打開

集群管理與功能使用

Elasticsearch-head插件

安裝chrome插件elasticsearch-head,連接到主機的19200端口,進行查看,除些之外,可以通過當前ip:19200/_cat/health來查看當前集群狀態

添加完成后,點擊圖標,如下圖

其中green說明集群健康完全可用。yellow說明有節點掛了,部分可用。red集群不可用

除了直接可以看到的,我們還可以

  • 通過索引來查看當前es索引庫中有哪些索引
  • 通過基本查詢使用簡單查詢功能,需要簡單查詢語法了解
  • 通過復合查詢使用復合查詢功能,當然使用這個功能需要了解復合查詢語法

查詢功能可以使用kibana進行查詢,那個更方便一些

查看索引數據,點擊右側指定的名稱即可查看保存的源數據

Kafka-Manager

使用主機ip:1900,如圖添加集群

拖到最下方,點save.如下圖添加成功

點擊Go to cluster view 立即查看集群

點擊左上方Clusters也可以看到集群如下圖,以后進來也是這個界面。點擊集群名即可查看,如上圖示

具體使用kafkaManager請參考官方github: https://github.com/yahoo/kafka-manager

Kibana

訪問kibana服務器ip:15601/app/kibana#/discover?_g=()

我們可以在Filters處直接搜索要找的日志,當然也可以使用kql,詳情見官網。

添加篩選可以為我們提供更准確的日志搜索,比如當前我們用message就是日志的內容,可以如下操作

我們還可以通過時間來過濾日志

kibana左下角有個隱藏按鈕,我們打開看看

ps: 暫時我們用到的也就是開始的時候創建索引,以及后續用的Discover與開發工具

腳本部分

這里先把腳本與文件結構先列出來

elk-docker/
├── docker-compose.yml
├── .env
├── es-data
│   ├── es-balance-data
│   ├── es-master-data
│   ├── es-slave1-data
│   ├── es-slave2-data
│   └── es-slave3-data
├── logstash
│   └── config
│       ├── logstash.conf
│       └── logstash.yml
└── ReadMeFirst.md

8 directories, 5 files

這里es-data下的所有都是文件夾,logstash文件夾為配置文件夾(官網沒給Docker設置的部分),docker-compose.yml就是我們的腳本,ReadMeFirst.md就是上邊的文檔部分,分別貼出來,好像git不會提交空文件夾,這里就不放github上了。

這里有一個.env文件是用來設置傳入參數的,docker-compose如果想一下子跑起來集群,是不能傳參的,不過.env提供了默認的參數,在docker-compose.yml 中可以很方便的取到

具體需要改的地方,請參見上邊文檔部分吧。

.env

# .env file for docker-compose default. please be careful.

# kibana use HOST_IP to connect to elasticsearch, need to change it to host machine intranet ip
HOST_IP=10.2.114.110

# elasticsearch's JVM args setting, for every elasticsearch instance.
# -Xms is es boostrap occupied memory size
# -Xmx is the biggest memory es can use.
ES_JVM_OPTS=-Xms256m -Xmx256m

# WARNINGS: after you set elasticsearch data dirs, you must mkdirs with login user.
# because the es-cluster need to save data to dirs. if you use root to create folders, they can not save data then cluster down.

# the es-master data mount dir set
ES_MASTER_DATA_DIR=./es-data/es-master-data
# the es-slave1 data mount dir set
ES_SLAVE1_DATA_DIR=./es-data/es-slave1-data
# the es-slave2 data mount dir set
ES_SLAVE2_DATA_DIR=./es-data/es-slave2-data
# the es-slave3 data mount dir set
ES_SLAVE3_DATA_DIR=./es-data/es-slave3-data
# the es-balance data mount dir set, ofcourse this node have no data but node info.
ES_BALANCE_DATA_DIR=./es-data/es-balance-data

# logstash config dir mount set. change inside dir config file to change logstash cluster settings.
# default use relation path. don't change if you don't know what means.
LOGSTASH_CONFIG_DIR=./logstash/config

# kafka bootstrap create topic name
# by default is TOPIC_NAME=all_logs:1:1, "all_logs" is topic's name, first "1" means have one partition, last 1 means have one replicas.
# it's also can set TOPIC_NAME=topicName:patitionSum:replicasNum:cleanupPolicy, e.g. "Topic1:1:3:compact", and that can also set multiple topics,such as "Topic1:1:3,Topic2:2:4:compact"
# the multiple topics separator default is "," you can set new separator by "KAFKA_CREATE_TOPICS_SEPARATOR".
KAFKA_BOOTSTRAP_CREATE_TOPICS=all_logs:1:1

docker-compose.yml

version: "3"
services:
    es-master: # use to be Tribe Node & Master Node, with no data save.
        image:  elasticsearch:7.1.0
        container_name: es-cluster-master
        environment: # setting container env
            - cluster.name=es-cluster
            - node.name=es-master
            - cluster.initial_master_nodes=es-master
            - node.master=true   # specific this node is master node.
            - node.data=false    # master node don't save data to prevent cluster down.
            - http.cors.enabled=true    # solve cross origin
            - http.cors.allow-origin=*
            - bootstrap.memory_lock=true    # lock bootstrap memory.
            - ES_JAVA_OPTS=${ES_JVM_OPTS}   # set es bootstrap jvm args
        ports:
            - "19200:9200"
        expose: # expose ports let other containers link it
            - "9200"    # let kibana connect this port. 
            - "9300"    # use this port let cluster other nodes to discovery.
        restart: always
        volumes:        # mount host's dirs
            - ${ES_MASTER_DATA_DIR}:/usr/share/elasticsearch/data:rw
        networks: 
            - elk-network
    es-slave1:
        image:  elasticsearch:7.1.0
        container_name: es-cluster-slave1
        depends_on:
            - es-master
        environment: # setting container env
            - cluster.name=es-cluster
            - node.name=slave1
            - node.master=false # no master and saving data
            - node.data=true
            - cluster.initial_master_nodes=es-master # point to init master node name.
            - discovery.zen.ping.unicast.hosts=es-master # unique master         
            - bootstrap.memory_lock=true    # lock bootstrap memory.
            - ES_JAVA_OPTS=${ES_JVM_OPTS}
        ports:
            - "19201:9200"
        expose: # expose ports let other containers link it
            - "9300"
        restart: always
        volumes:        # mount host's dirs to save data, has read and write privilege
            - ${ES_SLAVE1_DATA_DIR}:/usr/share/elasticsearch/data:rw
        networks: 
            - elk-network
    es-slave2:
        image:  elasticsearch:7.1.0
        container_name: es-cluster-slave2
        depends_on:
            - es-master
        environment: # setting container env
            - cluster.name=es-cluster
            - node.name=slave2
            - node.master=false
            - node.data=true
            - cluster.initial_master_nodes=es-master
            - discovery.zen.ping.unicast.hosts=es-master           
            - bootstrap.memory_lock=true    # lock bootstrap memory.
            - ES_JAVA_OPTS=${ES_JVM_OPTS}
        ports:
            - "19202:9200"
        expose: # expose ports let other containers link it
            - "9300"
        labels:         # add description
            com.jiuqi.description: "elk-cluster-slave2 on docker"
        restart: always
        volumes:        # mount host's dirs
            - ${ES_SLAVE2_DATA_DIR}:/usr/share/elasticsearch/data:rw 
        networks: 
            - elk-network
    es-slave3:
        image:  elasticsearch:7.1.0
        container_name: es-cluster-slave3
        depends_on:
            - es-master
        environment: # setting container env
            - cluster.name=es-cluster
            - node.name=slave3
            - node.master=false
            - node.data=true
            - cluster.initial_master_nodes=es-master
            - discovery.zen.ping.unicast.hosts=es-master
            - bootstrap.memory_lock=true    # lock bootstrap memory.
            - ES_JAVA_OPTS=${ES_JVM_OPTS}
        ports:
            - "19203:9200"
        expose: # expose ports let other containers link it
            - "9300"
        restart: always
        volumes:        # mount host's dirs
            - ${ES_SLAVE3_DATA_DIR}:/usr/share/elasticsearch/data:rw 
        networks: 
            - elk-network
    es-balance:
        image:  elasticsearch:7.1.0
        container_name: es-cluster-balance
        depends_on:
            - es-master
        environment: # setting container env
            - cluster.name=es-cluster
            - node.name=balance
            - node.master=false # the balance is no master and no data save. 
            - node.data=false
            - cluster.initial_master_nodes=es-master
            - discovery.zen.ping.unicast.hosts=es-master
            - bootstrap.memory_lock=true    # lock bootstrap memory.
            - ES_JAVA_OPTS=${ES_JVM_OPTS}
        ports:
            - "19204:9200"
        expose: # expose ports let other containers link it
            - "9300"
        restart: always
        volumes:        # mount host's dirs
            - ${ES_BALANCE_DATA_DIR}:/usr/share/elasticsearch/data:rw 
        networks: 
            - elk-network
    kibana:
        image: kibana:7.1.0
        container_name: kibana
        depends_on:
            - es-master
        environment:
            - ELASTICSEARCH_HOSTS=http://${HOST_IP}:19204 # connect the es-balance node
            - I18N_LOCALE=zh-CN
        ports:
            - "15601:5601"
        networks:
            - elk-network
    zookeeper:
        image: zookeeper:3.5.5
        restart: always
        container_name: zookeeper
        ports:
            - "12181:2181"
        expose:
            - "2181"    #let kafka manager connect.
        networks:
            - elk-network
    kafka1:
        image: wurstmeister/kafka:2.12-2.2.1
        restart: always
        container_name: kafka1
        ports:
            - "9091:9091"
        environment:
            - KAFKA_BROKER_ID=1
            - KAFKA_LISTENERS=PLAINTEXT://kafka1:9091
            - KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://kafka1:9091
            - KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181
            - KAFKA_MESSAGE_MAX_BYTES=2000000
            - KAFKA_CREATE_TOPICS=${KAFKA_BOOTSTRAP_CREATE_TOPICS}
        expose:
            - "9091"
        depends_on:
            - zookeeper
        networks:
            - elk-network
    kafka2:
        image: wurstmeister/kafka:2.12-2.2.1
        restart: always
        container_name: kafka2
        ports:
            - "9092:9092"
        environment:
            - KAFKA_BROKER_ID=2
            - KAFKA_LISTENERS=PLAINTEXT://kafka2:9092
            - KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://kafka2:9092
            - KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181
            - KAFKA_MESSAGE_MAX_BYTES=2000000
            - KAFKA_CREATE_TOPICS=${KAFKA_BOOTSTRAP_CREATE_TOPICS}
        expose:
            - "9092"
        depends_on:
            - zookeeper
        networks:
            - elk-network
    kafka3:
        image: wurstmeister/kafka:2.12-2.2.1
        restart: always
        container_name: kafka3
        ports:
            - "9093:9093"
        environment:
            - KAFKA_BROKER_ID=3
            - KAFKA_LISTENERS=PLAINTEXT://kafka3:9093
            - KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://kafka3:9093
            - KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181
            - KAFKA_MESSAGE_MAX_BYTES=2000000
            - KAFKA_CREATE_TOPICS=${KAFKA_BOOTSTRAP_CREATE_TOPICS}
        expose:
            - "9093"
        depends_on:
            - zookeeper
        networks:
            - elk-network
    kafka-manager:
        image: sheepkiller/kafka-manager
        container_name: kafka-manager
        ports:
            - "19000:9000"
        environment:
            ZK_HOSTS: zookeeper:2181
            APPLICATION_SECRET: "admin"
        depends_on:
            - zookeeper
        networks:
            - elk-network
    logstash1:
        image: logstash:7.1.0
        container_name: logstash-1
        ports:
            - "9601:9600"
        environment:
            - XPACK_MONITORING_ENABLED=true
        volumes:
            - ${LOGSTASH_CONFIG_DIR}/logstash.conf:/usr/share/logstash/pipeline/logstash.conf:rw
            - ${LOGSTASH_CONFIG_DIR}/logstash.yml:/usr/share/logstash/config/logstash.yml:rw
        depends_on:
            - kafka1
            - kafka2
            - kafka3
            - es-master
            - es-slave1
            - es-slave2
            - es-slave3
        networks:
            - elk-network     
    logstash2:
        image: logstash:7.1.0
        container_name: logstash-2
        ports:
            - "9602:9600"
        environment:
            - XPACK_MONITORING_ENABLED=true
        volumes:
            - ${LOGSTASH_CONFIG_DIR}/logstash.conf:/usr/share/logstash/pipeline/logstash.conf:rw
            - ${LOGSTASH_CONFIG_DIR}/logstash.yml:/usr/share/logstash/config/logstash.yml:rw
        depends_on:
            - kafka1
            - kafka2
            - kafka3
            - es-master
            - es-slave1
            - es-slave2
            - es-slave3
        networks:
            - elk-network
    logstash3:
        image: logstash:7.1.0
        container_name: logstash-3
        ports:
            - "9603:9600"
        environment:
            - XPACK_MONITORING_ENABLED=true
        volumes:
            - ${LOGSTASH_CONFIG_DIR}/logstash.conf:/usr/share/logstash/pipeline/logstash.conf:rw
            - ${LOGSTASH_CONFIG_DIR}/logstash.yml:/usr/share/logstash/config/logstash.yml:rw
        depends_on:
            - kafka1
            - kafka2
            - kafka3
            - es-master
            - es-slave1
            - es-slave2
            - es-slave3
        networks:
            - elk-network
networks:
    elk-network: 
        driver: bridge

logstash/config/logstash.yml

http.host: "0.0.0.0"
xpack.monitoring.elasticsearch.hosts: [ "http://10.2.114.110:19204" ]

logstash/config/logstash.conf

input {
  kafka {
    bootstrap_servers => "kafka1:9091,kafka2:9092,kafka3:9093"
    topics => ["all_logs"]
    group_id => "logstash"
    codec => json
  }
}

filter {

}

output {
  elasticsearch {
    hosts => ["10.2.114.110:19204"]
    index => "all-logs-%{+YYYY.MM.dd}"
    #user => "elastic"
    #password => "changeme"
  }
  stdout {
    codec => rubydebug
  }
}

結束語

本文只是為了驗證方案的可行性,並沒有考慮生產環境中的負載情況,所以不適合放到生產環境中使用。

僅用於提供一個思路,正確按照文檔操作是不會有問題的。如果有,請在下方評論,我會盡快改正。

聲明:原創文章禁止轉載


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM