Wednesday 7 August 2019

Grafana / Infludb K8s deployment via piepline

Grafana


1. Dockerfile


FROM grafana/grafana:latest
LABEL description="Grafana docker image with custom setup"
ENV GF_SMTP_ENABLED true
ENV GF_SMTP_HOST mxrelay.ara.ac.nz:25
ENV GF_SMTP_FROM_ADDRESS admin@grafana.ara.ac.nz

USER root

RUN apt-get -q update &&\
    DEBIAN_FRONTEND="noninteractive" apt-get -q upgrade -y -o Dpkg::Options::="--force-confnew" --no-install-recommends &&\
    DEBIAN_FRONTEND="noninteractive" apt-get -q install -y -o Dpkg::Options::="--force-confnew" --no-install-recommends curl gosu &&\
    apt-get -q autoremove &&\
    apt-get -q clean -y && rm -rf /var/lib/apt/lists/* && rm -f /var/cache/apt/*.bin

ADD run.sh /run.sh
RUN chmod +x /run.sh
RUN mkdir -p /opt/grafana/dashboards
ADD ["*.json", "/opt/grafana/dashboards/"]
ADD ["default-dashboard.yaml", "/etc/grafana/provisioning/dashboards/"]
ADD ["notification.yaml", "/etc/grafana/provisioning/notifiers/"]
ENTRYPOINT ["/run.sh", "GF_SMTP_ENABLED", "GF_SMTP_HOST", "GF_SMTP_FROM_ADDRESS"]

2. run.sh


#!/bin/bash -e

: "${GF_PATHS_DATA:=/var/lib/grafana}"
: "${GF_PATHS_LOGS:=/var/log/grafana}"
: "${GF_PATHS_PLUGINS:=/var/lib/grafana/plugins}"
: "${GF_PATHS_PROVISIONING:=/etc/grafana/provisioning}"
: "${GF_SMTP_FROM_ADDRESS:=admin@grafana.ara.ac.nz}"
: "${GF_SMTP_ENABLED:=true}"
: "${GF_SMTP_HOST:=mxrelay.ara.ac.nz:25}"

chown -R grafana:grafana "$GF_PATHS_DATA" "$GF_PATHS_LOGS"
chown -R grafana:grafana /etc/grafana

# Start grafana with gosu
exec gosu grafana /usr/share/grafana/bin/grafana-server  \
  --homepath=/usr/share/grafana             \
  --config=/etc/grafana/grafana.ini         \
  cfg:default.paths.data="$GF_PATHS_DATA"   \
  cfg:default.paths.logs="$GF_PATHS_LOGS"   \
  cfg:default.paths.plugins="$GF_PATHS_PLUGINS" \
  cfg:default.smtp.enabled="$GF_SMTP_ENABLED" \
  cfg:default.smtp.host="$GF_SMTP_HOST" \
  cfg:default.smtp.from_address="$GF_SMTP_FROM_ADDRESS" &

sleep 5

###############################################################
# Creating Default Data Source

# Set new Data Source name
INFLUXDB_DATA_SOURCE="InfluxDB"
INFLUXDB_DATA_SOURCE_WEB=`echo ${INFLUXDB_DATA_SOURCE} | sed 's/ /%20/g'`

# Set information about grafana host
GRAFANA_URL=`hostname -i`
GRAFANA_PORT="3000"
GRAFANA_USER="admin"
GRAFANA_PASSWORD="admin"

# Check $INFLUXDB_DATA_SOURCE status
INFLUXDB_DATA_SOURCE_STATUS=`curl -s -L -i \
 -H "Accept: application/json" \
 -H "Content-Type: application/json" \
 -X GET http://${GRAFANA_USER}:${GRAFANA_PASSWORD}@${GRAFANA_URL}:${GRAFANA_PORT}/api/datasources/name/${INFLUXDB_DATA_SOURCE_WEB} | head -1 | awk '{print $2}'`

#Debug Time!
curl -s -L -i \
 -H "Accept: application/json" \
 -H "Content-Type: application/json" \
 -X GET http://${GRAFANA_USER}:${GRAFANA_PASSWORD}@${GRAFANA_URL}:${GRAFANA_PORT}/api/datasources/name/${INFLUXDB_DATA_SOURCE_WEB} >>$GF_PATHS_LOGS/grafana.log 2>>$GF_PATHS_LOGS/grafana.log 
echo "http://${GRAFANA_USER}:${GRAFANA_PASSWORD}@${GRAFANA_URL}:${GRAFANA_PORT}/api/datasources/name/${INFLUXDB_DATA_SOURCE_WEB}" >> $GF_PATHS_LOGS/grafana.log
echo "INFLUXDB_DATA_SOURCE_STATUS: "$INFLUXDB_DATA_SOURCE_STATUS >> $GF_PATHS_LOGS/grafana.log
echo "GRAFANA_URL: "$GRAFANA_URL >> $GF_PATHS_LOGS/grafana.log
echo "GRAFANA_PORT: "$GRAFANA_PORT >> $GF_PATHS_LOGS/grafana.log
echo "GRAFANA_USER: "$GRAFANA_USER >> $GF_PATHS_LOGS/grafana.log
echo "GRAFANA_PASSWORD: "$GRAFANA_PASSWORD >> $GF_PATHS_LOGS/grafana.log

# Check if $INFLUXDB_DATA_SOURCE exists
if [ ${INFLUXDB_DATA_SOURCE_STATUS} != 200 ]
then
  # If not exists, create one 
  echo "Data Source: '"${INFLUXDB_DATA_SOURCE}"' not found in Grafana configuration"
  echo "Creating Data Source: '"$INFLUXDB_DATA_SOURCE"'"
  curl -L -i \
   -H "Accept: application/json" \
   -H "Content-Type: application/json" \
   -X POST -d '{
    "name":"'"${INFLUXDB_DATA_SOURCE}"'",
    "type":"influxdb",
    "url":"http://influxdb:8086",
    "access":"proxy",
    "basicAuth":false,
    "database":"telegraf",
    "user":"grafana",
    "password":"grafana"}
  ' \
  http://${GRAFANA_USER}:${GRAFANA_PASSWORD}@${GRAFANA_URL}:${GRAFANA_PORT}/api/datasources
else
  #Continue if it doesn't exists
  echo "Data Source '"${INFLUXDB_DATA_SOURCE}"' already exists."
fi

tail -f $GF_PATHS_LOGS/grafana.log

3. graf-serv-deploy.yml


---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: grafana
  namespace: default
  labels:
    app: grafana
spec:
  replicas: 1
  selector:
    matchLabels:
      app: grafana
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: grafana
    spec:
      containers:
      - image: araregistry.azurecr.io/ara/nashgrafana:latest
        imagePullPolicy: Always
        name: nashgrafana
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
      dnsPolicy: ClusterFirst
      imagePullSecrets:
      - name: azurecr
      restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: grafana
  name: grafana
  namespace: default
spec:
  type: NodePort
  ports:
  - nodePort: 30030
    port: 3000
    protocol: TCP
    targetPort: 3000
  selector:
    app: grafana

4. notification.yml


notifiers:
  - name: notification-channel
    type: email
    uid: notifier1
    org_name: Main Org.
    is_default: true
    disable_resolve_message: false
    settings:
      addresses: naveed.sheikh@ara.ac.nz

5. default-dashboard.yml


# # config file version
apiVersion: 1

providers:
 - name: 'default'
   orgId: 1
   folder: ''
   type: file
   options:
     path: /opt/grafana/dashboards

6. Jenkinsfile


pipeline {
  agent any
  stages {
    stage('Build') {
      environment {
        KUBECONFIG = '/home/isadmin/.kube/config-mon1'
      }
      steps {
        sh '''sudo docker build -t araregistry.azurecr.io/ara/nashgrafana:latest -f Dockerfile .

sudo docker push araregistry.azurecr.io/ara/nashgrafana:latest'''
      }
    }
    stage('Pull Changes') {
      steps {
        sh '''sudo ssh -T root@logmon1.ara.ac.nz docker login araregistry.azurecr.io -u AraRegistry -p xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

sudo ssh -T root@logmon1.ara.ac.nz docker pull araregistry.azurecr.io/ara/nashgrafana:latest'''
      }
    }
    stage('Deploy') {
      steps {
        sh '''# Deploy service
kubectl apply -f ${WORKSPACE}/fullgrafana.yml'''
      }
    }
  }
  environment {
    KUBECONFIG = '/home/isadmin/.kube/config-mon1'
  }
}

--------------------------------------------------------------------------------------------------------------------------

InfluxdB



1. Dockerfile


FROM influxdb:latest
LABEL description="InfluxDB docker image with custom setup"

USER root

ADD influxdb.template.conf /influxdb.template.conf

ADD run.sh /run.sh
RUN chmod +x /run.sh

CMD ["/run.sh"]


2. Jenkinsfile


pipeline {
  agent any
  stages {
    stage('Build') {
      environment {
        KUBECONFIG = '/home/isadmin/.kube/config-mon1'
      }
      steps {
        sh '''sudo docker build -t araregistry.azurecr.io/ara/nashflux:latest -f Dockerfile .

sudo docker push araregistry.azurecr.io/ara/nashflux:latest'''
      }
    }
    stage('Pull Changes') {
      steps {
        sh '''sudo ssh -T root@logmon1.ara.ac.nz docker login araregistry.azurecr.io -u AraRegistry -p xxxxxxxxxxxxxxxxxxx

sudo ssh -T root@logmon1.ara.ac.nz docker pull araregistry.azurecr.io/ara/nashflux:latest'''
      }
    }
    stage('Deploy') {
      steps {
        sh '''# Deploy service
kubectl apply -f ${WORKSPACE}/fulldeploymentinflux.yml'''
      }
    }
  }
  environment {
    KUBECONFIG = '/home/isadmin/.kube/config-mon1'
  }
}

3. run.sh


#!/bin/bash

set -m
CONFIG_TEMPLATE="/influxdb.template.conf"
CONFIG_FILE="/etc/influxdb/influxdb.conf"
CURR_TIMESTAMP=`date +%s`

INFLUX_HOST="localhost"
INFLUX_API_PORT="8086"
[ "${INFLUX_ADMIN_USER}" = "" ] &&
        INFLUX_ADMIN_USER="grafana"
[ "${INFLUX_ADMIN_PASS}" = "" ] &&
        INFLUX_ADMIN_PASS="grafana"
[ "${INFLUX_DATABASE}" = "" ] &&
        INFLUX_DATABASE="telegraf"

mv -v $CONFIG_FILE $CONFIG_FILE.$CURR_TIMESTAMP
cp -v $CONFIG_TEMPLATE $CONFIG_FILE

exec influxd -config=$CONFIG_FILE 1>>/var/log/influxdb/influxdb.log 2>&1 &
sleep 5

USER_EXISTS=`influx -host=${INFLUX_HOST} -port=${INFLUX_API_PORT} -execute="SHOW USERS" | awk '{print $1}' | grep "${INFLUX_ADMIN_USER}" | wc -l`

if [ -n ${USER_EXISTS} ]
then
  influx -host=${INFLUX_HOST} -port=${INFLUX_API_PORT} -execute="CREATE USER ${INFLUX_ADMIN_USER} WITH PASSWORD '${INFLUX_ADMIN_PASS}' WITH ALL PRIVILEGES"
  influx -host=${INFLUX_HOST} -port=${INFLUX_API_PORT} -username=${INFLUX_ADMIN_USER} -password="${INFLUX_ADMIN_PASS}" -execute="create database ${INFLUX_DATABASE} WITH DURATION 180d NAME biannual"
fi

tail -f /var/log/influxdb/influxdb.log

4. influx-serv-full.yml


---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  namespace: default
  name: standard
provisioner: kubernetes.io/host-path
volumeBindingMode: WaitForFirstConsumer
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: influxvol
  namespace: default
spec:
  storageClassName: 'standard'
  capacity:
    storage: 100Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/var/k8sdata"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: influxvol
  namespace: default
spec:
  storageClassName: 'standard'
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 100Gi
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: influxdb
  namespace: default
  labels:
    app: influxdb
spec:
  replicas: 1
  selector:
    matchLabels:
      app: influxdb
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: influxdb
    spec:
      containers:
      - image: araregistry.azurecr.io/ara/nashflux:latest
        imagePullPolicy: Always
        name: nashflux
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
        ports:
        - containerPort: 8086
        volumeMounts:
        - name: influxstorage
          mountPath: /var/lib/influxdb
      volumes:
      - name: influxstorage
        persistentVolumeClaim:
          claimName: influxvol
      dnsPolicy: ClusterFirst
      imagePullSecrets:
      - name: azurecr
      restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: influxdb
  name: influxdb
  namespace: default
spec:
  type: NodePort
  ports:
  - nodePort: 31050
    port: 8086
    protocol: TCP
    targetPort: 8086
  selector:
    app: influxdb

--------------------------------------------------------------------------------------------------------------------------

Dont forget to add secret and if 1 node master then untaint the master node for this to work.

Thanks

Tuesday 6 August 2019

Telegraf for K8s Cluster monitering

RBAC

kubectl create clusterrolebinding default-admin --clusterrole cluster-admin --serviceaccount=default:default

Secret

kubectl create secret -n monitoring generic telegraf --from-literal=env=prod --from-literal=monitor_username=youruser --from-literal=monitor_password=yourpassword --from-literal=monitor_host=https://your.influxdb.local --from-literal=monitor_database=yourdb

Daemon apply

apiVersion: v1
kind: ConfigMap
metadata:
  name: telegraf
  namespace: monitoring
  labels:
    k8s-app: telegraf
data:
  telegraf.conf: |+
    [global_tags]
      env = "$ENV"
    [agent]
      hostname = "$HOSTNAME"
    [[outputs.influxdb]]
      urls = ["$MONITOR_HOST"] # required
      database = "$MONITOR_DATABASE" # required
      timeout = "5s"
      username = "$MONITOR_USERNAME"
      password = "$MONITOR_PASSWORD"
   
    [[inputs.cpu]]
      percpu = true
      totalcpu = true
      collect_cpu_time = false
      report_active = false
    [[inputs.disk]]
      ignore_fs = ["tmpfs", "devtmpfs", "devfs"]
    [[inputs.diskio]]
    [[inputs.kernel]]
    [[inputs.mem]]
    [[inputs.processes]]
    [[inputs.swap]]
    [[inputs.system]]
    [[inputs.net]]
    [[inputs.docker]]
      endpoint = "unix:///var/run/docker/libcontainerd/docker-containerd.sock"
    [[inputs.kubernetes]]
      url = "https://$HOSTNAME:10250"
      #bearer_token = "/var/run/secrets/kubernetes.io/serviceaccount/token"
      bearer_token_string = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
      insecure_skip_verify = true

---
# Section: Daemonset
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: telegraf
  namespace: monitoring
  labels:
    k8s-app: telegraf
spec:
  selector:
    matchLabels:
      name: telegraf
  template:
    metadata:
      labels:
        name: telegraf
    spec:
      containers:
      - name: telegraf
        image: docker.io/telegraf:latest
        resources:
          limits:
            memory: 500Mi
          requests:
            cpu: 500m
            memory: 500Mi
        env:
        - name: HOSTNAME
          valueFrom:
            fieldRef:
              fieldPath: spec.nodeName
        - name: "HOST_PROC"
          value: "/rootfs/proc"
        - name: "HOST_SYS"
          value: "/rootfs/sys"
        - name: ENV
          valueFrom:
            secretKeyRef:
              name: telegraf
              key: env
        - name: MONITOR_USERNAME
          valueFrom:
            secretKeyRef:
              name: telegraf
              key: monitor_username
        - name: MONITOR_PASSWORD
          valueFrom:
            secretKeyRef:
              name: telegraf
              key: monitor_password
        - name: MONITOR_HOST
          valueFrom:
            secretKeyRef:
              name: telegraf
              key: monitor_host
        - name: MONITOR_DATABASE
          valueFrom:
            secretKeyRef:
              name: telegraf
              key: monitor_database
        volumeMounts:
        - name: sys
          mountPath: /rootfs/sys
          readOnly: true
        - name: proc
          mountPath: /rootfs/proc
          readOnly: true
        - name: docker-socket
          mountPath: /var/run/docker/libcontainerd/docker-containerd.sock
          readOnly: true
        - name: utmp
          mountPath: /var/run/utmp
          readOnly: true
        - name: config
          mountPath: /etc/telegraf
      terminationGracePeriodSeconds: 30
      volumes:
      - name: sys
        hostPath:
          path: /sys
      - name: docker-socket
        hostPath:
          path: /var/run/docker/libcontainerd/docker-containerd.sock
      - name: proc
        hostPath:
          path: /proc
      - name: utmp
        hostPath:
          path: /var/run/utmp
      - name: config
        configMap:
          name: telegraf