设置容器网络日志

本指南逐步讲解如何在 Advanced Container Networking Services 中为 Azure Kubernetes 服务 (AKS) 配置容器网络日志。 可以通过持久性存储来设置 存储日志,以实现连续收集,或者通过 按需日志进行实时故障排除。

有关捕获哪些容器网络日志以及何时使用每个模式的概述,请参阅 什么是容器网络日志?。

Important

容器网络日志由 ACNS 本身生成,因此日志生成不依赖于Azure Monitor。 启用 ACNS 并应用 ContainerNetworkLog CRD 后,流日志将写入 /var/log/acns/hubble/events.log 处的每个节点。

为了获得完整的生产级可观测性体验,我们建议启用Azure Monitor加载项。 它将主机本地日志收集到 Log Analytics 工作区,并启用长期保留、KQL、内置 Azure 门户仪表板和托管 Grafana 仪表板。

如果未启用Azure Monitor,仍可以直接使用主机本地日志,或将它们转发到任何与 OpenTelemetry 兼容的收集器或日志记录服务。

先决条件

  • 拥有有效订阅的 Azure 帐户。 如果没有订阅,请在开始之前创建一个试用帐户。
  • 如需在本地运行 CLI 参考命令,请安装 Azure CLI。 如果在 Windows 或 macOS 上运行,请考虑在 Docker 容器中运行 Azure CLI。 有关详细信息,请参阅如何在 Docker 容器中运行 Azure CLI。

    • 如果使用本地安装,请使用 az login 命令登录到Azure CLI。 若要完成身份验证过程,请遵循终端中显示的步骤。 有关其他登录选项,请参阅使用 Azure CLI 登录。

    • 出现提示时,请在首次使用时安装 Azure CLI 扩展。 有关扩展的详细信息,请参阅 将扩展与 Azure CLI 配合使用。

    • 运行az version命令,以查看已安装的版本和依赖库。 若要升级到最新版本,请运行az upgrade。

  • Azure CLI 2.85.0 或更高版本。 运行 az --version 以检查。 若要安装或升级,请参阅安装 Azure CLI。

  • aks-preview Azure CLI 扩展版本 20.0.0b4 或更高版本:

    # Install the aks-preview extension
    az extension add --name aks-preview
    # Update the extension to make sure you have the latest version installed
    az extension update --name aks-preview
    
  • 存储日志模式需要 Cilium 数据平面。

  • 按需日志模式适用于 Cilium 和非 Cilium 数据平面。

  • 群集必须运行 Kubernetes 版本 1.33 或更高版本。

  • 仅当启用第 7 层策略支持时,才会捕获第 7 层流数据。 有关详细信息,请参阅 配置第 7 层策略。

  • 仅当应用 Cilium FQDN 网络策略时,才会捕获 DNS 流和指标。 有关详细信息,请参阅 配置 FQDN 策略。

配置日志存储模式

存储日志模式允许 ACNS 在每个节点上持续捕获网络流日志。 日志开始流动需要两个条件:

  1. 必须在群集上启用 ACNS。 这会配置 Cilium 代理组件以捕获流。
  2. 必须应用至少一个 ContainerNetworkLog CRD。 这定义了捕获的流量。 如果没有 CRD,则不会生成日志。

两者都到位后,流日志将写入 /var/log/acns/hubble/events.log 每个节点上。 类似的流通过 流日志聚合自动分组到汇总记录中,从而削减数据量,同时保留所需的模式。

启用Azure Monitor加载项是一个单独的可选步骤,可将这些日志交付到Log Analytics工作区中。 它不会影响日志生成。

可以在新群集上设置此设置,也可以在现有群集上启用它。

已存储的日志如何端到端传输

                    ┌─────────────────────────────────────────────┐
                    │                AKS node                     │
                    │                                             │
   Pod traffic ───▶ │  Cilium agent (ACNS)                        │
                    │       │                                     │
                    │       ▼                                     │
                    │  ContainerNetworkLog CRD ── filters flows   │
                    │       │                                     │
                    │       ▼                                     │
                    │  /var/log/acns/hubble/events.log            │
                    │  (50 MB rotating, host-local)               │
                    └───────┬─────────────────────────────────────┘
                            │
              ┌─────────────┴──────────────┐
              ▼                            ▼
   Azure Monitor add-on        OpenTelemetry collector
   (optional)                  or logging service (optional)
              │                            │
              ▼                            ▼
   ContainerNetworkLogs        Your SIEM / observability
   table in Log Analytics      backend
              │
              ▼
   Azure portal / Grafana
   dashboards, KQL

部署选项

按照下面的 端到端设置操作 。 相同的三个步骤适用于新群集和现有群集。

端到端设置

按顺序执行这些步骤。 需要步骤 1 和 2。 步骤 3 是可选的,仅当需要将日志转发到Azure Monitor时才需要。

Step 你做的事情 Required?
1 确保您的群集(新建或现有)已启用 ACNS Yes
2 应用ContainerNetworkLog CRD 来启动日志收集 Yes
3 将日志转发到 Azure Monitor 以进行持久存储 Optional

设置环境变量一次,并在整个过程中重复使用它们:

# Replace placeholders with your own values
export CLUSTER_NAME="<aks-cluster-name>"
export RESOURCE_GROUP="<aks-resource-group>"
export LOCATION="<location>"

步骤 1:确保群集上启用了 ACNS

使用与情况匹配的选项。

选项 A:使用 ACNS 创建新群集

# Create the resource group if it doesn't already exist
az group create --name $RESOURCE_GROUP --location $LOCATION

# Create an AKS cluster with ACNS
az aks create \
  --resource-group $RESOURCE_GROUP \
  --name $CLUSTER_NAME \
  --location $LOCATION \
  --pod-cidr 192.168.0.0/16 \
  --network-plugin azure \
  --network-plugin-mode overlay \
  --network-dataplane cilium \
  --generate-ssh-keys \
  --enable-acns \
  --acns-advanced-networkpolicies L7

Tip

如果订阅中没有默认 VM 大小,请添加 --node-vm-size Standard_D4ads_v5。

如果已知道要将日志转发到Azure Monitor,则可以在一个命令中执行所有操作。 请参阅 Shortcut:从头开始创建具有Log Analytics的群集。

获取群集凭据,以便可以运行 kubectl 命令:

az aks get-credentials --name $CLUSTER_NAME --resource-group $RESOURCE_GROUP

选项 B:使用现有群集

如果群集已启用 ACNS,可以跳到步骤 2。 否则,请获取您的凭据,以便您可以运行 kubectl 命令。

az aks get-credentials --name $CLUSTER_NAME --resource-group $RESOURCE_GROUP

步骤 2:应用 ContainerNetworkLog CRD 以启动日志收集

在应用至少一个 ContainerNetworkLog 自定义资源之前,存储的日志模式不会收集任何内容。 此资源指定要捕获的流量:按命名空间、Pod、服务、协议或裁定。

应用 CRD 后,将在每个节点上写入 /var/log/acns/hubble/events.log 匹配流。

kubectl apply -f <crd.yaml>

有关所有可用字段,请参阅下面的完整 ContainerNetworkLog CRD 模板 。

Tip

有关实际示例,请参阅 AKS 实验室文档中的示例 CRD。

注释

主机节点上的日志是临时的。 文件在达到 50 MB 时自动切换,旧的记录会被覆盖。 对于永久性存储,请完成步骤 3。 还可以使用任何与 OpenTelemetry 兼容的收集器或日志记录服务(而不是Azure Monitor)将日志转发到 SIEM 或可观测性后端。

此时,每个节点都有 JSON 格式的流记录 /var/log/acns/hubble/events.log 。 如果这就是你需要的,那么你已经完成了。

步骤 3 (可选):将日志转发到持久性存储Azure Monitor

如果您希望将日志转发到 Log Analytics 工作区以便进行长期保留、KQL 查询,以及使用内置 Azure 门户和 Grafana 仪表板,请完成此步骤。 如果计划直接使用主机本地日志,或者通过自己的 OpenTelemetry 收集器或日志记录服务转发它们,请跳过它。

3a. 启用Azure Monitor加载项(Log Analytics):

# To use the default Log Analytics workspace
az aks enable-addons -a monitoring -g $RESOURCE_GROUP -n $CLUSTER_NAME

# To use an existing Log Analytics workspace
az aks enable-addons -a monitoring -g $RESOURCE_GROUP -n $CLUSTER_NAME --workspace-resource-id <workspace-resource-id>

3b. 启用容器网络日志标志:

az aks update --enable-acns \
  --enable-container-network-logs \
  -g $RESOURCE_GROUP \
  -n $CLUSTER_NAME

若要将日志发送到特定的Azure Monitor工作区,请添加 --azure-monitor-workspace-resource-id 标志:

az aks update --enable-acns \
  --enable-container-network-logs \
  --azure-monitor-workspace-resource-id $AZURE_MONITOR_ID \
  -g $RESOURCE_GROUP \
  -n $CLUSTER_NAME

注释

应用 ContainerNetworkLog CRD 时,流日志将写入主机。 如果稍后启用 Log Analytics 集成,Azure Monitor 代理将从那时开始收集数据。 超过两分钟的旧日志不会被引入。

快捷方式:从头开始创建具有Log Analytics的群集

如果要创建新群集并已知道要将日志发送到Log Analytics工作区,可以将步骤 1 和步骤 3 合并为单个创建命令:

az aks create \
  --resource-group $RESOURCE_GROUP \
  --name $CLUSTER_NAME \
  --location $LOCATION \
  --pod-cidr 192.168.0.0/16 \
  --network-plugin azure \
  --network-plugin-mode overlay \
  --network-dataplane cilium \
  --generate-ssh-keys \
  --enable-acns \
  --enable-addons monitoring \
  --enable-container-network-logs \
  --acns-advanced-networkpolicies L7

若要将日志发送到特定工作区,请添加标志 --azure-monitor-workspace-resource-id :

az aks create \
  --resource-group $RESOURCE_GROUP \
  --name $CLUSTER_NAME \
  --location $LOCATION \
  --pod-cidr 192.168.0.0/16 \
  --network-plugin azure \
  --network-plugin-mode overlay \
  --network-dataplane cilium \
  --generate-ssh-keys \
  --enable-acns \
  --enable-addons monitoring \
  --enable-container-network-logs \
  --azure-monitor-workspace-resource-id $AZURE_MONITOR_ID \
  --acns-advanced-networkpolicies L7

仍需要完成步骤 2(应用 ContainerNetworkLog CRD)以定义要捕获的流量。 Log Analytics集成已到位,因此会自动收集匹配的流并将其发送到工作区。

ContainerNetworkLog CRD 模板

ContainerNetworkLog自定义资源定义要捕获的网络流。 可以在单个群集中创建多个自定义资源,每个资源都可以针对不同的命名空间、Pod 或协议。

apiVersion: acn.azure.com/v1alpha1
kind: ContainerNetworkLog
metadata:
  name: sample-containernetworklog # Cluster scoped
spec:
  includefilters: # At least one filter is required
    - name: sample-filter
      from:
        namespacedPod: # Format: namespace/pod
          - sample-namespace/sample-pod
        labelSelector:
          matchLabels:
            app: frontend
            k8s:io.kubernetes.pod.namespace: sample-namespace
          matchExpressions:
            - key: environment
              operator: In
              values:
                - production
                - staging
        ip: # Single IP or CIDR
          - "192.168.1.10"
          - "10.0.0.1"
      to:
        namespacedPod:
          - sample-namespace2/sample-pod2
        labelSelector:
          matchLabels:
            app: backend
            k8s:io.kubernetes.pod.namespace: sample-namespace2
          matchExpressions:
            - key: tier
              operator: NotIn
              values:
                - dev
        ip:
          - "192.168.1.20"
          - "10.0.1.1"
      protocol: # tcp, udp, dns
        - tcp
        - udp
        - dns
      verdict: # forwarded, dropped
        - forwarded
        - dropped

只需使用上述模板创建 YAML 文件,根据需要自定义筛选器,并将其应用于 kubectl apply -f <crd.yaml>。

CRD 字段参考

领域 类型 说明 必需
includefilters []过滤器 用于定义要捕获的网络流的筛选器。 必须至少包含一个筛选器。 Yes
filters.name String 筛选器的名称。 No
filters.protocol []字符串 要匹配的协议:tcp、、udpdns。 如果省略,则包含所有协议。 No
filters.verdict []字符串 流裁定以匹配:forwarded、dropped。 如果省略,则包括所有判决。 No
filters.from 终结点 网络流的源。 可以包括 IP、标签选择器和命名空间/Pod 对。 No
filters.to 终结点 网络流的目标。 与from相同的选项。 No
Endpoint.ip []字符串 单个 IP 地址或 CIDR 范围。 No
Endpoint.labelSelector Object 标准 Kubernetes 标签选择器,包含 matchLabels 和 matchExpressions。 条件与 AND 结合使用。 如果为空,则匹配所有资源。 No
Endpoint.namespacedPod []字符串 namespace/pod 格式的命名空间/pod 对。 No

捕获第 7 层和 DNS 流

ContainerNetworkLog CRD 捕获您在includeFilters中选择的流量的第 3 层和第 4 层流量。 只有当匹配的流量也被选择 L7 检查或 DNS 可见性的 Cilium 网络策略覆盖时,才会显示第 7 层(HTTP、gRPC、Kafka)和 DNS 记录。 如果没有该策略,L7 和 DNS 字段会在流日志中保持空。

需要两部分:

  • 群集级 L7 支持。 必须在群集上启用 L7 策略支持。 有关详细信息,请参阅 配置第 7 层策略。
  • 范围为 L7 或 DNS 规则的 Cilium 网络策略。 对要检查其流量的负载应用CiliumNetworkPolicy、rules.http、rules.kafka 或 rules.dns。 对于 DNS 识别的出口流量,请结合使用 rules.dns 和 toFQDNs。 有关详细信息,请参阅 配置 FQDN 策略。

以下示例启用对 kube-dns 查询的 DNS 检查,并为流出至 *.example.com 的数据启用 L7 HTTP 检查:

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: l7-dns-policy
  namespace: default
spec:
  endpointSelector:
    matchLabels:
      app: myapp
  egress:
    - toEndpoints:
        - matchLabels:
            "k8s:io.kubernetes.pod.namespace": kube-system
            "k8s:k8s-app": kube-dns
      toPorts:
        - ports:
            - port: "53"
              protocol: UDP
          rules:
            dns:
              - matchPattern: "*.example.com"
    - toFQDNs:
        - matchPattern: "*.example.com"
      toPorts:
        - ports:
            - port: "443"
              protocol: TCP
          rules:
            http:
              - method: "GET"
                path: "/1"

应用它:

kubectl apply -f l7-dns-policy.yaml

应用策略后,ContainerNetworkLogs 中的匹配流将填充 Layer7 字段,DNS 查找将显示 dns.rcode 和相关元数据。

验证设置

这些步骤适用于新的和现有的群集设置。

获取群集凭据

az aks get-credentials --name $CLUSTER_NAME --resource-group $RESOURCE_GROUP

确认已启用容器网络日志

az aks show -g $RESOURCE_GROUP -n $CLUSTER_NAME

在输出中查找以下部分:

"networkProfile": {
  "advancedNetworking": {
    "enabled": true,
    "observability": {
      "enabled": true
    }
  }
}
"osmagent": {
  "config": {
    "enableContainerNetworkLogs": "True"
  }
}

检查自定义资源状态

列出群集中的所有 ContainerNetworkLog 资源:

kubectl get containernetworklog

它将提供您刚刚创建的 containernetworklog 资源的名称。 使用以下命令中的该名称检查其状态:

检查特定资源的状态:

kubectl describe containernetworklog <cr-name>

字段 Status>State 应显示 CONFIGURED。 如果显示 FAILED,请检查筛选器规范是否有效。

Spec:
  Includefilters:
    From:
      Namespaced Pod:
        namespace/pod-
    Name:  sample-filter
    Protocol:
      tcp
    To:
      Namespaced Pod:
        namespace/pod-
    Verdict:
      dropped
Status:
  State:      CONFIGURED
  Timestamp:  2025-05-01T11:24:48Z

可以应用多个 ContainerNetworkLog 自定义资源。 每个都有其自己的状态。

在 Log Analytics 中查询日志

配置Log Analytics后,可以使用Log Analytics工作区中的 ContainerNetworkLogs 表查询历史流日志。 使用 Kusto 查询语言(KQL)分析网络模式、识别安全事件、排查连接问题并执行根本原因分析。

有关示例查询,请参阅 AKS 实验室文档中 使用流日志进行渐进式诊断 。

使用 Grafana 仪表板进行可视化

可以通过 Azure 门户访问预生成的 Grafana 仪表板。 在开始之前,请确保 Azure Monitor 日志 Pod 正在运行:

kubectl get pods -o wide -n kube-system | grep ama-logs

预期输出:

ama-logs-9bxc6                                   3/3     Running   1 (39m ago)   44m
ama-logs-fd568                                   3/3     Running   1 (40m ago)   44m
ama-logs-rs-65bdd98f75-hqnd2                     2/2     Running   1 (43m ago)   22h

授予 Grafana 对监视数据的访问权限

托管 Grafana 工作区需要在包含 Log Analytics 工作区的订阅上拥有监控读取者角色。

如果您是订阅所有者或用户访问管理员,那么托管的 Grafana 工作区在创建时会自动分配该角色。

如果上述情况不符合(或者 Log Analytics 和 Grafana 工作区位于不同的订阅账户中),请手动授予角色:

  1. 在托管 Grafana 工作区中,转到 “设置>身份”。

    托管 Grafana 实例中身份选项的屏幕截图。

  2. 选择Azure角色分配>添加角色分配。

    在 Grafana 实例中选择 Azure 角色分配的屏幕截图。

  3. 将 范围 设置为 订阅,选择订阅,将 角色 设置为 “监视读取者”,然后选择“ 保存”。

    在托管 Grafana 实例中输入订阅详细信息的屏幕截图。

  4. 在托管 Grafana 实例的 “数据源 ”选项卡中验证数据源:

    在托管 Grafana 实例中检查数据源的屏幕截图。

访问仪表板

若要从Azure门户打开仪表板,请执行以下操作:

  1. 在 Azure 门户中,转到 AKS 群集。
  2. 选择“使用 Grafana 的仪表板(预览版)”。
  3. 浏览 Azure Monitor 或 Azure 托管的 Prometheus 下的可用仪表盘。

在 Azure Monitor>Insights>Containers>Networking 下查找仪表板。 有两个选项,具体取决于为 Log Analytics 中的 ContainerNetworkLogs 表选择的层:

Dashboard 路径 表格层级 Grafana ID
流日志 - 基本层 Azure>监控>容器>网络>流日志 - 基本层 基本 23155
流日志 - 分析层 Azure>见解>容器>网络>流量日志 - 分析层 分析(默认) 23156

这两个仪表板都显示哪些 AKS 工作负载相互通信,包括请求、响应、删除和错误。 使用与您为 ContainerNetworkLogs 表配置的等级相匹配的项。

Azure Monitor 中 Grafana 仪表板的屏幕截图。

有关仪表板组件的详细信息,请参阅 容器网络日志概述。

Tip

表 ContainerNetworkLogs 默认为 Analytics 层。 若要降低引入和保留成本,可以切换到 基本 层并使用相应的仪表板。 有关详细信息,请参阅日志分析表格计划。

配置按需日志模式

按需日志允许实时捕获流数据,而无需持久存储。 此模式适用于 Cilium 和非 Cilium 数据平面。

群集需要启用 高级容器网络服务 。 如果尚未启用 ACNS 群集,请创建一个:

export CLUSTER_NAME="<aks-cluster-name>"
export RESOURCE_GROUP="<aks-resource-group>"

az aks create \
    --name $CLUSTER_NAME \
    --resource-group $RESOURCE_GROUP \
    --generate-ssh-keys \
    --location eastus \
    --max-pods 250 \
    --network-plugin azure \
    --network-plugin-mode overlay \
    --network-dataplane cilium \
    --node-count 2 \
    --pod-cidr 192.168.0.0/16 \
    --kubernetes-version 1.33 \
    --enable-acns

在现有群集上启用 ACNS

在已配置的群集上启用 ACNS,请执行以下步骤:

az aks update \
    --resource-group $RESOURCE_GROUP \
    --name $CLUSTER_NAME \
    --enable-acns

注释

容器网络安全功能需要 Cilium 数据平面。

获取群集凭据:

az aks get-credentials --name $CLUSTER_NAME --resource-group $RESOURCE_GROUP

安装 Hubble CLI

export HUBBLE_VERSION=v1.16.3
export HUBBLE_ARCH=amd64

if [ "$(uname -m)" = "aarch64" ]; then HUBBLE_ARCH=arm64; fi
curl -L --fail --remote-name-all https://github.com/cilium/hubble/releases/download/$HUBBLE_VERSION/hubble-linux-${HUBBLE_ARCH}.tar.gz{,.sha256sum}
sha256sum --check hubble-linux-${HUBBLE_ARCH}.tar.gz.sha256sum
sudo tar xzvfC hubble-linux-${HUBBLE_ARCH}.tar.gz /usr/local/bin
rm hubble-linux-${HUBBLE_ARCH}.tar.gz{,.sha256sum}

使用 Hubble CLI

  1. 确认 Hubble Relay Pod 正在运行:

    kubectl get pods -o wide -n kube-system -l k8s-app=hubble-relay
    

    预期输出:

    hubble-relay-7ddd887cdb-h6khj     1/1  Running     0       23h
    
  2. 转发 Hubble Relay 的端口:

    kubectl port-forward -n kube-system svc/hubble-relay --address 127.0.0.1 4245:443
    
  3. 为 Hubble 客户端配置 mTLS 证书:

    #!/usr/bin/env bash
    set -euo pipefail
    set -x
    
    CERT_DIR="$(pwd)/.certs"
    mkdir -p "$CERT_DIR"
    
    declare -A CERT_FILES=(
      ["tls.crt"]="tls-client-cert-file"
      ["tls.key"]="tls-client-key-file"
      ["ca.crt"]="tls-ca-cert-files"
    )
    
    for FILE in "${!CERT_FILES[@]}"; do
      KEY="${CERT_FILES[$FILE]}"
      JSONPATH="{.data['${FILE//./\\.}']}"
    
      kubectl get secret hubble-relay-client-certs -n kube-system \
        -o jsonpath="${JSONPATH}" | \
        base64 -d > "$CERT_DIR/$FILE"
    
      hubble config set "$KEY" "$CERT_DIR/$FILE"
    done
    
    hubble config set tls true
    hubble config set tls-server-name instance.hubble-relay.cilium.io
    
  4. 验证机密是否存在:

    kubectl get secrets -n kube-system | grep hubble-
    

    预期输出:

    kube-system     hubble-relay-client-certs     kubernetes.io/tls     3     9d
    kube-system     hubble-relay-server-certs     kubernetes.io/tls     3     9d
    kube-system     hubble-server-certs           kubernetes.io/tls     3     9d
    
  5. 观察来自特定 Pod 的流:

    hubble observe --pod hubble-relay-7ddd887cdb-h6khj
    

设置 Hubble UI

  1. 将以下清单另存为 hubble-ui.yaml:

    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: hubble-ui
      namespace: kube-system
    ---
    kind: ClusterRole
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      name: hubble-ui
      labels:
        app.kubernetes.io/part-of: retina
    rules:
      - apiGroups:
          - networking.k8s.io
        resources:
          - networkpolicies
        verbs:
          - get
          - list
          - watch
      - apiGroups:
          - ""
        resources:
          - componentstatuses
          - endpoints
          - namespaces
          - nodes
          - pods
          - services
        verbs:
          - get
          - list
          - watch
      - apiGroups:
          - apiextensions.k8s.io
        resources:
          - customresourcedefinitions
        verbs:
          - get
          - list
          - watch
      - apiGroups:
          - cilium.io
        resources:
          - "*"
        verbs:
          - get
          - list
          - watch
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      name: hubble-ui
      labels:
        app.kubernetes.io/part-of: retina
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: hubble-ui
    subjects:
      - kind: ServiceAccount
        name: hubble-ui
        namespace: kube-system
    ---
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: hubble-ui-nginx
      namespace: kube-system
    data:
      nginx.conf: |
        server {
            listen       8081;
            server_name  localhost;
            root /app;
            index index.html;
            client_max_body_size 1G;
            location / {
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                # CORS
                add_header Access-Control-Allow-Methods "GET, POST, PUT, HEAD, DELETE, OPTIONS";
                add_header Access-Control-Allow-Origin *;
                add_header Access-Control-Max-Age 1728000;
                add_header Access-Control-Expose-Headers content-length,grpc-status,grpc-message;
                add_header Access-Control-Allow-Headers range,keep-alive,user-agent,cache-control,content-type,content-transfer-encoding,x-accept-content-transfer-encoding,x-accept-response-streaming,x-user-agent,x-grpc-web,grpc-timeout;
                if ($request_method = OPTIONS) {
                    return 204;
                }
                # /CORS
                location /api {
                    proxy_http_version 1.1;
                    proxy_pass_request_headers on;
                    proxy_hide_header Access-Control-Allow-Origin;
                    proxy_pass http://127.0.0.1:8090;
                }
                location / {
                    try_files $uri $uri/ /index.html /index.html;
                }
                # Liveness probe
                location /healthz {
                    access_log off;
                    add_header Content-Type text/plain;
                    return 200 'ok';
                }
            }
        }
    ---
    kind: Deployment
    apiVersion: apps/v1
    metadata:
      name: hubble-ui
      namespace: kube-system
      labels:
        k8s-app: hubble-ui
        app.kubernetes.io/name: hubble-ui
        app.kubernetes.io/part-of: retina
    spec:
      replicas: 1
      selector:
        matchLabels:
          k8s-app: hubble-ui
      template:
        metadata:
          labels:
            k8s-app: hubble-ui
            app.kubernetes.io/name: hubble-ui
            app.kubernetes.io/part-of: retina
        spec:
          serviceAccountName: hubble-ui
          automountServiceAccountToken: true
          containers:
          - name: frontend
            image: mcr.azk8s.cn/oss/cilium/hubble-ui:v0.12.2
            imagePullPolicy: Always
            ports:
            - name: http
              containerPort: 8081
            livenessProbe:
              httpGet:
                path: /healthz
                port: 8081
            readinessProbe:
              httpGet:
                path: /
                port: 8081
            resources: {}
            volumeMounts:
            - name: hubble-ui-nginx-conf
              mountPath: /etc/nginx/conf.d/default.conf
              subPath: nginx.conf
            - name: tmp-dir
              mountPath: /tmp
            terminationMessagePolicy: FallbackToLogsOnError
            securityContext: {}
          - name: backend
            image: mcr.azk8s.cn/oss/cilium/hubble-ui-backend:v0.12.2
            imagePullPolicy: Always
            env:
            - name: EVENTS_SERVER_PORT
              value: "8090"
            - name: FLOWS_API_ADDR
              value: "hubble-relay:443"
            - name: TLS_TO_RELAY_ENABLED
              value: "true"
            - name: TLS_RELAY_SERVER_NAME
              value: ui.hubble-relay.cilium.io
            - name: TLS_RELAY_CA_CERT_FILES
              value: /var/lib/hubble-ui/certs/hubble-relay-ca.crt
            - name: TLS_RELAY_CLIENT_CERT_FILE
              value: /var/lib/hubble-ui/certs/client.crt
            - name: TLS_RELAY_CLIENT_KEY_FILE
              value: /var/lib/hubble-ui/certs/client.key
            livenessProbe:
              httpGet:
                path: /healthz
                port: 8090
            readinessProbe:
              httpGet:
                path: /healthz
                port: 8090
            ports:
            - name: grpc
              containerPort: 8090
            resources: {}
            volumeMounts:
            - name: hubble-ui-client-certs
              mountPath: /var/lib/hubble-ui/certs
              readOnly: true
            terminationMessagePolicy: FallbackToLogsOnError
            securityContext: {}
          nodeSelector:
            kubernetes.io/os: linux
          volumes:
          - configMap:
              defaultMode: 420
              name: hubble-ui-nginx
            name: hubble-ui-nginx-conf
          - emptyDir: {}
            name: tmp-dir
          - name: hubble-ui-client-certs
            projected:
              defaultMode: 0400
              sources:
              - secret:
                  name: hubble-relay-client-certs
                  items:
                    - key: tls.crt
                      path: client.crt
                    - key: tls.key
                      path: client.key
                    - key: ca.crt
                      path: hubble-relay-ca.crt
    ---
    kind: Service
    apiVersion: v1
    metadata:
      name: hubble-ui
      namespace: kube-system
      labels:
        k8s-app: hubble-ui
        app.kubernetes.io/name: hubble-ui
        app.kubernetes.io/part-of: retina
    spec:
      type: ClusterIP
      selector:
        k8s-app: hubble-ui
      ports:
        - name: http
          port: 80
          targetPort: 8081
    
  2. 应用清单:

    kubectl apply -f hubble-ui.yaml
    
  3. 设置端口转发:

    kubectl -n kube-system port-forward svc/hubble-ui 12000:80
    
  4. 在浏览器中打开 http://localhost:12000/ 以访问 Hubble UI。

Troubleshooting

  • 未启用 ACNS。 在没有 ACNS 的情况下运行 --enable-container-network-logs 将生成:

    流日志要求启用“--enable-acns”标志,以启用高级网络功能。

  • Kubernetes 版本太旧。 在版本低于 1.33.0 的群集上运行 --enable-container-network-logs 将产生:

    The specified orchestrator version %s is not valid. Advanced Networking Flow Logs is only supported on Kubernetes version 1.33.0 or later.

  • CRD 无法识别。 在没有 ACNS 的群集上应用 ContainerNetworkLog 后,结果是:

    error: resource mapping not found for <....>": no matches for kind "ContainerNetworkLog" in version "acn.azure.com/v1alpha1"

    确保已在群集上启用 ACNS。

禁用存储日志模式

存储的日志有两个层: 节点上的日志生成,以及可选的转发到Azure Monitor。 可以单独关闭任一层。

停止生成日志

日志生成由 ContainerNetworkLog 自定义资源驱动。 删除所有这些记录会阻止将新流记录写入 /var/log/acns/hubble/events.log 每个节点上。

kubectl delete containernetworklog --all

若要删除特定资源而不是全部资源,请运行 kubectl delete containernetworklog <cr-name>。

停止将日志转发到Azure Monitor

如果只想停止将日志发送到Log Analytics工作区,但在节点上继续生成日志,请禁用Azure Monitor集成:

az aks update -n $CLUSTER_NAME -g $RESOURCE_GROUP --disable-container-network-logs

现有 ContainerNetworkLog 资源仍然有效,因此流会继续到达每个节点 /var/log/acns/hubble/events.log ,直到删除这些资源。

清理资源

如果不再需要资源,请删除资源组:

az group delete --name $RESOURCE_GROUP

局限性

数据平面和 Kubernetes 版本

  • 存储日志模式需要 Cilium 数据平面和 Kubernetes 1.33 或更高版本。
  • 按需日志(Hubble CLI 和 Hubble UI)适用于 Cilium 和非 Cilium 数据平面。

第 7 层和 DNS 可见性

  • 仅在群集 CiliumNetworkPolicy 上启用 L7 策略支持并且 L7 规则涵盖流量时,才会填充第 7 层流记录。 有关详细信息,请参阅 配置第 7 层策略。
  • 仅当 Cilium FQDN 策略(rules.dns 加上 toFQDNs)涵盖流量时,才会填充 DNS 记录。

主机本地存储

  • 如果没有Azure Monitor或外部收集器,流日志将存储在每个节点上/var/log/acns/hubble/events.log,上限为 50 MB。 达到上限后,旧的条目将被覆盖。
  • 流日志将写入主机节点,并由Azure Monitor代理收集。 如果在应用 ContainerNetworkLog CRD 后启用日志分析集成,则仅会引入自该点之后的新日志。 不会收集主机上的历史日志。

Log Analytics

  • 启用容器网络日志后切换Log Analytics工作区可能会导致日志停止流向新工作区。 发生这种情况是因为现有Azure Monitor数据收集配置不会自动更新。 若要防止此问题,请在首次启用容器网络日志时配置所需的工作区,或者在更改工作区时手动更新关联的数据收集规则。 请参阅 在容器洞察中配置数据收集。
  • 该 ContainerNetworkLogs 表支持 Analytics (默认)和 基本 层。 不支持 辅助 层。

聚合权衡

  • 流日志聚合不会保留单个流时间戳、每个 pod 的 IP 地址或 HTTP URL 和 DNS 查询名称等高基数字段。 使用按需日志对每个流进行分析。