How to use swift as object storage for Thanos (Prometheus)?
Thanos is gaining lot of popularity in the prometheus community. It’s easy to do deploy prometheus using operator but while running prometheus in HA setup, we have limited options like running two instances of prometheus which are scraping the same targets. Since they are scraping the same targets hence they are generating the same alert twice. Other issues with prometheus was with downsampling and long term storage retention. To overcome these challenges, thanos is introduced.
If you want to read more about Thanos
Official examples in Thanos repoistory provides the configuration for integrating GCS (Google cloud storage) but everybody doesn’t have access to public cloud storage. To do the PoC I was supposed to use opensource solution swift. By default, when you are deploying openstack setup using packstack, swift is deployed in it. Instead of spending time on standalone swift deployment I thought of using the existing swift in packstack setup.
For accessing the swift in packstack I am using admin credentials. I will put the same credentials in Thanos sidecar container so that it can push the dataset to swift bucket.
- Create a bucket or container in openstack swift. We don’t have objects in container by default.
[root@packstack1 ~]# source keystonerc_admin
[root@packstack1 ~(keystone_admin)]# swift post test3
[root@packstack1 ~(keystone_admin)]# swift stat test3
Account: AUTH_45a6706c831c42d5bf2da928573382b1
Container: test3
Objects: 0
Bytes: 0
Read ACL:
Write ACL:
Sync To:
Sync Key:
Accept-Ranges: bytes
X-Storage-Policy: Policy-0
Last-Modified: Thu, 10 Jan 2019 04:06:37 GMT
X-Timestamp: 1547093196.88206
X-Trans-Id: txe98f86f79560438db790f-005c36c4dc
Content-Type: application/json; charset=utf-8
X-Openstack-Request-Id: txe98f86f79560438db790f-005c36c4dc
- Use the following manifest for creating that prometheus setup with thanos-sidecar injected. I intentionally kept the
storage.tsdb.retention
to very low value so that it can quickly start dumping the datasets to object store.
If you want to try the same manifest in your environment. You need to change the swift config map according to your setup. IP address is obfuscated in manifest.
cat <<EOF | kubectl create -f -
apiVersion: v1
kind: ServiceAccount
metadata:
name: prometheus
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: prometheus
rules:
- apiGroups: [""]
resources:
- nodes
- services
- endpoints
- pods
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources:
- configmaps
verbs: ["get"]
- 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: prometheus
namespace: default
---
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
name: prometheus
labels:
app: prometheus
thanos-peer: "true"
spec:
serviceName: "prometheus"
replicas: 2
selector:
matchLabels:
app: prometheus
thanos-peer: "true"
template:
metadata:
labels:
app: prometheus
thanos-peer: "true"
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "10902"
spec:
serviceAccountName: prometheus
## Commented out because Minikube has only one node, should be commented in for any production setup
# affinity:
# podAntiAffinity:
# requiredDuringSchedulingIgnoredDuringExecution:
# - labelSelector:
# matchExpressions:
# - key: app
# operator: In
# values:
# - prometheus
# topologyKey: kubernetes.io/hostname
containers:
- name: prometheus
image: quay.io/prometheus/prometheus:v2.0.0
# To quickly see the objects in swift timing values are set to very low value. It's not recommended for production.
args:
- "--storage.tsdb.retention=10m"
- "--config.file=/etc/prometheus-shared/prometheus.yml"
- "--storage.tsdb.path=/var/prometheus"
- "--storage.tsdb.min-block-duration=5m"
- "--storage.tsdb.max-block-duration=5m"
- "--web.enable-lifecycle"
ports:
- name: prom-http
containerPort: 9090
volumeMounts:
- name: config-shared
mountPath: /etc/prometheus-shared
- name: data
mountPath: /var/prometheus
- name: thanos-sidecar
# Always use explicit image tags (release or master-<date>-sha) instead of ambigous `latest` or `master`.
image: improbable/thanos:v0.2.1
args:
- "sidecar"
- "--log.level=debug"
- "--tsdb.path=/var/prometheus"
- "--prometheus.url=http://127.0.0.1:9090"
- "--cluster.peers=thanos-peers.default.svc.cluster.local:10900"
- "--reloader.config-file=/etc/prometheus/prometheus.yml.tmpl"
- "--reloader.config-envsubst-file=/etc/prometheus-shared/prometheus.yml"
- "--objstore.config-file=/creds/swift_access_information.yaml"
ports:
- name: sidecar-http
containerPort: 10902
- name: grpc
containerPort: 10901
- name: cluster
containerPort: 10900
volumeMounts:
- name: data
mountPath: /var/prometheus
- name: config-shared
mountPath: /etc/prometheus-shared
- name: config
mountPath: /etc/prometheus
- name: swiftconfig
mountPath: /creds
volumes:
- name: config
configMap:
name: prometheus-config
- name: config-shared
emptyDir: {}
- name: data
emptyDir: {}
- name: swiftconfig
configMap:
name: swiftinfo
---
apiVersion: v1
kind: ConfigMap
metadata:
name: prometheus-config
data:
prometheus.yml.tmpl: |-
global:
external_labels:
monitor: prometheus
replica: '$(HOSTNAME)'
scrape_configs:
- job_name: prometheus
static_configs:
- targets:
- "127.0.0.1:9090"
- job_name: kubelets
kubernetes_sd_configs:
- role: node
- job_name: kube_pods
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
action: replace
target_label: __metrics_path__
regex: (.+)
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scheme]
action: replace
target_label: __scheme__
regex: (https?)
- source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]
action: replace
regex: (.+?)(?::\d+)?;(\d+)
replacement: ${1}:${2}
target_label: __address__
- action: labelmap
regex: __meta_kubernetes_pod_label_(.+)
- source_labels: [__meta_kubernetes_pod_namespace]
action: replace
target_label: kubernetes_namespace
- source_labels: [__meta_kubernetes_pod_name]
action: replace
target_label: kubernetes_pod_name
# Scrapes the endpoint lists for the main Prometheus endpoints
- job_name: kube_endpoints
kubernetes_sd_configs:
- role: endpoints
relabel_configs:
- action: keep
source_labels: [__meta_kubernetes_service_label_app]
regex: prometheus
- action: replace
source_labels: [__meta_kubernetes_service_label_app]
target_label: job
- action: replace
target_label: prometheus
source_labels: [__meta_kubernetes_service_label_prometheus]
---
apiVersion: v1
kind: Service
metadata:
labels:
app: prometheus
name: prometheus
spec:
externalTrafficPolicy: Cluster
ports:
- port: 9090
protocol: TCP
targetPort: prom-http
name: http-prometheus
- port: 10902
protocol: TCP
targetPort: sidecar-http
name: http-sidecar-metrics
selector:
app: prometheus
sessionAffinity: None
type: NodePort
status:
loadBalancer: {}
---
apiVersion: v1
kind: Service
metadata:
name: thanos-peers
spec:
type: ClusterIP
clusterIP: None
ports:
- name: cluster
port: 10900
targetPort: cluster
selector:
# Useful endpoint for gathering all thanos components for common gossip cluster.
thanos-peer: "true"
---
apiVersion: v1
kind: ConfigMap
metadata:
name: swiftinfo
# For example only ConfigMap is used for normal usage secret is recommended instead of ConfigMap
data:
swift_access_information.yaml: |
type: SWIFT
config:
auth_url: "http://10.121.xx.xx:5000/v3"
username: admin
password: 4019b525ee414a4c
tenant_name: admin
container_name: test3
domain_name: Default
- We should be able to see the two prometheus replica in the running status along with Thanos sidecar.
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
prometheus-0 2/2 Running 1 3m
prometheus-1 2/2 Running 1 3m
Also in openstack we can see that number of objects in container is increased.
[root@packstack1 ~(keystone_admin)]# swift stat test3
Account: AUTH_45a6706c831c42d5bf2da928573382b1
Container: test3
Objects: 48
Bytes: 8123441
Read ACL:
Write ACL:
Sync To:
Sync Key:
Accept-Ranges: bytes
X-Storage-Policy: Policy-0
Last-Modified: Thu, 10 Jan 2019 04:06:37 GMT
X-Timestamp: 1547093196.88206
X-Trans-Id: txa3c475b6c15749349d906-005c36ccdb
Content-Type: application/json; charset=utf-8
X-Openstack-Request-Id: txa3c475b6c15749349d906-005c36ccdb
- Keep an eye on thanos-sidecar logs to see the dataset dumped to object storage.
kubectl logs prometheus-0 -c thanos-sidecar | grep 'shipper.go'
level=info ts=2019-01-10T04:12:44.092071737Z caller=shipper.go:201 msg="upload new block" id=01D0TZC903FHNFMBHQGYGXXWJA
level=info ts=2019-01-10T04:17:43.682245251Z caller=shipper.go:201 msg="upload new block" id=01D0TZNDZ5Q09TVVZWG5XCF54K
level=info ts=2019-01-10T04:22:44.017883724Z caller=shipper.go:201 msg="upload new block" id=01D0TZYJZ7AHH45S86TSFQ4GE4
level=info ts=2019-01-10T04:27:44.011867423Z caller=shipper.go:201 msg="upload new block" id=01D0V07QYRPQT71MK27202NCPA
level=info ts=2019-01-10T04:32:44.553502153Z caller=shipper.go:201 msg="upload new block" id=01D0V0GWW5NABS9KFZP7ZPEPZB
level=info ts=2019-01-10T04:37:43.689988084Z caller=shipper.go:201 msg="upload new block" id=01D0V0T1WSSD5V1CJJ3M8AD96X
- Once the dataset is dumped to object storage to query that data from object store you need storage gateway. This storage gateway also need to use the swift credentials to query the datasets.
cat <<EOF | kubectl create -f -
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: thanos-store
spec:
serviceName: "thanos-store"
replicas: 1
selector:
matchLabels:
app: thanos
thanos-peer: "true"
template:
metadata:
labels:
app: thanos
thanos-peer: "true"
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "10902"
spec:
containers:
- name: thanos-store
# Always use explicit image tags (release or master-<date>-sha) instead of ambigous `latest` or `master`.
image: improbable/thanos:v0.2.1
args:
- "store"
- "--log.level=debug"
- "--data-dir=/var/thanos/store"
- "--cluster.peers=thanos-peers.default.svc.cluster.local:10900"
- "--objstore.config-file=/creds/swift_access_information.yaml"
ports:
- name: http
containerPort: 10902
- name: grpc
containerPort: 10901
- name: cluster
containerPort: 10900
volumeMounts:
- name: swiftconfig
mountPath: /creds
- name: data
mountPath: /var/thanos/store
volumes:
- name: data
emptyDir: {}
# configmap is not recommended for production use. It's used only for example.
- name: swiftconfig
configMap:
name: swiftinfo
EOF
- We spoke about query the dataset from object store but where is my query componenet here you go : Manifest to create the thanos-query.
cat <<EOF | kubectl create -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: thanos-query
labels:
app: thanos-query
thanos-peer: "true"
spec:
replicas: 2
selector:
matchLabels:
app: thanos-query
thanos-peer: "true"
template:
metadata:
labels:
app: thanos-query
thanos-peer: "true"
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "10902"
spec:
containers:
- name: thanos-query
# Always use explicit image tags (release or master-<date>-sha) instead of ambigous `latest` or `master`.
image: improbable/thanos:v0.2.1
args:
- "query"
- "--log.level=debug"
- "--cluster.peers=thanos-peers.default.svc.cluster.local:10900"
- "--query.replica-label=replica"
ports:
- name: http
containerPort: 10902
- name: grpc
containerPort: 10901
- name: cluster
containerPort: 10900
livenessProbe:
httpGet:
path: /-/healthy
port: http
---
apiVersion: v1
kind: Service
metadata:
labels:
app: thanos-query
name: thanos-query
spec:
externalTrafficPolicy: Cluster
ports:
- port: 9090
protocol: TCP
targetPort: http
name: http-query
selector:
app: thanos-query
sessionAffinity: None
type: NodePort
EOF
- We talked about downsampling in the introduction but which component is taking care of this task. Compactor is used for downsampling of the datasets in object store.
cat <<EOF | kubectl create -f -
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: thanos-compactor
spec:
serviceName: "thanos-compactor"
replicas: 1
selector:
matchLabels:
app: thanos-compactor
template:
metadata:
labels:
app: thanos-compactor
spec:
containers:
- name: thanos-compactor
# Always use explicit image tags (release or master-<date>-sha) instead of ambigous `latest` or `master`.
image: improbable/thanos:v0.2.1
args:
- "compact"
- "--log.level=debug"
- "--data-dir=/tmp/thanos-compact"
- "--objstore.config-file=/creds/swift_access_information.yaml"
- "--sync-delay=5m"
- "--retention.resolution-raw=10m"
- "--retention.resolution-5m=1h"
- "--retention.resolution-1h=2h"
- "-w"
volumeMounts:
- name: swiftconfig
mountPath: /creds
- name: data
mountPath: /tmp/thanos-compact
volumes:
- name: data
emptyDir: {}
- name: swiftconfig
configMap:
name: swiftinfo
EOF
Refer the link to know more about compactor options. We can see the following logs in compactor run.
kubectl logs thanos-compactor-0
level=info ts=2019-01-10T05:00:11.877653878Z caller=factory.go:39 msg="loading bucket configuration"
level=info ts=2019-01-10T05:00:12.552319625Z caller=compact.go:193 msg="retention policy of raw samples is enabled" duration=10m0s
level=info ts=2019-01-10T05:00:12.552453317Z caller=compact.go:196 msg="retention policy of 5 min aggregated samples is enabled" duration=1h0m0s
level=info ts=2019-01-10T05:00:12.552468338Z caller=compact.go:199 msg="retention policy of 1 hour aggregated samples is enabled" duration=2h0m0s
level=info ts=2019-01-10T05:00:12.552601749Z caller=compact.go:281 msg="starting compact node"
level=info ts=2019-01-10T05:00:12.552855301Z caller=main.go:308 msg="Listening for metrics" address=0.0.0.0:10902
level=info ts=2019-01-10T05:00:12.553153026Z caller=compact.go:816 msg="start sync of metas"
level=debug ts=2019-01-10T05:00:13.023376044Z caller=compact.go:174 msg="download meta" block=01D0V1NGPPV3FA8TMJXBFMN002
level=debug ts=2019-01-10T05:00:13.163197482Z caller=compact.go:174 msg="download meta" block=01D0V1NGR6DB612WD6NEEMZ17S
level=debug ts=2019-01-10T05:00:13.302204633Z caller=compact.go:174 msg="download meta" block=01D0V1YNNPM82YQRJ60189KGYN
level=debug ts=2019-01-10T05:00:13.441454572Z caller=compact.go:192 msg="block is too fresh for now" block=01D0V1YNNPM82YQRJ60189KGYN
level=debug ts=2019-01-10T05:00:13.441495172Z caller=compact.go:174 msg="download meta" block=01D0V1YNQCFBV9JCQMX03J76QM
level=debug ts=2019-01-10T05:00:13.582934377Z caller=compact.go:192 msg="block is too fresh for now" block=01D0V1YNQCFBV9JCQMX03J76QM
level=info ts=2019-01-10T05:00:13.724814306Z caller=compact.go:822 msg="start of GC"
level=info ts=2019-01-10T05:00:13.731974591Z caller=compact.go:207 msg="compaction iterations done"
level=info ts=2019-01-10T05:00:13.732213612Z caller=compact.go:214 msg="start first pass of downsampling"
level=info ts=2019-01-10T05:00:14.57574943Z caller=compact.go:220 msg="start second pass of downsampling"
level=info ts=2019-01-10T05:00:15.428989866Z caller=compact.go:225 msg="downsampling iterations done"
level=info ts=2019-01-10T05:00:15.429026068Z caller=retention.go:17 msg="start optional retention"
level=info ts=2019-01-10T05:00:15.724043874Z caller=retention.go:35 msg="deleting block" id=01D0V1NGPPV3FA8TMJXBFMN002 maxTime="2019-01-10 04:50:00 +0000 UTC"
level=info ts=2019-01-10T05:00:16.870180595Z caller=retention.go:35 msg="deleting block" id=01D0V1NGR6DB612WD6NEEMZ17S maxTime="2019-01-10 04:50:00 +0000 UTC"
level=info ts=2019-01-10T05:00:18.287429817Z caller=retention.go:46 msg="optional retention apply done"
Number of objects in swift container is reduced.
[root@packstack1 ~(keystone_admin)]# swift stat test3
Account: AUTH_45a6706c831c42d5bf2da928573382b1
Container: test3
Objects: 30
Bytes: 2192174
Read ACL:
Write ACL:
Sync To:
Sync Key:
Accept-Ranges: bytes
X-Storage-Policy: Policy-0
Last-Modified: Thu, 10 Jan 2019 04:06:37 GMT
X-Timestamp: 1547093196.88206
X-Trans-Id: tx246915ed24314585b3ac6-005c36d160
Content-Type: application/json; charset=utf-8
X-Openstack-Request-Id: tx246915ed24314585b3ac6-005c36d160
Summary
thanos-sidecar - To fetch the dataset information from prometheus and put the dataset in object store as per configuration. Storage Gateway - To run the query agains the object storage. Thanos query - To run the queries to fetch the information from prometheus and object store using storage gateway. Compactor - Run the downsampling and delete old data as per conf settings.