背景
隨著業務規模的發展,需要的kafka叢集越來越來,這給部署與管理帶來了很大的挑戰。我們期望能夠利用K8S優秀的擴容能力與快速部署能力,為日常的工作減負。所以就kafka上K8S的可行性方案進行了調研。
像kafka叢集這種,涉及到的元件比較多,且都是有狀態的叢集,業界採用自定義operator的解決方案。目前GitHub上有多個相關的倉庫,根據社群活躍度及使用數等綜合考慮,此次採用Strimzi Github地址。
kafka元件互動圖
方案
- 使用阿里雲K8S叢集部署Strimzi
- 由於組內使用的kafka是由開源版本二次開發而來,所以需要維護一個自定義的Strimzi-kafka映象
- Strimzi管理kafka叢集,其中包含kafka、zk、kafka-exporter、
- 使用zoo-entrance 代理叢集中的zk GitHub地址
- 部署prometheus,採集kafka和zk的metrics
- 開啟服務埠,暴露kafka及zk給K8S叢集外部使用
實戰過程
構建自定義kafka映象
- 從公司Git上拉取最新程式碼 strimzi-kafka-operator (與開源版本有些微的改動,做實驗可直接用開源版)
- 在docker-images 資料夾下,有個Makefile檔案,執行其中的docker_build, 它會去執行其中的build.sh指令碼;此步會從官網拉取kafka的安裝包,我們需要將這一步的包修改為我司內部的安裝包。
- 構建完映象,映象在本地,我們需要將映象上傳到公司內部的harbor伺服器上
部署operator
每個K8S叢集僅需部署一個operator
- 充分必要條件:一個健康的k8s叢集
- 建立namespace, 如已有則跳過,預設使用kafka,kubectl create namespace kafka
- 從公司Git上拉取最新程式碼(地址在前邊)
- 目前檔案中預設監聽的是名稱為 kafka 的namespace,如果需要修改則執行 sed -i 's/namespace: ./namespace: kafka/' install/cluster-operator/RoleBinding*.yaml (將命令中的kafka/ 替換掉)
- 然後將所有檔案都應用一下 kubectl apply -f install/cluster-operator/ -n kafka
- 此時稍等片刻,就能檢視到建立的自定義資源以及operator了 kubectl get pods -nkafka,
- 從阿里雲的k8s管控臺檢視這些資源的建立情況,以及operator的執行情況
部署kafka叢集
確保你的operator已經部署成功,且kafka部署的namespace需在上邊operator的監控中
- 還是來到最新的程式碼目錄中,其中examples/kafka目錄下邊就是本次部署所需要的檔案了
- 部署 kafka及zk
- 檢視kafka-persistent.yaml, 該檔案就是核心檔案了,這個檔案部署了kafka與zk及kafka-exporter, 部分內容如下:
apiVersion: kafka.strimzi.io/v1beta2
kind: Kafka
metadata:
name: my-cluster
spec:
kafka:
version: 2.8.1
replicas: 3
resources:
requests:
memory: 16Gi
cpu: 4000m
limits:
memory: 16Gi
cpu: 4000m
image: repository.poizon.com/kafka-operator/poizon/kafka:2.8.4
jvmOptions:
-Xms: 3072m
-Xmx: 3072m
listeners:
- name: external
port: 9092
type: nodeport
tls: false
- name: plain
port: 9093
type: internal
tls: false
config:
offsets.topic.replication.factor: 2
transaction.state.log.replication.factor: 2
transaction.state.log.min.isr: 1
default.replication.factor: 2
***
template:
pod:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: strimzi.io/name
operator: In
values:
- my-cluster-kafka
topologyKey: "kubernetes.io/hostname"
storage:
type: persistent-claim
size: 100Gi
class: rocketmq-storage
deleteClaim: false
metricsConfig:
type: jmxPrometheusExporter
valueFrom:
configMapKeyRef:
name: kafka-metrics
key: kafka-metrics-config.yml
zookeeper:
replicas: 3
resources:
requests:
memory: 3Gi
cpu: 1000m
limits:
memory: 3Gi
cpu: 1000m
jvmOptions:
-Xms: 2048m
-Xmx: 2048m
jmxOptions: {}
template:
pod:
affinity:
podAntiAffinity:
***
storage:
type: persistent-claim
size: 50Gi
class: rocketmq-storage
deleteClaim: false
metricsConfig:
type: jmxPrometheusExporter
valueFrom:
configMapKeyRef:
name: kafka-metrics
key: zookeeper-metrics-config.yml
***
***
- 可修改kafka叢集的名稱,在第四行的name屬性,目前預設為 my-cluster
- 可修改kafka的Pod個數,即節點數,預設為3
- 可修改Pod配置 記憶體CPU
- 可修改kafka JVM 啟動的堆記憶體大小
- 可修改kafka的配置,在36行 config配置
- 可修改磁碟型別及大小,型別為第50行,可修改為其它的儲存類,目前可選為高效雲盤、SSD、ESSD
- zk修改同kafka,可修改的東西類似, 且在同一個檔案中
- 檔案下邊是kafka與zk需要暴露的metrics,可按需求增刪改
- 修改完配置之後,直接執行 kubect apply -f kafka-persistent.yaml -nkafka 即可建立
- 部署 zk代理
- 由於官方不支援外部元件直接訪問zk,所以採用代理的方式訪問
- 出於安全性 的考慮,官方是故意不支援外部程式訪問zk的: https://github.com/strimzi/strimzi-kafka-operator/issues/1337
- 部署完zk的代理,我們需要在k8s控制檯上 建立一個loadbalance服務將這個代理暴露給叢集外的應用進行連線。具體操作:k8s控制檯-->網路-->服務-->建立(選擇loadbalance建立,然後找到zoo-entrance這個應用即可)
- 部署 zk-exporter
- 官方operator中沒有zk-exporter, 我們採用 https://github.com/dabealu/zo...
- 在資料夾中的zk-exporter.yaml 檔案中,我們僅需要修改被監聽的zk的地址(spec.container.args)
- 執行kubectl apply -f zk-exporter.yaml即可部署完成
- 部署 kafka-jmx
- 由於ingress不支援tcp連線,而loadbalance的成本又過高,所以kafka 的 jmx 使用nodeport對外暴露
- 可以在阿里雲控制檯上建立相應的nodeport,也可以使用kafka-jmx.yaml 檔案的方式建立
apiVersion: v1
kind: Service
metadata:
labels:
strimzi.io/cluster: my-cluster
strimzi.io/name: my-cluster-kafka-jmx
name: my-cluster-kafka-jmx-0
spec:
ports:
- name: kafka-jmx-nodeport
port: 9999
protocol: TCP
targetPort: 9999
selector:
statefulset.kubernetes.io/pod-name: my-cluster-kafka-0
strimzi.io/cluster: my-cluster
strimzi.io/kind: Kafka
strimzi.io/name: my-cluster-kafka
type: NodePort
- 部署 kafka-exporter-service
- 前面部署完kafka之後,我們的配置中是開啟了exporter的。但是官方開啟完exporter之後,並沒有自動生成一個相關的service,為了讓Prometheus連線更加方便,我們部署了一個service
- 在資料夾中kafka-exporter-service.yaml 檔案中
apiVersion: v1
kind: Service
metadata:
labels:
app: kafka-export-service
name: my-cluster-kafka-exporter-service
spec:
ports:
- port: 9404
protocol: TCP
targetPort: 9404
selector:
strimzi.io/cluster: my-cluster
strimzi.io/kind: Kafka
strimzi.io/name: my-cluster-kafka-exporter
type: ClusterIP
- 執行kubectl apply -f kafka-exporter-service.yaml即可部署完成
- 部署 kafka-prometheus
- 如果將Prometheus部署在k8s叢集外,資料採集會比較麻煩,所以我們直接將Prometheus部署到叢集內
- 在資料夾中kafka-prometheus.yaml檔案中,可以選擇性的修改其中prometheus的配置,比如需要的記憶體CPU的大小,比如監控資料儲存時間,外掛的雲盤大小,以及需要監聽的kafka與zk地址
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: kafka-prometheus
labels:
app: kafka-prometheus
spec:
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
app: kafka-prometheus
serviceName: kafka-prometheus
updateStrategy:
type: RollingUpdate
template:
metadata:
labels:
app: kafka-prometheus
spec:
containers:
- args:
- '--query.max-concurrency=800'
- '--query.max-samples=800000000'
***
command:
- /bin/prometheus
image: 'repository.poizon.com/prometheus/prometheus:v2.28.1'
imagePullPolicy: IfNotPresent
livenessProbe:
failureThreshold: 10
httpGet:
path: /status
port: web
scheme: HTTP
initialDelaySeconds: 300
periodSeconds: 5
successThreshold: 1
timeoutSeconds: 3
name: kafka-prometheus
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 200m
memory: 128Mi
volumeMounts:
- mountPath: /etc/localtime
name: volume-localtime
- mountPath: /data/prometheus/
name: kafka-prometheus-config
- mountPath: /data/database/prometheus
name: kafka-prometheus-db
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
terminationGracePeriodSeconds: 30
restartPolicy: Always
schedulerName: default-scheduler
securityContext:
fsGroup: 0
volumes:
- hostPath:
path: /etc/localtime
type: ''
name: volume-localtime
- configMap:
defaultMode: 420
name: kafka-prometheus-config
name: kafka-prometheus-config
volumeClaimTemplates:
- apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: kafka-prometheus-db
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
storageClassName: rocketmq-storage
volumeMode: Filesystem
status:
phase: Pending
- 執行kubectl apply -f kafka-prometheus.yaml即可部署完成
- 部署完成後將prometheus暴露給監控組的grafana,可以直連pod IP做驗證,然後在k8s管控臺的 網路-->路由-->建立, 建立一個ingress,選擇剛剛部署的這個Prometheus的service,然後找運維申請域名,即可。
總結
- 優點
- 快速部署叢集(分鐘級),快速叢集擴容(秒級),快速災難恢復(秒級)
- 支援滾動更新,支援備份以及還原
- 缺點
- 引入較多元件,複雜度升高
- 對K8S叢集外的訪問不太友好
文/ZUOQI
關注得物技術,做最潮技術人!