前面我們已經學習了 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 等)以及降低採樣率來加速大時間範圍的數據查詢。
ThanosThanos 是一個基於 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 協議的對象存儲服務。
安裝 MinioMinIO 是一個基於 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
按如下指紋可關注公眾