Skip to content

Commit

Permalink
ECK deployer bash script
Browse files Browse the repository at this point in the history
  • Loading branch information
Fotis Soldatos committed Aug 3, 2022
0 parents commit ea386af
Show file tree
Hide file tree
Showing 6 changed files with 293 additions and 0 deletions.
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# ECK stack Setup on Kubernetes

This directory includes all scripts needed for setting up a working ECK inside a Kubernetes cluster.

## Prerequisites

[Kubernetes](https://kubernetes.io/docs/setup/)

[kubectl](https://kubernetes.io/docs/tasks/tools/#kubectl)

[yq](https://github.com/mikefarah/yq)

## Run
```bash
./eck-deployer.sh <k8s-namespace> elastic-cluster.yaml kibana-agent.yaml beat-agent.yaml
```

## Legend

[elastic-cluster](./elastic-cluster.yaml), k8s manifest for a single `elasticsearch` CRD.

[kibana-agent](./kibana-agent.yaml),k8s manifest for a single `kibana` CRD.

[beat-agent](./beat-agent.yaml), k8s manifest for a single `beat` CRD.
86 changes: 86 additions & 0 deletions beat-agent.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
apiVersion: beat.k8s.elastic.co/v1beta1
kind: Beat
metadata:
name: filebeat
spec:
type: filebeat
version: 8.2.2 # version will be generated when running `./eck-deployer.sh`
elasticsearchRef:
name: elasticsearch
kibanaRef:
name: kibana
config:
filebeat.inputs:
- type: container
multiline.type: pattern
multiline.pattern: '^[[:space:]]'
multiline.negate: false
multiline.match: after
paths:
- /var/log/containers/*.log
processors:
- drop_fields:
fields: ["host.name", "ecs.version", "agent.version", "agent.type", "agent.id", "agent.ephemeral_id", "agent.hostname", "agent.name", "input.type", "stream", "log.offset", "log.flags"]
# https://discuss.elastic.co/t/docker-logs-includes-unreadable-in-kibana/303196/4
- decode_json_fields:
fields: ["message"]
process_array: false
max_depth: 2
target: ""
overwrite_keys: true
- script:
lang: javascript
source: >
function process(event){
var regex = new RegExp('\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])','g');
var clean = event.Get('message');
clean = clean.replace(regex, '');
event.Put('message',clean);
return event;
}
daemonSet:
podTemplate:
metadata:
labels:
app: filebeat
spec:
dnsPolicy: ClusterFirstWithHostNet
hostNetwork: true
securityContext:
runAsUser: 0
containers:
- name: filebeat
volumeMounts:
- name: varlogcontainers
mountPath: /var/log/containers
- name: varlogpods
mountPath: /var/log/pods
- name: varlibdockercontainers
mountPath: /var/lib/docker/containers
volumes:
- name: varlogcontainers
hostPath:
path: /var/log/containers
- name: varlogpods
hostPath:
path: /var/log/pods
- name: varlibdockercontainers
hostPath:
path: /var/lib/docker/containers
4 changes: 4 additions & 0 deletions config
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
ECK_VERSION=2.2.0
ELASTIC_CLUSTER_VERSION=8.2.2
KIBANA_AGENT_VERSION=8.2.2
BEAT_AGENT_VERSION=8.2.2
147 changes: 147 additions & 0 deletions eck-deployer.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
#!/usr/bin/env bash
set -o errexit
set -o nounset
#set -o xtrace

source config

if [ ! -x "$(command -v kubectl)" ]; then
echo >&2 "You must have kubectl installed to use this script."
exit 1
fi

if [ ! -x "$(command -v yq)" ]; then
echo >&2 "You must have yq (https://github.com/mikefarah/yq) installed to use this script."
exit 1
fi

function usage() {
echo >&2 "Usage: $0 <K8s-namespace> <elastic-cluster-manifest> <kibana-agent-manifest> <beat-agent-manifest>"
}

if [ $# -ne 4 ]; then
usage
exit 1
fi

K8S_NAMESPACE="${1}"
ELASTIC_CLUSTER_MANIFEST="${2}"
KIBANA_AGENT_MANIFEST="${3}"
BEAT_AGENT_MANIFEST="${4}"

function install-eck() {
install-eck-crds-and-operator
install-elastic-cluster
install-kibana-agent
install-beat-agent
print-kibana-connection-info
printf "\nDone!\n"
}

function install-eck-crds-and-operator() {
# Default namespace from the ECK operator deployment descriptors is `elastic-system`
DEFAULT_ECK_OPERATOR_NAMESPACE="elastic-system"
ECK_CRDS_DESCRIPTOR="https://download.elastic.co/downloads/eck/${ECK_VERSION}/crds.yaml"
ECK_OPERATOR_DESCRIPTOR="https://download.elastic.co/downloads/eck/${ECK_VERSION}/operator.yaml"

printf "\nInstalling ECK custom resource definitions...\n\n"
kubectl delete --wait=true --ignore-not-found=true -f "${ECK_CRDS_DESCRIPTOR}"
kubectl create -f "${ECK_CRDS_DESCRIPTOR}"
printf "\n"
kubectl --namespace "${DEFAULT_ECK_OPERATOR_NAMESPACE}" delete --wait=true --ignore-not-found=true -f "${ECK_OPERATOR_DESCRIPTOR}"
kubectl --namespace "${DEFAULT_ECK_OPERATOR_NAMESPACE}" wait pod -l control-plane=elastic-operator --for=delete --timeout=300s
kubectl --namespace "${DEFAULT_ECK_OPERATOR_NAMESPACE}" create -f "${ECK_OPERATOR_DESCRIPTOR}"
kubectl -n "${DEFAULT_ECK_OPERATOR_NAMESPACE}" wait --for=condition=Ready --timeout=300s pod -l control-plane=elastic-operator
printf "\nECK operator deployed successfully!\n"
}

function install-elastic-cluster() {
printf "\nInstalling Elastic cluster...\n\n"
# Bump elastic cluster version
yq e '.spec.version = "'"${ELASTIC_CLUSTER_VERSION}"'"' -i "${ELASTIC_CLUSTER_MANIFEST}"
ELASTIC_CLUSTER_NAME=$(yq e '.metadata.name' "${ELASTIC_CLUSTER_MANIFEST}")
ELASTIC_CLUSTER_LABEL=$(yq e '.spec.nodeSets[0].podTemplate.metadata.labels.app' "${ELASTIC_CLUSTER_MANIFEST}")

create-namespace "${K8S_NAMESPACE}" "${ELASTIC_CLUSTER_MANIFEST}"

# Waiting pod associated with CRD defined in $ELASTIC_CLUSTER_MANIFEST to be deleted
kubectl --namespace "${K8S_NAMESPACE}" wait pod -l app="${ELASTIC_CLUSTER_LABEL}" --for=delete --timeout=300s

kubectl --namespace "${K8S_NAMESPACE}" create -f "${ELASTIC_CLUSTER_MANIFEST}"
printf "\n"
kubectl --namespace "${K8S_NAMESPACE}" wait elasticsearch "${ELASTIC_CLUSTER_NAME}" --for=jsonpath='{.metadata.name}'="${ELASTIC_CLUSTER_NAME}" --timeout=400s

while ! kubectl -n "${K8S_NAMESPACE}" get secret "${ELASTIC_CLUSTER_NAME}"-es-elastic-user ; do echo "Waiting "${ELASTIC_CLUSTER_NAME}"-es-elastic-user secret to be created..."; sleep 3; done
while [[ $(kubectl --namespace "${K8S_NAMESPACE}" get pods -l app="${ELASTIC_CLUSTER_LABEL}" -o 'jsonpath={..status.conditions[?(@.type=="Ready")].status}') != "True" ]]; do echo "Waiting for elasticsearch pod to be Ready..." && sleep 3; done
kubectl --namespace "${K8S_NAMESPACE}" wait pod -l app="${ELASTIC_CLUSTER_LABEL}" --for=jsonpath='{.status.phase}'=Running --timeout=400s
printf "\nElastic cluster deployed successfully!\n"
}

function install-kibana-agent() {
printf "\nInstalling Kibana agent...\n\n"
# Bump kibana agent version
yq e '.spec.version = "'"${KIBANA_AGENT_VERSION}"'"' -i "${KIBANA_AGENT_MANIFEST}"
KIBANA_AGENT_NAME=$(yq e '.metadata.name' "${KIBANA_AGENT_MANIFEST}")
KIBANA_AGENT_LABEL=$(yq e '.spec.podTemplate.metadata.labels.app' "${KIBANA_AGENT_MANIFEST}")
create-namespace "${K8S_NAMESPACE}" "${KIBANA_AGENT_MANIFEST}"

# Waiting pod associated with CRD defined in $KIBANA_AGENT_MANIFEST to be deleted
kubectl --namespace "${K8S_NAMESPACE}" wait pod -l app="${KIBANA_AGENT_LABEL}" --for=delete --timeout=300s

kubectl --namespace "${K8S_NAMESPACE}" create -f "${KIBANA_AGENT_MANIFEST}"
printf "\n"
kubectl --namespace "${K8S_NAMESPACE}" wait kibana "${KIBANA_AGENT_NAME}" --for=jsonpath='{.metadata.name}'="${KIBANA_AGENT_NAME}" --timeout=400s

while [[ $(kubectl --namespace "${K8S_NAMESPACE}" get pods -l app="${KIBANA_AGENT_LABEL}" -o 'jsonpath={..status.conditions[?(@.type=="Ready")].status}') != "True" ]]; do echo "Waiting for kibana pod to be Ready..." && sleep 5; done
kubectl --namespace "${K8S_NAMESPACE}" wait pod -l app="${KIBANA_AGENT_LABEL}" --for=jsonpath='{.status.phase}'=Running --timeout=400s
printf "\nKibana agent deployed successfully!\n"
}

function install-beat-agent() {
printf "\nInstalling Beat agent...\n\n"
# Bump Beat agent version
yq e '.spec.version = "'"${BEAT_AGENT_VERSION}"'"' -i "${BEAT_AGENT_MANIFEST}"
yq e '.spec.version = "'"${BEAT_AGENT_VERSION}"'"' -i "${BEAT_AGENT_MANIFEST}"

BEAT_AGENT_NAME=$(yq e '.metadata.name' "${BEAT_AGENT_MANIFEST}")
BEAT_AGENT_LABEL=$(yq e '.spec.daemonSet.podTemplate.metadata.labels.app' "${BEAT_AGENT_MANIFEST}")

create-namespace "${K8S_NAMESPACE}" "${BEAT_AGENT_MANIFEST}"

# Waiting pod associated with CRD defined in $BEAT_AGENT_MANIFEST to be deleted
kubectl --namespace "${K8S_NAMESPACE}" wait pod -l app="${BEAT_AGENT_LABEL}" --for=delete --timeout=300s

kubectl --namespace "${K8S_NAMESPACE}" create -f "${BEAT_AGENT_MANIFEST}"
printf "\n"
kubectl --namespace "${K8S_NAMESPACE}" wait beat "${BEAT_AGENT_NAME}" --for=jsonpath='{.metadata.name}'="${BEAT_AGENT_NAME}" --timeout=400s

while ! kubectl --namespace "${K8S_NAMESPACE}" get pod -l app="${BEAT_AGENT_LABEL}" ; do echo "Waiting beat pods to be created..."; sleep 3; done
kubectl --namespace "${K8S_NAMESPACE}" wait pod -l app="${BEAT_AGENT_LABEL}" --for=jsonpath='{.status.phase}'=Running --timeout=400s
printf "\nBeat agent deployed successfully!\n"
}

function create-namespace() {
# Create namespace iff does not exist or delete the resources specified inside the manifest file
if [ "$(kubectl get ns | grep "${1}" | cut -d ' ' -f1)" == "${1}" ]; then
printf "K8s namespace [%s] already exists! \n\n" "$1"
printf "Deleting K8s resources specified in [%s] manifest... \n" "${2}"

kubectl --namespace "${1}" delete --wait=true --ignore-not-found=true -f "${2}"
printf "\n"
else
echo "Creating K8s namespace [${1}]..."
kubectl create namespace "${1}"
fi
}

function print-kibana-connection-info() {
NODE_IP=$(kubectl get nodes --selector=kubernetes.io/role!=master -o jsonpath={.items[0].status.addresses[?\(@.type==\"InternalIP\"\)].address})
ELASTICSEARCH_NAME=$(yq e '.metadata.name' "${ELASTIC_CLUSTER_MANIFEST}")
KIBANA_PASSWORD=$(kubectl -n "${K8S_NAMESPACE}" get secret "${ELASTICSEARCH_NAME}"-es-elastic-user -o=jsonpath='{.data.elastic}' | base64 --decode; echo)

printf "Access Kibana UI through [https://%s:5601]\n\n" "${NODE_IP}"
printf "Username: elastic\n"
printf "Password: %s\n" "${KIBANA_PASSWORD}"
}

install-eck
15 changes: 15 additions & 0 deletions elastic-cluster.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
apiVersion: elasticsearch.k8s.elastic.co/v1
kind: Elasticsearch
metadata:
name: elasticsearch
spec:
version: 8.2.2 # version will be generated when running `./eck-deployer.sh`
nodeSets:
- name: default
count: 1 # number of Elastic clusters to deploy
podTemplate:
metadata:
labels:
app: elasticsearch
config:
node.store.allow_mmap: false # https://www.elastic.co/guide/en/cloud-on-k8s/current/k8s-virtual-memory.html#k8s-virtual-memory
17 changes: 17 additions & 0 deletions kibana-agent.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
apiVersion: kibana.k8s.elastic.co/v1
kind: Kibana
metadata:
name: kibana
spec:
version: 8.2.2 # version will be generated when running `./eck-deployer.sh`
count: 1 # number of Kibana agents to deploy
podTemplate:
metadata:
labels:
app: kibana
elasticsearchRef:
name: elasticsearch
http:
service:
spec:
type: LoadBalancer

0 comments on commit ea386af

Please sign in to comment.