CNI є стандартним інтерфейсом для управління мережевими з'єднаннями між контейнерами. Зазвичай його використовують у платформах для оркестрації контейнерів, таких як Docker Swarm, Amazon ECS та Kubernetes, з яким ми зараз працюємо.
Але насправді CNI належить до рівня контейнерного виконання. Тобто, він має відношення до контейнерів Docker.
CNI був створений для того, щоб забезпечити спільний інтерфейс між мережевими плагінами та виконанням контейнерів, щоб уникнути дублювання у різних платформах оркестрації контейнерів і різних контейнерних виконаннях.
У межах одного кластера кожен под має свою IP-адресу. Ця IP-адреса є локальною, тому поди можуть взаємодіяти між собою через цю адресу. Однак оскільки поди є stateless, їх IP-адреси можуть змінюватися.
Тут на допомогу приходить CNI, який відповідає за мережевий роутінг між подами.
Коли контейнер створюється, виконуються команди ADD, DELETE, CHECK, які відповідають стандартам CNI і визначають, куди слід надсилати запити між подами.
CNI також дозволяє визначити, які запити приймати, а які відхиляти. Це в Kubernetes зазвичай називається NetworkPolicy, і можна сказати, що за своєю суттю це схоже на роль Security Group в AWS.
Але давайте подумаймо про це ще раз.
Уявімо, що існує два поди: Pod1 і Pod2, причому Pod1 не має доступу до бази даних, а Pod2 має доступ.
Те, що зображено як хмара, є вузлом. Це EC2-інстанс, на якому через Security Group ми можемо заблокувати доступ до вузла з Pod1 і дозволити доступ до вузла з Pod2. Однак в Kubernetes поди і вузли не завжди створюються так ідеально.
І ось поди були зруйновані і перезавантажені:
Якщо Pod1 і Pod2 потрапили на різні вузли, проблема з Security Group стає не такою очевидною, оскільки обсяг Security Group обмежений одним EC2-інстансом.
В AWS EKS це вирішується за допомогою Pod Security Group. Це саме та частина Amazon CNI, яка дозволяє налаштовувати Security Group для кожного поду окремо.
Існують різні типи CNI:
- weaverworks
- calico
- antrea
- amazon vpc cni
Ось чому CNI є необхідним, і давайте тепер спробуємо виконати прості практичні кроки та тести.
namespace, deployment
Спершу створимо кластер.
eksctl create cluster \
--name netpol-test \
--nodegroup-name ng-default \
--node-type t3.small \
--nodes 2
Далі запустимо по одному поду nginx у трьох різних неймспейсах з однаковою конфігурацією, але в різних просторах імен.
Ми створимо NetworkPolicy, щоб дозволити доступ з a -> c, але заблокувати доступ з b -> c.
# namespaces.yaml
apiVersion: v1
kind: Namespace
metadata:
name: namespace-a
---
apiVersion: v1
kind: Namespace
metadata:
name: namespace-b
---
apiVersion: v1
kind: Namespace
metadata:
name: namespace-c
Створимо три неймспейси.
# nginx-deployments.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-a
namespace: namespace-a
spec:
replicas: 1
selector:
matchLabels:
app: nginx-a
template:
metadata:
labels:
app: nginx-a
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-b
namespace: namespace-b
spec:
replicas: 1
selector:
matchLabels:
app: nginx-b
template:
metadata:
labels:
app: nginx-b
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-c
namespace: namespace-c
spec:
replicas: 1
selector:
matchLabels:
app: nginx-c
template:
metadata:
labels:
app: nginx-c
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
Далі розгорнемо поди nginx у кожному з неймспейсів.
kubectl apply -f namespaces.yaml
kubectl apply -f nginx-deployments.yaml
Тепер виконаємо команду apply
для запуску.
Отже, давайте з'ясуємо IP-адресу c, щоб перевірити доступ до неї.
kubectl get pod -n namespace-c -o wide
Тепер, знаючи IP-адресу, спробуємо отримати доступ до поду в namespace-a.
kubectl exec -it deployment/nginx-a -n namespace-a -- curl 192.168.89.245
kubectl exec -it deployment/nginx-b -n namespace-b -- curl 192.168.89.245
Якщо доступ отримано, відправимо запит.
curl
Таким чином, перевіримо, чи коректно виводиться index.html від nginx.
Оскільки NetworkPolicy ще не налаштовано, запит буде успішним.
Тепер давайте налаштуємо network policy.
Network Policy
Створимо маніфест для Network Policy, як показано нижче.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: namespace-c
spec:
podSelector:
matchLabels:
app: nginx-c
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: namespace-a
Цей файл має тип NetworkPolicy. Після створення його можна перевірити за допомогою команд
kubectl get networkpolicy
kubectl get netpol
Звісно, потрібно додати опцію для вказання неймспейсу.
Цей Network Policy обмежить мережеві запити для подів з ім'ям nginx-c, налаштовуючи обмеження для типів Ingress та Egress. Ingress – це вхідні запити, а Egress – вихідні. Можна налаштувати доступ через namespace або CIDR, як показано у файлі.
Детальнішу інформацію можна знайти в офіційному документі. В даному випадку файл обмежує доступ лише до Ingress з namespace-a для подів nginx-c в namespace-c.
Після створення файлу застосуємо його командою:
kubectl apply -f network-policy.yaml
Тепер спробуємо зробити запити з подів nginx в nginx-c.
CNI плагін
Якщо зробити запит з nginx-a або nginx-b, то запит все ще буде досягати nginx-c з обох подів. Попри те, що ми налаштували Network Policy на Ingress лише з namespace-a, зміни не вступили в силу. Причина цього в тому, що CNI плагін не працює належним чином.
У стандартному Kubernetes потрібно вручну встановити CNI плагін. Як згадувалося раніше, існує кілька типів CNI плагінів. Однак в AWS EKS за замовчуванням встановлено AWS VPC CNI. Проте навіть якщо він встановлений, він не працюватиме, оскільки не були налаштовані необхідні параметри.
Якщо перейти в веб-консоль і переглянути додатки в кластері, можна побачити, що Amazon VPC CNI активовано:
Якщо цього немає, можна додати Amazon VPC CNI через розділ Get more add-ons. Цей розділ містить додаткові плагіни для EKS, такі як kubecost, kafka, grafana тощо.
Щоб активувати, перейдіть до Amazon VPC CNI, натисніть кнопку Edit в правому верхньому куті:
У цьому вікні в розділі Configuration Values введіть:
{"enableNetworkPolicy": "true"}
Після цього застосуйте зміни.
Тепер, якщо знову спробувати надіслати запити з nginx-a та nginx-b до nginx-c, nginx-a успішно отримає index.html від nginx, а запит з nginx-b зазнає тайм-ауту, оскільки доступ з namespace-b заблоковано.
Також можна застосувати ці налаштування з терміналу за допомогою такої команди:
aws eks update-addon --cluster-name netpol-test --addon-name vpc-cni --configuration-values '{"enableNetworkPolicy": "true"}'
CNI плагіни можуть бути різними, і ви не обов'язково повинні використовувати тільки Amazon VPC CNI. Наприклад, одним з популярних плагінів є Calico.
Використання Amazon VPC CNI дозволяє безпосередньо призначати CIDR з вузлів для подів, що знижує складність мережі та підвищує швидкість. Однак використання Calico дозволяє змінити мережеві діапазони для вузлів та подів, що дає переваги у вигляді мережевої ізоляції та уникнення конфліктів IP-адрес.
Але є й недолік Amazon VPC CNI – діапазони IP-адрес можуть швидко закінчуватися. Це можна вирішити, розподіливши CIDR для подів ще до створення кластера.
Додатково:
https://faun.pub/choosing-your-cni-with-aws-eks-vpc-cni-or-calico-1ee6229297c5
Перекладено з: EKS #5 Network, CNI