EKS #5 Мережа, CNI

pic

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 має доступ.

pic

Те, що зображено як хмара, є вузлом. Це EC2-інстанс, на якому через Security Group ми можемо заблокувати доступ до вузла з Pod1 і дозволити доступ до вузла з Pod2. Однак в Kubernetes поди і вузли не завжди створюються так ідеально.

І ось поди були зруйновані і перезавантажені:

pic

Якщо 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 активовано:

pic

Якщо цього немає, можна додати Amazon VPC CNI через розділ Get more add-ons. Цей розділ містить додаткові плагіни для EKS, такі як kubecost, kafka, grafana тощо.

Щоб активувати, перейдіть до Amazon VPC CNI, натисніть кнопку Edit в правому верхньому куті:

pic

У цьому вікні в розділі 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 для подів ще до створення кластера.

Додатково:

EKS AWS VPC CNI

https://faun.pub/choosing-your-cni-with-aws-eks-vpc-cni-or-calico-1ee6229297c5

Перекладено з: EKS #5 Network, CNI

Leave a Reply

Your email address will not be published. Required fields are marked *