爲了更直觀的看出金絲雀發佈的效果,咱們這裏使用了Prometheus監控來觀察這個過程。不知道怎麼使用Prometheus的同窗請看使用Prometheus監控Kubernetes集羣,另外咱們這裏使用一個Python程序來做爲咱們要發佈的程序。html
要想讓Prometheus監控你的程序,你的程序運行在容器裏,而容器有被POD這種資源形式所管理,那麼監控程序就是監控POD,因此首先你就須要在POD文件中聲明該POD須要被Prometheus抓取,這就須要經過一個標識來完成。node
在Prometheus的配置文件中因爲使用了Kubernetes自動發現,那麼它會有這麼一端配置內容,python
global: scrape_interval: 10s evaluation_interval: 30s scrape_configs: ...... # 抓取POD進行監控 - job_name: 'kubernetes-pods' kubernetes_sd_configs: - role: pod relabel_configs: # POD的 annotation 中含有"prometheus.io/scrape: true" 的則保留, # 意思就是會被Prometheus抓取,不具備這個的POD則不會被抓取 - action: keep regex: true source_labels: - __meta_kubernetes_pod_annotation_prometheus_io_scrape # 獲取POD的 annotation 中定義的"prometheus.io/path: XXX"定義的值, # 這個值就是你的程序暴露符合prometheus規範的metrics的地址,若是你的 # metrics的地址不是 /metrics 的話,經過這個標籤說,那麼這裏就會把這個 # 值賦值給 __metrics_path__這個變量,由於prometheus是經過這個變量 # 獲取路徑而後進行拼接出來一個完整的URL,並經過這個URL來獲取metrics值的, # 由於prometheus默認使用的就是 http(s)://X.X.X.X/metrics # 這樣一個路徑來獲取的。 - action: replace regex: (.+) source_labels: - __meta_kubernetes_pod_annotation_prometheus_io_path target_label: __metrics_path__ # 這裏是端口信息,由於你的程序頗有可能在容器中並非以80端口運行的, # 那麼就須要作一個拼接http(s)://x.x.x.x:xx/metrics # __address__在prometheus中表明的就是實例的IP地址, # 而POD中的annotation 中定義的"prometheus.io/port: XX"就是你程序 # 被訪問到的端口,最終在prometheus中將會被顯示爲 instance=X.X.X.X:XX這樣 - action: replace regex: ([^:]+)(?::\d+)?;(\d+) replacement: $1:$2 source_labels: - __address__ - __meta_kubernetes_pod_annotation_prometheus_io_port target_label: __address__ - action: labelmap regex: __meta_kubernetes_pod_label_(.+) - source_labels: [__meta_kubernetes_namespace] action: replace target_label: kubernetes_namespace - source_labels: [__meta_kubernetes_pod_name] action: replace target_label: kubernetes_pod_name
因此最關鍵的就是在POD中配置上以下內容:git
annotations: prometheus.io/scrape: "true" prometheus.io/port: "your port" # 若是的metrics的路徑就是 /metrics的話就不用配置下面的內容 prometheus.io/path: "your path"
但不少概念不清的人會發現你在POD中配置了這樣的設置prometheus獲取過來會報錯,好比我這裏使用了一個標準的tomcat鏡像來啓動2個POD,下面是deployment配置清單文件:github
apiVersion: v1 kind: Service metadata: name: myapp-svc labels: appname: myapp-svc spec: type: ClusterIP ports: - name: tomcat-http port: 8080 targetPort: 8080 selector: appname: myapp --- apiVersion: apps/v1 kind: Deployment metadata: name: tomcat-deploy-v1.11.1 labels: appname: myapp spec: replicas: 2 selector: matchLabels: appname: myapp release: 1.11.1 template: metadata: name: myapp labels: appname: myapp release: 1.11.1 annotations: prometheus.io/scrape: "true" prometheus.io/port: "8080" spec: containers: - name: myapp image: tomcat:8.5.38-jre8 imagePullPolicy: IfNotPresent resources: requests: cpu: "250m" memory: "128Mi" limits: cpu: "500m" memory: "256Mi" ports: - name: http containerPort: 8080 protocol: TCP livenessProbe: httpGet: path: / port: http initialDelaySeconds: 20 periodSeconds: 10 timeoutSeconds: 2 readinessProbe: httpGet: path: / port: http initialDelaySeconds: 20 periodSeconds: 10 revisionHistoryLimit: 10 strategy: rollingUpdate: maxSurge: 1 maxUnavailable: 1 type: RollingUpdate
而後我應用這個清單文件,以下圖:docker
而後在Pormetheus中能夠看到那2個POD已經被抓取了,可是狀態爲DOWN,以下圖:flask
查詢指標也是沒有的api
其緣由就是由於標準Tomcat自帶的應用沒有/metrics這個路徑,prometheus獲取不到它能識別的格式數據,而指標數據就是從/metrics這裏獲取的。因此咱們使用標準Tomcat不行或者你就算有這個/metrics這個路徑,可是返回的格式不符合prometheus的規範也是不行的。tomcat
金絲雀發佈我這裏爲何非要讓prometheus來監控呢?其實金絲雀發佈和prometheus不要緊,弄2個配置清單文件就能夠了,可是爲了更加直觀的看出發佈過程的流量狀況我這裏才使用了prometheus來監控這個過程,不然你很難有一個更加直觀的認識,並且在實際工做中監控也是必須的尤爲是對核心應用的升級。那麼下面咱們就本身製做一個符合prometheus指標規範的程序。app
下面是目錄結構
下面是myapp.py文件的內容
import prometheus_client from prometheus_client import Counter, Gauge from prometheus_client import Summary, CollectorRegistry from flask import Response, Flask import time import random import os app = Flask(__name__) # 定義一個註冊器,註冊器能夠把指標都收集起來,而後最後返回註冊器數據 REGISTRY = CollectorRegistry(auto_describe=False) # 定義一個Counter類型的變量,這個變量不是指標名稱,這種Counter類型只增長 # 不減小,程序重啓的時候會被從新設置爲0,構造函數第一個參數是定義 指標名稱, # 第二個是定義HELP中顯示的內容,都屬於文本 # 第三個參數是標籤列表,也就是給這個指標加labels,這個也能夠不設置 http_requests_total = Counter("http_requests", "Total request cout of the host", ['method', 'endpoint'], registry=REGISTRY) # Summary類型,它能夠統計2個時間 # request_processing_seconds_count 該函數被調用的數量 # request_processing_seconds_sum 該函數執行所花的時長 request_time = Summary('request_processing_seconds', 'Time spent processing request', registry=REGISTRY) @app.route("/metrics") def requests_count(): """ 當訪問/metrics這個URL的時候就執行這個方法,並返回相關信息。 :return: """ return Response(prometheus_client.generate_latest(REGISTRY), mimetype="text/plain") # 這個是健康檢查用的 @app.route('/healthy') def healthy(): return "healthy" @app.route('/') @request_time.time() # 這個必需要放在app.route的下面 def hello_world(): # .inc()表示增長,默認是加1,你能夠設置爲加1.5,好比.inc(1.5) # http_requests_total.inc() # 下面這種寫法就是爲這個指標加上標籤,可是這裏的method和endpoint # 都在Counter初始化的時候放進去的。 # 你想統計那個ULR的訪問量就把這個放在哪裏 http_requests_total.labels(method="get", endpoint="/").inc() # 這裏設置0-1之間隨機數用於模擬頁面響應時長 time.sleep(random.random()) html = "Hello World!" \ "App Version: {version}" # 這裏我會讀取一個叫作VERSION的環境變量, # 這個變量會隨Dockerfile設置到鏡像中 return html.format(version=os.getenv("VERSION", "888")) if __name__ == '__main__': app.run(host="0.0.0.0", port="5555")
下面是requirements.txt文件內容
Flask prometheus_client
下面是Dockerfile文件的內容
# 使用官方提供的 Python 開發鏡像做爲基礎鏡像 FROM python:3.7.3-slim # 建立目錄 RUN mkdir /app # 將工做目錄切換爲 /app 該目錄爲容器中的目錄,至關於cd進入這個目錄 WORKDIR /app # 將Dockerfile所在目錄下的這兩個文件拷貝到 /app 下 ADD myapp.py requirements.txt /app/ # 使用 pip 命令安裝這個應用所須要的依賴,這裏經過-r指定依賴包的名稱文件 RUN pip install --trusted-host mirrors.aliyun.com -r requirements.txt # 容許外界訪問容器的 5555 端口 EXPOSE 5555 # 設置版本號 ENV VERSION 1.0 # 設置容器進程爲:python myapp.py,即:這個 Python 應用的啓動命令 CMD ["python", "myapp.py"]
使用下面的命令構建鏡像docker build -t myapp:v1.0 .
打完包,以下圖
使用docker save -o myapp.tar myapp:v1.0
命令導出該鏡像,而後拷貝到Kubernetes集羣中全部node節點上,而後使用這個命令進行導入docker load -i ./myapp.tar
。
其實這個配置清單文件我就是用上面那個Tomcat的文件修改的。
apiVersion: v1 kind: Service metadata: name: myapp-svc labels: appname: myapp-svc spec: type: ClusterIP ports: - name: http port: 5555 targetPort: 5555 selector: appname: myapp --- apiVersion: apps/v1 kind: Deployment metadata: name: myapp-deploy-v1.0 labels: appname: myapp spec: replicas: 4 selector: matchLabels: appname: myapp release: 1.0.0 template: metadata: name: myapp labels: appname: myapp release: 1.0.0 annotations: prometheus.io/scrape: "true" prometheus.io/port: "5555" spec: containers: - name: myapp image: myapp:v1.0 imagePullPolicy: IfNotPresent resources: requests: cpu: "250m" memory: "128Mi" limits: cpu: "500m" memory: "256Mi" ports: - name: http containerPort: 5555 protocol: TCP livenessProbe: httpGet: path: /healthy port: http initialDelaySeconds: 20 periodSeconds: 10 timeoutSeconds: 2 readinessProbe: httpGet: path: /healthy port: http initialDelaySeconds: 20 periodSeconds: 10 revisionHistoryLimit: 10 strategy: rollingUpdate: maxSurge: 1 maxUnavailable: 1 type: RollingUpdate
應用文件
如今查看Prometheus的監控你能夠看到你的程序了
獲取指標數據
這裏主要是在Grafana中創建一個圖表來監控發佈過程。
首先創建一個Graph的圖表,而後按照下面的參數設置
使用這個公式sum(rate(http_requests_total{appname="myapp"}[5m])) by (release)
再設置一個名字
最後保存圖表就能夠了
編寫v2.0版本的配置清單文件,這裏不須要設置service,且副本數量爲1,我這裏沒有修改程序,只是傳遞了一個環境變量進去表示是2.0版本。
apiVersion: apps/v1 kind: Deployment metadata: name: myapp-deploy-v2.0 labels: appname: myapp spec: replicas: 1 selector: matchLabels: appname: myapp release: 2.0.0 template: metadata: name: myapp labels: appname: myapp release: 2.0.0 annotations: prometheus.io/scrape: "true" prometheus.io/port: "5555" spec: containers: - name: myapp image: myapp:v1.0 imagePullPolicy: IfNotPresent resources: requests: cpu: "250m" memory: "128Mi" limits: cpu: "500m" memory: "256Mi" ports: - name: http containerPort: 5555 protocol: TCP env: - name: VERSION value: v2.0.0 livenessProbe: httpGet: path: /healthy port: http initialDelaySeconds: 20 periodSeconds: 10 timeoutSeconds: 2 readinessProbe: httpGet: path: /healthy port: http initialDelaySeconds: 20 periodSeconds: 10 revisionHistoryLimit: 10 strategy: rollingUpdate: maxSurge: 1 maxUnavailable: 1 type: RollingUpdate
應用該配置清單文件
查看監控,黃色表示v2.0.0版本已經有請求了
咱們V1.0版本有4個副本,V2.0有1個副本,這就意味着30%的流量會進入到v2.0版本上。若是沒有問題,咱們就會進行擴展V2.0的應用。其實你從圖上看流量也只有30%,以下圖:
下面進行擴展
kubectl scale --replicas=4 deploy myapp-deploy-v2.0
刪除版本V1.0的deployment,注意這裏是刪除的deployment而並無刪除那個service
kubectl delete deploy myapp-deploy-v1.0
以後你就能夠看到V2.0版本已經接管了全部流量
步驟:
4個副本的V1.0應用
部署1個V2.0的應用
觀察一段時間確認沒有問題
擴展V2.0的應用數量和V1.0一致
擴展完成後,刪除V1.0版本應用
這個實驗過程參考了一篇文章Kubernetes deployment strategies,它裏面還有不少部署方式,你們能夠練習。另外我這裏之因此選擇本身構建鏡像而不使用它提供的,是由於我想說明一下如何在Prometheus中監控本身的應用,由於這種需求在工做中會有,即使運維不會遇到,可是運行公司業務的程序也會有這種需求,prometheus提供了Java版本的客戶端來讓Java使用。其實我如今對Python版本的客戶端也不是很瞭解,只是參考官網簡單使用而已。