在k8s环境部署Apache kafka4.3.1

说明

在kubernetes环境部署Apache kafka 4.3.1 集群架构,多节点,combined模式,无SSL。支持集群内外访问,带web UI管理

配置文件v4.yaml

删掉注释使用,配置文件说明如下

bash 复制代码
---
# ==========================================
# 0. RBAC 权限配置 (允许 Pod 读取 Service 属性)
# ==========================================
apiVersion: v1
kind: ServiceAccount
metadata:
  name: kafka-sa
  labels:
    app: kafka
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: kafka-service-reader
  labels:
    app: kafka
rules:
  - apiGroups: [""]
    resources: ["services"]
    verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: kafka-service-reader-binding
  labels:
    app: kafka
subjects:
  - kind: ServiceAccount
    name: kafka-sa
roleRef:
  kind: Role
  name: kafka-service-reader
  apiGroup: rbac.authorization.k8s.io

---
# ==========================================
# 1. 内部 Headless 服务 (用于集群发现与选举)
# ==========================================
apiVersion: v1
kind: Service
metadata:
  name: kafka-headless
  labels:
    app: kafka
spec:
  publishNotReadyAddresses: true
  clusterIP: None
  ports:
    - name: broker
      port: 19092
      targetPort: 19092
    - name: controller
      port: 9093
      targetPort: 9093
  selector:
    app: kafka

---
# ==========================================
# 2. 外部暴露 NodePort 服务 (kafka-0)
# ==========================================
apiVersion: v1
kind: Service
metadata:
  name: kafka-0-ext
spec:
  type: NodePort
  selector:
    statefulset.kubernetes.io/pod-name: kafka-0
  ports:
    - name: external
      port: 9092
      targetPort: 9092
      nodePort: 30092 # <-- 可随意修改,不要注释

---
# ==========================================
# 3. 外部暴露 NodePort 服务 (kafka-1)
# ==========================================
apiVersion: v1
kind: Service
metadata:
  name: kafka-1-ext
spec:
  type: NodePort
  selector:
    statefulset.kubernetes.io/pod-name: kafka-1
  ports:
    - name: external
      port: 9092
      targetPort: 9092
      nodePort: 30093 # <-- 可随意修改,不要注释

---
# ==========================================
# 4. 外部暴露 NodePort 服务 (kafka-2)
# ==========================================
apiVersion: v1
kind: Service
metadata:
  name: kafka-2-ext
spec:
  type: NodePort
  selector:
    statefulset.kubernetes.io/pod-name: kafka-2
  ports:
    - name: external
      port: 9092
      targetPort: 9092
      nodePort: 30094 # <-- 可随意修改,不要注释

---
# ==========================================
# 5. StatefulSet 主体定义
# ==========================================
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: kafka
  labels:
    app: kafka
spec:
  serviceName: kafka-headless
  replicas: 3
  podManagementPolicy: Parallel
  selector:
    matchLabels:
      app: kafka
  template:
    metadata:
      labels:
        app: kafka
    spec:
      serviceAccountName: kafka-sa # <-- 绑定 RBAC 账户
      affinity:
        podAntiAffinity:
          # 软性反亲和,避免 Pod 部署在同一节点上,会出现多pod在同一node的情况。适合资源紧张的环境。
          preferredDuringSchedulingIgnoredDuringExecution:
            - weight: 100
              podAffinityTerm:
                labelSelector:
                  matchExpressions:
                    - key: app
                      operator: In
                      values:
                        - kafka
                topologyKey: kubernetes.io/hostname
      
      # ----------------------------------------------------
      # 重构后的 InitContainer (同时负责权限修复和API获取)
      # ----------------------------------------------------
      initContainers:
        - name: init-kafka
          image: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/library/busybox:1.38.0
          command:
            - /bin/sh
            - -c
            - |
              # 1. 修复数据目录权限
              chown -R 1000:1000 /tmp/kraft-combined-logs
              
              # 2. 利用 busybox 自带的 wget 请求 API 获取端口
              ORDINAL=${HOSTNAME##*-}
              APISERVER="https://kubernetes.default.svc"
              SERVICEACCOUNT="/var/run/secrets/kubernetes.io/serviceaccount"
              TOKEN=$(cat ${SERVICEACCOUNT}/token)
              NAMESPACE=$(cat ${SERVICEACCOUNT}/namespace)
              
              echo "Fetching NodePort for Service [ ${HOSTNAME}-ext ] in namespace [ ${NAMESPACE} ] using wget..."
              
              # 发送 HTTPS 请求 (通过 --no-check-certificate 跳过集群内自签证书验证)
              SVC_JSON=$(wget --no-check-certificate --header="Authorization: Bearer ${TOKEN}" -qO- ${APISERVER}/api/v1/namespaces/${NAMESPACE}/services/${HOSTNAME}-ext)
              
              # 提取 nodePort (兼容纯净 busybox 中的 grep)
              EXTERNAL_PORT=$(echo "$SVC_JSON" | grep -o '"nodePort": *[0-9]*' | grep -o '[0-9]*' | head -n 1)
              
              if [ -z "$EXTERNAL_PORT" ]; then
                echo "ERROR: Failed to retrieve NodePort from K8s API."
                echo "API Response: $SVC_JSON"
                exit 1
              fi
              
              echo "Successfully retrieved dynamic NodePort: ${EXTERNAL_PORT}"
              
              # 3. 将结果写入共享卷
              echo "${EXTERNAL_PORT}" > /tmp/shared/nodeport
          volumeMounts:
            - name: kafka-logs
              mountPath: /tmp/kraft-combined-logs
            - name: shared-data             # <-- 挂载临时共享目录
              mountPath: /tmp/shared
              
      containers:
        - name: kafka
          image: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/apache/kafka:4.3.1
          command:
            - /bin/bash
            - -c
            - |
              # 1. 基础环境获取
              ORDINAL=${HOSTNAME##*-}
              export KAFKA_NODE_ID=$((ORDINAL + 1))
              INTERNAL_NAME="${HOSTNAME}.kafka-headless"
              
              # 2. 从临时共享目录直接读取已获取的端口号
              if [ ! -f "/tmp/shared/nodeport" ]; then
                echo "ERROR: nodeport file not found in /tmp/shared!"
                exit 1
              fi
              EXTERNAL_PORT=$(cat /tmp/shared/nodeport)
              echo "Successfully read NodePort from shared volume: ${EXTERNAL_PORT}"
              
              # 3. 注入动态监听器并启动 Kafka
              export KAFKA_ADVERTISED_LISTENERS="PLAINTEXT://${INTERNAL_NAME}:19092,PLAINTEXT_HOST://${HOST_IP}:${EXTERNAL_PORT}"
              
              exec /etc/kafka/docker/run
          ports:
            - containerPort: 19092
              name: internal
            - containerPort: 9092
              name: external
            - containerPort: 9093
              name: controller
          env:
            - name: HOST_IP
              valueFrom:
                fieldRef:
                  fieldPath: status.hostIP
            - name: KAFKA_PROCESS_ROLES
              value: 'broker,controller'
            - name: KAFKA_LISTENER_SECURITY_PROTOCOL_MAP
              value: 'CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT'
            - name: KAFKA_CONTROLLER_QUORUM_VOTERS
              value: '1@kafka-0.kafka-headless:9093,2@kafka-1.kafka-headless:9093,3@kafka-2.kafka-headless:9093'
            - name: KAFKA_LISTENERS
              value: 'PLAINTEXT://0.0.0.0:19092,CONTROLLER://0.0.0.0:9093,PLAINTEXT_HOST://0.0.0.0:9092'
            - name: KAFKA_INTER_BROKER_LISTENER_NAME
              value: 'PLAINTEXT'
            - name: KAFKA_CONTROLLER_LISTENER_NAMES
              value: 'CONTROLLER'
            - name: CLUSTER_ID
              value: '4L6g3nShT-eMCtK--X86sw'
            - name: KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR
              value: '2'
            - name: KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS
              value: '1000'
            - name: KAFKA_TRANSACTION_STATE_LOG_MIN_ISR
              value: '2'
            - name: KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR
              value: '2'
            - name: KAFKA_SHARE_COORDINATOR_STATE_TOPIC_REPLICATION_FACTOR
              value: '2'
            - name: KAFKA_SHARE_COORDINATOR_STATE_TOPIC_MIN_ISR
              value: '2'
            - name: KAFKA_LOG_DIRS
              value: '/tmp/kraft-combined-logs'
          volumeMounts:
            - name: kafka-logs
              mountPath: /tmp/kraft-combined-logs
            - name: shared-data             # <-- 挂载临时共享目录
              mountPath: /tmp/shared
          readinessProbe:
            exec:
              command: ["/bin/bash", "-c", "/opt/kafka/bin/kafka-broker-api-versions.sh --bootstrap-server localhost:19092 || exit 1"]
            initialDelaySeconds: 30
            periodSeconds: 60
            timeoutSeconds: 5
            failureThreshold: 2
            
      # 定义 Pod 的卷信息
      volumes:
        - name: shared-data
          emptyDir: {}                        # <-- 在内存中使用的临时挂载卷,Pod 重启时自动销毁
  # 未指定storageclass,若环境有多个,需手动指定。
  volumeClaimTemplates:
    - metadata:
        name: kafka-logs
      spec:
        accessModes: [ "ReadWriteOnce" ]
        resources:
          requests:
            storage: 20Gi

---
# ==========================================
# 6. Kafka UI 部署定义  可选,不用可注释
# ==========================================
apiVersion: apps/v1
kind: Deployment
metadata:
  name: kafka-ui
  labels:
    app: kafka-ui
spec:
  replicas: 1
  selector:
    matchLabels:
      app: kafka-ui
  template:
    metadata:
      labels:
        app: kafka-ui
    spec:
      containers:
        - name: kafka-ui
          image: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/provectuslabs/kafka-ui:v0.7.2
          ports:
            - containerPort: 8080
          env:
            - name: KAFKA_CLUSTERS_0_NAME
              value: "kafka-cluster"
            - name: KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS
              value: "kafka-0.kafka-headless:19092,kafka-1.kafka-headless:19092,kafka-2.kafka-headless:19092"
            - name: DYNAMIC_CONFIG_ENABLED
              value: "true"

---
# ==========================================
# 7. Kafka UI 外部访问 NodePort
# ==========================================
apiVersion: v1
kind: Service
metadata:
  name: kafka-ui-ext
  labels:
    app: kafka-ui
spec:
  type: NodePort
  selector:
    app: kafka-ui
  ports:
    - name: http
      port: 8080
      targetPort: 8080
      nodePort: 31808

部署

bash 复制代码
kubectl create namespace kafka
kubectl apply -f v4.yaml -n kafka

查询

确认web 界面的端口

bash 复制代码
kubectl get all -n kafka -o wide

访问

查询节点IP

浏览器访问

相关推荐
qq_163135751 小时前
Apache NIFI MergeContent
apache
探索云原生15 小时前
终于搞懂 Kueue:5 个核心对象一次讲透
linux·docker·ai·云原生·kubernetes
众人皆醒我独醉16 小时前
etcd,其实不是你以为的"数据库"——Kubernetes 大脑的六个反直觉真相
面试·kubernetes
蜀道山老天师18 小时前
从零读懂 K8s:核心概念、集群架构与工作原理
容器·架构·kubernetes
静待雨落20 小时前
Docker 高频命令
docker·容器
OsDepK21 小时前
Windows快速部署Docker
运维·docker·容器
前端Baymax1 天前
kube-proxy iptables模式下NodePort间歇性超时
docker·容器·kubernetes
欢醉1 天前
k8s的pod容器中微服务无法创建新线程unable to create new native thread
kubernetes·springboot
一只积极向上的小咸鱼1 天前
多机Docker + InfiniBand 分布式运行实操手册
分布式·docker·容器