앞에서 Bastion 서버에 Pod
읽기 권한을 주었는데 이번 실습을 위하여 cluster-admin
권한을 주겠다. cluster-admin
은 쿠버네티스에서 제공하는 기본 ClusterRole
로 수퍼 유저 액세스를 허용하여 모든 리소스에 대한 작업을 수행 할 수 있다.
아래과 같이 ClusterRoleBinding
을 진행해주면 되겠다.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: bastion-cluster-role-binding
subjects:
- kind: User
name: L23724-bastion-eks-role
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.io
ClusterRole 참고 : 공식 문서
이번 글에서 배포할 서비스는 아래 글에서 자세히 다루고 있으니 먼저 보고 오는 것을 추천한다.
[Kubernetes] Minikube로 Front와 API 배포해보기 (Node.js, React)
Service
는 Pod
집합에서 실행중인 애플리케이션을 네트워크 서비스로 노출하는 추상화 방법이다.
ClusterIP
, NodePort
, LoadBalancer
이렇게 세가지 type
이 있다.
Service
의 기본 타입이 ClusterIP
이기 때문에 타입을 지정하지 않았을 때는 ClusterIP
타입이다.
Service
를 클러스터 내부 IP에 노출시키고 클러스터 내에서만 해당 Service
에 접근이 가능하다.
Kubernetes proxy
를 통하면 외부 접근이 가능하지만 실제 운영에서는 사용하지 않고 디버깅 용이나 내부 대시보드 등 내부 트래픽을 허용할 때 사용된다고 한다.
https://blog.leocat.kr/notes/2019/08/22/translation-kubernetes-nodeport-vs-loadbalancer-vs-ingress
yaml은 다음과 같이 작성 할 수 있다.
apiVersion: v1
kind: Service
metadata:
name: test-front
spec:
selector:
app: test-front
tier: front
ports:
- port: 80
타입은 지정하지 않아 기본 타입인 ClusterIP
이고 CLUSTER-IP
가 붙은 것을 볼 수 있다.
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.100.0.1 <none> 443/TCP 7d16h
test-api ClusterIP 10.100.35.21 <none> 8080/TCP 5d23h
test-front ClusterIP 10.100.128.100 <none> 80/TCP 19m
ClusterIP
타입은 외부에서 접근할 수 없다. test-front
처럼 외부에서 접근해야 하는 서비스는 NodePort
타입이나 LoadBalancer
타입으로 구성해야한다.
👉 Kubernetes에서의
Cluster IP
ClusterIP 는 두 가지를 의미 할 수 있다. Kubernetes 클러스터 내에서만 액세스 할 수있는 Service 타입 또는 Kubernetes 클러스터 내 구성 요소의 내부(가상) IP다.
https://stackoverflow.com/questions/33407638/what-is-the-cluster-ip-in-kubernetes
고정 포트(NodePort)로 각 노드의 IP에 서비스를 노출시킨다. NodePort
서비스가 라우팅되는 ClusterIP
서비스를 자동으로 생성한다. NodeIP:NodePort
를 요청하여, 클러스터 외부에서 NodePort
서비스에 접속할 수 있다.
이미지는 예시이다. 현재 실습에서는 Pod에 컨테이너가 여러대 떠 있진 않다.
ClusterIP
의 yaml
과 달라진 점은 .spec.type
과 .spec.ports[*].nodePort
부분이다.
.spec.ports[*].nodePort
는 노드의 고정 포트를 정해주는 부분인데 명세하지 않으면 자동으로 할당 된다.
apiVersion: v1
kind: Service
metadata:
name: test-front
spec:
type: NodePort
selector:
app: test-front
tier: front
ports:
- port: 80
nodePort: 30000
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.100.0.1 <none> 443/TCP 7d19h
test-api ClusterIP 10.100.35.21 <none> 8080/TCP 6d1h
test-front NodePort 10.100.75.136 <none> 80:30000/TCP 4s
Bastion 서버에서 curl [노드의 IP]:[nodePort]
을 실행해 주면 통신이 잘 이루어지는 것을 볼 수 있다.
(노드의 보안그룹 인바운드에 Bastion 서버에 대한 30000 포트를 오픈해 주어야한다.)
워커 노드가 Private 서브넷에 있기 때문에 현재는 Bastion 서버에서만 접근이 가능하지만 ALB를 추가하여 서비스가 가능하도록 뒤(Ingress 파트)에서 구성해보도록 하겠다.
클라우드 공급자의 로드 밸런서를 사용하여 서비스를 외부에 노출시킨다. 외부 로드 밸런서가 라우팅되는 NodePort
와 ClusterIP
서비스가 자동으로 생성된다.
AWS에서는 Classic LoadBalancer
와 Network LoadBalancer
를 사용할 수 있다.
Classic LoadBalancer
는 사용이 권장되지 않기 때문에 Network LoadBalancer
를 기준으로 실습을 진행했다.
yaml
을 살펴보면 다음과 같다.
apiVersion: v1
kind: Service
metadata:
name: test-front
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
service.beta.kubernetes.io/aws-load-balancer-subnets: subnet-0d8d50653b7935fee,subnet-088cab1b1e8d2966c
spec:
type: LoadBalancer
selector:
app: test-front
tier: front
ports:
- port: 80
.metadata.annotations
에 AWS 로드밸런서
타입을 정해줄 수 있다. 타입을 지정하지 않으면 기본으로 clb
가 선택된다. 그리고 로드밸런서가 만들어질 subnet
을 지정해준다.
.spec.type
은 LoadBalancer
이고 .spec.ports[*].nodePort
로 노드 포트를 정해줄 수 있지만 여기서는 지정하지 않았다.
yaml
을 apply
해준다.
$ kubectl apply -f front-lb-k8s.yml
deployment.apps/test-front created
service/test-front created
성공적으로 서비스가 만들어지면 Service
에 EXTERNAL-IP
가 붙고 이는 NLB
의 DNS
이다.
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.100.0.1 <none> 443/TCP 7d21h
test-api ClusterIP 10.100.35.21 <none> 8080/TCP 6d4h
test-front LoadBalancer 10.100.227.160 a1782fddd39664564b99704ed3844e6c-aa159285faf1acd0.elb.ap-northeast-1.amazonaws.com 80:31357/TCP 106s
AWS 콘솔
에서도 실제로 NLB
가 생성된 것을 확인할 수 있다.
NLB
의 상태가 active
로 바뀌면 브라우저에서 NLB
의 DNS
로 접근할 수 있다.
클러스터 내의 서비스에 대한 외부 접근
을 관리하는 API 오브젝트
이며, 일반적으로 HTTP
를 관리한다.
다른 유형의 컨트롤러와는 달리 Ingress 컨트롤러
는 클러스터와 함께 자동으로 시작되지 않는다. AWS Load Balancer Controller
는 Kubernetes 클러스터 용 Elastic Load Balancer
를 관리하는 컨트롤러이다. 이 컨트롤러를 클러스터에 직접 설치해주어야 한다.
AWS Load Balancer Controller 설치는 AWS 문서에 있는 과정을 따라 했다. 이미 AWS Load Balancer Controller가 있다면 이 부분은 건너뛰어도 된다.
먼저 AWS Load Balancer Controller
에 대하여 API를 호출할 수 있도록 해주는 AWS 정책을 생성해보도록 하겠다.
iam_policy.json의 내용으로 정책을 생성해준다.
(정책을 제대로 넣었는데 UnauthorizedOperation
에러가 난다면 AWS 공식문서의 최신 정책을 찾아서 넣어준다. - 며칠 사이 정책이 바껴서 몇시간 날렸다ㅠㅠ)
정책의 이름은 L23724-AWSLoadBalancerControllerIAMPolicy
라고 정해줬다.
방금 만든 정책을 사용할 수 있도록 역할
을 만들어 주겠다.
역할 만들기
로 들어가서 웹 ID
를 선택해주고 이전 글에서 만든 자격 증명 공급자
를 선택해 준다.
좀 전에 만든 정책 L23724-AWSLoadBalancerControllerIAMPolicy
를 연결해준다.
역할 이름을 정해주고 역할 만들기
를 완료한다.
만들어진 역할에 대해 신뢰 관계 편집
을 해주어야 한다.
신뢰 관계 편집
에 들어가면 아래와 비슷한 내용일 것이다.
블록 부분을 아래와 같이 바꿔주고 업데이트 해준다.
aud": "sts.amazonaws.com"
→ sub": "system:serviceaccount:kube-system:aws-load-balancer-controller"
IAM 역할
설정은 모두 마쳤다.
이제 이 IAM 역할을 사용하는 ServiceAccount
를 만들어주자.
아래와 같이 ServiceAccount
yaml
을 작성해준다.
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/name: aws-load-balancer-controller
name: aws-load-balancer-controller
namespace: kube-system
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::900184409169:role/L23724-eks-loadbalancer-controller-role-tokyo
ServiceAccount
생성한다.
$ kubectl apply -f aws-load-balancer-controller-service-account.yaml
serviceaccount/aws-load-balancer-controller created
아래 명령어를 통해 TargetGroupBinding
사용자 지정 리소스 정의를 설치한다.
$ kubectl apply -k "github.com/aws/eks-charts/stable/aws-load-balancer-controller//crds?ref=master"
eks-charts
리포지토리를 추가한다.
$ helm repo add eks https://aws.github.io/eks-charts
WARNING: Kubernetes configuration file is group-readable. This is insecure. Location: /home/aylee/.kube/config
WARNING: Kubernetes configuration file is world-readable. This is insecure. Location: /home/aylee/.kube/config
"eks" has been added to your repositories
AWS Load Balancer Controller
설치를 완료해 준다.
$ helm upgrade -i aws-load-balancer-controller eks/aws-load-balancer-controller \
--set clusterName=L23724-cluster-tokyo \
--set serviceAccount.create=false \
--set serviceAccount.name=aws-load-balancer-controller \
-n kube-system
WARNING: Kubernetes configuration file is group-readable. This is insecure. Location: /home/aylee/.kube/config
WARNING: Kubernetes configuration file is world-readable. This is insecure. Location: /home/aylee/.kube/config
Release "aws-load-balancer-controller" does not exist. Installing it now.
NAME: aws-load-balancer-controller
LAST DEPLOYED: Fri Apr 23 08:18:25 2021
NAMESPACE: kube-system
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
AWS Load Balancer controller installed!
aws-load-balancer-controller
를 조회해 보면 아래와 같이 잘 배포된 것을 볼 수 있다.
$ kubectl get deployment -n kube-system aws-load-balancer-controller
NAME READY UP-TO-DATE AVAILABLE AGE
aws-load-balancer-controller 1/1 1 1 24m
드디어 AWS ALB
를 사용하여 애플리케이션과 통신해보도록 하겠다.
아키텍처는 AWS Blog에 잘 나와있다.
먼저 Service
를 NodePort
타입으로 생성해준다.
앞에서 실습했던 NodePort
와 같은 yaml
이다.
apiVersion: v1
kind: Service
metadata:
name: test-front
spec:
type: NodePort
selector:
app: test-front
tier: front
ports:
- port: 80
nodePort: 30000
Ingres
의 yaml
은 아래와 같이 작성해 준다.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-alb
labels:
app.kubernetes.io/name: external-ingress
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/subnets: subnet-0d8d50653b7935fee,subnet-088cab1b1e8d2966c
alb.ingress.kubernetes.io/target-type: instance
spec:
rules:
- http:
paths:
- path: /*
backend:
serviceName: test-front
servicePort: 80
.metadata.annotations
에 필요한 값들을 넣어주고 .spec.rules[*].http.paths[*].backend.serviceName
에는 우리가 배포한 NodePort 타입
의 Service
이름을 넣어준다.
Ingress
를 배포하고 조회해 보면 다음과 같이 ADDRESS(ALB DNS)
가 붙은 것을 볼 수 있고 AWS 콘솔
에 들어가 보면 ALB
가 생성된 것을 볼 수 있다.
$ kubectl get ing
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress-alb <none> * k8s-default-ingressa-21e1e3916d-171521608.ap-northeast-1.elb.amazonaws.com 80 5s
ALB의 규칙에 들어가서 보면 우리가 설정한 path(/*)
가 임의의 이름의 대상그룹
으로 전달된다.
해당 대상그룹
으로 가보면 nodePort
로 설정한 포트로 워커노드가 자동으로 등록되어 있다.
브라우저에서 ADDRESS(ALB DNS)
로 접속해 보면 잘 실행되는 것을 볼 수 있다.
참고
- https://www.ovh.com/blog/getting-external-traffic-into-kubernetes-clusterip-nodeport-loadbalancer-and-ingress/
- https://blog.leocat.kr/notes/2019/08/22/translation-kubernetes-nodeport-vs-loadbalancer-vs-ingress
- https://kubernetes.io/ko/docs/concepts/services-networking/ingress/
- https://kubernetes.io/ko/docs/concepts/services-networking/service/
이제까지 읽은 글들이 정말로 정리가 잘되어있고, 이해하기 좋았습니다.
좋은글 작성해주셔서 감사합니다. :)