天天看點

Kubernetes-在Kubernetes叢集上搭建Stateful Elasticsearch叢集

準備工作

  1. Elasticsearch鏡像,我以Elasticsearch官方鏡像的5.6.10版本為基礎建立的。

Dockerfile

FROM docker.elastic.co/elasticsearch/elasticsearch:5.6.10
MAINTAINER leo.lee([email protected])
WORKDIR /usr/share/elasticsearch
USER root
# copying custom-entrypoint.sh and configuration (elasticsearch.yml, log4j2.properties)
# to their respective directories in /usr/share/elasticsearch (already the WORKDIR)
COPY custom-entrypoint.sh bin/
COPY elasticsearch.yml config/
COPY log4j2.properties config/

# assuring "elasticsearch" user have appropriate access to configuration and custom-entrypoint.sh
# make sure custom-entrypoint.sh is executable
RUN chown elasticsearch:elasticsearch config/elasticsearch.yml config/log4j2.properties bin/custom-entrypoint.sh && \
    chmod +x bin/custom-entrypoint.sh

# start by running the custom entrypoint (as root)
CMD ["/bin/bash", "bin/custom-entrypoint.sh"]
           

custom-entrypoint.sh

#!/bin/bash
# This is expected to run as root for setting the ulimits

set -e
##################################################################################
# ensure increased ulimits - for nofile - for the Elasticsearch containers
# the limit on the number of files that a single process can have open at a time (default is 1024)
ulimit -n 65536

# ensure increased ulimits - for nproc - for the Elasticsearch containers
# the limit on the number of processes that elasticsearch can create
# 2048 is min to pass the linux checks (default is 50)
# https://www.elastic.co/guide/en/elasticsearch/reference/current/max-number-threads-check.html
ulimit -u 2048

# swapping needs to be disabled for performance and node stability
# in ElasticSearch config we are using: [bootstrap.memory_lock=true]
# this additionally requires the "memlock: true" ulimit; specifically set for each container
# -l: max locked memory 
ulimit -l unlimited

# running command to start elasticsearch
# passing all inputs of this entry point script to the es-docker startup script
# NOTE: this entry point script is run as root; but executes the es-docker
# startup script as the elasticsearch user, passing all the root environment-variables 
# to the elasticsearch user 
su elasticsearch bin/es-docker "$@"
           

elasticsearch.yml

# attaching the namespace to the cluster.name to differentiate different clusters
# ex. elasticsearh-acceptance, elasticsearh-production, elasticsearh-monitoring
cluster.name: "elasticsearch-${NAMESPACE}"

# we provide a node.name that is the POD_NAME-NAMESPACE
# ex. elasticsearh-0-acceptance, elasticsearh-1-acceptance, elasticsearh-2-acceptance
node.name: "${POD_NAME}-${NAMESPACE}"

network.host: ${POD_IP}

# A hostname that resolves to multiple IP addresses will try all resolved addresses 
# we provide the name for the headless service 
# which resolves to the ip addresses of all the live attached pods
# alternatively we can directly reference the hostnames of the pods
discovery.zen.ping.unicast.hosts: es-discovery-svc

# minimum_master_nodes need to be explicitly set when bound on a public IP
# set to 1 to allow single node clusters
# more info: https://github.com/elastic/elasticsearch/pull/17288
discovery.zen.minimum_master_nodes: 2

bootstrap.memory_lock: true

#-------------------------------------------------------------------------------------
# RECOVERY: https://www.elastic.co/guide/en/elasticsearch/guide/current/important-configuration-changes.html
# SETTINGS TO avoid the excessive shard swapping that can occur on cluster restarts
#-------------------------------------------------------------------------------------
# how many nodes shall be present to consider the cluster functional;
# prevents Elasticsearch from starting recovery until these nodes are available
gateway.recover_after_nodes: 2

# how many nodes are expected in the cluster
gateway.expected_nodes: 3

# how long we want to wait after [gateway.recover_after_nodes] is reached in order to start recovery process (if applicable). 
gateway.recover_after_time: 5m
#-------------------------------------------------------------------------------------

# The following settings control the fault detection process using the discovery.zen.fd prefix:
# How often a node gets pinged. Defaults to 1s.
discovery.zen.fd.ping_interval: 1s

# How long to wait for a ping response, defaults to 30s.
discovery.zen.fd.ping_timeout: 10s

# How many ping failures / timeouts cause a node to be considered failed. Defaults to 3.
discovery.zen.fd.ping_retries: 2
           

log4j2.properties

status = error
appender.console.type = Console
appender.console.name = console
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = [%d{ISO8601}][%-5p][%-25c{1.}] %marker%m%n
rootLogger.level = info
rootLogger.appenderRef.console.ref = console
           

将這4個檔案放入同一級目錄下,然後在該目錄下使用指令建立鏡像

docker build -t [image name]:[version] .
           

建立完成後将鏡像上傳到私有鏡像倉庫中。

  1. ES需要用到存儲,需要提前建立持久卷(PV)

persistent-volume-es.yaml

kind: PersistentVolume
apiVersion: v1
metadata:
  name: k8s-pv-es1
  labels:
    type: local
spec:
  storageClassName: gce-standard-sc
  capacity:
    storage: 20Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/usr/share/elasticsearch/data"
  persistentVolumeReclaimPolicy: Recycle
---
kind: PersistentVolume
apiVersion: v1
metadata:
  name: k8s-pv-es2
  labels:
    type: local
spec:
  storageClassName: gce-standard-sc
  capacity:
    storage: 20Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/usr/share/elasticsearch/data"
  persistentVolumeReclaimPolicy: Recycle
---
kind: PersistentVolume
apiVersion: v1
metadata:
  name: k8s-pv-es3  
  labels:
    type: local
spec:
  storageClassName: gce-standard-sc
  capacity:
    storage: 20Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/usr/share/elasticsearch/data"
  persistentVolumeReclaimPolicy: Recycle
           

使用如下指令建立

kubectl create -f persistent-volume-es.yaml
           
Kubernetes-在Kubernetes叢集上搭建Stateful Elasticsearch叢集

create pv

部署Elasticsearch叢集

elasticsearch.yaml

#create the statefulset headless service
apiVersion: v1
kind: Service
metadata:
  name: es-discovery-svc
  labels:
    app: es-discovery-svc
spec:
  # the set of Pods targeted by this Service are determined by the Label Selector
  selector:
    app: elasticsearch
  # exposing elasticsearch transport port (only)
  # this service will be used by es-nodes for discovery;
  # communication between es-nodes happens through 
  # the transport port (9300)
  ports:
  - protocol: TCP
    # port exposed by the service (service reacheable at)
    port: 9300
    # port exposed by the Pod(s) the service abstracts (pod reacheable at) 
    # can be a string representing the name of the port @the pod (ex. transport)
    targetPort: 9300
    name: transport
  # specifying this is a headless service by providing ClusterIp "None"
  clusterIP: None
---
#create the cluster-ip service
apiVersion: v1
kind: Service
metadata:
  name: es-ia-svc
  labels:
    app: es-ia-svc
spec:
  selector:
    app: elasticsearch
  ports:
  - name: http
    port: 9200
    protocol: TCP
  - name: transport
    port: 9300
    protocol: TCP
---
#create the stateful set
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
  name: elasticsearch
  labels:
    app: elasticsearch
spec:
  # the headless-service that governs this StatefulSet
  # responsible for the network identity of the set.
  serviceName: es-discovery-svc
  replicas: 3
  # Template is the object that describes the pod that will be created
  template:
    metadata:
      labels:
        app: elasticsearch
    spec:
      securityContext:
        # allows read/write access for mounted volumes  
        # by users that belong to a group with gid: 1000
        fsGroup: 1000
      initContainers:
      # init-container for setting the mmap count limit
      - name: sysctl
        image: busybox
        imagePullPolicy: IfNotPresent
        command: ["sysctl", "-w", "vm.max_map_count=262144"]
        securityContext:
          privileged: true
      containers:
      - name: elasticsearch
        securityContext:
          # applying fix in: https://github.com/kubernetes/kubernetes/issues/3595#issuecomment-287692878 
          # https://docs.docker.com/engine/reference/run/#operator-exclusive-options
          capabilities:
            add:
              # Lock memory (mlock(2), mlockall(2), mmap(2), shmctl(2))
              - IPC_LOCK  
              # Override resource Limits
              - SYS_RESOURCE
        image: registry.docker.uih/library/leo-elsticsearch:5.6.10
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 9300
          name: transport
          protocol: TCP
        - containerPort: 9200
          name: http
          protocol: TCP
        env:
        # environment variables to be directly refrenced from the configuration
        - name: NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: POD_IP
          valueFrom:
            fieldRef:
              fieldPath: status.podIP
        # elasticsearch heapsize (to be adjusted based on need)
        - name: "ES_JAVA_OPTS"
          value: "-Xms2g -Xmx2g"
        # mounting storage persistent volume completely on the data dir
        volumeMounts:
        - name: es-data-vc
          mountPath: /usr/share/elasticsearch/data
  # The StatefulSet guarantees that a given [POD] network identity will 
  # always map to the same storage identity
  volumeClaimTemplates:
  - metadata:
      name: es-data-vc
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          # elasticsearch mounted data directory size (to be adjusted based on need)
          storage: 20Gi
      storageClassName: gce-standard-sc
      # no LabelSelector  defined
      # claims can specify a label selector to further filter the set of volumes
      # currently, a PVC with a non-empty selector can not have a PV dynamically provisioned for it
      # no volumeName is provided
           

使用如下指令進行部署

kubectl create -f elasticsearch.yaml
           

部署完後發現還沒運作起來,通過日志查出是使用者對檔案夾【/usr/share/elasticsearch】沒有權限引起的,檔案夾的權限是root使用者,這裡可以在外面通過root使用者手動修改檔案夾權限,将檔案夾權限賦給普通使用者即可。