본문 바로가기

Computer Science/Kubernetes(CKA) 자격증 준비

Kubernetes 정리 226: Ingress

제품을 판매하는 온라인 매장이 있는 회사를 위해 Kubernetes에 애플리케이션을 배포하고 있습니다. 애플리케이션은 예를 들어 myonlinestore.com에서 사용할 수 있습니다. 애플리케이션을 Docker 이미지로 빌드하고 Kubernetes 클러스터에 Deployment의 Pod로 배포합니다. 애플리케이션에는 데이터베이스가 필요하므로 MySQL 데이터베이스를 파드로 배포하고 mysql-service이라는 클러스터 IP 유형의 서비스를 생성하여 애플리케이션에 액세스할 수 있도록 합니다. 이제 애플리케이션이 작동합니다.
외부 세계에서 애플리케이션에 액세스할 수 있도록 하려면 이번에는 노드 포트 유형인 또 다른 서비스를 만들고 클러스터의 노드에 있는 high 포트에서 애플리케이션을 사용할 수 있도록 합니다. 이 예에서는 포트 38080이 서비스에 할당됩니다. 이제 사용자는 포트 38080 다음에 오는 노드의 URL HTTP://IP를 사용하여 애플리케이션에 액세스할 수 있습니다. 해당 설정이 작동하고 사용자가 애플리케이션에 액세스할 수 있습니다. 트래픽이 증가할 때마다 추가 트래픽을 처리하기 위해 파드의 replicas 수를 늘리고 파드 간에 트래픽을 분할하는 서비스를 처리합니다.
그러나 이전에 프로덕션 애플리케이션을 배포한 적이 있다면 단순히 파드 간에 트래픽을 분할하는 것 외에도 더 많은 작업이 관련되어 있음을 알고 있습니다. 예를 들어 우리는 사용자가 매번 IP 주소를 입력해야 하는 것을 원하지 않습니다. 따라서 노드의 IP를 가리키도록 DNS 서버를 구성합니다. 이제 사용자는 URL myonlinestore.com 및 포트 38080을 사용하여 애플리케이션에 액세스할 수 있습니다.

이제 사용자가 포트 번호도 기억하지 않아도 되기를 바랍니다. 그러나 서비스 노드 포트는 30,000보다 큰 높은 번호의 포트만 할당할 수 있습니다. 따라서 DNS 서버와 클러스터 사이에 프록시 서버와 같은 추가 계층을 가져옵니다. 포트 80의 요청을 노드의 포트 38080으로 프록시합니다. 그런 다음 DNS를 이 서버로 지정하면 사용자는 이제 myonlinestore.com을 방문하기만 하면 애플리케이션에 액세스할 수 있습니다.

이제 애플리케이션이 데이터 센터에서 온프레미스로 호스팅되는 경우입니다. 한 걸음 물러서서 Google Cloud 플랫폼과 같은 퍼블릭 클라우드 환경에 있다면 무엇을 할 수 있는지 살펴보겠습니다. 이 경우 wear 애플리케이션에 대해 노드 포트 유형의 서비스를 생성하는 대신, 로드 밸런서 유형으로 설정할 수 있습니다. 이렇게 하면 Kubernetes는 서비스에 대해 high 포트를 프로비저닝하는 노드 포트에 대해 수행해야 하는 모든 작업을 계속 수행합니다. 그러나 그 외에도 Kubernetes는 이 서비스에 대한 네트워크 로드 밸런서를 프로비저닝하기 위해 Google Cloud 플랫폼에 요청을 보냅니다. 요청을 받으면 GCP는 트래픽을 모든 노드의 서비스 포트로 라우팅하도록 구성된 로드 밸런서를 자동으로 배포하고, 해당 정보를 Kubernetes에 반환합니다. 로드 밸런서에는 애플리케이션에 액세스하기 위해 사용자에게 제공할 수 있는 외부 IP가 있습니다. 이 경우에는 DNS가 이 IP를 가리키도록 설정하고 사용자는 URL myonlinestore.com을 사용하여 애플리케이션에 액세스합니다.

회사의 비즈니스가 성장하고 이제 고객을 위한 새로운 서비스를 갖게 되었습니다. 예를 들어 비디오 스트리밍 서비스의 경우 사용자가 myonlinestore.com/watch로 이동하여 새 비디오 스트리밍 서비스에 액세스할 수 있기를 원합니다. myonlinestore.com/wear에서 이전 애플리케이션에 액세스할 수 있도록 하고 싶습니다.

귀하의 개발자는 기존의 것과 관련이 없기 때문에 완전히 다른 애플리케이션으로 새로운 비디오 스트리밍 애플리케이션을 개발했습니다. 그러나 동일한 클러스터 리소스를 공유하려면 동일한 클러스터 내에서 별도의 deployment로 새 애플리케이션을 배포합니다. 로드 밸런서 유형의 video-service라는 서비스를 생성합니다. Kubernetes는 이 서비스에 대해 포트 38282를 프로비저닝하고 클라우드에 네트워크 로드밸런서도 프로비저닝합니다.

새 로드 밸런서에는 새 IP가 있습니다. 이러한 로드 밸런서 각각에 대해 비용을 지불해야 하며 이러한 로드 밸런서가 많으면 클라우드 청구서에 역으로 영향을 미칠 수 있습니다. 그렇다면 사용자가 입력하는 URL을 기반으로 각 로드 밸런서 간에 어떻게 트래픽을 전달할까요? URL을 기반으로 트래픽을 다른 서비스로 리디렉션할 수 있는 또 다른 프록시 또는 로드 밸런서가 필요합니다. 새로운 서비스를 도입할 때마다 로드 밸런서를 재구성해야 합니다.

마지막으로 사용자가 HTTPS를 사용하여 애플리케이션에 액세스할 수 있도록 애플리케이션에 SSL을 활성화해야 합니다. 어디서 구성할까요? 이것은 애플리케이션 자체 레벨, 로드 밸런서 또는 프록시 서버 레벨 등 다양한 레벨에서 수행할 수 있습니다.

당신은 당신의 개발자들이 다른 방식으로 그것을 할 것이기 때문에 그들의 애플리케이션에서 그것을 구현하는 것을 원하지 않습니다. 최소한의 유지 관리로 한 곳에서 구성하기를 원합니다. 이제는 다양한 configuration이 있으며 애플리케이션이 확장되면 이러한 모든 configuration을 관리하기가 어려워집니다. 서로 다른 팀에 서로 다른 개인을 참여시켜야 합니다. 각각의 새 서비스에 대해 방화벽 rule을 구성해야 하며 비용이 많이 들 뿐만 아니라 각 서비스에 대해 새 클라우드 native 로드 밸런서를 프로비저닝해야 합니다. Kubernetes 클러스터 내에서 모든 것을 관리하고 나머지 애플리케이션 deployment 파일과 함께 존재하는 또 다른 Kubernetes definition 파일로 모든 configuration을 가질 수 있다면 좋지 않을까요?

 

Ingress

이것이 Ingress가 필요한 이유입니다. Ingress는 사용자가 URL 경로를 기반으로 클러스터 내의 다른 서비스로 라우팅하도록 구성할 수 있는 외부에서 액세스 가능한 단일 URL을 사용하여 애플리케이션에 액세스할 수 있도록 도와줍니다. 동시에 SSL 보안도 구현할 수 있습니다. 간단히 말해 Ingress를 Kubernetes의 다른 오브젝트와 마찬가지로 builtin Kubernetes 프리미티브를 사용하여 구성할 수 있는 Kubernetes 클러스터에 builtin된 레이어 7 로드 밸런서라고 생각하면 됩니다.

이제 Ingress를 사용하더라도 클러스터 외부에서 액세스할 수 있도록 expose해야 합니다. 따라서 여전히 노드 포트로 게시하거나 클라우드 네이티브 로드 밸런서를 사용하여 publish해야 하지만 이는 일회성 configration일 뿐입니다. 앞으로 Ingress 컨트롤러에서 모든 로드 밸런싱 authentication, SSL, URL 기반 라우팅 configuration을 수행하게 됩니다.

Ingress는 Kubernetes에서 같은 방식으로 구현됩니다. 먼저 여기에 나열된 솔루션 중 하나인 지원 솔루션을 배포한 다음 rule 집합을 지정하여 Ingress를 configuration합니다. 배포하는 솔루션을 Ingress 컨트롤러라고 하고 구성하는 rule 집합을 Ingress 리소스라고 합니다. ingress 리소스는 이 과정의 앞부분에서 파드, deployment 및 서비스를 생성하는 데 사용하는 것과 같은 definition 파일을 사용하여 생성됩니다.

이제 Kubernetes 클러스터는 default로 Ingress 컨트롤러와 함께 제공되지 않는다는 점을 기억하세요. 이 과정의 데모에 따라 클러스터를 설정하면 Ingress 컨트롤러가 builtin되어 있지 않습니다. 따라서 단순히 Ingress 리소스를 생성하고 작동할 것으로 기대한다면 작동하지 않을 것입니다.

 

Ingress Controller

Ingress에 사용할 수 있는 솔루션은 여러 가지가 있으며 그 중 일부는 HTTP 로드 밸런서인 Google의 레이어 7인 GCE, NGINX, Contour, HAProxy, Traefik, Astel입니다. 이 중 GCE와 NGINX는 현재 쿠버네티스 프로젝트에서 지원 및 유지 관리하고 있는데, 이번 강의에서는 NGINX를 예로 들어 설명하겠습니다. 이러한 interests 컨트롤러는 단순한 로드 밸런서나 NGINX 서버가 아닙니다. 로드 밸런서 컴포넌트는 그 일부일 뿐입니다. ingress 컨트롤러에는 새로운 definition 또는 ingress 리소스에 대해 Kubernetes 클러스터를 모니터링하고 그에 따라 NGINX 서버를 구성하기 위한 추가 인텔리전스가 builtin되어 있습니다.

NGINX 컨트롤러는 Kubernetes에서 또 다른 배포로 배포됩니다. 따라서 하나의 replicas과 간단한 파드 definition 템플릿이 있는 NGINX Ingress 컨트롤러라는 deployment definition 파일로 시작합니다. NGINX Ingress라는 레이블을 지정하고 사용된 이미지는 올바른 버전의 NGINX Ingress 컨트롤러입니다. 이제 이것은 Kubernetes에서 ingress 컨트롤러로 사용하도록 특별히 제작된 NGINX의 특수 빌드이므로 고유한 요구 사항이 있습니다. 이미지 내에서 NGINX 프로그램은 NGINX ingress 컨트롤러 위치에 저장되므로 NGINX 컨트롤러 서비스를 시작하기 위한 커맨드로 전달해야 합니다. 이전에 NGINX로 작업한 적이 있다면 path to store the logs, keep alive threshold, SSL settings,등과 같은 일련의 configuration 옵션이 있다는 것을 알고 있을 것입니다.

NGINX 컨트롤러 이미지에서 이러한 configuration 데이터를 분리하려면 config map 오브젝트를 생성하고 이를 전달해야 합니다.  config map 오브젝트에는 이 시점에서 entry가 필요하지 않으며 빈 오브젝트가 있으면 되지만 하나를 생성해서 나중에 configuration 설정을 쉽게 수정할 수 있게 하겠습니다. 이 config map에 추가하기만 하면 NGINX configuration file 수정에 대해 걱정할 필요가 없습니다.

또한 파드 이름과 네임스페이스를 포함하는 두 개의 환경 변수를 전달해야 합니다. NGINX 서비스는 파드 내에서 configuration 데이터를 읽고 최종적으로 ingress 컨트롤러가 사용하는 포트(80 및 443)를 지정하기 위해 이들을 필요로 합니다.

그런 다음 ingress 컨트롤러를 외부 세계에 expose하는 서비스가 필요하므로 우리는 서비스를 deployment에 연결하기 위해 NGINX Ingress 레이블 selector로 노드 포트 유형의 서비스를 만듭니다. 앞에서 언급했듯이 Ingress 컨트롤러에는 Kubernetes 클러스터에서 Ingress 리소스를 모니터링하고 변경 사항이 있을 때 underlying NGINX 서버를 구성하기 위한 추가 인텔리전스가 builtin되어 있습니다. 그러나 ingress 컨트롤러가 이를 수행하려면 올바른 권한 집합이 있는 서비스 계정이 필요합니다. 이를 위해 올바른 롤과 롤 바인딩으로 서비스 계정을 만듭니다.