AWS EKS에서 Service 타입 별 / Ingress 테스트

ShinChul Bang
finda 기술 블로그
16 min readJan 8, 2020

Overview

EKS 환경에서 쿠버네티스 Pod로 외부 통신 되도록 설정하는 다양한 방법을 테스트하여 각 장단점을 파악한다.

  • ClusterIP 타입의 Service를 사용하여 구성
  • NodePort 타입의 Service를 사용하여 구성
  • Load Balancer 타입의 Service를 사용하여 구성
  • ALB Ingress를 사용하여 구성

각 Service 타입 별 특징 혹은 Ingress에 대해서는 아래 링크를 통해 학습한다.

Kubernetes 네트워크 정리

사전 준비

3개의 Deployment 매니페스트를 사용하여 kubectl apply -f 명령어를 통해 여러개의 Pod를 띄운다.

사용할 Deployment 매니페스트는 아래와 같다.

nginx-deployment-1.yaml

kind: Deployment
apiVersion: apps/v1
metadata:
name: nginx-deployment-1
spec:
replicas: 4
selector:
matchLabels:
app: nginx_pod_1
template:
metadata:
labels:
app: nginx_pod_1
spec:
containers:
- name: simple-http
image: nginx:1.17.6-alpine
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80

nginx-deployment-2.yaml

kind: Deployment
apiVersion: extensions/v1beta1
metadata:
name: nginx-deployment-2
spec:
replicas: 2
template:
metadata:
labels:
app: nginx_pod_2
spec:
containers:
- image: nginx:1.17.6-alpine
imagePullPolicy: IfNotPresent
name: "2048"
ports:
- containerPort: 80

nginx-deployment-3.yaml

kind: Deployment
apiVersion: apps/v1
metadata:
name: nginx-deployment-3
spec:
replicas: 3
selector:
matchLabels:
app: nginx_pod_3
template:
metadata:
labels:
app: nginx_pod_3
spec:
containers:
- name: nginx
image: nginx:1.17.6-alpine
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80

ClusterIP 타입의 Service를 사용하여 구성

사전 준비 섹션에서 생성한 Pod들을 ClusterIP 타입(default)의 Service를 통해 라우팅 되도록 Service를 생성한다.

아래의 Service 매니페스트를 사용한다.

service-clusterip.yaml

apiVersion: v1
kind: Service
metadata:
name: clusterip-service-1
spec:
selector:
app: nginx_pod_1
ports:
- protocol: TCP
port: 80
targetPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: clusterip-service-2
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
selector:
app: nginx_pod_2
---
apiVersion: v1
kind: Service
metadata:
name: clusterip-service-3
spec:
selector:
app: nginx_pod_3
ports:
- protocol: TCP
port: 80
targetPort: 80

정리

  • 기본적인 클러스터 내부의 Service 구성 방법이다.
  • Service 생성만으로는 외부와 통신이 되지 않는다. (ClusterIP 특성)
  • 외부와 통신이 되도록 하려면 내부적으로 직접 netfilter chain rule을 등록하여 Public IP 주소로 들어온 패킷을 각 Pod들에게 포워딩 해줄 수 있도록 설정 해야할 것 같다.
  • 혹은 워커 노드 내부에 Reverse Proxy를 생성해서 클러스터 내부의 ClusterIP로 패킷을 포워딩 해주면 될 것 같다.
  • EKS 워커 노드는 기본적으로 SSH로 접근이 가능하도록 구현되어 있지 않아(내부 ~/.ssh/authorized_keys가 세팅되지 않음) 위의 솔루션을 구현하기 힘들다.(ssh 접속을 위해서는 eks 클러스터 생성 시 미리 설정 필요)

NodePort 타입의 Service를 사용하여 구성

사전 준비 섹션에서 생성한 Pod들을 NodePort 타입의 Service를 통해 라우팅 되도록 Service를 생성한다.

아래의 Service 매니페스트를 사용한다.

service-nodeport.yaml

apiVersion: v1
kind: Service
metadata:
name: nodeport-service-1
spec:
type: NodePort
selector:
app: nginx_pod_1
ports:
- protocol: TCP
port: 80
targetPort: 80
nodePort: 30500
---
apiVersion: v1
kind: Service
metadata:
name: nodeport-service-2
spec:
type: NodePort
selector:
app: nginx_pod_2
ports:
- port: 80
targetPort: 80
protocol: TCP
nodePort: 30501
---
apiVersion: v1
kind: Service
metadata:
name: nodeport-service-3
spec:
type: NodePort
selector:
app: nginx_pod_3
ports:
- protocol: TCP
port: 80
targetPort: 80
nodePort: 30502

다음에는 AWS 대시보드에 접속하여 로드밸런서를 생성한다.

로드밸런서는 경로에 따라 여러 서비스를 통신해주어야 하므로 Layer 7 까지 기능을 제공하는 Application Load Balancer를 생성한다.

정리

  • 외부 통신이 가능한 NodePort 번호를 부여받아 <워커 노드의 Public IP>:<지정한 NodePort>로 통신이 가능하다.
  • Application Load Balancer를 사용하여 클러스터 내부에 생성한 NodePort 타입의 서비스들을 로드밸런싱 해줄 수 있다.
  • 하지만 로드밸런서와 대상 그룹을 직접 생성해서 설정 해줘야 하고, 워커 노드의 보안 그룹에서 인바운드 그룹 설정에 30000–32767 범위의 포트를 public하게 열어줘야 한다.(NodePort의 포트 범위)

Load Balancer 타입의 Service를 사용하여 구성

사전 준비 섹션에서 생성한 Pod들을 Load Balancer 타입의 Service를 통해 라우팅 되도록 Service를 생성한다.

아래의 Service 매니페스트를 사용한다.

service-loadbalancer.yaml

apiVersion: v1
kind: Service
metadata:
name: loadbalancer-service-1
spec:
type: LoadBalancer
selector:
app: nginx_pod_1
ports:
- protocol: TCP
port: 80
targetPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: loadbalancer-service-2
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: 80
protocol: TCP
selector:
app: nginx_pod_2
---
apiVersion: v1
kind: Service
metadata:
name: loadbalancer-service-3
spec:
type: LoadBalancer
selector:
app: nginx_pod_3
ports:
- protocol: TCP
port: 80
targetPort: 80

정리

  • 위 매니페스트를 통해 LoadBalancer 타입의 Service를 생성하면, AWS에서 자동적으로 Service의 갯수만큼 Classic Load Balancer를 생성한다.
  • 그리고 해당 Classic Load Balancer에서 각 Service의 Pod로 트래픽을 라우팅 하기 위해 워커 노드(인스턴스)를 추가한다.
  • Classic Load Balancer는 대상 그룹이라는 개념이 없기 때문에 직접 로드밸런서에 인스턴스를 추가하는 형태로 구성된다.
  • 따라서 Application Load Balancer와 같이 Layer 7에서의(경로를 통한) 라우팅 설정은 불가능하다.

ALB Ingress를 사용하여 구성

Ingress를 사용하여 eks 외부 통신을 구현해보자.

Ingress를 사용하기 이전에 워커 노드에 ALB Ingress Controller와 Pod를 담당하는 Service(ClusterIP 혹은 NodePort 타입)가 생성되어 있어야한다.

왜냐하면 Ingress는 로드밸런서의 동작만 정의하는 것일 뿐 실제 트래픽을 전달해주는 것은 로드밸런서이고(혹은 Ingress를 통해 워커 노드 내부에 구성되는 reverse proxy) 이 트래픽을 전달받아 Pod로 바로 전달해주는 것이 아니라 Service로 전달해줘서 Service가 Pod로 트래픽을 전달해주도록 구현되어있기 때문이다. 즉, Ingress와 Service는 뗄 수 없는 사이이다.

또한 워커 노드 내부에 Ingress를 감지하여 로드밸런서를 프로비저닝 해줄 Ingress Controller가 꼭 필요하다.

사전 작업

Amazon EKS의 ALB 수신 컨트롤러

아래의 Ingress 매니페스트를 사용하여 Ingress를 생성한다.

aws eks에서 Ingress를 사용하려면 Ingress 매니페스트 파일작성 시 아래와 같은 annotations를 추가 해주어야 한다.

  • kubernetes.io/ingress.class: alb
  • alb.ingress.kubernetes.io/target-type: ip
  • alb.ingress.kubernetes.io/scheme: internet-facing

또한 eks 클러스터를 담당하는 vpc에 아래의 태그를 추가 해주어야 한다.

+---------------------------------+---------+
| key | value |
+---------------------------------+---------+
| kubernetes.io/role/elb | 1 |
| kubernetes.io/role/internal-elb | 1 |
+---------------------------------+---------+

쉽게 한큐에 ALB Ingress Controller를 워커 노드 내부에 생성하기 위해 아래와 같은 쉘 스크립트를 작성해서 실행하여 생성한다.

다만, 스크립트를 실행할 PC(자신의 PC?)에서 아래 작업들이 모두 해결되었다는 가정 하에 진행한다.

  • aws cli 설치
  • aws configure 설정
  • kubectl 설치
  • eksctl 설치 및 EKS 클러스터 생성
  • jq 라이브러리 설치
#/bin/bash  echo '>>> CREATE ALBIngressControllerIAMPolicy ' 
aws iam create-policy \
--policy-name ALBIngressControllerIAMPolicy \
--policy-document https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.1.3/docs/examples/iam-policy.json echo ''
echo '>>> Connecting ALBIngressControllerIAMPolicy To WorkerNode Role'
NG_ROLE=`kubectl -n kube-system describe configmap aws-auth | grep rolearn`
ACCOUNT=${NG_ROLE:24:12}
WN_ROLE=${NG_ROLE:42}
echo "ACCOUNT : $ACCOUNT"
echo "WORKER NODE ROLE : $WN_ROLE"
echo "NODE GROUP ROLE : $NG_ROLE"
aws iam attach-role-policy \
--policy-arn arn:aws:iam::${ACCOUNT}:policy/ALBIngressControllerIAMPolicy \
--role-name ${WN_ROLE}
echo ''
echo '>>> Create ClusterRole for ALB Ingress Controller'
kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.1.3/docs/examples/rbac-role.yaml echo ''
echo '>>> Create ALB Ingress Controller'
CLUSTER_NAME='eks-cluster' # write your's cluster name
AWS_REGION='ap-northeast-2' # write cluster's region
VPC_ID=`eksctl get cluster --name ${CLUSTER_NAME} --region ${AWS_REGION} --output json | jq -r '.[0].ResourcesVpcConfig.VpcId'`
echo "CLUSTER NAME : $CLUSTER_NAME"
echo "VPC ID : $VPC_ID"
echo "AWS REGION : $AWS_REGION"
echo ''
echo '>>> Remove Old alb-ingress-controller.yaml file && New alb-ingress-controller.yaml file Download'
rm -rf alb-ingress-controller.yaml* &&
curl -O https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.1.3/docs/examples/alb-ingress-controller.yaml &&
# alb-ingress-controller.yaml
sed -i -e "s/# - --cluster-name=devCluster/- --cluster-name=$CLUSTER_NAME/g" alb-ingress-controller.yaml &&
sed -i -e "s/# - --aws-vpc-id=vpc-xxxxxx/- --aws-vpc-id=$VPC_ID/g" alb-ingress-controller.yaml &&
sed -i -e "s/# - --aws-region=us-west-1/- --aws-region=$AWS_REGION/g" alb-ingress-controller.yaml &&
kubectl apply -f ./alb-ingress-controller.yaml
echo '>>> FINISH'
sleep 5
echo '>>> Checking Create ALB Ingress Controller'
kubectl get pods -n kube-system | grep alb

ALB Ingress Controller가 워커 노드 내부에 잘 생성되었으면 아래의 ingress.yaml 매니페스트 파일을 통해 Ingress를 생성한다.

ingress.yaml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test-ingress
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/scheme: internet-facing
spec:
rules:
- http:
paths:
- path: /hello
backend:
serviceName: clusterip-service-1
servicePort: 80
- path: /test
backend:
serviceName: clusterip-service-2
servicePort: 80
- path: /game
backend:
serviceName: clusterip-service-3
servicePort: 80

정리

  • Ingress를 생성하면 AWS 내부에서 자동적으로 Application Load Balancer를 생성해준다.
  • 그리고 Service별로 대상 그룹도 생성해준다.
  • 또한 외부 통신을 위한 보안 그룹도 생성해준다. 하지만 모든 포트가 열려있다.
  • Application Load Balancer의 리스너 규칙도 Ingress 매니페스트에 정의해놓은 대로 구현해준다.
  • 사용자는 ingress 매니페스트를 통해 간단하게 외부 통신을 구현할 수 있다.

--

--