제품을 판매하는 온라인 매장이 있는 회사를 위해 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는 사용자가 URL 경로를 기반으로 클러스터 내의 다른 서비스로 라우팅하도록 구성할 수 있는 외부에서 액세스 가능한 단일 URL을 사용하여 애플리케이션에 액세스할 수 있도록 도와줍니다. 동시에 SSL 보안도 구현할 수 있습니다. 간단히 말해 Ingress를 Kubernetes의 다른 오브젝트와 마찬가지로 builtin Kubernetes 프리미티브를 사용하여 구성할 수 있는 Kubernetes 클러스터에 builtin된 레이어 7 로드 밸런서라고 생각하면 됩니다.
이제 Ingress를 사용하더라도 클러스터 외부에서 액세스할 수 있도록 expose해야 합니다. 따라서 여전히 노드 포트로 게시하거나 클라우드 네이티브 로드 밸런서를 사용하여 publish해야 하지만 이는 일회성 configration일 뿐입니다. 앞으로 Ingress 컨트롤러에서 모든 로드 밸런싱 authentication, SSL, URL 기반 라우팅 configuration을 수행하게 됩니다.
이는 어떻게 작동할까요? 무엇이며, 어디에 있으며, 어떻게 볼 수 있을까요? 어떻게 구성할 수 있을까요? 로드밸런싱은 어떻게 할까요? SSL을 어떻게 구현할까요? Ingress가 없다면 어떻게 이 모든 것을 할 수 있을까요? 역방향 프록시나 NGINX, HAProxy 또는 Traefik과 같은 로드 밸런싱 솔루션을 사용합니다. 이것들을 Kubernetes 클러스터에 배포하고 트래픽을 다른 서비스로 라우팅하도록 구성합니다. configuration에는 URL route 정의, SSL 인증서 configuration 등이 포함됩니다.
Ingress는 Kubernetes에서 같은 방식으로 구현됩니다. 먼저 여기에 나열된 솔루션 중 하나인 지원 솔루션을 배포한 다음 rule 집합을 지정하여 Ingress를 configuration합니다. 배포하는 솔루션을 Ingress 컨트롤러라고 하고 구성하는 rule 집합을 Ingress 리소스라고 합니다. ingress 리소스는 이 과정의 앞부분에서 파드, deployment 및 서비스를 생성하는 데 사용하는 것과 같은 definition 파일을 사용하여 생성됩니다.
이제 Kubernetes 클러스터는 default로 Ingress 컨트롤러와 함께 제공되지 않는다는 점을 기억하세요. 이 과정의 데모에 따라 클러스터를 설정하면 Ingress 컨트롤러가 builtin되어 있지 않습니다. 따라서 단순히 Ingress 리소스를 생성하고 작동할 것으로 기대한다면 작동하지 않을 것입니다.
각각에 대해 좀 더 자세히 살펴보겠습니다. 앞서 언급했듯이 Kubernetes에는 default로 Ingress 컨트롤러가 없으므로 하나를 배포해야 합니다. 무엇을 배포합니까?
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, session timeouts 등과 같은 일련의 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 컨트롤러가 이를 수행하려면 올바른 권한 집합이 있는 서비스 계정이 필요합니다. 이를 위해 올바른 롤과 롤 바인딩으로 서비스 계정을 만듭니다.
요약하면 NGINX ingress 이미지 배포, 이를 expose하는 서비스, NGINX configuration 데이터를 제공하는 config map, 이러한 모든 오브젝트에 액세스할 수 있는 올바른 롤이 있는 서비스 계정을 배포하면 ingress 컨트롤러가 가장 간단한 형태로 준비된 것입니다.
이제 Ingress 리소스 생성의 다음 부분으로 넘어갑니다. ingress 리소스는 ingress 컨트롤러에 적용되는 rule 및 configuration 집합입니다. 들어오는 모든 트래픽을 단일 애플리케이션으로 전달하거나 URL을 기반으로 트래픽을 다른 애플리케이션으로 라우팅하도록 rule을 configuration할 수 있습니다. 따라서 사용자가 myonlinestore.com/wear로 이동하면 애플리케이션 중 하나로 라우팅하거나 사용자가 watch URL을 방문하면 비디오 앱으로 라우팅하는 등의 작업을 수행합니다. 또는 도메인 이름 자체를 기반으로 사용자를 라우팅할 수 있습니다. 예를 들어 사용자가 wear.myonlinestore.com을 방문하면 사용자를 wear 애플리케이션으로 라우팅하거나 비디오 앱으로 라우팅합니다.
이를 좀 더 자세히 configuration하는 방법을 살펴보겠습니다. Ingress 리소스는 Kubernetes definition 파일(이 경우 Ingress-where.yaml)로 생성됩니다. 다른 오브젝트와 마찬가지로 APIversion, kind, metadata 및 spec이 있습니다. API 버전은 extensions/v1beta1이고 kind는 Ingress이며 이름은 Ingress-wear로 지정하고 spec에는 backend가 있습니다. 따라서 트래픽은 물론 파드가 아닌 애플리케이션 서비스로 직접 라우팅됩니다. 이미 알고 계시겠지만 backend 섹션은 트래픽이 라우팅되는 위치를 정의합니다. 따라서 단일 backend인 경우 실제로 rule이 없습니다. backend wear service의 서비스 이름과 포트만 지정하면 됩니다.
kubectl create 커맨드를 실행하여 Ingress 리소스를 생성합니다. kubectl get Ingress 커맨드를 실행하여 생성된 Ingress 리소스를 확인합니다.
이제 새 Ingress가 생성되고 모든 수신 트래픽을 Wear 서비스로 직접 라우팅합니다. 다른 조건에 따라 트래픽을 라우팅하려는 경우 rule을 사용합니다. 예를 들어 각 도메인 또는 호스트 이름에서 발생하는 트래픽에 대해 하나의 rule을 생성합니다. 즉, 사용자가 도메인 이름 myonlinestore.com을 사용하여 클러스터에 도달하면 rule 1을 사용하여 해당 트래픽을 처리할 수 있습니다. 사용자가 도메인 이름 wear.myonlinestore.com을 사용하여 클러스터에 도달하면 별도의 rule인 rule 2를 사용하여 해당 트래픽을 처리할 수 있습니다. rule 3을 사용하여 watch.myonline store.com의 트래픽을 처리하고 네 번째 rule을 사용하여 다른 모든 것을 처리합니다. 이제 각 rule 내에서 다른 경로를 처리할 수 있습니다. 예를 들어, rule 1 내에서 해당 트래픽을 cloth 애플리케이션으로 라우팅하는 wear 경로와 비디오 스트리밍 애플리케이션으로 트래픽을 라우팅하는 watch rout, 및 처음 두 개를 제외한 모든 경로를 404 not found로 라우팅하는 세 번째 경로를 처리할 수 있습니다. 마찬가지로 두 번째 rule은 wear.myonlinestore.com의 모든 트래픽을 처리합니다. 이 rule 내에서 경로 정의를 사용하여 다른 경로를 기반으로 트래픽을 라우팅할 수 있습니다. 예를 들어 쇼핑, 반품 또는 지원을 위해 의류 섹션 내에 다양한 애플리케이션과 서비스가 있다고 가정합니다. 사용자가 wear.myonlinestore.com으로 이동하면 default로 쇼핑 페이지에 도달하지만 교환 또는 지원 URL로 이동하면 다른 백엔드 서비스에 도달합니다. watch.myonlinestore.com에 대한 트래픽을 비디오 스트리밍 애플리케이션으로 라우팅하지만 영화나 TV와 같은 추가 경로를 포함할 수 있는 rule 3도 마찬가지입니다. 그리고 마지막으로 여기에 나열된 것 이외의 모든 것은 네 번째 rule으로 이동합니다. 그것은 단순히 404 찾을 수 없음 오류 페이지를 표시합니다. 따라서 각 호스트 또는 도메인 이름에 대한 rule이 맨 위에 있고 각 rule 내에는 URL을 기반으로 트래픽을 라우팅하는 서로 다른 파드이 있음을 기억하세요.
이제 Kubernetes에서 Ingress 리소스를 구성하는 방법을 살펴보겠습니다. 중단한 부분부터 시작하겠습니다. 유사한 definition 파일로 시작합니다. 이번에는 spec 아래에 일련의 rule이 있습니다.
이제 여기에서 우리의 요구 사항은 myonlinestore.com으로 들어오는 모든 트래픽을 처리하고 URL 경로를 기반으로 라우팅하는 것입니다. 그래서 우리는 myonlinestore.com이라는 단일 도메인 이름에 대한 트래픽만 처리하기 때문에 이에 대한 단일 rule만 필요합니다. rule 아래에는 다른 파드를 지정하는 HTTP rule인 하나의 항목이 있습니다. 따라서 파드는 각 URL에 대한 하나의 path인 여러 항목의 배열입니다. 그런 다음 첫 번째 path 아래의 첫 번째 예에서 사용한 백엔드를 제거합니다(?). 백엔드 spec은 동일하게 유지됩니다. 서비스 이름과 서비스 포트가 있습니다. 마찬가지로 watch 서비스가 watch URL을 통해 들어오는 모든 트래픽을 watch 서비스로 라우팅하기 위해 두 번째 URL 파드에 유사한 백엔드 항목을 만듭니다.
kubectl 생성 커맨드를 사용하여 Ingress 리소스를 생성합니다. 일단 생성되면 kubectl describe Ingress 커맨드를 실행하여 Ingress 리소스에 대한 추가 세부 정보를 확인합니다. 이제 rule 아래에 두 개의 백엔드 URL과 백엔드 서비스가 표시되고 방금 생성되었다고 확인됩니다. 이제 이 커맨드의 출력을 자세히 살펴보면 default 백엔드에 대한 내용이 있음을 알 수 있습니다. 그게 뭘까요? 사용자가 이러한 rule과 일치하지 않는 URL에 액세스하려고 하면 사용자는 default 백엔드로 지정된 서비스로 이동됩니다. 이 경우에는 이름이 default-http-backend인 서비스입니다. 따라서 이러한 서비스를 배포하는 것을 기억해야 합니다.
애플리케이션으로 돌아가서 사용자가 URL myonlinestore.com/listen 또는 eat을 방문하고 오디오 스트리밍이나 음식 배달 서비스가 없다고 가정하면 멋진 메시지를 보여주고 싶을 수 있습니다. 이 404 찾을 수 없음 오류 페이지를 표시하도록 default 백엔드 서비스를 구성하면 됩니다.
세 번째 configuration 유형은 도메인 이름 또는 호스트 이름을 사용하는 것입니다. Ingress에 대한 유사한 definition 파일을 생성하여 시작합니다.
이제 두 개의 도메인 이름이 있으므로 각 도메인에 대해 하나씩 두 개의 rule을 만듭니다. 도메인 이름별로 트래픽을 분할하기 위해 호스트 필드를 사용합니다. 각 rule의 호스트 필드는 지정된 값을 요청 URL에 사용된 도메인 이름과 일치시키고 트래픽을 적절한 백엔드로 라우팅합니다. 이제 이전 사례에서 호스트 필드를 지정하지 않았음을 기억하세요. 호스트 필드를 지정하지 않으면 단순히 별표로 간주하거나 호스트 이름과 일치하지 않고 특정 rule을 통해 들어오는 모든 트래픽을 수락합니다. 이 경우 각 rule에 대해 백엔드 경로가 하나만 있으므로 괜찮습니다. 이러한 도메인 이름의 모든 트래픽은 URL path에 관계없이 적절한 백엔드로 라우팅됩니다. 이전 예제에서 본 것처럼 서로 다른 URL 경로를 처리하기 위해 이들 각각에 여러 path spec을 가질 수 있습니다.
그럼 둘을 비교해봅시다.
URL별로 트래픽을 분할하는 데는 rule이 하나뿐이었고 트래픽을 두 개의 파드으로 분할했습니다. 호스트 이름별로 트래픽을 분할하는 데는 각 rule에서 두 개의 rule과 하나의 파드 spec을 사용했습니다.
테스트 문제 기록
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-ingress
namespace: critical-space
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
rules:
- http:
paths:
- path: /pay
pathType: Prefix
backend:
service:
name: pay-service
port:
number: 8282
k create ns ingress-nginx
kubectl create configmap ingress-nginx-controller --namespace ingress-nginx
kubectl create serviceaccount ingress-nginx --namespace ingress-nginx
kubectl create serviceaccount ingress-nginx-admission --namespace ingress-nginx
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-wear-watch
namespace: app-space
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
rules:
- http:
paths:
- path: /wear
pathType: Prefix
backend:
service:
name: wear-service
port:
number: 8080
- path: /watch
pathType: Prefix
backend:
service:
name: video-service
port:
number: 8080
테스트 통과 완료