使用 Thanos 實現 Prometheus 的高可用

2021-02-18 DevOps和k8s全棧技術

前面我們已經學習了 Prometheus 的使用,了解了基本的 PromQL 語句以及結合 Grafana 來進行監控圖表展示,通過 AlertManager 來進行報警,這些工具結合起來已經可以幫助我們搭建一套比較完整的監控報警系統了,但是也僅僅局限於測試環境,對於生產環境來說則還有許多需要改進的地方,其中一個非常重要的就是 Prometheus 的高可用。

單臺的 Prometheus 存在單點故障的風險,隨著監控規模的擴大,Prometheus 產生的數據量也會非常大,性能和存儲都會面臨問題。毋庸置疑,我們需要一套高可用的 Prometheus 集群。

可用性

我們知道 Prometheus 是採用的 Pull 機制獲取監控數據,即使使用 PushGateway 對於 Prometheus 也是 Pull,為了確保 Prometheus 服務的可用性,我們只需要部署多個 Prometheus 實例,然後採集相同的 metrics 數據即可:

這個方式來滿足服務的可用性應該是平時我們使用得最多的一種方式,當一個實例掛掉後從 LB 裡面自動剔除掉,而且還有負載均衡的作用,可以降低一個 Prometheus 的壓力,但這種模式缺點也是非常明顯的,就是不滿足數據一致性以及持久化問題,因為 Prometheus 是 Pull 的方式,即使多個實例抓取的是相同的監控指標,也不能保證抓取過來的值就是一致的,更何況在實際的使用過程中還會遇到一些網絡延遲問題,所以會造成數據不一致的問題,不過對於監控報警這個場景來說,一般也不會要求數據強一致性,所以這種方式從業務上來說是可以接受的,因為這種數據不一致性影響基本上沒什麼影響。這種場景適合監控規模不大,只需要保存短周期監控數據的場景。

數據持久化

使用上面的基本 HA 的模式基本上是可以滿足監控這個場景,但是還有一個數據持久化的問題,如果其中一個實例數據丟了就沒辦法呢恢復回來了,這個時候我們就可以為 Prometheus 添加遠程存儲來保證數據持久化。

在給 Prometheus 配置上遠程存儲過後,我們就不用擔心數據丟失的問題了,即使當一個 Prometheus 實例宕機或者數據丟失過後,也可以通過遠程存儲的數據進行恢復。

通過鎖獲取 Leader

其實上面的基本 HA 加上遠程存儲的方式基本上可以滿足 Prometheus 的高可用了,這種方式的多個 Prometheus 實例都會去定時拉取監控指標數據,然後將熱數據存儲在本地,然後冷數據同步到遠程存儲中去,對於大型集群來說頻繁的去拉取指標數據勢必會對網絡造成更大的壓力。所以我們也通過服務註冊的方式來實現 Prometheus 的高可用性,集群啟動的時候每個節點都嘗試去獲取鎖,獲取成功的節點成為 Leader 執行任務,若主節點宕機,從節點獲取鎖成為 Leader 並接管服務。

不過這種方案需要我們通過去寫代碼進行改造,如果在 Kubernetes 中我們完全可以使用自帶的 Lease 對象來獲取分布式鎖🔒,這不是很困難,只是以後要更新版本稍微麻煩點。

上面的幾種方案基本上都可以滿足基本的 Prometheus 高可用,但是對於大型集群來說,一個 Prometheus 實例的壓力始終非常大。

聯邦集群

當單個 Promthues 實例 無法處理大量的採集任務時,這個時候我們就可以使用基於 Prometheus 聯邦集群的方式來將監控任務劃分到不同的 Prometheus 實例中去。

我們可以將不同類型的採集任務劃分到不同的 Prometheus 實例中去執行,進行功能分片,比如一個 Prometheus 負責採集節點的指標數據,另外一個 Prometheus 負責採集應用業務相關的監控指標數據,最後在上層通過一個 Prometheus 對數據進行匯總。

具體的採集任務如何去進行分區也沒有固定的標準,需要結合實際的業務進行考慮,除了上面的方式之外,還有一種情況就是單個的採集數據量就非常非常大,比如我們要採集上萬個節點的監控指標數據,這種情況即使我們已經進行了分區,但是對於單個 Prometheus 來說壓力也是非常大的,這個時候我們就需要按照任務的不同實例進行劃分,我們通過 Prometheus 的 relabel 功能,通過 hash 取模的方式可以確保當前 Prometheus 只採集當前任務的一部分實例的監控指標。

# 省略其他配置.

relabel_configs:

- source_labels: [__address__]

modulus: 4 # 將節點分片成 4 個組

target_label: __tmp_hash

action: hashmod

- source_labels: [__tmp_hash]

regex: ^1$ # 只抓第2個組中節點的數據(序號0為第1個組)

action: keep

到這裡我們基本上就完成了 Prometheus 高可用的改造。對於小規模集群和大規模集群可以採用不同的方案,但是其中有一個非常重要的部分就是遠程存儲,我們需要保證數據的持久化就必須使用遠程存儲。所以下面我們將重點介紹下遠程存儲的時候,這裡我們主要講解目前比較流行的方案:Thanos,它完全兼容 Prometheus API,提供統一查詢聚合分布式部署 Prometheus 數據的能力,同時也支持數據長期存儲到各種對象存儲(比如 S3、阿里雲 OSS 等)以及降低採樣率來加速大時間範圍的數據查詢。

Thanos

Thanos 是一個基於 Prometheus 實現的監控方案,其主要設計目的是解決原生 Prometheus 上的痛點,並且做進一步的提升,主要的特性有:全局查詢,高可用,動態拓展,長期存儲。下圖是 Thanos 官方的架構圖:

Thanos 主要由如下幾個特定功能的組件組成:

邊車組件(Sidecar):連接 Prometheus,並把 Prometheus 暴露給查詢網關(Querier/Query),以供實時查詢,並且可以上傳 Prometheus 數據給雲存儲,以供長期保存

查詢網關(Querier/Query):實現了 Prometheus API,與匯集底層組件(如邊車組件 Sidecar,或是存儲網關 Store Gateway)的數據

存儲網關(Store Gateway):將雲存儲中的數據內容暴露出來

壓縮器(Compactor):將雲存儲中的數據進行壓縮和下採樣

接收器(Receiver):從 Prometheus 的 remote-write WAL(Prometheus 遠程預寫式日誌)獲取數據,暴露出去或者上傳到雲存儲

規則組件(Ruler):針對監控數據進行評估和報警

Bucket:主要用於展示對象存儲中歷史數據的存儲情況,查看每個指標源中數據塊的壓縮級別,解析度,存儲時段和時間長度等信息。

工作流程

Thanos 是同時支持 Prometheus 讀和寫的遠程存儲方案,首先我們先看下指標寫入的整個流程:

首先 Prometheus 從所採集服務的 metrics 接口抓取指標數據,同時根據自身所配置的 recording rules 定期對抓取到的指標數據進行評估,將結果以 TSDB 格式分塊存儲到本地,每個數據塊的存儲時長為2小時,且默認禁用了壓縮功能。

然後 sidecar 嗅探到 Prometheus 的數據存儲目錄生成了新的只讀數據塊時,會將該數據塊上傳到對象存儲桶中做為長期歷史數據保存,在上傳時會將數據塊中的 meta.json 進行修改添加 thanos 相關的欄位,如 external_labels。

rule 根據所配置的 recording rules 定期地向 query 發起查詢獲取評估所需的指標值,並將結果以 TSDB格式分塊存儲到本地。每個數據塊的存儲時長為2小時,且默認禁用了壓縮功能,每個數據塊的 meta.json 也附帶了 thanos 拓展的 external_lables 欄位。當本地生成了新的只讀數據塊時,其自身會將該數據塊上傳到遠端對象存儲桶中做為長期歷史數據保存。

compact 定期將對象存儲中地數據塊進行壓縮和降準採樣,進行壓縮時數據塊中的 truck 會進行合併,對應的 meta.json 中的 level 也會一同增長,每次壓縮累加1,初始值為1。在進行降準採樣時會創建新的數據塊,根據採樣步長從原有的數據塊中抽取值存儲到新的數據塊中,在 meta.json 中記錄 resolution 為採樣步長。

讀取指標的流程為:

首先客戶端通過 query API 向 query 發起查詢, query 將請求轉換成 StoreAPI 發送到其他的 query、 sidecar、 rule 和 store 上。

sidecar 接收到來自於 query 發起的查詢請求後將其轉換成 query API 請求,發送給其綁定的 Prometheus,由Prometheus 從本地讀取數據並響應,返回短期的本地採集和評估數據。

rule 接收到來自於 query 發起的查詢請求後直接從本地讀取數據並響應,返回短期的本地評估數據。

store 接收到來自於 query 發起的查詢請求後首先從對象存儲桶中遍歷數據塊的 meta.json,根據其中記錄的時間範圍和標籤先進行一次過濾。接下來從對象存儲桶中讀取數據塊的 index 和 chunks 進行查詢,部分查詢頻率較高的 index 會被緩存下來,下次查詢使用到時可以直接讀取。最終返回長期的歷史採集和評估指標。

對於發送報警的流程如下所示:

Prometheus 根據自身配置的 alerting 規則定期地對自身採集的指標進行評估,當告警條件滿足的情況下發起告警到 Alertmanager 上。

rule 根據自身配置的 alerting 規則定期的向 query 發起查詢請求獲取評估所需的指標,當告警條件滿足的情況下發起告警到 Alertmanager 上。

Alertmanager 接收到來自於 Prometheus 和 rule 的告警消息後進行分組合併後發出告警通知。

Sidecar 組件

首先將前面章節中的 Prometheus 相關的資源對象全部刪除,然後我們需要在 Prometheus 中去自動發現集群的一些資源對象,所以依然需要對應的 RBAC 權限聲明:(rbac.yaml)

apiVersion: v1

kind: ServiceAccount

metadata:

name: prometheus

namespace: kube-mon

---

apiVersion: rbac.authorization.k8s.io/v1

kind: ClusterRole

metadata:

name: prometheus

rules:

- apiGroups:

- ""

resources:

- nodes

- services

- endpoints

- pods

- nodes/proxy

verbs:

- get

- list

- watch

- apiGroups:

- "extensions"

resources:

- ingresses

verbs:

- get

- list

- watch

- apiGroups:

- ""

resources:

- configmaps

- nodes/metrics

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: kube-mon

然後需要部署 Prometheus 的配置文件,下面的資源對象是創建 Prometheus 配置文件的模板,該模板將由 Thanos sidecar 組件進行讀取,最終會通過該模板生成實際的配置文件,在同一個 Pod 中的 Prometheus 容器將讀取最終的配置文件,在配置文件中添加 external_labels 標籤是非常重要的,以便讓 Queirer 可以基於這些標籤對數據進行去重處理:(configmap.yaml)

apiVersion: v1

kind: ConfigMap

metadata:

name: prometheus-config

namespace: kube-mon

data:

prometheus.yaml.tmpl: | # 注意這裡的名稱是 prometheus.yaml.tmpl

global:

scrape_interval: 15s

scrape_timeout: 15s

external_labels:

cluster: ydzs-test

replica: $(POD_NAME) # 每個 Prometheus 有一個唯一的標籤

rule_files: # 報警規則文件配置

- /etc/prometheus/rules/*rules.yaml

alerting:

alert_relabel_configs: # 我們希望告警從不同的副本中也是去重的

- regex: replica

action: labeldrop

alertmanagers:

- scheme: http

path_prefix: /

static_configs:

- targets: ['alertmanager:9093']

scrape_configs:

. # 其他抓取任務配置

上面配置了報警規則文件,由於這裡配置文件太大了,所以為了更加清晰,我們將報警規則文件拆分到另外的 ConfigMap 對象中來,下面我們配置了兩個報警規則:(rules-configmap.yaml)

apiVersion: v1

kind: ConfigMap

metadata:

name: prometheus-rules

namespace: kube-mon

data:

alert-rules.yaml: |-

groups:

- name: Deployment

rules:

- alert: Deployment at 0 Replicas

annotations:

summary: Deployment {{$labels.deployment}} in {{$labels.namespace}} is currently having no pods running

expr: |

sum(kube_deployment_status_replicas) by (deployment,namespace) < 1

for: 1m

labels:

team: node

- name: Pods

rules:

- alert: Container restarted

annotations:

summary: Container named {{$labels.container}} in {{$labels.pod}} in {{$labels.namespace}} was restarted

expr: |

sum(increase(kube_pod_container_status_restarts_total[1m])) by (pod,namespace,container) > 0

for: 0m

labels:

team: node

Thanos 通過 Sidecar 和現有的 Prometheus 進行集成,將 Prometheus 的數據備份到對象存儲中,所以首先我們需要將 Prometheus 和 Sidecar 部署在同一個 Pod 中,另外 Prometheus 中一定要開啟下面兩個參數:

由於 Prometheus 默認每2h生成一個 TSDB 數據塊,所以仍然並不意味著 Prometheus 可以是完全無狀態的,因為如果它崩潰並重新啟動,我們將丟失〜2個小時的指標,因此強烈建議依然對 Prometheus 做數據持久化,所以我們這裡使用了 StatefulSet 來管理這個應用,添加 volumeClaimTemplates 來聲明了數據持久化的 PVC 模板:(sidecar.yaml)

apiVersion: apps/v1

kind: StatefulSet

metadata:

name: prometheus

namespace: kube-mon

labels:

app: prometheus

spec:

serviceName: "prometheus"

replicas: 2

selector:

matchLabels:

app: prometheus

thanos-store-api: "true"

template:

metadata:

labels:

app: prometheus

thanos-store-api: "true"

spec:

serviceAccountName: prometheus

volumes:

- name: prometheus-config

configMap:

name: prometheus-config

- name: prometheus-rules

configMap:

name: prometheus-rules

- name: prometheus-config-shared

emptyDir: {}

containers:

- name: prometheus

image: prom/prometheus:v2.14.0

imagePullPolicy: IfNotPresent

args:

- "--config.file=/etc/prometheus-shared/prometheus.yaml"

- "--storage.tsdb.path=/prometheus"

- "--storage.tsdb.retention.time=6h"

- "--storage.tsdb.no-lockfile"

- "--storage.tsdb.min-block-duration=2h" # Thanos處理數據壓縮

- "--storage.tsdb.max-block-duration=2h"

- "--web.enable-admin-api" # 通過一些命令去管理數據

- "--web.enable-lifecycle" # 支持熱更新 localhost:9090/-/reload 加載

ports:

- name: http

containerPort: 9090

resources:

requests:

memory: "2Gi"

cpu: "1"

limits:

memory: "2Gi"

cpu: "1"

volumeMounts:

- name: prometheus-config-shared

mountPath: /etc/prometheus-shared/

- name: prometheus-rules

mountPath: /etc/prometheus/rules

- name: data

mountPath: "/prometheus"

- name: thanos

image: thanosio/thanos:v0.11.0

imagePullPolicy: IfNotPresent

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/

ports:

- name: http-sidecar

containerPort: 10902

- name: grpc

containerPort: 10901

env:

- name: POD_NAME

valueFrom:

fieldRef:

fieldPath: metadata.name

resources:

requests:

memory: "2Gi"

cpu: "1"

limits:

memory: "2Gi"

cpu: "1"

volumeMounts:

- name: prometheus-config-shared

mountPath: /etc/prometheus-shared/

- name: prometheus-config

mountPath: /etc/prometheus

- name: prometheus-rules

mountPath: /etc/prometheus/rules

- name: data

mountPath: "/prometheus"

volumeClaimTemplates: # 由於prometheus每2h生成一個TSDB數據塊,所以還是需要保存本地的數據

- metadata:

name: data

labels:

app: prometheus

spec:

storageClassName: rook-ceph-block

accessModes:

- ReadWriteOnce

resources:

requests:

storage: 2Gi

由於 Prometheus 和 Thanos 的 Sidecar 在同一個 Pod 中了,所以我們完全可以用 localhost 就可以訪問到了,然後將數據目錄做了聲明掛載,所以同樣可以在兩個容器中共享數據目錄了,一定要注意幾個配置文件的掛載方式。此外在上面的配置文件中我們通過 POD_NAME 這個環境變量作為 external 標籤附加到了 Prometheus 實例上,這裡我們通過 DownwardAPI 去設置該環境變量。

由於現在使用的是 StatefulSet 控制器,所以需要創建一個 Headless Service,而且後面的 Thanos Query 還將使用該無頭服務來查詢所有 Prometheus 實例中的數據,當然我們也可以為每一個 Prometheus 實例去創建一個 Service 對象便於調試,當然這個不是必須的:(headless.yaml)

# 該服務為查 querier 創建 srv 記錄,以便查找 store-api 的信息

apiVersion: v1

kind: Service

metadata:

name: thanos-store-gateway

namespace: kube-mon

spec:

type: ClusterIP

clusterIP: None

ports:

- name: grpc

port: 10901

targetPort: grpc

selector:

thanos-store-api: "true"

然後我們就可以使用上面的這些資源對象來創建帶有 Thanos Sidecar 容器的高可用 Prometheus 應用了:

$ kubectl apply -f rbac.yaml

$ kubectl apply -f configmap.yaml

$ kubectl apply -f rules-configmap.yaml

$ kubectl apply -f headless.yaml

$ kubectl apply -f sidecar.yaml

$ kubectl get pods -n kube-mon -l app=prometheus

NAME READY STATUS RESTARTS AGE

prometheus-0 2/2 Running 0 86s

prometheus-1 2/2 Running 0 74s

Querier 組件

現在我們就創建成功了兩個 Prometheus 實例,但是我們真正去使用的時候並不是像上面提到的在前面加一個負載均衡器去查詢監控數據,而是使用 Thanos 的 Querier 組件來提供一個全局的統一查詢入口。對於 Quierier 最重要的就是要配置上 Thanos 的 Sidecar 地址,我們這裡完全可以直接使用 Headless Service 去自動發現:(querier.yaml)

apiVersion: apps/v1

kind: Deployment

metadata:

name: thanos-querier

namespace: kube-mon

labels:

app: thanos-querier

spec:

selector:

matchLabels:

app: thanos-querier

template:

metadata:

labels:

app: thanos-querier

spec:

containers:

- name: thanos

image: thanosio/thanos:v0.11.0

args:

- query

- --log.level=debug

- --query.replica-label=replica

# Discover local store APIs using DNS SRV.

- --store=dnssrv+thanos-store-gateway:10901

ports:

- name: http

containerPort: 10902

- name: grpc

containerPort: 10901

resources:

requests:

memory: "2Gi"

cpu: "1"

limits:

memory: "2Gi"

cpu: "1"

livenessProbe:

httpGet:

path: /-/healthy

port: http

initialDelaySeconds: 10

readinessProbe:

httpGet:

path: /-/healthy

port: http

initialDelaySeconds: 15

---

apiVersion: v1

kind: Service

metadata:

name: thanos-querier

namespace: kube-mon

labels:

app: thanos-querier

spec:

ports:

- port: 9090

protocol: TCP

targetPort: http

name: http

selector:

app: thanos-querier

type: NodePort

容器中的參數 --store=dnssrv+thanos-store-gateway:10901 可以幫助自動發現可以查詢指標數據的所有組件;然後創建一個 thanos-querier 的 Serivce 對象可以來提供一個運行 PromQL 的 web 頁面,也提供了一個是否對不同集群數據進行去重的入口。直接創建上面的對象:

$ kubectl apply -f querier.yaml

$ kubectl get pods -n kube-mon -l app=thanos-querier

NAME READY STATUS RESTARTS AGE

thanos-querier-cf566866b-r4jcj 1/1 Running 0 3m26s

$ kubectl get svc -n kube-mon -l app=thanos-querier

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE

thanos-querier NodePort 10.108.199.11 <none> 9090:31854/TCP 3m30s

部署完成後我們就可以通過 http://<任意節點IP>:31854 去訪問 Querier 了,在 Stores 頁面下面就會顯示通過服務發現獲取到的 Sidecar 信息:

在 Graph 頁面下同樣可以去使用 PromQL 語句來查詢監控信息,這個頁面和 Prometheus 原生的頁面幾乎是一致的,比如我們查詢 master 節點的節點信息:

這裡我沒有勾上 deduplication,所以 Thanos 不會幫我合併數據,所以能夠看到 prometheus-0 和 prometheus-1 兩條數據,因為我們有兩個副本去抓取監控數據。

如果將 deduplication 選中,結果會根據 replica 這個標籤進行合併,如果兩個副本都有對應的數據, Querier 會取 timestamp 更小的結果:

當然這個時候我們在前面章節中 Grafana 裡面配置的 Prometheus 的數據源也就失效了,因為現在監控數據的來源是 ThanosQuerier,所以我們需要重新配置 Prometheus 的數據源地址為 http://thanos-querier:9090:

之前的監控圖表也可以正常顯示了:

Ruler 組件

現在我們可以測試下 Prometheus 裡面配置的監控報警規則是否生效,比如對於 Deploymentat0Replicas 這個報警規則,當集群中有 Deployment 的副本數變成0過後就會觸發報警:

$ kubectl get deploy

NAME READY UP-TO-DATE AVAILABLE AGE

vault-demo 1/1 1 1 41d

我們可以手動將某個 Deployment 的副本數縮減為0:

$ kubectl scale --replicas=0 deployment/vault-demo

deployment.apps/vault-demo scaled

$ kubectl get deploy

NAME READY UP-TO-DATE AVAILABLE AGE

vault-demo 0/0 0 0 41d

這個時候 Alertmanager 同樣也會根據外部的 replica 標籤對告警進行去重,上面的報警規則中我們添加了 team=node 這樣的標籤,所以會通過前面章節中的 webhook 接收器發送給釘釘進行告警:

當然除了直接使用 Prometheus 做報警和記錄規則之外,同樣我們也可以使用 Thanos 的 Ruler 組件,該組件本身不會抓取 metrics 接口數據,而是通過 query API 從 query 組件定期地獲取指標數據,如果配置了多個 query 地址,則會採用輪詢方式獲取。

Ruler 組件獲取評估數據的路徑為 rule-->query-->sidecar-->prometheus 需要經過一整個查詢鏈條,這也提升了發生故障的風險,且評估原本就可以在 Prometheus 中進行,所以非必要的情況下還是更加推薦使用 Prometheus 來直接做 alerting 和 recording 評估,對於 Ruler 組件的具體使用方式感興趣的也可以直接查看官方文檔 https://thanos.io/components/rule.md/ 了解更多細節。

Store 組件

上面我們安裝了 Thanos 的 Sidecar 和 Querier 組件,已經可以做到 Prometheus 的高可用,通過 Querier 提供一個統一的入口來查詢監控數據,而且還可以對監控數據自動去重,但是還有一個非常重要的地方是還沒有配置對象存儲,如果想要查看歷史監控數據就不行了,這個時候我們就需要去配置 Thanos Store 組件,將歷史監控指標存儲在對象存儲中去。

目前 Thanos 支持的對象存儲有:

要在生產環境使用最好使用 Stable 狀態的,比如 S3 或者兼容 S3 的服務,比如 Ceph、Minio 等等。

對於國內用戶當然最方便的還是直接使用阿里雲 OSS 或者騰訊雲 COS 這樣的服務,很多時候可能我們的服務並不是跑在公有雲上面的,所以這裡我們用 Minio 來部署一個兼容 S3 協議的對象存儲服務。

安裝 Minio

MinIO 是一個基於 Apache License v2.0 開源協議的對象存儲服務。它兼容亞馬遜 S3 雲存儲服務接口,非常適合於存儲大容量非結構化的數據,例如圖片、視頻、日誌文件、備份數據和容器/虛擬機鏡像等,而一個對象文件可以是任意大小,從幾 kb 到最大 5T 不等。

要安裝 Minio 非常容易的,同樣我們這裡將 Minio 安裝到 Kubernetes 集群中,可以直接參考官方文檔 使用Kubernetes部署MinIO,在 Kubernetes 集群下面可以部署獨立、分布式或共享幾種模式,可以根據實際情況部署,我們這裡為了簡單直接部署獨立模式。

為了方便管理,將所有的資源對象都部署在一個名為 minio 的命名空間中,如果沒有的話需要手動創建。直接使用 Deployment 來管理 Minio 的服務:(minio-deploy.yaml)

apiVersion: apps/v1

kind: Deployment

metadata:

name: minio

namespace: 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:RELEASE.2020-03-25T07-03-04Z

args:

- server

- /data

env:

- name: MINIO_ACCESS_KEY

value: "minio"

- name: MINIO_SECRET_KEY

value: "minio123"

ports:

- containerPort: 9000

readinessProbe:

httpGet:

path: /minio/health/ready

port: 9000

initialDelaySeconds: 90

periodSeconds: 10

livenessProbe:

httpGet:

path: /minio/health/live

port: 9000

initialDelaySeconds: 30

periodSeconds: 10

通過一個名為 minio-pvc 的 PVC 對象將數據持久化,當然我們可以使用靜態的 PV 來提供存儲,這裡我們直接使用前面的 Ceph RBD 來提供存儲服務,使用 rook-ceph-block 這個 StorageClass 對象來提供動態 PV,對於這裡不熟悉的可以查看前面我們講解的存儲章節內容:(minio-pvc.yaml)

apiVersion: v1

kind: PersistentVolumeClaim

metadata:

name: minio-pvc

namespace: minio

spec:

storageClassName: rook-ceph-block

accessModes:

- ReadWriteOnce

resources:

requests:

storage: 50Gi

最後我們可以通過 Service 和 Ingress 對象將 Minio 暴露給外部用戶使用:(minio-ingress.yaml)

apiVersion: v1

kind: Service

metadata:

name: minio

namespace: minio

spec:

ports:

- port: 9000

targetPort: 9000

protocol: TCP

selector:

app: minio

---

apiVersion: traefik.containo.us/v1alpha1

kind: Middleware

metadata:

name: redirect-https

namespace: minio

spec:

redirectScheme:

scheme: https

---

apiVersion: traefik.containo.us/v1alpha1

kind: IngressRoute

metadata:

name: minio

namespace: minio

spec:

entryPoints:

- web

routes:

- kind: Rule

match: Host(`minio.qikqiak.com`)

services:

- kind: Service

name: minio

port: 9000

middlewares:

- name: redirect-https

---

apiVersion: traefik.containo.us/v1alpha1

kind: IngressRoute

metadata:

name: minio-https

namespace: minio

spec:

entryPoints:

- websecure

routes:

- kind: Rule

match: Host(`minio.qikqiak.com`)

services:

- kind: Service

name: minio

port: 9000

tls:

certResolver: ali

domains:

- main: "*.qikqiak.com"

這裡我們使用的是 Traefik2.X 版本的 Ingress 控制器,使用 IngressRoute 這個資源對象來定義 Ingress 信息,對於這部分內容不熟悉的可以查看前面的網絡章節部分的內容。然後直接創建上面的資源對象即可:

$ kubectl create ns minio

$ kubectl apply -f minio-deploy.yaml

$ kubectl apply -f minio-pvc.yaml

$ kubectl apply -f minio-ingress.yaml

部署成功後,將域名 minio.qikqiak.com 解析到 Ingress 控制器所在的節點即可通過瀏覽器訪問到 MinIO 服務了,通過上面定義的 MINIO_ACCESS_KEY 和 MINIO_SECRET_KEY 即可登錄:

安裝 Thanos Store

現在對象存儲準備好了,我們就可以來不是 Store 組件了,該組件會從對象存儲到給 Querier 提供 metrics 數據。

首先登錄 MinIO 創建一個 thanos 的 bucket。然後創建一個對象存儲配置文件:(thanos-storage-minio.yaml)

type: s3

config:

bucket: thanos

endpoint: minio.minio.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

secret/thanos-objectstorage created

然後創建 Store 組件的資源清單文件,這裡有一個需要注意的地方是需要添加一個 thanos-store-api:"true" 的標籤,這樣前面我們創建的 thanos-store-gateway 這個 Headless Service 就可以自動發現到這個服務,Querier 組件查詢數據的時候除了可以通過 Sidecar 去獲取數據也可以通過這個 Store 組件去對象存儲裡面獲取數據了。將上面的 Secret 對象通過 Volume 形式掛載到容器中的 /etc/secret 目錄下,通過 objstore.config-file 參數指定即可:(store.yaml)

apiVersion: apps/v1

kind: StatefulSet

metadata:

name: thanos-store-gateway

namespace: kube-mon

labels:

app: thanos-store-gateway

spec:

replicas: 1

selector:

matchLabels:

app: thanos-store-gateway

serviceName: thanos-store-gateway

template:

metadata:

labels:

app: thanos-store-gateway

thanos-store-api: "true"

spec:

containers:

- name: thanos

image: thanosio/thanos:v0.11.0

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

volumes:

- name: object-storage-config

secret:

secretName: thanos-objectstorage

直接創建上面的資源對象即可:

$ kubectl apply -f store.yaml

$ kubectl get pods -n kube-mon -l thanos-store-api=true

NAME READY STATUS RESTARTS AGE

prometheus-0 2/2 Running 0 15h

prometheus-1 2/2 Running 0 15h

thanos-store-gateway-0 1/1 Running 0 100s

部署成功後這個時候去 Thano 的 Querier 頁面上查看 Store 信息就可以發現這裡我們配置的 Store 組件了:

到這裡證明我們的 Thanos 組件也配置成功了。但是還有一個明顯的問題是這裡我們只是配置去對象存儲中查詢數據的組件,那什麼地方往對象存儲中寫入數據呢?當然還是在 Sidecar 組件裡面了。所以同樣我們需要把 objstore.config-file 參數和 Secret 對象也要配置到 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 組件即可。配置生效過後正常的話就會有數據傳入到 MinIO 裡面去了,我們可以去 MinIO 的頁面上查看驗證:

Compactor 組件

現在歷史監控數據已經上傳到對象存儲中去了,但是由於監控數據量非常龐大,所以一般情況下我們會去安裝一個 Thanos 的 Compactor 組件,用來將對象存儲中的數據進行壓縮和下採樣。Compactor 組件的部署和 Store 非常類似,指定對象存儲的配置文件即可,如下所示的資源清單文件:(compactor.yaml)

apiVersion: apps/v1

kind: StatefulSet

metadata:

name: thanos-compactor

namespace: kube-mon

labels:

app: thanos-compactor

spec:

replicas: 1

selector:

matchLabels:

app: thanos-compactor

serviceName: thanos-compactor

template:

metadata:

labels:

app: thanos-compactor

spec:

containers:

- name: thanos

image: thanosio/thanos:v0.11.0

args:

- "compact"

- "--log.level=debug"

- "--data-dir=/data"

- "--objstore.config-file=/etc/secret/thanos.yaml"

- "--wait"

ports:

- name: http

containerPort: 10902

livenessProbe:

httpGet:

port: 10902

path: /-/healthy

initialDelaySeconds: 10

readinessProbe:

httpGet:

port: 10902

path: /-/ready

initialDelaySeconds: 15

volumeMounts:

- name: object-storage-config

mountPath: /etc/secret

readOnly: false

volumes:

- name: object-storage-config

secret:

secretName: thanos-objectstorage

最重要的還是提供對象存儲的配置文件,然後直接創建上面的資源清單文件:

$ kubectl apply -f compactor.yaml

$ kubectl get pods -n kube-mon -l app=thanos-compactor

NAME READY STATUS RESTARTS AGE

thanos-compactor-0 1/1 Running 0 68s

到這裡我們就完成了使用 Thanos 來部署高可用的 Prometheus 集群,當然 Thanos 還有其他的一些組件,比如 Check、Bucket、Receiver 等,對於這些組件的使用感興趣的可以查看官方文檔 https://thanos.io/。

將 Thanos 與 Prometheus 集成可讓我們對 Prometheus 進行水平伸縮。由於 ThanosQuerier 可以從其他查詢器實例中提取指標,因此我們也可以跨集群提取指標並在 Grafana 中可視化它們,Thanos 使我們可以將度量標準數據歸檔到對象存儲中,該對象存儲為我們的監控系統提供了無限的存儲空間,而且它還可以從對象存儲中提供指標,如果我們對這些對象存儲設置一些適當的保留策略,還可以將費用降到更低。

- END -

Kubernetes全棧技術培訓

往期精彩文章

kubernetes全棧技術+企業案例演示【帶你快速掌握和使用k8s】

突破運維和開發瓶頸、Python、k8s、DevOps轉型一網打盡!

python運維開發實戰-基礎篇

python運維和開發實戰-高級篇

python運維和開發實戰-安裝和創建Django項目

Docker公司禁止被列入美國"實體名單"的國家、企業使用

Jenkis pipeline構建項目實踐-編寫podTemplate實現和k8s對接

安裝kubernetes集群-靈活安裝k8s各個版本高可用集群

Kubernetes v1.19 正式發布

kubernetes面試題匯總

DevOps視頻和資料免費領取

kubernetes技術分享-可用於企業內部培訓

談談我的IT發展之路

kubernetes系列文章第一篇-k8s基本介紹

kubernetes系列文章第二篇-kubectl

了解pod和pod的生命周期-這一篇文章就夠了

Kubernetes中部署MySQL高可用集群

Prometheus+Grafana+Alertmanager搭建全方位的監控告警系統-超詳細文檔

k8s1.18多master節點高可用集群安裝-超詳細中文官方文檔

k8s中藍綠部署、金絲雀發布、滾動更新匯總

運維常見問題匯總-tomcat篇

關於linux內核參數的調優,你需要知道

kubernetes掛載ceph rbd和cephfs

報警神器Alertmanager發送報警到多個渠道

jenkins+kubernetes+harbor+gitlab構建企業級devops平臺

kubernetes網絡插件-flannel篇

kubernetes網絡插件-calico篇

kubernetes認證、授權、準入控制

限制不同的用戶操作k8s資源

面試真題&技術資料免費領取-覆蓋面超全~

Prometheus監控MySQL

Prometheus監控Nginx

Prometheus監控Tomcat

linux面試題匯總

測試通過storageclass動態生成pv

通過編寫k8s的資源清單yaml文件部署gitlab服務

helm安裝和使用-通過helm部署k8s應用

k8s基於Ingress-nginx實現灰度發布

k8s的Pod安全策略

Prometheus Operator-上篇-安裝和使用篇

Prometheus Operator-下篇

通過kubeconfig登陸k8s的dashboard ui界面

通過token令牌登陸k8s dashboard ui界面 

kubernetes集群的etcd資料庫詳細介紹

Linux網絡流量監控工具

kubernetes搭建EFK日誌管理系統

prometheus operator監控k8s集群之外的haproxy組件         

kubernetes ConfigMap存儲卷                                           

技術交流

學無止境,了解更多關於kubernetes/docker/devops/openstack/openshift/linux/IaaS/PaaS相關內容,想要獲取更多資料和免費視頻,可按如下方式進入技術交流群

微信:luckylucky421302

按如下指紋可關注公眾


相關焦點

  • Prometheus+Grafana+Alertmanager實現告警推送教程圖文詳解
    前言本文主要介紹的是Prometheus採集數據,通過Grafana加上PromQL語句實現數據可視化以及通過Alertmanage實現告警推送功能。溫馨提示,本篇文章特長,2w多的文字加上幾十張圖片,建議收藏觀看。Prometheus 介紹Prometheus 是一套開源的系統監控報警框架。
  • 監控工具之Prometheus普羅米修斯,搭建和使用
    Prometheus使用在多維度上靈活的查詢語言(PromQl)。PromQL (Prometheus Query Language) 是 Prometheus 自己開發的數據查詢 DSL 語言。Prometheus具有易管理、易集成、可擴展、支持自動發信等優勢。
  • Prometheus+Grafana+Alertmanager實現告警推送教程——圖文詳解
    最後Prometheus Server對外提供了自定義的PromQL語言,實現對數據的查詢以及分析。 Prometheus Server內置的Express Browser UI,通過這個UI可以直接通過PromQL實現數據的查詢以及可視化。
  • 小白也能輕鬆上手的Prometheus教程
    我們來詳細看看prometheus-server和prometheus-alertmanager。我們從第一個開始並理解其配置,我們如何編輯它並了解服務在哪個埠上運行。點擊垂直省略號菜單按鈕並點擊View/Edit YAML。
  • Prometheus Operator 監控ETCD集群
    kubectl edit prometheus k8s -n monitoring2.修改prometheus.yaml文件vim kube-prometheus-master/manifests/prometheus-prometheus.yaml nodeSelector:
  • CentOS7下簡單搭建Prometheus+Grafana監控系統
    服務端groupadd prometheususeradd -g prometheus -m -d /opt/prometheus/ -s /sbin/nologin prometheustar -zxf /data/prometheus-2.17.2.linux-amd64
  • Prometheus(普羅米修斯)——適合k8s和docker的監控系統
    介紹Prometheus(普羅米修斯)是一套開源的監控&報警&時間序列資料庫的組合.由SoundCloud公司開發。Prometheus基本原理是通過HTTP協議周期性抓取被監控組件的狀態,這樣做的好處是任意組件只要提供HTTP接口就可以接入監控系統,不需要任何SDK或者其他的集成過程。這樣做非常適合虛擬化環境比如VM或者Docker 。Prometheus應該是為數不多的適合Docker、Mesos、Kubernetes環境的監控系統之一。
  • 聊聊下一代監控:Prometheus
    ,大部分的組件都是用 Go 語言編寫的,因此部署非常方便,而這些組件大部分都是可選的,主要組件介紹如下:Prometheus ServerPrometheus Server 是 Prometheus 組件中的核心部分,負責實現對監控數據的獲取,存儲以及查詢。
  • 使用ssl_exporter監控K8S集群證書
    使用kubeadm搭建的集群默認證書有效期是1年,續費證書其實是一件很快的事情。但是就怕出事了才發現,畢竟作為專業搬磚工程師,每天都很忙的。鑑於此,監控集群證書有效期是一件不得不做的事情。然後修改prometheus-prometheus.yaml配置文件,新增如下內容:  additionalScrapeConfigs:    name: additional-config     key: prometheus-additional.yaml
  • 報警神器 AlertManager 的使用
    /alertmanager --config.file=simple.yml其中-config.file參數是用來指定對應的配置文件的,由於我們這裡同樣要運行到 Kubernetes 集群中來,所以我們使用docker鏡像的方式來安裝,使用的鏡像是:prom/alertmanager:v0.15.3。
  • 高可用是什麼意思?該如何保障系統的高可用?
    在討論伺服器領域的時候,我們常常會聽到「高可用」一詞,那麼「高可用」到底是什麼意思,應該怎麼去理解呢?高可用(HA)是分布式系統架構設計中必須考慮的因素之一,它通常是指,通過設計減少系統不能提供服務的時間。
  • 阿木實驗室推出Prometheus項目校園贊助計劃
    贊助對象—使用Prometheus進行科學研究,並發表論文的在校學生。 贊助要求 ○ 論文研究內容與自主無人機相關,並使用Prometheus項目進行相關仿真或實驗。 ○ 在文章中提及Prometheus項目,並且在參考文獻中引用項目Github主頁。 如何申請?
  • 架構師成長計劃|如何利用雲原生構建一個企業級高可用架構?
    Gartner 報告指出,到 2022 年,有 75% 的全球化企業將在生產中使用雲原生的服務化應用。不僅是網際網路行業,製造、房地產、生物醫藥、政府等各行各業都將擁抱雲原生技術。在這種背景下,行業也出現了較為徹底的預判:未來成功的企業都將採用雲原生技術,並且是深度應用。