Миграция EKS с VPC CNI на Cilium без даунтайма

Если вы запускаете Kubernetes в продакшене, сетевая безопасность и наблюдаемость рано или поздно становятся приоритетами первого порядка. Недавно я решил перевести наши кластеры Amazon EKS (версия 1.35 на базе Bottlerocket OS) с дефолтного AWS VPC CNI и kube-proxy на Cilium.

Зачем переходить?

Миграцию обусловили три главные задачи:

  1. Соответствие SOC 2: требовалось обеспечить прозрачное шифрование трафика между подами в транзите.

  2. Глубокая наблюдаемость: хотелось получить детальную видимость потоков трафика и визуализировать взаимодействие подов с помощью Hubble.

  3. Без сайдкаров: благодаря архитектуре Cilium на основе eBPF можно добиться продвинутой маршрутизации, безопасности и наблюдаемости, не внедряя ресурсоёмкие sidecar-прокси (как в Istio) в каждый под. Такой подход без сайдкаров заметно снижает вычислительные накладные расходы, уменьшает сетевую задержку и упрощает управление жизненным циклом подов в кластере.

Замена CNI (интерфейса сетевых плагинов) на живом кластере выглядит пугающе, однако стратегия blue/green пулов нод позволила провести переход абсолютно бесшовно, без какого-либо простоя внутренних и внешних сервисов. Ниже — пошаговое описание того, как это было сделано.

Фаза 1: подготовка конфигурации Cilium

Вместо того чтобы запускать Cilium параллельно с kube-proxy, я выбрал полноценную замену — чтобы Cilium управлял маршрутизацией нативно через eBPF.

1. IPAM и нативная маршрутизация

Cilium настроен на использование режима ENI IPAM с задействованием существующего CIDR виртуальной сети для нативной маршрутизации. Поскольку мы используем Bottlerocket OS, сетевые интерфейсы начинаются с eth* — это указано в списке устройств. Установка Cilium в режиме ENI является рекомендованным способом для кластеров Amazon EKS.

ipam:
  mode: "eni"
  ciliumNodeUpdateRate: "15s"

eni:
  enabled: true
  awsReleaseExcessIPs: true
  awsEnablePrefixDelegation: true
  nodeSpec:
    firstInterfaceIndex: 1

2. Полная замена kube-proxy

Я отключил устаревшую хост-маршрутизацию и включил нативную маршрутизацию вместе с BPF-маскарадингом. Кроме того, Cilium явно указывает на конкретный эндпоинт (endpoint) EKS API (поскольку стандартный ClusterIP kubernetes.default.svc не будет разрешим и достижим до тех пор, пока агент Cilium фактически не запустится), что обеспечивает прямое взаимодействие с плоскостью управления.

routingMode: native
ipv4NativeRoutingCIDR: "10.50.0.0/16"

endpointRoutes:
  enabled: false

bpf:
  hostLegacyRouting: false
  masquerade: true

kubeProxyReplacement: true
kubeProxyReplacementHealthzBindAddr: 0.0.0.0:10256

devices:
  - "eth+" # Специально для Bottlerocket OS

# Указываем эндпоинт и порт EKS
namespaceOverride: kube-system
k8sServiceHost: "REDACTED.gr7.ap-southeast-3.eks.amazonaws.com"
k8sServicePort: 443

3. Включение шифрования WireGuard

Включить шифрование для соответствия SOC 2 в Cilium на удивление просто. Я выбрал WireGuard вместо IPsec из-за более высокой производительности и современной архитектуры. Подробнее о шифровании WireGuard в Cilium: документация Cilium.

encryption:
  enabled: true
  type: wireguard

4. Привязка к нодам и taint-ы

Чтобы обеспечить плавный переход, нужно было направить Cilium только на новый пул нод (с меткой cni=cilium) и настроить его на снятие taint’а agent-not-ready после успешного запуска.

agentNotReadyTaintKey: node.cilium.io/agent-not-ready
removeNodeTaints: true
priorityClassName: system-node-critical

affinity:
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
        - matchExpressions:
            - key: cni
              operator: In
              values: ["cilium"]

5. Усмирение оператора Cilium (предотвращение перезапусков CoreDNS)

По умолчанию оператор Cilium агрессивно перезапускает неуправляемые поды CoreDNS ещё до того, как под Cilium успевает стартовать, чтобы обеспечить создание эндпоинтов. В нашем случае это приводило к постоянным циклам перезапуска CoreDNS на нодах, где Cilium ещё даже не работал. Чтобы остановить это, я отключил поведение перезапуска и зафиксировал оператор на новых нодах.

operator:
  priorityClassName: system-node-critical
  unmanagedPodWatcher:
    restart: false # отключаем перезапуск неуправляемых подов
  tolerations:
    - operator: "Exists"
      effect: "NoSchedule"
    - operator: "Exists"
      effect: "NoExecute"
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
          - matchExpressions:
              - key: cni
                operator: In
                values:
                  - cilium

6. Включение Hubble для наблюдаемости

Наконец, мы включили Hubble UI, relay и метрики Prometheus, чтобы получить необходимую глубокую визуальную аналитику.

hubble:
  enabled: true
  metrics:
    enabled:
    - dns:query;ignoreAAAA
    - drop
    - tcp
    - flow # метрики потоков между подами
    - icmp
    - http
  relay:
    enabled: true
    replicas: 1
    # ... [Добавьте лимиты ресурсов и tolerations здесь]
  ui:
    enabled: true
    # ... [Добавьте лимиты ресурсов и tolerations здесь]

Фаза 2: подготовка нод EKS

Чтобы избежать резкой кластерной замены CNI, мы воспользовались подходом blue/green для нод.

  • Изолируем старые ноды: существующим нодам проставили метку cni=aws-vpc. Затем обновили DaemonSet’ы aws-node (VPC CNI) и kube-proxy, добавив правило nodeAffinity с таргетингом на cni: aws-vpc. Это гарантирует, что они не будут пытаться запуститься на новых нодах с Cilium.

  • Разворачиваем новые ноды: выкатили новую группу нод Terraform с меткой cni=cilium и специальным taint’ом инициализации.

module "green-app-nodes" {
  source                 = "git@bitbucket.org:REDACTED/terraform-modules.git//eks-data-asg"
  cluster_name           = "dev"
  cluster_version        = "1.35"
  # ...
  node-labels = {
    "nodesrole" = "app"
    "cni"       = "cilium"
  }
  node-taints = {
    "noderole"                       = "app:NoSchedule"
    "node.cilium.io/agent-not-ready" = "true:NoSchedule"
  }
}

После поднятия ноды корректно перешли в состояние NotReady, ожидая установки CNI.

10538 ◯  k get node -l nodesrole=app
NAME                                              STATUS     ROLES    AGE     VERSION
ip-10-50-72-142.ap-southeast-3.compute.internal   NotReady   <none>   3s      v1.35.2-eks-f69f56f
ip-10-50-74-33.ap-southeast-3.compute.internal    Ready      <none>   6d20h   v1.35.2-eks-f69f56f
ip-10-50-75-232.ap-southeast-3.compute.internal   NotReady   <none>   4s      v1.35.2-eks-f69f56f
ip-10-50-77-10.ap-southeast-3.compute.internal    Ready      <none>   6d20h   v1.35.2-eks-f69f56f
ip-10-50-78-3.ap-southeast-3.compute.internal     NotReady   <none>   4s      v1.35.2-eks-f69f56f
ip-10-50-80-93.ap-southeast-3.compute.internal    NotReady   <none>   4s      v1.35.2-eks-f69f56f
ip-10-50-81-120.ap-southeast-3.compute.internal   Ready      <none>   6d20h   v1.35.2-eks-f69f56f
ip-10-50-93-88.ap-southeast-3.compute.internal    Ready      <none>   6d20h   v1.35.2-eks-f69f56f

Фаза 3: развёртывание Cilium

Когда blue/green-инфраструктура была готова, мы применили Helm-чарт Cilium. Как только поды Cilium инициализировались на новых нодах, они автоматически сняли taint’ы agent-not-ready и перевели ноды в состояние Ready.

10541 ◯  k get po -A --sort-by .metadata.creationTimestamp | grep cilium;
kube-system                cilium-q7cwp                                             1/1     Running             0               24s
kube-system                cilium-ltclf                                             1/1     Running             0               24s
kube-system                cilium-f9cjx                                             1/1     Running             0               24s
kube-system                cilium-zx4fc                                             1/1     Running             0               23s

10542 ◯  k get node -l nodesrole=app
NAME                                              STATUS                     ROLES    AGE     VERSION
ip-10-50-72-142.ap-southeast-3.compute.internal   Ready                      <none>   48s     v1.35.2-eks-f69f56f
ip-10-50-74-33.ap-southeast-3.compute.internal    Ready,SchedulingDisabled   <none>   6d20h   v1.35.2-eks-f69f56f
ip-10-50-75-232.ap-southeast-3.compute.internal   Ready                      <none>   49s     v1.35.2-eks-f69f56f
ip-10-50-77-10.ap-southeast-3.compute.internal    Ready,SchedulingDisabled   <none>   6d20h   v1.35.2-eks-f69f56f
ip-10-50-78-3.ap-southeast-3.compute.internal     Ready                      <none>   49s     v1.35.2-eks-f69f56f
ip-10-50-80-93.ap-southeast-3.compute.internal    Ready                      <none>   49s     v1.35.2-eks-f69f56f
ip-10-50-81-120.ap-southeast-3.compute.internal   Ready,SchedulingDisabled   <none>   6d20h   v1.35.2-eks-f69f56f
ip-10-50-93-88.ap-southeast-3.compute.internal    Ready,SchedulingDisabled   <none>   6d20h   v1.35.2-eks-f69f56f

Cordon, Drain и проверка

10543 ◯ alias drain='k drain --delete-emptydir-data --ignore-daemonsets'
10544 ◯  drain ip-10-50-74-33.ap-southeast-3.compute.internal
node/ip-10-50-74-33.ap-southeast-3.compute.internal already cordoned
Warning: ignoring DaemonSet-managed Pods: kube-system/aws-node-m6ngm, kube-system/ebs-csi-node-hspq4, kube-system/kube-proxy-4rqxp, kube-system/s3-csi-node-vkczb, observability/grafana-k8s-monitoring-alloy-logs-x5hj8, observability/grafana-k8s-monitoring-alloy-receiver-qvgmj, ops/prometheus-node-exporter-6zrxj
evicting pod ...
...
...

Подтверждение шифрования для SOC 2

Чтобы убедиться, что WireGuard активно защищает трафик, мы выполнили команду внутри пода Cilium:

$ kubectl -n kube-system exec ds/cilium -- cilium-dbg status | grep -A5 Encryption
Encryption:              Wireguard         [NodeEncryption: Disabled, cilium_wg0 (Pubkey: z7DPaEWcp7Ph8zUJVgmoRJyDnr5F7NX3Sk965LnLKkc=, Port: 51871, Peers: 9)]
Cluster health:          10/10 reachable   (2026-05-20T05:38:27Z)   (Probe interval: 3m2.671346263s)
Name                     IP                Node                     Endpoints
Modules Health:          Stopped(24) Degraded(0) OK(106)

Это означает следующее:

  1. Шифрование WireGuard в Cilium включено.

  2. Интерфейс WireGuard активен.

  3. Межнодовый трафик подов проходит через зашифрованные туннели.

NodeEncryption: Disabled — не означает, что шифрование отключено. Это значит:

  • трафик под-под между нодами шифруется;

  • трафик на уровне хоста/ноды (host-network) не шифруется.

По умолчанию Cilium автоматически отключает шифрование нода-нода для нод плоскости управления Kubernetes, то есть любая нода с меткой node-role.kubernetes.io/control-plane исключается из шифрования нода-нода — это предотвращает блокировку рабочих нод в случае потери связи с API-сервером и невозможности обновить ключи.

WireGuard создаёт выделенный интерфейс (cilium_wg0) и работает исключительно через UDP-порт 51871. Чтобы окончательно доказать факт шифрования трафика, мы запустили tcpdump на интерфейсе eth0 ноды:

root@ip-10-50-78-3:/home/cilium# tcpdump -ni eth0
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
06:24:34.424254 IP 10.50.78.3.10250 > 10.50.198.120.47334: Flags [P.], seq 1350630264:1350630294,
ack 1497774172, win 112, length 30
06:24:34.424290 IP 10.50.78.3.10250 > 10.50.198.120.47334: Flags [P.], seq 30:205, ack 1, win 112,
length 175
06:24:34.424732 IP 10.50.198.120.47334 > 10.50.78.3.10250: Flags [.], ack 30, win 1880, length 0
06:24:34.424776 IP 10.50.198.120.47334 > 10.50.78.3.10250: Flags [.], ack 205, win 1903, length 0
06:24:34.463848 IP 10.50.78.3.10250 > 10.50.198.120.47334: Flags [P.], seq 205:235, ack 1, win 112,
length 30
06:24:34.463867 IP 10.50.78.3.10250 > 10.50.198.120.47334: Flags [P.], seq 235:907, ack 1, win 112,
length 672
06:24:34.464314 IP 10.50.198.120.47334 > 10.50.78.3.10250: Flags [.], ack 235, win 1903, length 0
06:24:34.464314 IP 10.50.198.120.47334 > 10.50.78.3.10250: Flags [.], ack 907, win 1926, length 0
06:24:34.475654 IP 10.50.194.106.4240 > 10.50.78.3.44874: Flags [.], ack 364212217, win 70, length 0
06:24:34.475695 IP 10.50.78.3.44874 > 10.50.194.106.4240: Flags [.], ack 1, win 71, length 0
06:24:34.573830 IP 10.50.78.3.10250 > 10.50.198.120.47334: Flags [P.], seq 907:937, ack 1, win 112,
length 30
06:24:34.573849 IP 10.50.78.3.10250 > 10.50.198.120.47334: Flags [P.], seq 937:1888, ack 1, win 112,
length 951
06:24:34.574316 IP 10.50.198.120.47334 > 10.50.78.3.10250: Flags [.], ack 937, win 1926, length 0
06:24:34.574316 IP 10.50.198.120.47334 > 10.50.78.3.10250: Flags [.], ack 1888, win 1948, length 0
06:24:34.909027 IP 10.50.78.3.51871 > 10.50.200.138.51871: UDP, length 128
06:24:34.909565 IP 10.50.200.138.51871 > 10.50.78.3.51871: UDP, length 224
06:24:34.909721 IP 10.50.78.3.51871 > 10.50.200.182.51871: UDP, length 128
06:24:34.910428 IP 10.50.200.182.51871 > 10.50.78.3.51871: UDP, length 304
06:24:34.913857 IP 10.50.78.3.10250 > 10.50.198.120.47334: Flags [P.], seq 3258:4151, ack 1, win
112, length 893
06:24:35.167178 IP 10.50.72.142.51871 > 10.50.78.3.51871: UDP, length 2256
06:24:35.183742 IP 108.137.60.165.443 > 10.50.78.3.54038: Flags [P.], seq 4276399503:4276399644, ack
1783024787, win 443, length 141
06:24:35.183799 IP 10.50.78.3.54038 > 108.137.60.165.443: Flags [.], ack 141, win 2640, length 0
06:24:35.539689 IP 10.50.80.93.51871 > 10.50.78.3.51871: UDP, length 2752
06:24:36.283539 ARP, Request who-has 10.50.93.155 tell 10.50.78.3, length 28
06:24:36.283567 ARP, Reply 10.50.93.155 is-at 0e:b7:8f:96:d7:77, length 28
06:24:37.535835 IP 10.50.78.3.39382 > 108.137.60.165.443: Flags [P.], seq 3748905810:3748905849, ack
741212595, win 1188, length 39
06:24:37.614016 IP 10.50.78.3.51871 > 10.50.94.106.51871: UDP, length 2048
06:24:37.937039 IP 10.50.78.3.51871 > 10.50.194.57.51871: UDP, length 2672
06:24:38.867098 IP 10.50.78.3.51871 > 10.50.75.232.51871: UDP, length 2672
... [Сокращено для читаемости — всего захвачено 274 пакета] ...
^C
274 packets captured
279 packets received by filter
0 packets dropped by kernel
  1. Трафик WireGuard под-под (UDP-порт 51871). Каждый раз, когда вы видите UDP, length [X] на порту 51871 (например, трафик к 10.50.200.138 или 10.50.75.232), перед вами зашифрованные полезные данные подов, проходящие по сети. Внутренние IP-адреса и протоколы не видны, потому что eth0 видит только внешнюю зашифрованную оболочку.

  2. Незашифрованный трафик на уровне нод (TCP-порты 10250 и 4240). Поскольку шифрование нода-нода отключено, мы ожидаем видеть хост-уровневые взаимодействия Kubernetes на eth0 в открытом виде. Дамп это подтверждает.

06:24:34.573830 IP 10.50.78.3.10250 > 10.50.198.120.47334: Flags [P.], seq 907:937, ack 1, win 112,
length 30
  • Порт 10250 (Kubelet API): много TCP-трафика между нодой (10.50.78.3) и 10.50.198.120. Порт 10250 — это Kubelet. Скорее всего, это API-сервер Kubernetes, metrics-server или Prometheus, собирающий логи/метрики с Kubelet этой ноды.

  • Порт 4240 (Cilium Health): в 06:24:34.475654 мы видим пинг от 10.50.194.106 на нашу ноду на порту 4240. Это агент cilium-health проверяет межнодовую связность.

Как анализировать дальше

Сейчас мы перехватываем трафик на eth0. Это хорошо подходит для проверки работы WireGuard (по наличию порта 51871) и подтверждения, что трафик нод не зашифрован.

Однако при диагностике проблем связности под-под перехват на eth0 заходит в тупик, потому что полезные данные зашифрованы.

Чтобы заглянуть внутрь туннеля WireGuard и проанализировать реальный трафик подов (внутренние IP-заголовки, HTTP-запросы, DNS-запросы и т. д.), нужно запустить tcpdump на расшифрованном интерфейсе WireGuard cilium_wg0, который создаёт Cilium:

root@ip-10-50-78-3:/home/cilium# tcpdump -ni cilium_wg0
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on cilium_wg0, link-type RAW (Raw IP), snapshot length 262144 bytes
06:22:29.757950 IP 10.50.77.69.42844 > 10.50.194.47.4317: Flags [P.], seq 512615461:512618006, ack 2027503549, win 70, options [nop,nop,TS val 3290570405 ecr 836288998], length 2545
06:22:29.758498 IP 10.50.194.47.4317 > 10.50.77.69.42844: Flags [P.], seq 1:31, ack 2545, win 548, options [nop,nop,TS val 836299000 ecr 3290570405], length 30
06:22:29.758529 IP 10.50.77.69.42844 > 10.50.194.47.4317: Flags [.], ack 31, win 70, options [nop,nop,TS val 3290570406 ecr 836299000], length 0
06:22:29.758653 IP 10.50.77.69.42844 > 10.50.194.47.4317: Flags [P.], seq 2545:2562, ack 31, win 70, options [nop,nop,TS val 3290570406 ecr 836299000], length 17
06:22:29.758707 IP 10.50.194.47.4317 > 10.50.77.69.42844: Flags [P.], seq 31:69, ack 2545, win 548, options [nop,nop,TS val 836299000 ecr 3290570405], length 38
06:22:29.805429 IP 10.50.194.47.4317 > 10.50.77.69.42844: Flags [.], ack 2562, win 548, options [nop,nop,TS val 836299047 ecr 3290570406], length 0
06:22:29.813562 IP 10.50.77.69.42844 > 10.50.194.47.4317: Flags [.], ack 69, win 70, options [nop,nop,TS val 3290570461 ecr 836299000], length 0
06:22:30.071898 IP 10.50.77.188.43018 > 10.50.92.86.4317: Flags [P.], seq 3451821091:3451823127, ack 2879682561, win 70, options [nop,nop,TS val 3836044087 ecr 1119428115], length 2036
06:22:30.071949 IP 10.50.92.86.4317 > 10.50.77.188.43018: Flags [.], ack 2036, win 2396, options [nop,nop,TS val 1119433116 ecr 3836044087], length 0
06:22:30.072069 IP 10.50.92.86.4317 > 10.50.77.188.43018: Flags [P.], seq 1:31, ack 2036, win 2397, options [nop,nop,TS val 1119433116 ecr 3836044087], length 30
06:22:30.072277 IP 10.50.77.188.43018 > 10.50.92.86.4317: Flags [.], ack 31, win 70, options [nop,nop,TS val 3836044088 ecr 1119433116], length 0
06:22:30.072349 IP 10.50.92.86.4317 > 10.50.77.188.43018: Flags [P.], seq 31:69, ack 2036, win 2397, options [nop,nop,TS val 1119433116 ecr 3836044088], length 38
06:22:30.072363 IP 10.50.77.188.43018 > 10.50.92.86.4317: Flags [P.], seq 2036:2053, ack 31, win 70, options [nop,nop,TS val 3836044088 ecr 1119433116], length 17
06:22:30.103429 IP 10.50.77.180.33472 > 10.50.92.86.4317: Flags [P.], seq 113065905:113068070, ack 2840479140, win 70, options [nop,nop,TS val 3302910205 ecr 3064157493], length 2165
06:22:30.103464 IP 10.50.92.86.4317 > 10.50.77.180.33472: Flags [.], ack 2165, win 476, options [nop,nop,TS val 3064162494 ecr 3302910205], length 0
06:22:30.103577 IP 10.50.92.86.4317 > 10.50.77.180.33472: Flags [P.], seq 1:31, ack 2165, win 480, options [nop,nop,TS val 3064162495 ecr 3302910205], length 30
06:22:30.103845 IP 10.50.92.86.4317 > 10.50.77.180.33472: Flags [P.], seq 31:69, ack 2165, win 480, options [nop,nop,TS val 3064162495 ecr 3302910205], length 38
06:22:30.103877 IP 10.50.77.180.33472 > 10.50.92.86.4317: Flags [.], ack 31, win 70, options [nop,nop,TS val 3302910205 ecr 3064162495], length 0
06:22:30.103946 IP 10.50.77.180.33472 > 10.50.92.86.4317: Flags [P.], seq 2165:2182, ack 31, win 70, options [nop,nop,TS val 3302910205 ecr 3064162495], length 17
06:22:30.119035 IP 10.50.77.188.43018 > 10.50.92.86.4317: Flags [.], ack 69, win 70, options [nop,nop,TS val 3836044135 ecr 1119433116], length 0
06:22:30.123553 IP 10.50.92.86.4317 > 10.50.77.188.43018: Flags [.], ack 2053, win 2397, options [nop,nop,TS val 1119433168 ecr 3836044088], length 0
06:22:30.149032 IP 10.50.77.180.33472 > 10.50.92.86.4317: Flags [.], ack 69, win 70, options [nop,nop,TS val 3302910251 ecr 3064162495], length 0
06:22:30.153541 IP 10.50.92.86.4317 > 10.50.77.180.33472: Flags [.], ack 2182, win 480, options [nop,nop,TS val 3064162545 ecr 3302910205], length 0
06:22:30.470892 IP 10.50.81.60.35960 > 10.50.92.86.4317: Flags [P.], seq 1809322773:1809325439, ack 3356280991, win 70, options [nop,nop,TS val 502399374 ecr 493412681], length 2666
06:22:30.470950 IP 10.50.92.86.4317 > 10.50.81.60.35960: Flags [.], ack 2666, win 618, options [nop,nop,TS val 493417628 ecr 502399374], length 0
06:22:30.471080 IP 10.50.92.86.4317 > 10.50.81.60.35960: Flags [P.], seq 1:31, ack 2666, win 620, options [nop,nop,TS val 493417628 ecr 502399374], length 30
06:22:30.471410 IP 10.50.81.60.35960 > 10.50.92.86.4317: Flags [.], ack 31, win 70, options [nop,nop,TS val 502399374 ecr 493417628], length 0
06:22:30.471417 IP 10.50.92.86.4317 > 10.50.81.60.35960: Flags [P.], seq 31:69, ack 2666, win 620, options [nop,nop,TS val 493417628 ecr 502399374], length 38
06:22:30.471425 IP 10.50.81.60.35960 > 10.50.92.86.4317: Flags [P.], seq 2666:2683, ack 31, win 70, options [nop,nop,TS val 502399374 ecr 493417628], length 17
06:22:30.513558 IP 10.50.92.86.4317 > 10.50.81.60.35960: Flags [.], ack 2683, win 620, options [nop,nop,TS val 493417671 ecr 502399374], length 0
...
..
.
^C
695 packets captured
703 packets received by filter
0 packets dropped by kernel

Итог: хотя взаимодействие между локальным сокетом kubelet и плоскостью управления осталось незашифрованным (что ожидаемо), весь трафик под-под был полностью инкапсулирован. Никаких сырых HTTP 1.1 пакетов на проводе не наблюдалось — всё было надёжно завёрнуто в WireGuard UDP-пакеты на порту 51871.

Сравнение задержек

Параметры теста
- инструмент: qperf (запущен в поде)
- команда клиента qperf: "qperf","-t", "60","-v" ,"<QPERF_SERVER_POD_IP>", "tcp_lat", "tcp_bw", "udp_lat", "udp_bw", "-m", "128k"
клиент и сервер qperf запланированы в одной зоне доступности, но на разных нодах

10937 ± k get po -owide
NAME           READY   STATUS      RESTARTS   AGE    IP             NODE                                              NOMINATED NODE   READINESS GATES
qperf-client   0/1     Completed   0          112m   10.50.77.252   ip-10-50-80-93.ap-southeast-3.compute.internal    <none>           <none>
qperf-server   1/1     Running     0          133m   10.50.77.181   ip-10-50-72-142.ap-southeast-3.compute.internal   <none>           <none>
Результаты сравнения задержек между VPC CNI и Cilium

Обновление

Одной из главных причин перехода с VPC CNI на Cilium было включение шифрования трафика между подами. Я получил обратную связь о том, что инстансы AWS Nitro уже по умолчанию обеспечивают TLS-шифрование без накладных расходов на инкапсуляцию, позволяя сети работать на линейной скорости даже с включённым шифрованием.

Однако нет простого способа самостоятельно верифицировать это шифрование и предоставить команде GRC конкретные доказательства для соответствия SOC 2. Если ваши требования к соответствию предполагают верифицируемые свидетельства, а не просто ссылки на документацию AWS, я бы рекомендовал обратиться в AWS напрямую за дополнительными документами о соответствии.

Это не означает, что миграция на Cilium была бесполезной. Даже без включённого шифрования Cilium демонстрирует лучшую производительность по сравнению с VPC CNI.

Спасибо за прочтение :)

Полный файл helm values.yaml доступен на GitHub.

© 2026 meganuke