
上传到对象存储当中的数据如何读取呢? 它提供了store gateway的组件,store gateway就是简单的去读取对象存储当中的数据,也是通过store api暴露给query,query就去调用store api然后获取数据,这样就能够获取到对象存储当中的数据,这样就可以实现了查询很久之前的数据了。

query可以向多个后端实现了storeapi组件查询数据,这个storeapi就是暴露数据给query去查询的。

某个Prometheus实例挂了,其他实例没有挂,这样还是可以查询到数据的。
上面我们安装了 Thanos 的 Sidecar 和 Querier 组件,已经可以做到 Prometheus 的高可用,通过 Querier 提供一个统一的入口来查询多个Prometheus的监控数据,而且还可以对监控数据自动去重,但是还有一个非常重要的地方是还没有配置对象存储,如果想要查看历史监控数据就不行了,这个时候我们就需要去配置 Thanos Store 组件,将历史监控指标存储在对象存储中去。(2小时之后的数据没有上传到对象存储,如果要去查看历史的监控数据就需要去配置store组件,之前配置的是6个小时)
目前 Thanos 支持的对象存储有:

要在生产环境使用最好使用 Stable 状态的,比如 S3 或者兼容 S3 的服务,比如 Ceph、Minio 等等。
对于国内用户当然最方便的还是直接使用阿里云 OSS 或者腾讯云 COS 这样的服务,但是很多时候可能我们的服务并不是跑在公有云上面的,所以这里我们用 Minio 来部署一个兼容 S3 协议的对象存储服务。
MinIO 是一个基于 Apache License v2.0 开源协议的高性能分布式对象存储服务,为大规模私有云基础设施而设计。它兼容亚马逊 S3 云存储服务接口,非常适合于存储大容量非结构化的数据,例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等,而一个对象文件可以是任意大小,从几 kb 到最大 5T 不等。
要安装 Minio 非常容易的,同样我们这里将 Minio 安装到 Kubernetes 集群中,可以直接参考官方文档 使用 Kubernetes 部署 MinIO,在 Kubernetes 集群下面可以部署独立、分布式或共享几种模式,可以根据实际情况部署,我们这里只是单纯测试用最简单的独立模式即可。
直接使用如下所示的 Deployment 来管理 Minio 的服务:
- # minio-deploy.yaml
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: minio
- spec:
- selector:
- matchLabels:
- app: minio
- strategy:
- type: Recreate
- template:
- metadata:
- labels:
- app: minio
- spec:
- volumes:
- - name: data
- persistentVolumeClaim:
- claimName: minio-pvc
- containers:
- - name: minio
- volumeMounts:
- - name: data
- mountPath: "/data"
- image: minio/minio:latest
- args: ["server", "--console-address", ":9001", "/data"]
- env:
- - name: MINIO_ACCESS_KEY
- value: "minio"
- - name: MINIO_SECRET_KEY
- value: "minio123"
- ports:
- - containerPort: 9000
- - containerPort: 9001
- readinessProbe:
- httpGet:
- path: /minio/health/ready
- port: 9000
- initialDelaySeconds: 10
- periodSeconds: 10
- livenessProbe:
- httpGet:
- path: /minio/health/live
- port: 9000
- initialDelaySeconds: 10
- periodSeconds: 10
由于新版本的镜像区分了 Console 和 API 两个服务的端口,所以在启动的时候我们需要通过 --console-address 参数来指定 Console 服务的端口,默认的 API 服务在 9000 端口上。
然后通过一个名为 minio-pvc 的 PVC 对象将数据持久化:
- # minio-pvc.yaml
- apiVersion: v1
- kind: PersistentVolumeClaim
- metadata:
- name: minio-pvc
- spec:
- accessModes:
- - ReadWriteOnce
- resources:
- requests:
- storage: 10G
- storageClassName: longhorn # 最好使用LocalPV
最后我们可以通过 NodePort 类型的 Service 服务将 Minio 暴露给外部用户使用:
- # minio-svc.yaml
- apiVersion: v1
- kind: Service
- metadata:
- name: minio
- spec:
- ports:
- - name: console
- port: 9001
- targetPort: 9001
- nodePort: 30091
- - name: api
- port: 9000
- targetPort: 9000
- selector:
- app: minio
- type: NodePort
直接创建上面的资源对象即可:
☸ ➜ kubectl apply -f https://p8s.io/docs/thanos/manifests/minio.yaml
部署成功后,可以在浏览器中访问 http://<nodeip>:30091 访问到 MinIO Console 服务,通过上面定义的 MINIO_ACCESS_KEY 和 MINIO_SECRET_KEY 即可登录:

然后创建一个名为 thanos 的 bucket 桶:

现在对象存储准备好了,我们就可以来部署 Store 组件了,该组件会从对象存储给 Querier 提供 metrics 数据。
根据上面创建的 Minio 创建一个如下所示的对象存储配置文件:
- # thanos-storage-minio.yaml
- type: s3
- config:
- bucket: thanos
- endpoint: minio.default.svc.cluster.local:9000
- access_key: minio
- secret_key: minio123
- insecure: true
- signature_version2: false
使用上面的配置文件来创建一个 Secret 对象:
☸ ➜ kubectl create secret generic thanos-objectstorage --from-file=thanos.yaml=thanos-storage-minio.yaml -n kube-mon
上面就是配置好了对接对象存储的配置文件
然后创建 Store 组件的资源清单文件,这里有一个需要注意的地方是需要添加一个 thanos-store-api: "true" 的标签,这样前面我们创建的 thanos-store-gateway 这个 Headless Service 就可以自动发现到这个服务,Querier 组件查询数据的时候除了可以通过 Sidecar 去获取数据也可以通过这个 Store 组件去对象存储里面获取数据了。(这个标签是告诉querystore组件也实现了store-api,query组件对接具有thanos-store-api的组件,以后可以通过query组件查询store里面数据,也可以查询sidecar数据)

它下面就是匹配的所有实现了thanos-store-api的pod关联起来。
将上面的 Secret 对象通过 Volume 形式挂载到容器中的 /etc/secret 目录下,通过 objstore.config-file 参数指定即可:
- # thanos-store.yaml
- apiVersion: apps/v1
- kind: StatefulSet
- metadata:
- name: thanos-store-gateway
- namespace: kube-mon
- labels:
- app: thanos-store-gateway
- spec:
- replicas: 2
- selector:
- matchLabels:
- app: thanos-store-gateway
- serviceName: thanos-store-gateway
- template:
- metadata:
- labels:
- app: thanos-store-gateway
- thanos-store-api: "true" //告诉系统当前store组件也实现了store-api,那么query可以查询store里面数据,也可以去查询sidecar里面的数据
- spec:
- affinity:
- podAntiAffinity:
- preferredDuringSchedulingIgnoredDuringExecution:
- - weight: 100
- podAffinityTerm:
- topologyKey: kubernetes.io/hostname
- labelSelector:
- matchExpressions:
- - key: app
- operator: In
- values:
- - thanos-store-gateway
- containers:
- - name: thanos
- image: thanosio/thanos:v0.25.1
- args:
- - "store"
- - "--log.level=debug"
- - "--data-dir=/data"
- - "--objstore.config-file=/etc/secret/thanos.yaml"
- - "--index-cache-size=500MB"
- - "--chunk-pool-size=500MB"
- ports:
- - name: http
- containerPort: 10902
- - name: grpc
- containerPort: 10901
- livenessProbe:
- httpGet:
- port: 10902
- path: /-/healthy
- readinessProbe:
- httpGet:
- port: 10902
- path: /-/ready
- volumeMounts:
- - name: object-storage-config
- mountPath: /etc/secret
- readOnly: false
- - mountPath: /data
- name: data
- volumes:
- - name: object-storage-config
- secret:
- secretName: thanos-objectstorage
- volumeClaimTemplates:
- - metadata:
- name: data
- spec:
- accessModes:
- - ReadWriteOnce
- storageClassName: longhorn
- resources:
- requests:
- storage: 1Gi
Store Gateway 实际也可以做到一定程度的无状态,它会需要一点磁盘空间来对对象存储做索引以加速查询,但数据不那么重要,是可以删除的,删除后会自动去拉对象存储查数据重新建立索引,这里为了避免每次重启都重新建立索引,所以用 StatefulSet 部署 Store Gateway,挂载一个小容量的 PV。部署两个副本,可以实现 Store Gateway 的高可用。
然后直接创建上面的资源对象即可:(可以看到thanos-store-api=true的标签的pod有4个,那么query组件在对接的时候就要对接到这个4个pod上面去了)
- ☸ ➜ kubectl apply -f https://p8s.io/docs/thanos/manifests/thanos-store.yaml
- ☸ ➜ kubectl get pods -n kube-mon -l thanos-store-api=true
- NAME READY STATUS RESTARTS AGE
- prometheus-0 2/2 Running 0 20m
- prometheus-1 2/2 Running 0 21m
- thanos-store-gateway-0 1/1 Running 0 24m
- thanos-store-gateway-1 1/1 Running 0 24m
部署成功后这个时候去 Thano 的 Querier 页面上查看 Store 信息就可以发现这里我们配置的 Store 组件了:

到这里证明我们的 Store 组件也配置成功了。但是还有一个明显的问题是这里我们只是配置去对象存储中查询数据的,那什么地方往对象存储中写入数据呢?当然还是在 Sidecar 组件里面了。所以同样我们需要把 objstore.config-file 参数和 Secret 对象也要配置到 Sidecar 组件中去:(还没有将对象的数据上传到对象存储当中,只是去创建了这个store组件,数据是由谁传给store组件的呢?sidecar将数据上传到对象存储,所以还需要在sidecar中去配置上传到对象存储当中)
- ......
- volumes:
- - name: object-storage-config
- secret:
- secretName: thanos-objectstorage
- ......
- args:
- - sidecar
- - --log.level=debug
- - --tsdb.path=/prometheus
- - --prometheus.url=http://localhost:9090
- - --reloader.config-file=/etc/prometheus/prometheus.yaml.tmpl
- - --reloader.config-envsubst-file=/etc/prometheus-shared/prometheus.yaml
- - --reloader.rule-dir=/etc/prometheus/rules/
- - --objstore.config-file=/etc/secret/thanos.yaml
- ......
- volumeMounts:
- - name: object-storage-config
- mountPath: /etc/secret
- readOnly: false
- ......
当sidecar读取到我们配置的对象存储如果发现本地Prometheus数据目录里面有了tsdb数据块就上传到对象存储里面去。每2个小时生成新的数据块,如果有新的数据块才上传上去。

配置完成后重新更新 Sidecar 组件即可,配置生效过后正常的话就会有数据传入到 MinIO 里面去了(本地有超过两小时的 TSDB 块数据),我们可以去 MinIO 的页面上查看验证:

那么以后的历史数据就不会丢失了。