【硬要手動部署】GCP架設Prometheus+Grafana監控K8S集群上之Flask-app

Hachibye
16 min readJun 4, 2023

--

GCP sets up Prometheus+Grafana to monitor Flask-app on Kubernetes cluster

【事前準備大綱】

  1. 申請Google Cloud Platform (GCP) 試用帳號
  2. 開設兩台虛擬主機,分別為主機A與主機B
  3. 申請Docker Hub帳號,並建立好repository(用來上傳docker映像檔)
  4. 主機A,以Docker-compose部署Prometheus+Grafana+Flask
  5. 主機B,安裝Docker以及K8S的基本三件套(kubectl kubelet kubeadm)
  6. 設置GCP上虛擬私有雲網路的防火牆權限,開通相關port(3000,5000,9090等)
  7. 測試A伺服器是否能獲取B伺服器的數據源,完成監控項目

申請帳號就不多說了,新帳號申請都有試用額度。

申請好帳號就直接前往控制台的Compute Engine開啟虛擬機器

選擇虛擬主機的所在區域以及類型
選擇作業系統以及硬碟大小
勾選允許HTTP以集HTTPS流量
進階選項可直接分配靜態外部IP(點擊保留靜態外部IP地址)

以上就完成了步驟1~2

申請Docker Hub帳號,並建立好repository
待會需要上傳封裝在docker映像檔的flask-app

再來就是設定防火牆規則

建立一個防火牆規則,將會使用到的port開啟

設定好防火牆規則之後就能以SSH連入主機

點擊SSH將會另開視窗連入主機

首先進入主機A
以Docker-compose部署Prometheus+Grafana+Flask

安裝Docker

sudo apt-get update
sudo apt-get install -y docker.io
sudo ln -sf /usr/bin/docker.io /usr/local/bin/docker

安裝Docker-Compose

sudo curl -L "https://github.com/docker/compose/releases/download/v2.6.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose 
sudo chmod +x /usr/local/bin/docker-compose
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose

開始建立Flask-app
首先要知道建立一個Docker映像檔需要有三件要素
1. Dockerfile(讓docker創建映像檔)
2. requirements.txt(指定所需的相依套件)
3. app.py(flask-app程式主體)

sudo mkdir app/
cd app/
sudo vim Dockerfile
# 官方Python映像檔
FROM python:3.9

# 工作目錄
WORKDIR /app

# 複製程式碼到容器
COPY app.py /app
COPY requirements.txt /app

# 安裝相依套件
RUN pip install --no-cache-dir -r requirements.txt

# 容器執行時的指令
CMD [ "python", "app.py" ]

以上寫好Dockerfile再來是requirements.txt

sudo vim requirements.txt
flask
prometheus_client

再來是程式主體app.py
這裡因為要提供給prometheus獲取數據源
因此較hello world的最最最基本flask還要來得多幾行

sudo vim app.py
import prometheus_client
from prometheus_client import Counter
from flask import Response, Flask, jsonify

app = Flask(__name__)

total_requests = Counter('request_count', 'Total webapp request count')

@app.route('/metrics')
def requests_count():
total_requests.inc()
return Response(prometheus_client.generate_latest(total_requests), mimetype='text/plain')

@app.route('/')
def index():
total_requests.inc()
return jsonify({
'status': 'ok'
})

if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)

再來就能製作為docker映像檔,並上傳至Docker Hub倉庫

# 建立
sudo docker build -t 映像檔名稱 .
# 上傳
sudo docker push 你的DockerHub帳號/映像檔名稱:標籤名稱

# 範例
# sudo docker build -t appk8s .
# 範例
# sudo docker push hachi4sre/appk8s:latest

再來先寫好Prometheus獲取數據源的YAML檔

sudo vim prometheus.yaml
# 設定 global 全域設定
# scrape_interval 是多久抓取一次資料
global:
scrape_interval: 5s
external_labels:
monitor: 'demo-monitor'

# scrape_configs 是抓取來源,若要新增數據源,就再新增一塊job_name區域
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: 'api_monitor'
scrape_interval: 5s
static_configs:
- targets: ['web:5000']

再來撰寫docker-compose.yaml
一口氣建立Prometheus+Grafana+Flask

sudo vim docker-compose.yaml
version: '3.7'

volumes:
prometheus_data: {}
grafana_data: {}

services:
prometheus:
image: prom/prometheus:v2.1.0
volumes:
- ./prometheus.yaml:/etc/prometheus/prometheus.yaml
command:
- '--web.enable-lifecycle'
- '--config.file=/etc/prometheus/prometheus.yaml'
ports:
- '9090:9090'
grafana:
image: grafana/grafana
volumes:
- grafana_data:/var/lib/grafana
environment:
- GF_SECURITY_ADMIN_PASSWORD=pass
depends_on:
- prometheus
ports:
- '3000:3000'
web:
build: .
ports:
- "5000:5000"
volumes:
- .:/app
depends_on:
- prometheus

以docker-compose建立服務並在背景執行

sudo docker-compose up -d
docker-compose-running

*記得要在YAML配置檔所在目錄底下執行喲!不然會報錯

測試是否能訪問

  1. Flask
    http://虛擬機器的外部ip:5000
  2. Prometheus
    http://虛擬機器的外部ip:9090
  3. Grafana
    http://虛擬機器的外部ip:9090
    預設密碼在docker-compose.yaml中設定為"pass"

查看Prometheus是否有獲取數據源

選擇需要查詢的指標再點擊execute就能看到獲取結果

至Grafana導入數據源並呈現為圖表

登入之後點擊主頁的加入數據源
選擇來源為Prometheus
填入虛擬主機的外網ip之後保存即可
獲取數據源之後就能自訂dashboard根據各項參數建立圖表

到這裡就建立好主機A
建立一個Flask-app,端口5000
通過Prometheus獲取數據源
並且能呈現數據在Grafana上

再來要設置主機B,一樣建立Flask-app只是通過K8S來部署

安裝Docker

sudo apt-get update
sudo apt-get install -y docker.io
sudo ln -sf /usr/bin/docker.io /usr/local/bin/docker

安裝K8S(事前)

# 關閉swap 
sudo swapoff -a

安裝K8S(正式)

sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl
curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
sudo apt-add-repository "deb http://apt.kubernetes.io/ kubernetes-xenial main"
sudo apt-get update
sudo apt-get install -y kubectl kubelet kubeadm
sudo apt-mark hold kubelet kubeadm kubectl

初始化K8S

sudo kubeadm init --pod-network-cidr=你的GCP虛擬機器內網的網段
# 範例
sudo kubeadm init --pod-network-cidr=10.140.0.0/16

讓使用者擁有執行權限

mkdir -p $HOME/.kube 
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

(重要)需要再幫K8S裝下網路套件
常見有三種:flannel、weave、calico
直接套用的話會報錯,需要修改預設的內網網段,以下拿flannel為例

首先在主機B上先開好flannel配置文件

sudo vim kube-flannel.yml

直接在瀏覽器打開下方kube-flannel.yaml的內容,全選並複製 https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

貼入自己建立的kube-flannel.yml之後
手動修改以下這一段(輸入你的GCP虛擬機器內網的網段)

  net-conf.json: |
{
"Network": "10.140.0.0/16",
"Backend": {
"Type": "vxlan"
}
}

2023.08.02更新,換了個CNI套件
https://antrea.io/docs/v1.4.0/docs/getting-started/

kubectl apply -f https://raw.githubusercontent.com/antrea-io/antrea/main/build/yamls/antrea.yml

上面的撰寫kube-flannel.yml內容若撰寫完畢之後,需要"套用"

kubectl apply -f kube-flannel.yml
kube-flannel-running

到這裡就會看到flannel已經在運行,並且node節點也是ready狀態

kubectl get pods --all-namespaces
kubectl get node

完整的安裝好K8S之後,再來要部署Flask-app了

撰寫部署的YAML

sudo vim deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: flask-deployment
spec:
replicas: 1
selector:
matchLabels:
app: flask-app
template:
metadata:
labels:
app: flask-app
spec:
containers:
- name: flask-container
image: <你的倉庫帳號>/<你的鏡像名稱>:<標籤>
ports:
- containerPort: 5000

因為在部署主機A的時候已經有把flask-app打包上傳hub
所以現在就很簡單只要從hub再把映像檔拉下來就能跑了

撰寫完畢之後需要"套用"

kubectl apply -f deployment.yaml

再來就能檢查pod是否有起來

kubectl get pods
pods-running

到這裡就已經成功以K8S部署Flask-app了
最後最麻煩的是K8S需要暴露端口提供給外網訪問
以下有兩種做法:

1. NodePort

撰寫service.yaml

sudo vim service.yaml
# NodePort版本

apiVersion: v1
kind: Service
metadata:
name: flask-service
spec:
type: NodePort
ports:
- protocol: TCP
port: 80
targetPort: 5000
selector:
app: flask-app

2. LoadBalancer

# LoadBalancer版本

apiVersion: v1
kind: Service
metadata:
name: flask-service
spec:
type: LoadBalancer
loadBalancerIP: <外部静态 IP>
ports:
- protocol: TCP
port: 80
targetPort: 5000
selector:
app: flask-app

查看service是否有配上外網ip以及暴露端口

# 查看service
kubectl get service

# 暴露端口
kubectl expose deployment <你的service名稱> --type=LoadBalancer --port=<你的容器端口> --external-ip=<你的外部IP> --target-port=<你的開放端口>

# 懶人包(防火牆規則自動建立)

kubectl expose deployment <你的service名稱> --type="LoadBalancer"

結果如下

訪問看看外網ip+指定端口是否可行

再來一樣到Prometheus查看是否有數據源

最後到Grafana導入數據源並匯出圖表就完成本日的大工程啦

--

--

Hachibye
Hachibye

Written by Hachibye

字幕組退休勞工 ... DevOps/系統/雲端/資安

No responses yet