C# OpenVINO YOLOv8实例分割可执行程序:从模型导出到C#推理的完整部署指南
2026/10/3 9:35:11
yaml文件方式,只需要对存储类名、名空间、节点IP和镜像地址进行调整,就可以在k8s部署起来的kafka集群(Kraft模式),该yaml适用于bitnami版本镜像,该yaml支持集群内外访问。
--- apiVersion: v1 kind: Service metadata: name: kafka-headless namespace: test spec: clusterIP: None publishNotReadyAddresses: true selector: app: kafka ports: - name: plaintext port: 9092 targetPort: 9092 - name: controller port: 9093 targetPort: 9093 --- apiVersion: v1 kind: Service metadata: name: kafka-svc namespace: test spec: type: ClusterIP selector: statefulset.kubernetes.io/pod-name: kafka-0 ports: - protocol: TCP port: 9092 targetPort: 9092 --- apiVersion: v1 kind: Service metadata: name: kafka-0 namespace: test spec: type: NodePort selector: statefulset.kubernetes.io/pod-name: kafka-0 ports: - protocol: TCP port: 39092 targetPort: 9092 nodePort: 39092 --- apiVersion: v1 kind: Service metadata: name: kafka-1 namespace: test spec: type: NodePort selector: statefulset.kubernetes.io/pod-name: kafka-1 ports: - protocol: TCP port: 39093 targetPort: 9092 nodePort: 39093 --- apiVersion: v1 kind: Service metadata: name: kafka-2 namespace: test spec: type: NodePort selector: statefulset.kubernetes.io/pod-name: kafka-2 ports: - protocol: TCP port: 39094 targetPort: 9092 nodePort: 39094 --- apiVersion: apps/v1 kind: StatefulSet metadata: name: kafka namespace: test spec: selector: matchLabels: app: kafka serviceName: kafka-headless replicas: 3 updateStrategy: type: RollingUpdate podManagementPolicy: OrderedReady template: metadata: labels: app: kafka spec: affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app operator: In values: [kafka] topologyKey: kubernetes.io/hostname securityContext: runAsUser: 1000 fsGroup: 1000 containers: - name: kafka image: kafka:3.9.0-debian-12-r13 imagePullPolicy: Always command: - bash - -ec - | HOSTNAME=`hostname -s` if [[ $HOSTNAME =~ (.*)-([0-9]+)$ ]]; then ORD=${BASH_REMATCH[2]} PORT=$((ORD + 39092)) export KAFKA_CFG_NODE_ID="$ORD" export KAFKA_CFG_ADVERTISED_LISTENERS="PLAINTEXT://192.168.100.100:$PORT" else echo "Failed to get index from hostname $HOSTNAME" exit 1 fi exec /entrypoint.sh /run.sh env: - {name: ALLOW_PLAINTEXT_LISTENER, value: 'yes'} - {name: KAFKA_KRAFT_CLUSTER_ID, value: 'MkU3OEVBNTcwNTJENDM2Qk'} - {name: KAFKA_CFG_PROCESS_ROLES, value: 'broker,controller'} - {name: KAFKA_CFG_LISTENERS, value: 'PLAINTEXT://:9092,CONTROLLER://:9093'} - {name: KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP, value: 'CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT'} - {name: KAFKA_CFG_INTER_BROKER_LISTENER_NAME, value: 'PLAINTEXT'} - {name: KAFKA_CFG_CONTROLLER_LISTENER_NAMES, value: 'CONTROLLER'} - {name: KAFKA_CFG_CONTROLLER_QUORUM_VOTERS, value: '0@kafka-0.kafka-headless.test.svc.cluster.local:9093,1@kafka-1.kafka-headless.test.svc.cluster.local:9093,2@kafka-2.kafka-headless.test.svc.cluster.local:9093'} - {name: KAFKA_CFG_OFFSETS_TOPIC_REPLICATION_FACTOR, value: '3'} - {name: KAFKA_CFG_TRANSACTION_STATE_LOG_MIN_ISR, value: '3'} - {name: KAFKA_CFG_TRANSACTION_STATE_LOG_REPLICATION_FACTOR, value: '3'} - {name: KAFKA_CFG_DEFAULT_REPLICATION_FACTOR, value: '3'} - {name: TZ, value: Asia/Shanghai} ports: - {containerPort: 9092, name: plaintext} - {containerPort: 9093, name: controller} resources: limits: {cpu: 500m, memory: 1Gi} requests: {cpu: 100m, memory: 500Mi} volumeMounts: - {name: kafka-data, mountPath: /bitnami/kafka} volumeClaimTemplates: - metadata: {name: kafka-data} spec: accessModes: [ReadWriteOnce] storageClassName: managed-nfs-storage resources: requests: {storage: 1000Gi}仅供参考。
官方kafka版本镜像,apache/kakfa
# ============================================================================= # Apache Kafka KRaft 模式 · Kubernetes StatefulSet 部署(Combined 模式 / 3 节点) # 镜像:apache/kafka:4.3.1(Apache 官方 JVM 镜像,自 3.7.0 起提供) # # 拓扑:3 个 Pod 同时承担 broker + controller 角色,可容忍 1 个节点故障。 # 适用:中小规模生产、测试/预发环境、希望用最少组件跑通 KRaft 的场景。 # 用法:kubectl apply -f kafka-kraft-combined.yaml # # 部署前必须确认/修改: # 1) CLUSTER_ID —— 换成自己生成的集群 ID(见 README「部署步骤」第 1 步) # 2) storageClassName —— 换成集群中实际存在的 StorageClass # 3) 存储容量、CPU/内存 requests/limits 按实际环境调整 # ============================================================================= # kafka-kraft-combined.yaml --- apiVersion: v1 kind: Namespace metadata: name: kafka labels: app.kubernetes.io/name: kafka --- # 无头 Service:为每个 Pod 提供稳定 DNS # kafka-0.kafka-headless.kafka.svc.cluster.local # kafka-1.kafka-headless.kafka.svc.cluster.local # kafka-2.kafka-headless.kafka.svc.cluster.local # publishNotReadyAddresses 必须为 true:KRaft 组建 quorum 时 Pod 之间需要互相解析, # 若等到 Ready 才注册 DNS,会因互相解析不到而永远无法 Ready(死锁)。 apiVersion: v1 kind: Service metadata: name: kafka-headless namespace: kafka labels: app.kubernetes.io/name: kafka spec: clusterIP: None publishNotReadyAddresses: true selector: app.kubernetes.io/name: kafka ports: - name: plaintext port: 9092 targetPort: 9092 protocol: TCP - name: controller port: 9093 targetPort: 9093 protocol: TCP --- # 普通 ClusterIP Service:给集群内客户端做 bootstrap 入口 # 客户端使用 kafka-bootstrap.kafka.svc.cluster.local:9092 apiVersion: v1 kind: Service metadata: name: kafka-bootstrap namespace: kafka labels: app.kubernetes.io/name: kafka spec: type: ClusterIP selector: app.kubernetes.io/name: kafka ports: - name: plaintext port: 9092 targetPort: 9092 protocol: TCP --- apiVersion: apps/v1 kind: StatefulSet metadata: name: kafka namespace: kafka labels: app.kubernetes.io/name: kafka spec: serviceName: kafka-headless replicas: 3 # 关键:Parallel。KRaft 的 quorum 需要多个 Pod 同时起来, # 若用默认的 OrderedReady,kafka-0 会因 quorum 不完整而无法 Ready, # 导致 kafka-1/kafka-2 永远不被创建。 podManagementPolicy: Parallel updateStrategy: type: RollingUpdate selector: matchLabels: app.kubernetes.io/name: kafka template: metadata: labels: app.kubernetes.io/name: kafka spec: # Kafka 关停需要时间做数据落盘,留足优雅退出时间 terminationGracePeriodSeconds: 60 securityContext: runAsUser: 1000 # 官方镜像内建 appuser(uid=1000, gid=1000) runAsGroup: 1000 runAsNonRoot: true fsGroup: 1000 # 让 PVC 挂载后对 appuser 可写,缺了会报权限错误 # 尽量把 3 个副本打散到不同节点(软约束,节点不足时仍可调度) affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: topologyKey: kubernetes.io/hostname labelSelector: matchLabels: app.kubernetes.io/name: kafka containers: - name: kafka image: apache/kafka:4.3.1 imagePullPolicy: IfNotPresent # 官方镜像的启动命令是 /etc/kafka/docker/run(CMD,非 ENTRYPOINT,可被覆盖)。 # 这里包一层 bash:用 Pod 名推导本节点的 node.id 与 advertised.listeners, # 因为这两个值每个 Pod 都不同,无法用静态 env 写死。 # 注意:${POD_NAME##*-} 是运行时由 bash 解析的,Kubernetes 只替换 $(VAR) 形式,不会误伤。 command: - bash - -c - | set -euo pipefail export KAFKA_NODE_ID="${POD_NAME##*-}" export KAFKA_ADVERTISED_LISTENERS="PLAINTEXT://${POD_NAME}.kafka-headless.kafka.svc.cluster.local:9092" exec /etc/kafka/docker/run ports: - name: plaintext containerPort: 9092 - name: controller containerPort: 9093 env: - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name # ---- 集群标识 ---------------------------------------------------- # 示例值,务必替换为自己生成的集群 ID(kafka-storage.sh random-uuid)。 # 同一集群所有节点必须一致;集群 ID 只在首次格式化数据目录时写入, # 之后想更换必须清空数据卷重新格式化。 - name: CLUSTER_ID value: "4L6g3nShT-eMCtK--X86sw" # ---- KRaft 角色与监听 -------------------------------------------- - name: KAFKA_PROCESS_ROLES value: "broker,controller" - name: KAFKA_LISTENERS value: "PLAINTEXT://:9092,CONTROLLER://:9093" - name: KAFKA_LISTENER_SECURITY_PROTOCOL_MAP value: "CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT" - name: KAFKA_INTER_BROKER_LISTENER_NAME value: "PLAINTEXT" - name: KAFKA_CONTROLLER_LISTENER_NAMES value: "CONTROLLER" # 控制器 quorum 成员:nodeId@Pod 的稳定 DNS - name: KAFKA_CONTROLLER_QUORUM_VOTERS value: "0@kafka-0.kafka-headless.kafka.svc.cluster.local:9093,1@kafka-1.kafka-headless.kafka.svc.cluster.local:9093,2@kafka-2.kafka-headless.kafka.svc.cluster.local:9093" # ---- 存储 -------------------------------------------------------- - name: KAFKA_LOG_DIRS value: "/var/lib/kafka/data" # ---- 副本因子:单节点测试环境要改成 1 ----------------------------- - name: KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR value: "3" - name: KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR value: "3" - name: KAFKA_TRANSACTION_STATE_LOG_MIN_ISR value: "2" # Kafka 4.x 新增的 share group(队列)协调器内部主题 - name: KAFKA_SHARE_COORDINATOR_STATE_TOPIC_REPLICATION_FACTOR value: "3" - name: KAFKA_SHARE_COORDINATOR_STATE_TOPIC_MIN_ISR value: "2" - name: KAFKA_DEFAULT_REPLICATION_FACTOR value: "3" - name: KAFKA_MIN_INSYNC_REPLICAS value: "2" - name: KAFKA_NUM_PARTITIONS value: "3" # ---- 常规参数 ---------------------------------------------------- - name: KAFKA_AUTO_CREATE_TOPICS_ENABLE value: "false" - name: KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS value: "0" - name: KAFKA_LOG_RETENTION_HOURS value: "168" # JVM 堆:按容器内存 limits 的 1/2 左右设置,留出页缓存和直接内存 - name: KAFKA_HEAP_OPTS value: "-Xms1g -Xmx1g" # 官方镜像里 bin 脚本齐全,用 broker API 探测更贴近"真的能服务请求", # 比单纯 TCP 端口探测更可靠。 startupProbe: exec: command: - /bin/sh - -c - /opt/kafka/bin/kafka-broker-api-versions.sh --bootstrap-server localhost:9092 >/dev/null 2>&1 initialDelaySeconds: 20 periodSeconds: 10 timeoutSeconds: 10 failureThreshold: 30 readinessProbe: exec: command: - /bin/sh - -c - /opt/kafka/bin/kafka-broker-api-versions.sh --bootstrap-server localhost:9092 >/dev/null 2>&1 periodSeconds: 10 timeoutSeconds: 10 failureThreshold: 6 # 刻意不配 livenessProbe:Kafka 启动慢且重启不能自愈(多为 quorum/存储问题), # 探活失败重启只会造成滚动失败循环,靠 startupProbe + readinessProbe 已足够。 resources: requests: cpu: "1" memory: "2Gi" limits: cpu: "2" memory: "4Gi" volumeMounts: - name: data mountPath: /var/lib/kafka/data volumeClaimTemplates: - metadata: name: data spec: accessModes: - ReadWriteOnce storageClassName: standard # TODO 改成集群实际的 StorageClass resources: requests: storage: 20Gi --- # 滚动升级/节点维护时保证最多只有 1 个 Kafka Pod 不可用 apiVersion: policy/v1 kind: PodDisruptionBudget metadata: name: kafka namespace: kafka spec: maxUnavailable: 1 selector: matchLabels: app.kubernetes.io/name: kafka# ============================================================================= # 可选:把 Kafka 暴露到集群外(NodePort 方案) # 镜像:apache/kafka:4.3.1(Apache 官方 JVM 镜像) # # 原理:客户端连接 broker 后会拿到 broker 自报的 advertised.listeners 地址并直连, # 所以每个 broker 必须有"自己的"对外入口,不能共用一个 Service/NodePort, # 否则客户端会被转发到错误的 broker。因此这里给每个 Pod 建一个独立 Service, # 用 selector: statefulset.kubernetes.io/pod-name 精确绑定到单个 Pod, # 并固定 nodePort,使地址可预测。 # # 使用前需要同时修改 StatefulSet(kafka-kraft-combined.yaml): # # 1) 增加一个 EXTERNAL 监听端口与安全协议映射: # - name: KAFKA_LISTENERS # value: "PLAINTEXT://:9092,CONTROLLER://:9093,EXTERNAL://:9094" # - name: KAFKA_LISTENER_SECURITY_PROTOCOL_MAP # value: "CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT,EXTERNAL:PLAINTEXT" # # 2) 增加容器端口 9094(containerPort: 9094, name: external) # # 3) 增加下行 API 环境变量,拿到 Pod 所在节点 IP: # - name: NODE_IP # valueFrom: # fieldRef: # fieldPath: status.hostIP # # 4) 改写 command 中的 advertised.listeners,把 EXTERNAL 指向"节点 IP + 固定 nodePort" # (nodePort 与下方 Service 的 30092/30093/30094 一一对应): # export KAFKA_ADVERTISED_LISTENERS="PLAINTEXT://${POD_NAME}.kafka-headless.kafka.svc.cluster.local:9092,EXTERNAL://${NODE_IP}:$((30092 + ${POD_NAME##*-}))" # # 5) 客户端 bootstrap 用 <任一节点IP>:30092,<另一节点IP>:30093,<第三节点IP>:30094 # 若集群前面有负载均衡/LB,建议把三个 nodePort 都注册到同一个对外地址上。 # # 安全提醒:PLAINTEXT 暴露到公网等于无认证无加密,生产环境务必改用 # SASL_SSL / SSL 监听(镜像支持挂载 /etc/kafka/secrets 下的证书与 JAAS 配置)。 # ============================================================================= --- apiVersion: v1 kind: Service metadata: name: kafka-external-0 namespace: kafka labels: app.kubernetes.io/name: kafka app.kubernetes.io/component: external spec: type: NodePort selector: statefulset.kubernetes.io/pod-name: kafka-0 ports: - name: external port: 9094 targetPort: 9094 nodePort: 30092 protocol: TCP --- apiVersion: v1 kind: Service metadata: name: kafka-external-1 namespace: kafka labels: app.kubernetes.io/name: kafka app.kubernetes.io/component: external spec: type: NodePort selector: statefulset.kubernetes.io/pod-name: kafka-1 ports: - name: external port: 9094 targetPort: 9094 nodePort: 30093 protocol: TCP --- apiVersion: v1 kind: Service metadata: name: kafka-external-2 namespace: kafka labels: app.kubernetes.io/name: kafka app.kubernetes.io/component: external spec: type: NodePort selector: statefulset.kubernetes.io/pod-name: kafka-2 ports: - name: external port: 9094 targetPort: 9094 nodePort: 30094 protocol: TCP# ============================================================================= # Apache Kafka KRaft 模式 · Kubernetes StatefulSet 部署(Isolated 模式) # 镜像:apache/kafka:4.3.1(Apache 官方 JVM 镜像) # # 拓扑:3 个专用 controller + 3 个专用 broker(角色分离),共 6 个 Pod。 # 适用:生产环境。controller 只跑元数据共识,不受 broker 流量影响,职责清晰、可独立扩缩容。 # 用法:kubectl apply -f kafka-kraft-isolated.yaml # (与 kafka-kraft-combined.yaml 二选一,不要同时部署) # # 部署前必须确认/修改: # 1) CLUSTER_ID、2) storageClassName、3) 容量与资源配置 # ============================================================================= # --- apiVersion: v1 kind: Namespace metadata: name: kafka labels: app.kubernetes.io/name: kafka # ============================== Controller 层 ============================== --- apiVersion: v1 kind: Service metadata: name: kafka-controller-headless namespace: kafka labels: app.kubernetes.io/name: kafka app.kubernetes.io/component: controller spec: clusterIP: None publishNotReadyAddresses: true selector: app.kubernetes.io/name: kafka app.kubernetes.io/component: controller ports: - name: controller port: 9093 targetPort: 9093 protocol: TCP --- apiVersion: apps/v1 kind: StatefulSet metadata: name: kafka-controller namespace: kafka labels: app.kubernetes.io/name: kafka app.kubernetes.io/component: controller spec: serviceName: kafka-controller-headless replicas: 3 podManagementPolicy: Parallel # quorum 组建要求多个 Pod 同时启动 selector: matchLabels: app.kubernetes.io/name: kafka app.kubernetes.io/component: controller template: metadata: labels: app.kubernetes.io/name: kafka app.kubernetes.io/component: controller spec: terminationGracePeriodSeconds: 60 securityContext: runAsUser: 1000 runAsGroup: 1000 runAsNonRoot: true fsGroup: 1000 affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: topologyKey: kubernetes.io/hostname labelSelector: matchLabels: app.kubernetes.io/name: kafka app.kubernetes.io/component: controller containers: - name: kafka image: apache/kafka:4.3.1 imagePullPolicy: IfNotPresent # controller 节点只需要 node.id;注意 controller-only 节点严禁设置 # KAFKA_ADVERTISED_LISTENERS(镜像启动脚本会直接报错退出)。 command: - bash - -c - | set -euo pipefail export KAFKA_NODE_ID="${POD_NAME##*-}" exec /etc/kafka/docker/run ports: - name: controller containerPort: 9093 env: - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: CLUSTER_ID value: "4L6g3nShT-eMCtK--X86sw" # TODO 替换为自己生成的集群 ID - name: KAFKA_PROCESS_ROLES value: "controller" - name: KAFKA_LISTENERS value: "CONTROLLER://:9093" - name: KAFKA_LISTENER_SECURITY_PROTOCOL_MAP value: "CONTROLLER:PLAINTEXT" - name: KAFKA_CONTROLLER_LISTENER_NAMES value: "CONTROLLER" - name: KAFKA_CONTROLLER_QUORUM_VOTERS value: "0@kafka-controller-0.kafka-controller-headless.kafka.svc.cluster.local:9093,1@kafka-controller-1.kafka-controller-headless.kafka.svc.cluster.local:9093,2@kafka-controller-2.kafka-controller-headless.kafka.svc.cluster.local:9093" - name: KAFKA_LOG_DIRS value: "/var/lib/kafka/data" # controller 也承载元数据日志,保留策略可略短于业务数据 - name: KAFKA_LOG_RETENTION_HOURS value: "168" - name: KAFKA_HEAP_OPTS value: "-Xms1g -Xmx1g" # controller 节点不提供 broker 端口,用 TCP 探测其 CONTROLLER 监听端口; # 更精确的 quorum 状态可用 kafka-metadata-quorum.sh 人工检查(见部署手册「验证」)。 startupProbe: tcpSocket: port: 9093 initialDelaySeconds: 20 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 30 readinessProbe: tcpSocket: port: 9093 periodSeconds: 15 timeoutSeconds: 5 failureThreshold: 6 resources: requests: cpu: "500m" memory: "2Gi" limits: cpu: "1" memory: "4Gi" volumeMounts: - name: data mountPath: /var/lib/kafka/data volumeClaimTemplates: - metadata: name: data spec: accessModes: - ReadWriteOnce storageClassName: standard # TODO 改成集群实际的 StorageClass resources: requests: storage: 10Gi # =============================== Broker 层 ================================ --- apiVersion: v1 kind: Service metadata: name: kafka-broker-headless namespace: kafka labels: app.kubernetes.io/name: kafka app.kubernetes.io/component: broker spec: clusterIP: None publishNotReadyAddresses: true selector: app.kubernetes.io/name: kafka app.kubernetes.io/component: broker ports: - name: plaintext port: 9092 targetPort: 9092 protocol: TCP --- # 客户端 bootstrap 入口:kafka-bootstrap.kafka.svc.cluster.local:9092 apiVersion: v1 kind: Service metadata: name: kafka-bootstrap namespace: kafka labels: app.kubernetes.io/name: kafka app.kubernetes.io/component: broker spec: type: ClusterIP selector: app.kubernetes.io/name: kafka app.kubernetes.io/component: broker ports: - name: plaintext port: 9092 targetPort: 9092 protocol: TCP --- apiVersion: apps/v1 kind: StatefulSet metadata: name: kafka-broker namespace: kafka labels: app.kubernetes.io/name: kafka app.kubernetes.io/component: broker spec: serviceName: kafka-broker-headless replicas: 3 podManagementPolicy: Parallel selector: matchLabels: app.kubernetes.io/name: kafka app.kubernetes.io/component: broker template: metadata: labels: app.kubernetes.io/name: kafka app.kubernetes.io/component: broker spec: terminationGracePeriodSeconds: 60 securityContext: runAsUser: 1000 runAsGroup: 1000 runAsNonRoot: true fsGroup: 1000 affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: topologyKey: kubernetes.io/hostname labelSelector: matchLabels: app.kubernetes.io/name: kafka app.kubernetes.io/component: broker containers: - name: kafka image: apache/kafka:4.3.1 imagePullPolicy: IfNotPresent # broker 的 node.id 从 3 开始,避免与 controller 的 0/1/2 冲突 command: - bash - -c - | set -euo pipefail export KAFKA_NODE_ID="$(( ${POD_NAME##*-} + 3 ))" export KAFKA_ADVERTISED_LISTENERS="PLAINTEXT://${POD_NAME}.kafka-broker-headless.kafka.svc.cluster.local:9092" exec /etc/kafka/docker/run ports: - name: plaintext containerPort: 9092 env: - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: CLUSTER_ID value: "4L6g3nShT-eMCtK--X86sw" # TODO 与 controller 保持一致 - name: KAFKA_PROCESS_ROLES value: "broker" - name: KAFKA_LISTENERS value: "PLAINTEXT://:9092" - name: KAFKA_LISTENER_SECURITY_PROTOCOL_MAP value: "CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT" - name: KAFKA_INTER_BROKER_LISTENER_NAME value: "PLAINTEXT" - name: KAFKA_CONTROLLER_LISTENER_NAMES value: "CONTROLLER" - name: KAFKA_CONTROLLER_QUORUM_VOTERS value: "0@kafka-controller-0.kafka-controller-headless.kafka.svc.cluster.local:9093,1@kafka-controller-1.kafka-controller-headless.kafka.svc.cluster.local:9093,2@kafka-controller-2.kafka-controller-headless.kafka.svc.cluster.local:9093" - name: KAFKA_LOG_DIRS value: "/var/lib/kafka/data" - name: KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR value: "3" - name: KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR value: "3" - name: KAFKA_TRANSACTION_STATE_LOG_MIN_ISR value: "2" - name: KAFKA_SHARE_COORDINATOR_STATE_TOPIC_REPLICATION_FACTOR value: "3" - name: KAFKA_SHARE_COORDINATOR_STATE_TOPIC_MIN_ISR value: "2" - name: KAFKA_DEFAULT_REPLICATION_FACTOR value: "3" - name: KAFKA_MIN_INSYNC_REPLICAS value: "2" - name: KAFKA_NUM_PARTITIONS value: "3" - name: KAFKA_AUTO_CREATE_TOPICS_ENABLE value: "false" - name: KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS value: "0" - name: KAFKA_LOG_RETENTION_HOURS value: "168" - name: KAFKA_HEAP_OPTS value: "-Xms2g -Xmx2g" startupProbe: exec: command: - /bin/sh - -c - /opt/kafka/bin/kafka-broker-api-versions.sh --bootstrap-server localhost:9092 >/dev/null 2>&1 initialDelaySeconds: 20 periodSeconds: 10 timeoutSeconds: 10 failureThreshold: 30 readinessProbe: exec: command: - /bin/sh - -c - /opt/kafka/bin/kafka-broker-api-versions.sh --bootstrap-server localhost:9092 >/dev/null 2>&1 periodSeconds: 10 timeoutSeconds: 10 failureThreshold: 6 resources: requests: cpu: "1" memory: "4Gi" limits: cpu: "2" memory: "8Gi" volumeMounts: - name: data mountPath: /var/lib/kafka/data volumeClaimTemplates: - metadata: name: data spec: accessModes: - ReadWriteOnce storageClassName: standard # TODO 改成集群实际的 StorageClass resources: requests: storage: 50Gi --- apiVersion: policy/v1 kind: PodDisruptionBudget metadata: name: kafka-controller namespace: kafka spec: maxUnavailable: 1 selector: matchLabels: app.kubernetes.io/name: kafka app.kubernetes.io/component: controller --- apiVersion: policy/v1 kind: PodDisruptionBudget metadata: name: kafka-broker namespace: kafka spec: maxUnavailable: 1 selector: matchLabels: app.kubernetes.io/name: kafka app.kubernetes.io/component: broker