Mon, 22 Oct 2018 03:34:00 +0100

How to use Prometheus with Kubernetes on Docker for Mac

Prometheus is a tool for monitoring. It works by fetching information from user-defined servers that provides a certain endpoint for stats. The data is stored in a time series database and can easily be queried by a visualization tool like grafana.

A service that provides an endpoint does it in a Prometheus specific way. Say you want to count "pageviews". You create a counter and you call for every pageview, then whenever Prometheus scapes your endpoint, the counter resets. This way only have to fetch a single number, but it knows the time since last crawl and can therefore divide it.

Say the counter says 1000 pageviews and Prometheus knows it was 10 seconds ago it last crawled the endpoint, it can then show that you have 100 pageviews / per second.

Simple, efficient and smart!

And Kubernetes has a built in way to automatically query the Kubernetes API server which lets you get started even quicker and with less manual work!

Running Prometheus

First, we need to run Prometheus just to get started and see we can get it working.

We can find Prometheus on Docker hub which makes it easy for us to get started.

https://hub.docker.com/r/prom/prometheus/

Then we can create a folder and create our first prometheus config file called prometheus.yaml:

global:
  scrape_interval:     15s # By default, scrape targets every 15 seconds.

  # Attach these labels to any time series or alerts when communicating with
  # external systems (federation, remote storage, Alertmanager).
  external_labels:
    monitor: 'codelab-monitor'

# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
  # The job name is added as a label `job=<job_name>`
  # to any timeseries scraped from this config.
  - job_name: 'prometheus'

    # Override the global default and scrape targets
    # from this job every 5 seconds.
    scrape_interval: 5s

    static_configs:
      - targets: ['localhost:9090']

and then run it first with docker locally to test it:

docker run -it -p 9090:9090 -v $PWD/prometheus.yaml:/etc/prometheus.yaml \
  prom/prometheus --config.file=/etc/prometheus.yaml

To test it open it up in you browser and navigate to localhost:9090.

You will se a simple interface and try to run your first query.

Try typing in:

prometheus_target_interval_length_seconds

Running in Kubernetes for Mac

Now we need a config for Kubernetes, and we are going to use this documentation to write it.

Append a new job that will query all the kubernetes nodes:

- job_name: 'kubernetes-nodes'

  scheme: https

  tls_config:
    ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
    insecure_skip_verify: true
  bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token

  kubernetes_sd_configs:
  - role: node

And your file will looks like this:

global:
  scrape_interval:     15s # By default, scrape targets every 15 seconds.

  # Attach these labels to any time series or alerts when communicating with
  # external systems (federation, remote storage, Alertmanager).
  external_labels:
    monitor: 'codelab-monitor'

# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
  # The job name is added as a label `job=<job_name>`
  # to any timeseries scraped from this config.
  - job_name: 'prometheus'

    # Override the global default and scrape targets
    # from this job every 5 seconds.
    scrape_interval: 5s

    static_configs:
      - targets: ['localhost:9090']
  - job_name: 'kubernetes-nodes'

    kubernetes_sd_configs:
    - role: node

First we create a namespace where we can store all the config and deployments:

kubectl create namespace monitoring

We need to create a service account that will be injected in a namespace:

apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
  name: prometheus
rules:
- apiGroups: [""]
  resources:
  - nodes
  - nodes/proxy
  - services
  - endpoints
  - pods
  verbs: ["get", "list", "watch"]
- apiGroups:
  - extensions
  resources:
  - ingresses
  verbs: ["get", "list", "watch"]
- nonResourceURLs: ["/metrics"]
  verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: prometheus
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: prometheus
subjects:
- kind: ServiceAccount
  name: default
  namespace: monitoring

and we can convert that into a configMap in Kubernetes:

apiVersion: v1
kind: ConfigMap
metadata:
  name: prometheus-server-conf
  labels:
    name: prometheus-server-conf
  namespace: monitoring
data:
  prometheus.yml: |-
    global:
      scrape_interval: 5s # By default, scrape targets every 15 seconds.

      # Attach these labels to any time series or alerts when communicating with
      # external systems (federation, remote storage, Alertmanager).
      external_labels:
        monitor: 'codelab-monitor'

    # A scrape configuration containing exactly one endpoint to scrape:
    # Here it's Prometheus itself.
    scrape_configs:
      # The job name is added as a label `job=<job_name>`
      # to any timeseries scraped from this config.
      - job_name: 'prometheus'

        # Override the global default and scrape targets
        # from this job every 5 seconds.
        scrape_interval: 5s

        static_configs:
          - targets: ['localhost:9090']
      - job_name: 'kubernetes-nodes'

        scheme: https

        tls_config:
          ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
          insecure_skip_verify: true
        bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token

        kubernetes_sd_configs:
        - role: node

and to deploy it we need a deployment.yaml

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: prometheus-deployment
  namespace: monitoring
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: prometheus-server
    spec:
      containers:
        - name: prometheus
          image: prom/prometheus:v2.4.3
          args:
            - "--config.file=/etc/prometheus/prometheus.yml"
            - "--storage.tsdb.path=/prometheus/"
          ports:
            - containerPort: 9090
          volumeMounts:
            - name: prometheus-config-volume
              mountPath: /etc/prometheus/
            - name: prometheus-storage-volume
              mountPath: /prometheus/
      volumes:
        - name: prometheus-config-volume
          configMap:
            defaultMode: 420
            name: prometheus-server-conf
        - name: prometheus-storage-volume
          emptyDir: {}

Now you can port forward to the prometheus container with and see it in the browser:

$ kubectl port-forward deploy/prometheus-deployment 9090 --namespace=monitoring

Now you can visit the prometheus site on localhost:9090 again.

Now type in:

kubelet_running_container_count

And you will get how many containers are running per node.

Congrats, you now have Prometheus running on Docker for Mac and you can now try even more!