서론
이전 포스팅들을 통해 cluster 내부에 deployment로 생성된 pod들로 트래픽을 보내야 합니다. 우리는 파드로의 접근을 이전 포스팅에서 서비스라는 쿠버네티스 오브젝트를 사용하여 이미 완성시켜 놨습니다.
[이전글]
본론
1. Service
1-1. 기존 service.yaml 설명
아래는 이전 NextJs 프로젝트를 배포할때 사용했던 service.yaml 파일입니다.
apiVersion: v1
kind: Service
metadata:
name: mingyu-cms-service
namespace: test
spec:
type: NodePort
selector:
app: mingyu-cms-deployment
ports:
- name: http
port: 80
protocol: TCP
targetPort: 3000
해당 내용을 확인해보면, mingyu-cms-service라는 이름의 Service 리소스를 test 네임스페이스에 생성하는데, type을 NodePort로 지정하여 클러스터 외부에서 노드 IP와 할당된 포트를 통해 접근할 수 있도록 하고, mingyu-cms-deployment 라벨을 가지는 파드들로 트래픽을 라우팅 합니다.
즉, 이 Service는 클러스터 내의 mingyu-cms-deployment 라벨이 붙은 파드들에 대해 외부에서 접근할 수 있도록, 노드의 지정된 포트를 통해 HTTP 요청(80번 포트)을 받아 내부 파드의 3000번 포트로 전달하는 역할을 수행합니다.
실제로 생성된 서비스들을 직접 확인해 볼 수 있습니다.
$ kubectl get svc -n namespace
1-2. NordPort 타입의 서비스 사용 이유
모든 서비스를 NodePort로 지정한 이유는 Ingress를 사용하는 구성은 주로 외부 트래픽을 안정적으로 클러스터 내부의 서비스로 전달하기 위한 전략으로 Ingress는 NodePort, LoadBalncer 유형의 의 서비스만 사용할 수 있기 때문입니다. 저는 평범한 Ingress가 아닌 AWS의 ALB Ingress를 사용해서 구성했고, 이 alb ingress는 자동으로 Application Load Balancer가 프로비저닝 되기 때문에 NodePort 타입으로 지정하면 되기 때문입니다. ( 아니 근데, 왜 네이버에서 aws 서비스를,,,라고 하기엔 objectstorage도 s3 api를 활용하고,, ncp 너네 혹시..? ㅎ)
2. Ingress & Ingress Controller
2-1. Ingress
그래서 인그레스가 도대체 뭐 하는 친구일인가 하면, 클러스터 외부에서 클러스터 내부 Service로 HTTP와 HTTPS 경로를 노출하는 친구입니다. 트래픽 라우팅의 경우 인그레스 리소스를 생성할 때 정의할 수 있습니다. 아래는 인그레스가 트래픽을 하나의 서비스로 보내는 예시입니다.
그렇지만 이 인그레스가 동작하기 위해서는 전제조건이 있는데, 그것은 바로 인그레스 컨트롤러가 있어야만 한다는 것입니다.
2-2. Ingress Controller
클러스터 내의 인그레스가 동작하려면 인그레스 컨트롤러가 실행되고 있어야 합니다. 최소 하나의 인그레스 컨트롤러를 선택하여 클러스터 내에 설치하는데, 쿠버네티스는 aws, gce, nginx 인그레스 컨트롤러를 지원하고 유지해 줍니다. 저는 여기서 aws의 alb를 사용할 것입니다. 더 자세한 내용은 쿠버네티스 공식 문서를 확인하면 쉽게 확인할 수 있습니다.
인그레스 컨트롤러
클러스터 내의 [인그레스](/ko/docs/concepts/services-networking/ingress/)가 작동하려면, 인그레스 컨트롤러가 실행되고 있어야 한다. 적어도 하나의 인그레스 컨트롤러를 선택하고 이를 클러스터 내에 설
kubernetes.io
3. ingress.yaml 파일 작성 및 ingress 생성
아래와 같이 ingressClassName을 alb로 지정하여 alb ingress anotations를 활용할 수 있습니다. 저는 80,443 포트를 열고있는 test-ingress를 무조건 https로 redirect시키고 /health uri로 healthcheck를 하는 인그레스를 생성하려 합니다.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-ingress
namespace: test
annotations:
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS": 443}]'
alb.ingress.kubernetes.io/ssl-certificate-no: "인증서번호"
alb.ingress.kubernetes.io/description: "test-ingress controller"
alb.ingress.kubernetes.io/ssl-redirect: "443"
alb.ingress.kubernetes.io/healthcheck-path: "/health"
alb.ingress.kubernetes.io/healthcheck-interval-seconds: "120"
spec:
ingressClassName: alb
rules:
- host: dev-www.test.co.kr
http:
paths:
- path: /*
pathType: Prefix
backend:
service:
name: test-service
port:
number: 80
- host: dev-m.test.co.kr
http:
paths:
- path: /*
pathType: Prefix
backend:
service:
name: test-service
port:
number: 80
- host: dev-api.test.co.kr
http:
paths:
- path: /*
pathType: Prefix
backend:
service:
name: test-api-service
port:
number: 80
- host: dev-cms.test.co.kr
http:
paths:
- path: /*
pathType: Prefix
backend:
service:
name: test-cms-service
port:
number: 80
- host: dev-cms2.test.co.kr
http:
paths:
- path: /*
pathType: Prefix
backend:
service:
name: test-cms2-service
port:
number: 80
- host: dev-cms2-api.test.co.kr
http:
paths:
- path: /*
pathType: Prefix
backend:
service:
name: cms2-api-service
port:
number: 80
이제 kubectl 명령어를 사용하여 해당 ingress를 apply해줍니다.
$ kubectl apply -f ingress.yaml
그리고 kubernetes 대시보드의 서비스 > 인그레스 탭에 접속하면 인그레스가 아래와 같이 정상적으로 잘 생성된것을 확인할 수 있습니다.
4. LB 생성 확인 및 DNS 설정 (NCP)
Naver Cloud Platform의 Load Balncer 메뉴에 들어가보면 ingress.yaml로 생성한 로드벨런서가 정상적으로 잘 생성된것들을 확인할 수 있습니다.
이제 Global DNS 메뉴로 접속하여 도메인에 맞는 호스트(2차도메인)을 설정해주고, 레코드 타입을 A (LB VPC)로 설정하여 생성된 LoadBalancer를 설정해주면 모든 준비는 끝납니다.
아맞다!
개발 환경은 사내망(내부 네트워크)에서만 접근 가능하도록 구성해야 합니다. 이를 위해 dev 클러스터를 생성할 때, 해당 클러스터가 위치한 서브넷에 적용된 Network ACL에서 inbound 및 outbound 규칙을 사내 IP(내부망 IP)만 허용하고 나머지 트래픽은 모두 차단하도록 설정하여, 외부 접근을 원천 봉쇄할 수 있었습니다.
물론 보안그룹(Security Group) 단위로도 접근 제어를 할 수 있지만, 보안그룹은 인스턴스(또는 파드) 단위에서 상태 기반(stateful)으로 작동하는 반면, Network ACL은 서브넷 단위에서 stateless하게 작동하여 네트워크 레벨에서 최초부터 접근을 차단할 수 있다는 점에서 보다 근본적인 봉쇄 효과를 기대할 수 있습니다.
따라서, 만약 서버 단에서 추가적인 제어를 원한다면 보안그룹으로도 설정할 수 있지만, 네트워크 자체에서 접근을 아예 막으려면 Network ACL로 원천 봉쇄하는 것이 효과적입니다.
결론
일반 api나 front application은 이 정도로 개발환경 구성을 끝마칠 수 있었습니다. 다만 문자나 알림톡, 이메일 전송기능을 담당하는 전송 관련 어플리케이션이나 배치 어플리케이션의 경우 좀 다른 방법으로 개발환경을 구성하였었는데, 그 내용은 추후 포스팅 하도록 하겠습니다.