メインコンテンツまでスキップ

EKS Networking (Advanced)

Phần này đi sâu vào các chủ đề networking quan trọng khi vận hành EKS trong môi trường production: load balancing, DNS, network policy, và service mesh.


🌐 1. Kubernetes Service Types

Trước khi đến ALB/NLB, cần hiểu rõ các loại Service trong K8s.

1.1. ClusterIP (Default)

Service chỉ accessible bên trong cluster. Dùng cho giao tiếp nội bộ giữa các microservice.

apiVersion: v1
kind: Service
metadata:
name: backend-svc
spec:
type: ClusterIP
selector:
app: backend
ports:
- port: 80
targetPort: 8080

1.2. NodePort

Mở port trực tiếp trên mỗi Node EC2 (range 30000–32767). Ít dùng trong production vì lộ port EC2 ra ngoài.

1.3. LoadBalancer

Tạo AWS Load Balancer tự động. Mặc định tạo Classic Load Balancer (CLB) — đã lỗi thời. Muốn dùng ALB/NLB hiện đại cần cài AWS Load Balancer Controller.


⚖️ 2. AWS Load Balancer Controller

2.1. AWS Load Balancer Controller là gì?

AWS Load Balancer Controller là Kubernetes controller do AWS phát triển, thay thế in-tree CLB provisioner. Nó tạo và quản lý ALB/NLB từ Kubernetes Ingress và Service objects.

  • Ingress → tạo Application Load Balancer (ALB) — Layer 7, routing theo path/hostname.
  • Service type=LoadBalancer → tạo Network Load Balancer (NLB) — Layer 4, hiệu năng cao.
Cài qua EKS Addon

AWS Load Balancer Controller hiện có sẵn dưới dạng EKS Addon, không cần cài bằng Helm thủ công.

2.2. Cài đặt

Bước 1: Tạo IAM Policy và IRSA

# Tải IAM policy
curl -O https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/main/docs/install/iam_policy.json

# Tạo IAM Policy
aws iam create-policy \
--policy-name AWSLoadBalancerControllerIAMPolicy \
--policy-document file://iam_policy.json

# Tạo IRSA
eksctl create iamserviceaccount \
--cluster my-cluster \
--namespace kube-system \
--name aws-load-balancer-controller \
--attach-policy-arn arn:aws:iam::123456789012:policy/AWSLoadBalancerControllerIAMPolicy \
--approve

Bước 2: Cài bằng Helm

helm repo add eks https://aws.github.io/eks-charts
helm install aws-load-balancer-controller eks/aws-load-balancer-controller \
-n kube-system \
--set clusterName=my-cluster \
--set serviceAccount.create=false \
--set serviceAccount.name=aws-load-balancer-controller

2.3. Tạo ALB bằng Ingress

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
namespace: production
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/scheme: internet-facing # hoặc internal
alb.ingress.kubernetes.io/target-type: ip # ip = route thẳng tới Pod
alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:ap-southeast-1:123456789012:certificate/xxx
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS": 443}]'
alb.ingress.kubernetes.io/ssl-redirect: "443"
spec:
rules:
- host: api.example.com
http:
paths:
- path: /users
pathType: Prefix
backend:
service:
name: user-service
port:
number: 80
- path: /orders
pathType: Prefix
backend:
service:
name: order-service
port:
number: 80

2.4. Tạo NLB bằng Service

apiVersion: v1
kind: Service
metadata:
name: game-server
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: external
service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip
service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing
spec:
type: LoadBalancer
selector:
app: game-server
ports:
- port: 7777
targetPort: 7777
protocol: UDP

2.5. IngressGroup - Chia sẻ 1 ALB cho nhiều Ingress

Mặc định, mỗi Ingress tạo 1 ALB riêng → tốn tiền. IngressGroup cho phép nhiều Ingress dùng chung 1 ALB.

# ingress-team-a.yaml
metadata:
annotations:
alb.ingress.kubernetes.io/group.name: shared-alb
alb.ingress.kubernetes.io/group.order: "10"

# ingress-team-b.yaml
metadata:
annotations:
alb.ingress.kubernetes.io/group.name: shared-alb
alb.ingress.kubernetes.io/group.order: "20"

🔍 3. ExternalDNS

3.1. ExternalDNS là gì?

ExternalDNS tự động tạo DNS record trên Route 53 khi bạn tạo Ingress hoặc Service LoadBalancer. Không cần vào console tạo record thủ công.

3.2. Cài đặt

# Tạo policy tối thiểu cho ExternalDNS (giới hạn theo Hosted Zone ARN)
cat > externaldns-policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"route53:ChangeResourceRecordSets",
"route53:ListResourceRecordSets"
],
"Resource": [
"arn:aws:route53:::hostedzone/Z1111111111111",
"arn:aws:route53:::hostedzone/Z2222222222222"
]
},
{
"Effect": "Allow",
"Action": [
"route53:ListHostedZonesByName"
],
"Resource": "*"
}
]
}
EOF

aws iam create-policy \
--policy-name ExternalDNSRoute53LimitedPolicy \
--policy-document file://externaldns-policy.json

# Tạo IRSA và chỉ attach policy tối thiểu
eksctl create iamserviceaccount \
--cluster my-cluster \
--namespace kube-system \
--name external-dns \
--attach-policy-arn arn:aws:iam::123456789012:policy/ExternalDNSRoute53LimitedPolicy \
--approve

# Cài bằng Helm
helm repo add external-dns https://kubernetes-sigs.github.io/external-dns/
helm install external-dns external-dns/external-dns \
--namespace kube-system \
--set provider=aws \
--set aws.zoneType=public \
--set txtOwnerId=my-cluster \
--set serviceAccount.name=external-dns \
--set serviceAccount.create=false
Không dùng quyền quá rộng

Tránh dùng AmazonRoute53FullAccess cho ExternalDNS trong production. Hãy giới hạn policy theo đúng Hosted Zone ARN mà cluster cần quản lý.

3.3. Sử dụng

Chỉ cần thêm annotation vào Ingress hoặc Service:

# Với Ingress
metadata:
annotations:
external-dns.alpha.kubernetes.io/hostname: api.example.com

# Với Service LoadBalancer
metadata:
annotations:
external-dns.alpha.kubernetes.io/hostname: grpc.example.com

ExternalDNS sẽ tự động tạo record sau ~30 giây.


🛡️ 4. Network Policy

4.1. Network Policy là gì?

NetworkPolicy là Kubernetes resource dùng để kiểm soát traffic giữa các Pod ở tầng L3/L4 (IP và port). Mặc định, tất cả Pod trong cluster có thể nói chuyện với nhau — NetworkPolicy giúp cách ly theo nguyên tắc least privilege.

Cần CNI hỗ trợ

Amazon VPC CNI không hỗ trợ NetworkPolicy mặc định. Cần bật tính năng Network Policy của VPC CNI (hỗ trợ từ EKS 1.25+) hoặc cài Calico.

# Bật Network Policy trong VPC CNI addon
aws eks update-addon \
--cluster-name my-cluster \
--addon-name vpc-cni \
--configuration-values '{"enableNetworkPolicy": "true"}'

4.2. Ví dụ: Deny all ingress mặc định

# Deny tất cả ingress traffic vào namespace production
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: production
spec:
podSelector: {} # áp dụng cho toàn bộ Pod
policyTypes:
- Ingress

4.3. Ví dụ: Chỉ cho phép frontend → backend

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-backend
namespace: production
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080

4.4. Ví dụ: Backend truy cập RDS (egress)

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-backend-to-rds
namespace: production
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Egress
egress:
- ports:
- protocol: TCP
port: 5432 # PostgreSQL
to:
- ipBlock:
cidr: 10.0.2.0/24 # Subnet chứa RDS

📡 5. CoreDNS Tuning

5.1. CoreDNS là gì?

CoreDNS là DNS server mặc định trong K8s, xử lý toàn bộ DNS lookup nội bộ cluster: my-service.my-namespace.svc.cluster.local.

5.2. Vấn đề DNS thường gặp

DNS Lookup Storm: Mỗi Pod thực hiện nhiều DNS query song song (IPv4 + IPv6, với và không có search domain). Trên cluster lớn, CoreDNS có thể bị quá tải.

Search domain chain: Mỗi query redis → thực ra K8s thử lần lượt:

  1. redis.production.svc.cluster.local
  2. redis.svc.cluster.local
  3. redis.cluster.local
  4. redis.ap-southeast-1.compute.internal
  5. redis (bare name)

→ 1 query thực tế = 5 DNS query.

5.3. Giải pháp

Dùng FQDN: Khai báo tên đầy đủ để tránh search domain chain.

# Thay vì: redis
# Dùng: redis.production.svc.cluster.local. (có dấu . cuối)
env:
- name: REDIS_HOST
value: "redis.production.svc.cluster.local"

Scale CoreDNS:

kubectl -n kube-system scale deployment coredns --replicas=4

Bật CoreDNS Autoscaler:

apiVersion: apps/v1
kind: Deployment
metadata:
name: coredns-autoscaler
namespace: kube-system
spec:
template:
spec:
containers:
- name: autoscaler
command:
- /cluster-proportional-autoscaler
- --namespace=kube-system
- --configmap=coredns-autoscaler
- --target=Deployment/coredns
- --default-params={"linear":{"coresPerReplica":256,"nodesPerReplica":16,"min":2}}

NodeLocal DNSCache: Cache DNS ngay tại mỗi node, giảm tải cho CoreDNS trung tâm.

# Cài NodeLocal DNSCache
kubectl apply -f https://raw.githubusercontent.com/kubernetes/kubernetes/master/cluster/addons/dns/nodelocaldns/nodelocaldns.yaml

🔗 6. Service Mesh - AWS App Mesh và Istio

6.1. Khi nào cần Service Mesh?

Service Mesh giải quyết các vấn đề không thể làm với chỉ Kubernetes networking thuần:

Tính năngK8s thuầnService Mesh
Load balancingRound-robin đơn giảnWeighted, least-conn, circuit breaker
mTLS giữa service✅ Auto
Traffic shifting (canary/blue-green)KhóDễ
Observability (traces, metrics)Cần cấu hình manual✅ Auto
Retry / timeout policyCần code trong app✅ Transparent

6.2. AWS App Mesh

App Mesh là managed service mesh của AWS, dùng Envoy làm sidecar proxy.

Các khái niệm chính:

  • Mesh: Đơn vị quản lý tổng thể.
  • VirtualNode: Đại diện cho 1 Deployment/Service.
  • VirtualRouter + Route: Định nghĩa traffic routing.
  • VirtualService: Tên logic của service, decoupled với backend thực.

6.3. Traffic Shifting với App Mesh (Canary Deploy)

apiVersion: appmesh.k8s.aws/v1beta2
kind: VirtualRouter
metadata:
name: order-router
spec:
routes:
- name: order-route
httpRoute:
match:
prefix: /
action:
weightedTargets:
- virtualNodeRef:
name: order-v1
weight: 90 # 90% traffic → v1
- virtualNodeRef:
name: order-v2
weight: 10 # 10% traffic → v2 (canary)

6.4. Istio trên EKS

Istio là service mesh mã nguồn mở phổ biến nhất. Cài bằng Helm:

helm repo add istio https://istio-release.storage.googleapis.com/charts
helm install istio-base istio/base -n istio-system --create-namespace
helm install istiod istio/istiod -n istio-system

# Enable auto injection cho namespace
kubectl label namespace production istio-injection=enabled

VirtualService với traffic splitting (Istio):

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- route:
- destination:
host: reviews
subset: v1
weight: 80
- destination:
host: reviews
subset: v2
weight: 20

📊 7. Tóm tắt - Chọn giải pháp nào?

Nhu cầuGiải pháp khuyến nghị
Expose HTTP/HTTPS ra internetALB Ingress + AWS Load Balancer Controller
Expose TCP/UDP (game, gRPC)NLB via Service LoadBalancer
Nhiều service, tiết kiệm chi phí ALBIngressGroup (dùng chung 1 ALB)
Tự động tạo DNS recordExternalDNS + Route 53
Cách ly traffic giữa namespace/PodNetworkPolicy (bật VPC CNI Network Policy)
DNS chậm trên cluster lớnScale CoreDNS + NodeLocal DNSCache
mTLS, canary deploy, observability sâuService Mesh (App Mesh hoặc Istio)