From 5e378c3aec80ae982a10de09b5fe54be8d00effc Mon Sep 17 00:00:00 2001 From: Shaun Berryman Date: Thu, 6 Apr 2017 16:24:58 -0700 Subject: [PATCH 01/15] Fairly major changes, they work locally... haven't tested on triton yet --- Dockerfile | 91 ++++++++++++++---------- bin/elastic-server.sh | 6 ++ bin/manage.sh | 151 ++++++++++++++++++++++++++++------------ etc/containerpilot.json | 38 +++++++--- etc/elasticsearch.yml | 101 ++++++++++++--------------- local-compose.yml | 93 +++++++++++++------------ 6 files changed, 284 insertions(+), 196 deletions(-) create mode 100644 bin/elastic-server.sh diff --git a/Dockerfile b/Dockerfile index 8ff459c..058f81f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,54 +1,71 @@ -FROM debian:jessie +FROM docker.elastic.co/elasticsearch/elasticsearch:5.3.0 -RUN apt-get update && \ - apt-get install -y \ - openjdk-7-jre-headless \ - curl \ - jq \ - && rm -rf /var/lib/apt/lists/* +# need to drop back into root! +USER root -ENV JAVA_HOME /usr/lib/jvm/java-7-openjdk-amd64 - -# If we wanted the development version we could pull that instead but we want to -# run a production environment here. -RUN export ES_PKG=elasticsearch-2.2.0.deb && \ - curl -LO https://download.elasticsearch.org/elasticsearch/release/org/elasticsearch/distribution/deb/elasticsearch/2.2.0/${ES_PKG} && \ - dpkg -i ${ES_PKG} && \ - rm ${ES_PKG} && \ - rm /etc/elasticsearch/elasticsearch.yml +RUN apk update && \ + apk add jq curl unzip tar && \ + rm -rf /var/cache/apk/* # Add Containerpilot and set its configuration -ENV CONTAINERPILOT_VER 2.1.0 -ENV CONTAINERPILOT file:///etc/containerpilot.json +ENV CONSUL_VERSION=0.7.5 \ + CONSUL_CLI_VER=0.3.1 \ + CONTAINERPILOT_VER=2.7.2 \ + CONTAINERPILOT=file:///etc/containerpilot.json + +# Add consul agent +RUN export CONSUL_CHECKSUM=40ce7175535551882ecdff21fdd276cef6eaab96be8a8260e0599fadb6f1f5b8 \ + && curl --retry 7 --fail -vo /tmp/consul.zip "https://releases.hashicorp.com/consul/${CONSUL_VERSION}/consul_${CONSUL_VERSION}_linux_amd64.zip" \ + && echo "${CONSUL_CHECKSUM} /tmp/consul.zip" | sha256sum -c \ + && unzip /tmp/consul -d /usr/local/bin \ + && rm /tmp/consul.zip + +# Consul client +RUN export CONSUL_CLIENT_CHECKSUM=037150d3d689a0babf4ba64c898b4497546e2fffeb16354e25cef19867e763f1 \ + && curl -Lso /tmp/consul-cli.tgz "https://github.com/CiscoCloud/consul-cli/releases/download/v${CONSUL_CLI_VER}/consul-cli_${CONSUL_CLI_VER}_linux_amd64.tar.gz" \ + && echo "${CONSUL_CLIENT_CHECKSUM} /tmp/consul-cli.tgz" | sha256sum -c \ + && tar zxf /tmp/consul-cli.tgz -C /usr/local/bin --strip-components 1 \ + && rm /tmp/consul-cli.tgz -RUN export CONTAINERPILOT_CHECKSUM=e7973bf036690b520b450c3a3e121fc7cd26f1a2 \ +# Add ContainerPilot and set its configuration file path +RUN export CONTAINERPILOT_CHECKSUM=e886899467ced6d7c76027d58c7f7554c2fb2bcc \ && curl -Lso /tmp/containerpilot.tar.gz \ - "https://github.com/joyent/containerpilot/releases/download/${CONTAINERPILOT_VER}/containerpilot-${CONTAINERPILOT_VER}.tar.gz" \ + "https://github.com/joyent/containerpilot/releases/download/${CONTAINERPILOT_VER}/containerpilot-${CONTAINERPILOT_VER}.tar.gz" \ && echo "${CONTAINERPILOT_CHECKSUM} /tmp/containerpilot.tar.gz" | sha1sum -c \ && tar zxf /tmp/containerpilot.tar.gz -C /usr/local/bin \ && rm /tmp/containerpilot.tar.gz +# Add our configuration files and scripts +COPY /etc/containerpilot.json /etc/containerpilot.json +COPY /etc/elasticsearch.yml /usr/share/elasticsearch/config/elasticsearch.yml +COPY /bin/* /usr/local/bin/ + +# Should we remove unzip? +# RUN apk del unzip tar + # Create and take ownership over required directories -RUN mkdir -p /var/lib/elasticsearch/data && \ - chown -R elasticsearch:elasticsearch /var/lib/elasticsearch/data && \ - chown -R root:elasticsearch /etc/elasticsearch && \ - chmod g+w /etc/elasticsearch +RUN mkdir -p /opt/consul/config \ + && mkdir -p /opt/consul/data \ + && chmod 770 /opt/consul/data \ + && chown -R elasticsearch:elasticsearch /opt/consul \ + && mkdir -p /etc/containerpilot \ + && chmod -R g+w /etc/containerpilot \ + && chmod +x /usr/local/bin/elastic-server.sh \ + && chown -R elasticsearch:elasticsearch /etc/containerpilot +# back to elastic USER USER elasticsearch -# Add our configuration files and scripts -COPY /etc/containerpilot.json /etc -COPY /etc/elasticsearch.yml /etc/elasticsearch/elasticsearch.yml -COPY /bin/manage.sh /usr/local/bin - # Expose the data directory as a volume in case we want to mount these # as a --volumes-from target; it's important that this VOLUME comes # after the creation of the directory so that we preserve ownership. -VOLUME /var/lib/elasticsearch/data - -# We don't need to expose these ports in order for other containers on Triton -# to reach this container in the default networking environment, but if we -# leave this here then we get the ports as well-known environment variables -# for purposes of linking. -EXPOSE 9200 -EXPOSE 9300 +VOLUME ["/usr/share/elasticsearch/data"] + +# Override the parent entrypoint +ENTRYPOINT [] +CMD ["containerpilot", "/usr/local/bin/elastic-server.sh"] +# CMD ["bin/es-docker"] +# CMD ["/bin/bash", "bin/es-docker", "--default.path.conf=/etc/elasticsearch"] +# ENTRYPOINT ["/bin/bash", "containerpilot"] +# CMD ["bin/es-docker", "--default.path.conf=/etc/elasticsearch"] +# CMD ["containerpilot"] diff --git a/bin/elastic-server.sh b/bin/elastic-server.sh new file mode 100644 index 0000000..160f9f3 --- /dev/null +++ b/bin/elastic-server.sh @@ -0,0 +1,6 @@ +#!/bin/sh -xe +manage.sh onStart #|| exit $? +if [[ $? != 0 ]]; then + exit $? +fi +exec /usr/share/elasticsearch/bin/es-docker $* diff --git a/bin/manage.sh b/bin/manage.sh index d8bd9e7..d23c389 100755 --- a/bin/manage.sh +++ b/bin/manage.sh @@ -1,67 +1,130 @@ #!/bin/bash MASTER=null +CONSUL_HOST=${CONSUL} +CONSUL_AGENT=${CONSUL_AGENT:=false} -if [[ -z ${CONSUL} ]]; then +readonly lockPath=service/elasticsearch-master/locks/master + +if [ $CONSUL_AGENT != false ]; then + CONSUL_HOST='localhost' +fi + +if [[ -z $CONSUL_HOST ]]; then echo "Missing CONSUL environment variable" exit 1 fi +consulCommand() { + consul-cli --quiet --consul="${CONSUL_HOST}:8500" $* +} + preStart() { - # happy path is that there's a master available and we can cluster - configureMaster - - # data-only nodes can only loop until there's a master available - if [ ${ES_NODE_MASTER} == false ]; then - while true - do - sleep 1.7 - configureMaster + logDebug "preStart" +} + +onStart() { + logDebug "onStart" + + waitForLeader + + getRegisteredServiceName + if [[ "${registeredServiceName}" == "elasticsearch-data" ]]; then + + # wait for a healthy master + local i + for (( i = 0; i < ${MASTER_WAIT_TIMEOUT-60}; i++ )); do + getServiceAddresses "elasticsearch-master" + if [[ ${serviceAddresses} ]]; then + MASTER=$serviceAddresses + break + fi + sleep 1 done - exit 0 - fi - # for a master+data node, we'll retry to see if there's another - # master in the cluster in the process of starting up. But we - # bail out if we exceed the retries and just bootstrap the cluster - if [ ${ES_NODE_DATA} == true ]; then - local n=0 - until [ $n -ge 2 ] - do - sleep 1.7 - configureMaster - n=$((n+1)) + else + + # wait for a healthy master + local i + for (( i = 0; i < ${MASTER_WAIT_TIMEOUT-60}; i++ )); do + getServiceAddresses "elasticsearch-master" + if [[ ${serviceAddresses} ]]; then + MASTER=$serviceAddresses + break + fi + sleep 1 done + fi - # for a master-only node or master+data node that's exceeded the - # retry attempts, we'll assume this is the first master and bootstrap - # the cluster - MASTER=127.0.0.1 - replace + # replace zen hosts + replaceZenHosts } -# get the list of ES master nodes from Consul -configureMaster() { - MASTER=$(curl -Ls --fail http://${CONSUL}:8500/v1/catalog/service/elasticsearch-master | jq -r '.[0].ServiceAddress') - if [[ $MASTER != "null" ]] && [[ -n $MASTER ]]; then - replace - exit 0 - fi - # if there's no master we fall thru and let the caller figure - # out what to do next +health() { + local privateIp=$(ip addr show eth0 | grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}') + /usr/bin/curl --fail -s -o /dev/null http://${privateIp}:9200 +} + +waitForLeader() { + logDebug "Waiting for consul leader" + local tries=0 + while true + do + logDebug "Waiting for consul leader" + tries=$((tries + 1)) + local leader=$(consulCommand --template="{{.}}" status leader) + if [[ -n "$leader" ]]; then + break + elif [[ $tries -eq 60 ]]; then + echo "No consul leader" + exit 1 + fi + sleep 1 + done +} + +getServiceAddresses() { + local serviceInfo=$(consulCommand health service --passing "$1") + serviceAddresses=($(echo $serviceInfo | jq -r '.[].Service.Address')) + logDebug "serviceAddresses $1 ${serviceAddresses[*]}" +} + +getRegisteredServiceName() { + registeredServiceName=$(jq -r '.services[0].name' /etc/containerpilot.json) +} + +getNodeAddress() { + nodeAddress=$(ifconfig eth0 | awk '/inet addr/ {gsub("addr:", "", $2); print $2}') } -# update discovery.zen.ping.unicast.hosts -replace() { +replaceZenHosts() { REPLACEMENT=$(printf 's/^discovery\.zen\.ping\.unicast\.hosts.*$/discovery.zen.ping.unicast.hosts: ["%s"]/' ${MASTER}) - sed -i "${REPLACEMENT}" /etc/elasticsearch/elasticsearch.yml + sed -i "${REPLACEMENT}" /usr/share/elasticsearch/config/elasticsearch.yml } -health() { - local privateIp=$(ip addr show eth0 | grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}') - /usr/bin/curl --fail -s -o /dev/null http://${privateIp}:9200 +logDebug() { + if [[ "${LOG_LEVEL}" == "DEBUG" ]]; then + echo "manage: $*" + fi +} + +help() { + echo "Usage: ./manage.sh preStart => configure Consul agent" + echo " ./manage.sh onStart => first-run configuration" + echo " ./manage.sh health => health check Elastic" + echo " ./manage.sh preStop => prepare for stop" } -# do whatever the arg is -$1 +until + cmd=$1 + if [[ -z "$cmd" ]]; then + help + fi + shift 1 + $cmd "$@" + [ "$?" -ne 127 ] +do + help + exit +done diff --git a/etc/containerpilot.json b/etc/containerpilot.json index 9adac5f..0599df1 100644 --- a/etc/containerpilot.json +++ b/etc/containerpilot.json @@ -1,13 +1,29 @@ { - "consul": "{{ .CONSUL }}:8500", - "preStart": "/usr/local/bin/manage.sh preStart", - "services": [ - { - "name": "{{ .ES_SERVICE_NAME }}", - "port": 9300, - "health": "/usr/local/bin/manage.sh health", - "poll": 10, - "ttl": 25 - } - ] + "consul": "{{ if .CONSUL_AGENT }}localhost{{ else }}{{ if .CONSUL }}{{ .CONSUL }}{{ else }}consul{{ end }}{{ end }}:8500", + "logging": { + "level": "{{ if .LOG_LEVEL }}{{ .LOG_LEVEL }}{{ else }}INFO{{ end }}", + "format": "text", + "output": "stdout" + }, + "preStart": "/usr/local/bin/manage.sh preStart", + "services": [{ + "name": "{{ .ES_SERVICE_NAME }}", + "port": 9300, + "health": "/usr/local/bin/manage.sh health", + "poll": 10, + "ttl": 25 + }], + "coprocesses": [{{ if .CONSUL_AGENT }} + { + "command": ["/usr/local/bin/consul", "agent", + "-data-dir=/opt/consul/data", + "-config-dir=/opt/consul/config", + "-rejoin", + "-retry-join", "{{ if .CONSUL }}{{ .CONSUL }}{{ else }}consul{{ end }}", + "-retry-max", "10", + "-retry-interval", "10s" + ], + "restarts": "unlimited" + } + {{ end }}] } diff --git a/etc/elasticsearch.yml b/etc/elasticsearch.yml index a21bb11..cebef48 100644 --- a/etc/elasticsearch.yml +++ b/etc/elasticsearch.yml @@ -7,97 +7,82 @@ # The primary way of configuring a node is via this file. This template lists # the most important settings you may want to configure for a production cluster. # -# Please see the documentation for further information on configuration options: -# +# Please consult the documentation for further information on configuration options: +# https://www.elastic.co/guide/en/elasticsearch/reference/index.html # # ---------------------------------- Cluster ----------------------------------- - +# # Use a descriptive name for your cluster: - -cluster.name: ${CLUSTER_NAME} - +# +cluster.name: ${ES_CLUSTER_NAME} +# # ------------------------------------ Node ------------------------------------ - -# Assign the container ID to the node name so to eliminate having to translate -# between the two while debugging. - -node.name: es-${HOSTNAME} - -# By default, all nodes are eligible to become masters and store data. - -node.master: ${ES_NODE_MASTER} -node.data: ${ES_NODE_DATA} - +# +# Use a descriptive name for the node: +# +node.name: node-${HOSTNAME} +# # Add custom attributes to the node: # -# node.rack: r1 - +#node.attr.rack: r1 +# # ----------------------------------- Paths ------------------------------------ - +# # Path to directory where to store the data (separate multiple locations by comma): - -path.data: /var/lib/elasticsearch/data - +# +#path.data: /path/to/data +# # Path to log files: - -path.logs: /var/log/elasticsearch - +# +#path.logs: /path/to/logs +# # ----------------------------------- Memory ----------------------------------- # # Lock the memory on startup: # -# bootstrap.mlockall: true +#bootstrap.memory_lock: true # -# Make sure that the `ES_HEAP_SIZE` environment variable is set to about half the memory -# available on the system and that the owner of the process is allowed to use this limit. +# Make sure that the heap size is set to about half the memory available +# on the system and that the owner of the process is allowed to use this +# limit. # # Elasticsearch performs poorly when the system is swapping the memory. # # ---------------------------------- Network ----------------------------------- - +# # Set the bind address to a specific IP (IPv4 or IPv6): - +# network.host: _eth0:ipv4_ - +# # Set a custom port for HTTP: # -# http.port: 9200 +#http.port: 9200 # -# For more information, see the documentation at: -# +# For more information, consult the network module documentation. # -# ---------------------------------- Gateway ----------------------------------- +# --------------------------------- Discovery ---------------------------------- # -# Block initial recovery after a full cluster restart until N nodes are started: +# Pass an initial list of hosts to perform discovery when new node is started: +# The default list of hosts is ["127.0.0.1", "[::1]"] # -# gateway.recover_after_nodes: 3 +discovery.zen.ping.unicast.hosts: ["${ES_BOOTSTRAP_HOST}"] # -# For more information, see the documentation at: -# +# Prevent the "split brain" by configuring the majority of nodes (total number of master-eligible nodes / 2 + 1): # -# --------------------------------- Discovery ---------------------------------- +#discovery.zen.minimum_master_nodes: 3 # -# Elasticsearch nodes will find each other via unicast, by default. -# For more information, see the documentation at: -# +# For more information, consult the zen discovery module documentation. # -# Prevent the "split brain" by configuring the majority of nodes (total number of nodes / 2 + 1): +# ---------------------------------- Gateway ----------------------------------- # -# discovery.zen.minimum_master_nodes: 3 - -# We'll bootstrap cluster communications by getting a master node via -# the ContainerPilot `preStart` directive, which will rewrite this -# configuration value with the appropriate hostname. - -discovery.zen.ping.multicast.enabled: false -discovery.zen.ping.unicast.hosts: ["${ES_BOOTSTRAP_HOST}"] - -# ---------------------------------- Various ----------------------------------- +# Block initial recovery after a full cluster restart until N nodes are started: +# +#gateway.recover_after_nodes: 3 # -# Disable starting multiple nodes on a single system: +# For more information, consult the gateway module documentation. # -# node.max_local_storage_nodes: 1 +# ---------------------------------- Various ----------------------------------- # # Require explicit names when deleting indices: # -# action.destructive_requires_name: true +#action.destructive_requires_name: true diff --git a/local-compose.yml b/local-compose.yml index 642cfa3..d5dd0d1 100644 --- a/local-compose.yml +++ b/local-compose.yml @@ -1,50 +1,51 @@ -# Local testing version of Elasticsearch stack designed for -# container-native deployment on Joyent's Triton platform. +version: '2.1' +services: + # Local testing version of Elasticsearch stack designed for + # container-native deployment on Joyent's Triton platform. + elasticsearch: + build: . + environment: + - CONSUL_AGENT=1 + - CONSUL=consul + - ES_CLUSTER_NAME=famished_test + - ES_SERVICE_NAME=elasticsearch-master + - ES_NODE_MASTER=true + - ES_NODE_DATA=true + - ES_ENVIRONMENT=dev + # - ES_CLUSTER_SIZE=1 -elasticsearch_master: - extends: - file: docker-compose.yml - service: elasticsearch - mem_limit: 512m - build: . - environment: - - CONSUL=consul - - ES_SERVICE_NAME=elasticsearch-master - - ES_NODE_MASTER=true - - ES_NODE_DATA=false - - CONTAINERPILOT=file:///etc/containerpilot.json - links: - - consul:consul + # are these even remotely accurate? + - ES_JAVA_OPTS=-Djava.security.egd=file:/dev/./urandom -XX:-UseGCTaskAffinity -XX:-BindGCTaskThreadsToCPUs -XX:ParallelGCThreads=1 -XX:ParallelCMSThreads=1 -Xms128m -Xmx128m -elasticsearch: - extends: - file: docker-compose.yml - service: elasticsearch - mem_limit: 512m - build: . - environment: - - CONSUL=consul - - ES_SERVICE_NAME=elasticsearch-master - links: - - consul:consul + # disable x-pack + - xpack.security.enabled=false -elasticsearch_data: - extends: - file: docker-compose.yml - service: elasticsearch - mem_limit: 512m - build: . - environment: - - CONSUL=consul - - ES_SERVICE_NAME=elasticsearch-data - - ES_NODE_MASTER=false - - ES_NODE_DATA=true - links: - - consul:consul + elasticsearch_master: + extends: + service: elasticsearch + ports: + - 9200:9200 + - 9300:9300 + environment: + - ES_NODE_MASTER=true + - ES_NODE_DATA=false -consul: - extends: - file: docker-compose.yml - service: consul - ports: - - 8500:8500 + elasticsearch_data: + extends: + service: elasticsearch + environment: + - ES_SERVICE_NAME=elasticsearch-data + - ES_NODE_MASTER=false + - ES_NODE_DATA=true + + consul: + image: autopilotpattern/consul:0.7.2-r0.8 + command: > + /usr/local/bin/containerpilot + /bin/consul agent -server + -bootstrap + -config-dir=/etc/consul + -ui-dir /ui + -client=0.0.0.0 + ports: + - 8500:8500 From a3b5b14154e480ad4cc79a8169e76e9fc214791c Mon Sep 17 00:00:00 2001 From: Shaun Berryman Date: Thu, 6 Apr 2017 16:33:02 -0700 Subject: [PATCH 02/15] Cleanup --- Dockerfile | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/Dockerfile b/Dockerfile index 058f81f..0c5ee19 100644 --- a/Dockerfile +++ b/Dockerfile @@ -61,11 +61,5 @@ USER elasticsearch # after the creation of the directory so that we preserve ownership. VOLUME ["/usr/share/elasticsearch/data"] -# Override the parent entrypoint -ENTRYPOINT [] +# Start with containerpilot then to our wrapper CMD ["containerpilot", "/usr/local/bin/elastic-server.sh"] -# CMD ["bin/es-docker"] -# CMD ["/bin/bash", "bin/es-docker", "--default.path.conf=/etc/elasticsearch"] -# ENTRYPOINT ["/bin/bash", "containerpilot"] -# CMD ["bin/es-docker", "--default.path.conf=/etc/elasticsearch"] -# CMD ["containerpilot"] From 62bbc55b690776551ec85822da04e390032eb8a2 Mon Sep 17 00:00:00 2001 From: Shaun Berryman Date: Fri, 7 Apr 2017 08:44:51 -0700 Subject: [PATCH 03/15] preStart doesn't do anything, need to research when preStart triggers --- bin/manage.sh | 4 ---- etc/containerpilot.json | 1 - 2 files changed, 5 deletions(-) diff --git a/bin/manage.sh b/bin/manage.sh index d23c389..af91900 100755 --- a/bin/manage.sh +++ b/bin/manage.sh @@ -19,10 +19,6 @@ consulCommand() { consul-cli --quiet --consul="${CONSUL_HOST}:8500" $* } -preStart() { - logDebug "preStart" -} - onStart() { logDebug "onStart" diff --git a/etc/containerpilot.json b/etc/containerpilot.json index 0599df1..3a3da18 100644 --- a/etc/containerpilot.json +++ b/etc/containerpilot.json @@ -5,7 +5,6 @@ "format": "text", "output": "stdout" }, - "preStart": "/usr/local/bin/manage.sh preStart", "services": [{ "name": "{{ .ES_SERVICE_NAME }}", "port": 9300, From f061dc003b1829ba59581ef777d120b53c47f287 Mon Sep 17 00:00:00 2001 From: Shaun Berryman Date: Fri, 7 Apr 2017 08:45:20 -0700 Subject: [PATCH 04/15] No point in the if/else as they do the same thing... --- bin/manage.sh | 38 ++++++++++---------------------------- 1 file changed, 10 insertions(+), 28 deletions(-) diff --git a/bin/manage.sh b/bin/manage.sh index af91900..95b5ea8 100755 --- a/bin/manage.sh +++ b/bin/manage.sh @@ -24,34 +24,16 @@ onStart() { waitForLeader - getRegisteredServiceName - if [[ "${registeredServiceName}" == "elasticsearch-data" ]]; then - - # wait for a healthy master - local i - for (( i = 0; i < ${MASTER_WAIT_TIMEOUT-60}; i++ )); do - getServiceAddresses "elasticsearch-master" - if [[ ${serviceAddresses} ]]; then - MASTER=$serviceAddresses - break - fi - sleep 1 - done - - else - - # wait for a healthy master - local i - for (( i = 0; i < ${MASTER_WAIT_TIMEOUT-60}; i++ )); do - getServiceAddresses "elasticsearch-master" - if [[ ${serviceAddresses} ]]; then - MASTER=$serviceAddresses - break - fi - sleep 1 - done - - fi + # wait for a healthy master + local i + for (( i = 0; i < ${MASTER_WAIT_TIMEOUT-60}; i++ )); do + getServiceAddresses "elasticsearch-master" + if [[ ${serviceAddresses} ]]; then + MASTER=$serviceAddresses + break + fi + sleep 1 + done # replace zen hosts replaceZenHosts From cf4613aa22546686281c07b0cc241eef065ad8be Mon Sep 17 00:00:00 2001 From: Shaun Berryman Date: Fri, 7 Apr 2017 08:45:56 -0700 Subject: [PATCH 05/15] Wouldn't save space as this isn't squashed prior to release --- Dockerfile | 3 --- 1 file changed, 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 0c5ee19..58ca4d2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -40,9 +40,6 @@ COPY /etc/containerpilot.json /etc/containerpilot.json COPY /etc/elasticsearch.yml /usr/share/elasticsearch/config/elasticsearch.yml COPY /bin/* /usr/local/bin/ -# Should we remove unzip? -# RUN apk del unzip tar - # Create and take ownership over required directories RUN mkdir -p /opt/consul/config \ && mkdir -p /opt/consul/data \ From 6a5ecc95b72d6766d76881b199726385b293531c Mon Sep 17 00:00:00 2001 From: Shaun Berryman Date: Fri, 7 Apr 2017 09:10:29 -0700 Subject: [PATCH 06/15] Pull out ES_BOOTSTRAP_HOST --- bin/manage.sh | 2 +- etc/elasticsearch.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/manage.sh b/bin/manage.sh index 95b5ea8..d2afa5a 100755 --- a/bin/manage.sh +++ b/bin/manage.sh @@ -77,7 +77,7 @@ getNodeAddress() { } replaceZenHosts() { - REPLACEMENT=$(printf 's/^discovery\.zen\.ping\.unicast\.hosts.*$/discovery.zen.ping.unicast.hosts: ["%s"]/' ${MASTER}) + REPLACEMENT=$(printf 's/^# discovery\.zen\.ping\.unicast\.hosts.*$/discovery.zen.ping.unicast.hosts: ["%s"]/' ${MASTER}) sed -i "${REPLACEMENT}" /usr/share/elasticsearch/config/elasticsearch.yml } diff --git a/etc/elasticsearch.yml b/etc/elasticsearch.yml index cebef48..1c4d5d3 100644 --- a/etc/elasticsearch.yml +++ b/etc/elasticsearch.yml @@ -65,7 +65,7 @@ network.host: _eth0:ipv4_ # Pass an initial list of hosts to perform discovery when new node is started: # The default list of hosts is ["127.0.0.1", "[::1]"] # -discovery.zen.ping.unicast.hosts: ["${ES_BOOTSTRAP_HOST}"] +# discovery.zen.ping.unicast.hosts: [] # # Prevent the "split brain" by configuring the majority of nodes (total number of master-eligible nodes / 2 + 1): # From 30059ba065cc3b03b81417cff71ee9892bf3b9e6 Mon Sep 17 00:00:00 2001 From: Shaun Berryman Date: Fri, 7 Apr 2017 09:32:47 -0700 Subject: [PATCH 07/15] Remove x-pack --- Dockerfile | 5 +++++ local-compose.yml | 3 --- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 58ca4d2..6902d56 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,6 +3,11 @@ FROM docker.elastic.co/elasticsearch/elasticsearch:5.3.0 # need to drop back into root! USER root +# Remove x-pack +# RUN /usr/share/elasticsearch/bin/elasticsearch-plugin remove x-pack +# Bug in ES plugin (https://github.com/elastic/elasticsearch-docker/issues/35#issuecomment-285912424) +RUN rm -rf /usr/share/elasticsearch/plugins/x-pack + RUN apk update && \ apk add jq curl unzip tar && \ rm -rf /var/cache/apk/* diff --git a/local-compose.yml b/local-compose.yml index d5dd0d1..7478f66 100644 --- a/local-compose.yml +++ b/local-compose.yml @@ -17,9 +17,6 @@ services: # are these even remotely accurate? - ES_JAVA_OPTS=-Djava.security.egd=file:/dev/./urandom -XX:-UseGCTaskAffinity -XX:-BindGCTaskThreadsToCPUs -XX:ParallelGCThreads=1 -XX:ParallelCMSThreads=1 -Xms128m -Xmx128m - # disable x-pack - - xpack.security.enabled=false - elasticsearch_master: extends: service: elasticsearch From ed21abe7b1e48cc1c65bfb23893f63891238ad7b Mon Sep 17 00:00:00 2001 From: Shaun Berryman Date: Fri, 7 Apr 2017 09:52:31 -0700 Subject: [PATCH 08/15] Update readme to include links to the dockerfile --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index 8325b32..f367132 100644 --- a/README.md +++ b/README.md @@ -141,3 +141,14 @@ $ curl "http://${MASTER_IP}:9200/_cluster/state?pretty=true" } ``` + +### Dockerfile + +Elastic has depreciated the official repository in favor of their own registry. + +> This image will receive no further updates after 2017-06-20 (June 20, 2017). Please adjust your usage accordingly. - [Docker Hub](https://hub.docker.com/_/elasticsearch/) + +Unfortunately they don't include the Dockerfile as part of the elasticsearch repository, links are included below for easy reference. + +* [Dockerfile](https://github.com/elastic/elasticsearch-docker/blob/master/build/elasticsearch/Dockerfile) +* [Base Dockerfile](https://github.com/elastic/elasticsearch-alpine-base/blob/master/build/elasticsearch-alpine-base/Dockerfile) From c41705eaae9f08a99937726782b38d4822c2a549 Mon Sep 17 00:00:00 2001 From: Shaun Berryman Date: Fri, 7 Apr 2017 10:08:42 -0700 Subject: [PATCH 09/15] Remove unused lockPath --- bin/manage.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/bin/manage.sh b/bin/manage.sh index d2afa5a..c8356f8 100755 --- a/bin/manage.sh +++ b/bin/manage.sh @@ -4,8 +4,6 @@ MASTER=null CONSUL_HOST=${CONSUL} CONSUL_AGENT=${CONSUL_AGENT:=false} -readonly lockPath=service/elasticsearch-master/locks/master - if [ $CONSUL_AGENT != false ]; then CONSUL_HOST='localhost' fi From cfae2f659ef160f095e6c41f3b9e4cc781cb8c8b Mon Sep 17 00:00:00 2001 From: Shaun Berryman Date: Fri, 7 Apr 2017 10:09:24 -0700 Subject: [PATCH 10/15] Removed preStart from help --- bin/manage.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bin/manage.sh b/bin/manage.sh index c8356f8..74db714 100755 --- a/bin/manage.sh +++ b/bin/manage.sh @@ -86,8 +86,7 @@ logDebug() { } help() { - echo "Usage: ./manage.sh preStart => configure Consul agent" - echo " ./manage.sh onStart => first-run configuration" + echo "Usage: ./manage.sh onStart => first-run configuration" echo " ./manage.sh health => health check Elastic" echo " ./manage.sh preStop => prepare for stop" } From 2f807599ea62bf41d3fc811586ffd0648ac40496 Mon Sep 17 00:00:00 2001 From: Shaun Berryman Date: Tue, 11 Apr 2017 14:47:08 -0700 Subject: [PATCH 11/15] Change the base docker image MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Requires us to duplicate a few files from dockers official image. Also add in a seccomp check to disable it on systems that don’t have it --- Dockerfile | 73 +++++++++++++++++++++------------ bin/es-docker | 39 ++++++++++++++++++ bin/manage.sh | 12 ++++++ etc/elasticsearch.yml | 95 +++++++------------------------------------ etc/log4j2.properties | 9 ++++ 5 files changed, 122 insertions(+), 106 deletions(-) create mode 100644 bin/es-docker create mode 100644 etc/log4j2.properties diff --git a/Dockerfile b/Dockerfile index 6902d56..e44c985 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,22 +1,37 @@ -FROM docker.elastic.co/elasticsearch/elasticsearch:5.3.0 +FROM docker.elastic.co/elasticsearch/elasticsearch-alpine-base:latest -# need to drop back into root! -USER root +# LICENSE - Apache License 2.0 +# https://github.com/elastic/elasticsearch-alpine-base/blob/master/LICENSE -# Remove x-pack -# RUN /usr/share/elasticsearch/bin/elasticsearch-plugin remove x-pack -# Bug in ES plugin (https://github.com/elastic/elasticsearch-docker/issues/35#issuecomment-285912424) -RUN rm -rf /usr/share/elasticsearch/plugins/x-pack +ENV ELASTIC_VERSION=5.3.0 \ + PATH=/usr/share/elasticsearch/bin:$PATH \ + JAVA_HOME=/usr/lib/jvm/java-1.8-openjdk \ + CONSUL_VERSION=0.7.5 \ + CONSUL_CLI_VER=0.3.1 \ + CONTAINERPILOT_VER=2.7.2 \ + CONTAINERPILOT=file:///etc/containerpilot.json +WORKDIR /usr/share/elasticsearch + +# Required dependencies RUN apk update && \ apk add jq curl unzip tar && \ rm -rf /var/cache/apk/* -# Add Containerpilot and set its configuration -ENV CONSUL_VERSION=0.7.5 \ - CONSUL_CLI_VER=0.3.1 \ - CONTAINERPILOT_VER=2.7.2 \ - CONTAINERPILOT=file:///etc/containerpilot.json +# Download/extract defined ES version. busybox tar can't strip leading dir. +RUN export ELASTIC_CHECKSUM=9273fdecb2251755887f1234d6cfcc91e44a384d && \ + wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-${ELASTIC_VERSION}.tar.gz && \ + test $ELASTIC_CHECKSUM == $(sha1sum elasticsearch-${ELASTIC_VERSION}.tar.gz | awk '{print $1}') && \ + tar zxf elasticsearch-${ELASTIC_VERSION}.tar.gz && \ + chown -R elasticsearch:elasticsearch elasticsearch-${ELASTIC_VERSION} && \ + mv elasticsearch-${ELASTIC_VERSION}/* . && \ + rmdir elasticsearch-${ELASTIC_VERSION} && \ + rm elasticsearch-${ELASTIC_VERSION}.tar.gz + +RUN set -ex && for esdirs in config data logs; do \ + mkdir -p "$esdirs"; \ + chown -R elasticsearch:elasticsearch "$esdirs"; \ + done # Add consul agent RUN export CONSUL_CHECKSUM=40ce7175535551882ecdff21fdd276cef6eaab96be8a8260e0599fadb6f1f5b8 \ @@ -40,22 +55,25 @@ RUN export CONTAINERPILOT_CHECKSUM=e886899467ced6d7c76027d58c7f7554c2fb2bcc \ && tar zxf /tmp/containerpilot.tar.gz -C /usr/local/bin \ && rm /tmp/containerpilot.tar.gz -# Add our configuration files and scripts -COPY /etc/containerpilot.json /etc/containerpilot.json -COPY /etc/elasticsearch.yml /usr/share/elasticsearch/config/elasticsearch.yml +USER elasticsearch +COPY /etc/containerpilot.json /etc/ +COPY /etc/elasticsearch.yml config/ +COPY /etc/log4j2.properties config/ +COPY /bin/es-docker bin/es-docker COPY /bin/* /usr/local/bin/ -# Create and take ownership over required directories -RUN mkdir -p /opt/consul/config \ - && mkdir -p /opt/consul/data \ - && chmod 770 /opt/consul/data \ - && chown -R elasticsearch:elasticsearch /opt/consul \ - && mkdir -p /etc/containerpilot \ - && chmod -R g+w /etc/containerpilot \ - && chmod +x /usr/local/bin/elastic-server.sh \ - && chown -R elasticsearch:elasticsearch /etc/containerpilot - -# back to elastic USER +USER root +RUN chown elasticsearch:elasticsearch config/elasticsearch.yml config/log4j2.properties bin/es-docker && \ + chmod 0750 bin/es-docker && \ + mkdir -p /opt/consul/config && \ + mkdir -p /opt/consul/data && \ + chmod 770 /opt/consul/data && \ + chown -R elasticsearch:elasticsearch /opt/consul && \ + mkdir -p /etc/containerpilot && \ + chmod -R g+w /etc/containerpilot && \ + chmod +x /usr/local/bin/elastic-server.sh && \ + chown -R elasticsearch:elasticsearch /etc/containerpilot + USER elasticsearch # Expose the data directory as a volume in case we want to mount these @@ -65,3 +83,6 @@ VOLUME ["/usr/share/elasticsearch/data"] # Start with containerpilot then to our wrapper CMD ["containerpilot", "/usr/local/bin/elastic-server.sh"] + + +EXPOSE 9200 9300 diff --git a/bin/es-docker b/bin/es-docker new file mode 100644 index 0000000..c9c285c --- /dev/null +++ b/bin/es-docker @@ -0,0 +1,39 @@ +#!/bin/bash + +# Run Elasticsearch and allow setting default settings via env vars +# +# e.g. Setting the env var cluster.name=testcluster +# +# will cause Elasticsearch to be invoked with -Ecluster.name=testcluster +# +# see https://www.elastic.co/guide/en/elasticsearch/reference/current/settings.html#_setting_default_settings + +es_opts='' + +while IFS='=' read -r envvar_key envvar_value +do + # Elasticsearch env vars need to have at least two dot separated lowercase words, e.g. `cluster.name` + if [[ "$envvar_key" =~ ^[a-z]+\.[a-z]+ ]] + then + if [[ ! -z $envvar_value ]]; then + es_opt="-E${envvar_key}=${envvar_value}" + es_opts+=" ${es_opt}" + fi + fi +done < <(env) + +# The virtual file /proc/self/cgroup should list the current cgroup +# membership. For each hierarchy, you can follow the cgroup path from +# this file to the cgroup filesystem (usually /sys/fs/cgroup/) and +# introspect the statistics for the cgroup for the given +# hierarchy. Alas, Docker breaks this by mounting the container +# statistics at the root while leaving the cgroup paths as the actual +# paths. Therefore, Elasticsearch provides a mechanism to override +# reading the cgroup path from /proc/self/cgroup and instead uses the +# cgroup path defined the JVM system property +# es.cgroups.hierarchy.override. Therefore, we set this value here so +# that cgroup statistics are available for the container this process +# will run in. +export ES_JAVA_OPTS="-Des.cgroups.hierarchy.override=/ $ES_JAVA_OPTS" + +exec bin/elasticsearch ${es_opts} diff --git a/bin/manage.sh b/bin/manage.sh index 74db714..df4ab8c 100755 --- a/bin/manage.sh +++ b/bin/manage.sh @@ -35,6 +35,9 @@ onStart() { # replace zen hosts replaceZenHosts + + # seccomp (not supported on joyent) + replaceSeccomp } health() { @@ -79,6 +82,15 @@ replaceZenHosts() { sed -i "${REPLACEMENT}" /usr/share/elasticsearch/config/elasticsearch.yml } +replaceSeccomp() { + SECCOMP_ENABLED=$(zcat /proc/config.gz | grep CONFIG_SECCOMP=y) + if [[ "${SECCOMP_ENABLED}" != "CONFIG_SECCOMP=y" ]]; then + echo "WARNING: seccomp unavailable, disabling system_call_filter..." + REPLACEMENT=$(printf 's/^# bootstrap\.system_call_filter.*$/bootstrap.system_call_filter: false/') + sed -i "${REPLACEMENT}" /usr/share/elasticsearch/config/elasticsearch.yml + fi +} + logDebug() { if [[ "${LOG_LEVEL}" == "DEBUG" ]]; then echo "manage: $*" diff --git a/etc/elasticsearch.yml b/etc/elasticsearch.yml index 1c4d5d3..435acc4 100644 --- a/etc/elasticsearch.yml +++ b/etc/elasticsearch.yml @@ -1,88 +1,23 @@ -# ======================== Elasticsearch Configuration ========================= -# -# NOTE: Elasticsearch comes with reasonable defaults for most settings. -# Before you set out to tweak and tune the configuration, make sure you -# understand what are you trying to accomplish and the consequences. -# -# The primary way of configuring a node is via this file. This template lists -# the most important settings you may want to configure for a production cluster. -# -# Please consult the documentation for further information on configuration options: -# https://www.elastic.co/guide/en/elasticsearch/reference/index.html -# -# ---------------------------------- Cluster ----------------------------------- -# # Use a descriptive name for your cluster: -# cluster.name: ${ES_CLUSTER_NAME} -# -# ------------------------------------ Node ------------------------------------ -# + # Use a descriptive name for the node: -# node.name: node-${HOSTNAME} -# -# Add custom attributes to the node: -# -#node.attr.rack: r1 -# -# ----------------------------------- Paths ------------------------------------ -# -# Path to directory where to store the data (separate multiple locations by comma): -# -#path.data: /path/to/data -# -# Path to log files: -# -#path.logs: /path/to/logs -# -# ----------------------------------- Memory ----------------------------------- -# -# Lock the memory on startup: -# -#bootstrap.memory_lock: true -# -# Make sure that the heap size is set to about half the memory available -# on the system and that the owner of the process is allowed to use this -# limit. -# -# Elasticsearch performs poorly when the system is swapping the memory. -# -# ---------------------------------- Network ----------------------------------- -# + # Set the bind address to a specific IP (IPv4 or IPv6): -# -network.host: _eth0:ipv4_ -# -# Set a custom port for HTTP: -# -#http.port: 9200 -# -# For more information, consult the network module documentation. -# -# --------------------------------- Discovery ---------------------------------- -# +# network.host: _eth0:ipv4_ +network.host: [_site_] + # Pass an initial list of hosts to perform discovery when new node is started: # The default list of hosts is ["127.0.0.1", "[::1]"] -# +# THIS GETS OVERWRITTEN AUTOMATICALLY via `bin/manage.sh onStart` # discovery.zen.ping.unicast.hosts: [] -# -# Prevent the "split brain" by configuring the majority of nodes (total number of master-eligible nodes / 2 + 1): -# -#discovery.zen.minimum_master_nodes: 3 -# -# For more information, consult the zen discovery module documentation. -# -# ---------------------------------- Gateway ----------------------------------- -# -# Block initial recovery after a full cluster restart until N nodes are started: -# -#gateway.recover_after_nodes: 3 -# -# For more information, consult the gateway module documentation. -# -# ---------------------------------- Various ----------------------------------- -# -# Require explicit names when deleting indices: -# -#action.destructive_requires_name: true + +# minimum_master_nodes need to be explicitly set when bound on a public IP +# set to 1 to allow single node clusters +# Details: https://github.com/elastic/elasticsearch/pull/17288 +discovery.zen.minimum_master_nodes: 1 + +# Turn off seccomp on systems that don't have it enabled (see manage.sh) +# https://docs.docker.com/engine/security/seccomp/ +# bootstrap.system_call_filter: true diff --git a/etc/log4j2.properties b/etc/log4j2.properties new file mode 100644 index 0000000..46877d0 --- /dev/null +++ b/etc/log4j2.properties @@ -0,0 +1,9 @@ +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 From b31c5e67597e9312d937cc19c6458626abf170b0 Mon Sep 17 00:00:00 2001 From: Shaun Berryman Date: Thu, 13 Apr 2017 11:25:12 -0700 Subject: [PATCH 12/15] =?UTF-8?q?=F0=9F=90=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bin/manage.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/manage.sh b/bin/manage.sh index df4ab8c..cf38d65 100755 --- a/bin/manage.sh +++ b/bin/manage.sh @@ -36,7 +36,7 @@ onStart() { # replace zen hosts replaceZenHosts - # seccomp (not supported on joyent) + # disable seccomp (only supported on newer Linux kernels) replaceSeccomp } From 10546c61bb523db537a275bf20e9cddb5facf704 Mon Sep 17 00:00:00 2001 From: Shaun Berryman Date: Thu, 13 Apr 2017 12:29:33 -0700 Subject: [PATCH 13/15] Use consul members instead of consul-client --- bin/manage.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bin/manage.sh b/bin/manage.sh index cf38d65..414173c 100755 --- a/bin/manage.sh +++ b/bin/manage.sh @@ -46,17 +46,17 @@ health() { } waitForLeader() { - logDebug "Waiting for consul leader" + logDebug "Waiting for consul server" local tries=0 while true do - logDebug "Waiting for consul leader" + logDebug "Waiting for consul server" tries=$((tries + 1)) - local leader=$(consulCommand --template="{{.}}" status leader) - if [[ -n "$leader" ]]; then + local server=$(consul members -status alive | grep server) + if [[ -n "$server" ]]; then break elif [[ $tries -eq 60 ]]; then - echo "No consul leader" + echo "No consul server" exit 1 fi sleep 1 From 54eb733b32707260201214491a30b72fcb56147c Mon Sep 17 00:00:00 2001 From: Shaun Berryman Date: Tue, 23 May 2017 13:29:03 -0700 Subject: [PATCH 14/15] No need to wait for a leader if using consul-agent --- bin/manage.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bin/manage.sh b/bin/manage.sh index 414173c..0a73812 100755 --- a/bin/manage.sh +++ b/bin/manage.sh @@ -46,6 +46,11 @@ health() { } waitForLeader() { + # no need to wait for a leader unless we are using consul in agent mode + if [ $CONSUL_HOST != 'localhost' ]; then + return + fi + logDebug "Waiting for consul server" local tries=0 while true From 80d9c2b2d4d92ee674bd907e62babb36d7473f9e Mon Sep 17 00:00:00 2001 From: Shaun Berryman Date: Tue, 23 May 2017 13:29:29 -0700 Subject: [PATCH 15/15] Not sure why I was using 9200 here? We want to discover on port 9200 for other services --- etc/containerpilot.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/containerpilot.json b/etc/containerpilot.json index 3a3da18..80d7486 100644 --- a/etc/containerpilot.json +++ b/etc/containerpilot.json @@ -7,7 +7,7 @@ }, "services": [{ "name": "{{ .ES_SERVICE_NAME }}", - "port": 9300, + "port": 9200, "health": "/usr/local/bin/manage.sh health", "poll": 10, "ttl": 25