Cloud CDN

이 페이지에서는 BackendConfig 커스텀 리소스를 사용하여 Google Kubernetes Engine에 Cloud CDN을 구성하는 방법을 보여줍니다.

개요

GKE 클러스터에서 들어오는 트래픽은 Cloud Load Balancing의 구성요소인 HTTP(S) 부하 분산에 의해 처리됩니다. 일반적으로 HTTP(S) 부하 분산기는 Kubernetes Ingress 객체에서 구성 정보를 가져오는 [GKE Ingress controller]{:.external}에 의해 구성됩니다. Ingress는 하나 이상의 서비스 객체와 연결됩니다. 각 서비스는 들어오는 요청을 특정 포드 및 포트로 보내기 위해 사용되는 라우팅 정보를 포함합니다.

Kubernetes 버전 1.10.5-gke.3부터는 서비스 포트를 BackendConfig라는 커스텀 리소스와 연결하여 부하 분산기에 대해 추가 구성을 제공할 수 있습니다.

GKE Ingress 컨트롤러는 BackendConfig에서 구성 정보를 읽고 그에 따라 부하 분산기를 설정합니다. BackendConfig는 Cloud Load Balancing과 관련된 구성 정보를 포함합니다. Kubernetes 수신 및 서비스 리소스는 Cloud CDN과 같은 공급자별 기능을 구성할 수 있는 방법을 제공하지 않습니다. BackendConfig를 사용하여 이러한 구성을 수행할 수 있습니다.

이 연습에서 BackendConfig를 설정하는 방법은 크게 다음과 같습니다.

  1. BackendConfig를 만듭니다.
  2. 서비스를 만들고 포트 중 하나를 BackendConfig와 연결합니다.
  3. Ingress를 만들고 이를 (서비스, 포트) 쌍과 연결합니다.

시작하기 전에

이 작업을 준비하려면 다음 단계를 수행하세요.

  • Google Kubernetes Engine API가 사용 설정되었는지 확인합니다.
  • Google Kubernetes Engine API 사용 설정
  • Cloud SDK가 설치되었는지 확인합니다.
  • 기본 프로젝트 ID를 설정합니다.
    gcloud config set project [PROJECT_ID]
  • 영역 클러스터를 사용하는 경우 기본 컴퓨팅 영역을 설정합니다.
    gcloud config set compute/zone [COMPUTE_ZONE]
  • 지역 클러스터를 사용하는 경우 기본 컴퓨팅 지역을 설정합니다.
    gcloud config set compute/region [COMPUTE_REGION]
  • gcloud를 최신 버전으로 업데이트합니다.
    gcloud components update
  • [Cloud CDN 개요]를 읽습니다.

  • [Cloud CDN 캐싱] 관련 정보를 읽습니다.

  • Kubernetes Ingress서비스 리소스 관련 정보를 읽습니다.

  • BackendConfig 커스텀 리소스를 숙지합니다.

네임스페이스 만들기

이 가이드의 객체를 위한 Kubernetes 네임스페이스를 만듭니다.

kubectl create namespace cdn-how-to

배포 만들기

이 배포 매니페스트는 ingress-gce-echo-amd64 웹 애플리케이션의 두 복제본을 실행하려 한다고 선언합니다.

apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: cdn-how-to
  name: my-deployment
spec:
  selector:
    matchLabels:
      purpose: demonstrate-cdn
  replicas: 2
  template:
    metadata:
      labels:
        purpose: demonstrate-cdn
    spec:
      containers:
      - name: echo-amd64
        image: gcr.io/google-samples/hello-app-cdn:1.0

이름이 my-deployment.yaml인 파일에 매니페스트를 복사하고 배포를 만듭니다.

kubectl apply -f my-deployment.yaml

BackendConfig 만들기

BackendConfig의 매니페스트는 다음과 같습니다. 이 매니페스트는 Cloud CDN 캐시 정책을 지정하고 Cloud CDN이 사용 설정되도록 선언합니다.

apiVersion: cloud.google.com/v1beta1
kind: BackendConfig
metadata:
  namespace: cdn-how-to
  name: my-backend-config
spec:
  cdn:
    enabled: true
    cachePolicy:
      includeHost: true
      includeProtocol: true
      includeQueryString: false

이름이 my-backend-config.yaml인 파일에 매니페스트를 복사하고 BackendConfig를 만듭니다.

kubectl apply -f my-backend-config.yaml

BackendConfig를 확인합니다.

kubectl get backendconfig my-backend-config --output yaml --namespace cdn-how-to

출력에서 Cloud CDN 캐시 정책을 볼 수 있습니다.

apiVersion: cloud.google.com/v1beta1
kind: BackendConfig
metadata:
  name: my-backend-config
  namespace: cdn-how-to
  ...
spec:
  cdn:
    cachePolicy:
      includeHost: true
      includeProtocol: true
      includeQueryString: false
    enabled: true

서비스 만들기

서비스의 매니페스트는 다음과 같습니다.

apiVersion: v1
kind: Service
metadata:
  namespace: cdn-how-to
  name: my-service
  labels:
    purpose: demonstrate-cdn
  annotations:
    beta.cloud.google.com/backend-config: '{"ports": {"80":"my-backend-config"}}'
spec:
  type: NodePort
  selector:
    purpose: demonstrate-cdn
  ports:
  - port: 80
    protocol: TCP
    targetPort: 8080

이름이 my-service.yaml인 파일로 매니페스트를 저장하고 서비스를 만듭니다.

kubectl apply -f my-service.yaml

서비스를 확인합니다.

kubectl get service my-service --namespace cdn-how-to --output yaml

출력은 다음과 비슷합니다.

apiVersion: v1
kind: Service
metadata:
  annotations:
    beta.cloud.google.com/backend-config: '{"ports": {"80":"my-backend-config"}}'
    ...
  labels:
    purpose: demonstrate-cdn
  name: my-service
  namespace: cdn-how-to
  ...
spec:
  clusterIP: 10.51.255.39
  externalTrafficPolicy: Cluster
  ports:
  - nodePort: 31484
    port: 80
    protocol: TCP
    targetPort: 8080
  selector:
    purpose: demonstrate-cdn
  sessionAffinity: None
  type: NodePort
status:
  loadBalancer: {}

이 연습에서 서비스와 관련된 중요한 유의 사항은 다음과 같습니다.

  • 서비스의 포트 80이 my-backend-config라는 BackendConfig와 연결됩니다. beta.cloud.google.com/backend-config 주석에 이 항목이 지정되어 있습니다.

  • 서비스의 유형은 NodePort입니다. 이 유형은 Ingress와 연결할 서비스에 일반적으로 사용됩니다.

  • purpose: demonstrate-cdn 라벨을 포함하는 모든 포드가 서비스의 구성원입니다. selector 필드에 이 항목이 지정되어 있습니다.

  • TCP 포트 80으로 서비스로 전송되는 트래픽은 구성원 포드 중 하나에서 TCP 포트 8080으로 라우팅됩니다. porttargetPort 필드에 이 항목이 지정되어 있습니다.

정적 외부 IP 주소 예약

정적 외부 IP 주소를 예약합니다.

gcloud compute addresses create cdn-how-to-address --global

정적 외부 IP 주소를 확인합니다.

gcloud compute addresses list --filter "name=cdn-how-to-address"

출력에 주소 이름 및 값이 표시됩니다.

NAME                ...     ADDRESS        STATUS
cdn-how-to-address          203.0.113.1    RESERVED

Ingress 만들기

Ingress의 매니페스트는 다음과 같습니다.

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  namespace: cdn-how-to
  name: my-ingress
  annotations:
    kubernetes.io/ingress.global-static-ip-name: "cdn-how-to-address"
spec:
  rules:
  - http:
      paths:
      - path: /*
        backend:
          serviceName: my-service
          servicePort: 80

이름이 my-ingress.yaml인 파일에 매니페스트를 복사하고 Ingress를 만듭니다.

kubectl apply -f my-ingress.yaml

Kubernetes Ingress 컨트롤러가 Cloud 부하 분산기를 구성할 때까지 10분 정도 기다린 후 Ingress를 확인합니다.

kubectl get ingress my-ingress --output yaml --namespace cdn-how-to

출력은 다음과 비슷합니다.

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  ...
  name: my-ingress
  namespace: cdn-how-to
  ...
spec:
  rules:
  - http:
      paths:
      - backend:
          serviceName: my-service
          servicePort: 80
        path: /*
status:
  loadBalancer:
    ingress:
    - ip: 201.0.113.1

이 연습에서 Ingress와 관련된 중요한 유의 사항은 다음과 같습니다.

  • 들어오는 트래픽의 IP 주소는 loadBalancer:ingress: 아래에 나열됩니다.

  • Ingress에는 모든 호스트에서 들어오는 HTTP 요청에 적용되는 하나의 규칙이 있습니다. 이것은 규칙에 host 필드가 없기 때문입니다. 따라서 기본적으로 규칙이 모든 호스트에 적용됩니다.

  • 모든 들어오는 요청은 URL 경로에 관계없이 동일하게 취급됩니다. 이것은 path/*로 지정되어 있습니다.

  • 들어오는 요청은 my-service의 구성원인 포드로 라우팅됩니다. 이 연습에서는 구성원 포드에 purpose: demonstrate-cdn 라벨이 포함됩니다.

  • 요청이 my-service에 지정된 대상 포트의 포드로 라우팅됩니다. 이 연습에서 포드 대상 포트는 8080입니다.

웹 앱 보기

curl 명령어를 두 번 입력합니다.

curl -v [STATIC_ADDRESS]/?cache=true

여기서 [STATIC_ADDRESS]는 정적 외부 IP 주소입니다.

출력에는 응답 헤더와 본문이 표시됩니다. 응답 헤더에서 콘텐츠가 캐싱된 것을 확인할 수 있습니다. Age 헤더는 콘텐츠가 캐싱된 후 경과된 시간을 초 단위로 나타냅니다.

...
< HTTP/1.1 200 OK
< Date: Fri, 25 Jan 2019 02:34:08 GMT
< Content-Length: 70
< Content-Type: text/plain; charset=utf-8
< Via: 1.1 google
< Cache-Control: max-age=86400,public
< Age: 2716
<
Hello, world!
Version: 1.0.0
Hostname: my-deployment-7f589cc5bc-l8kr8

부하 분산 로그 보기

HTTP 부하 분산에 대한 Stackdriver 로그를 조회하여 콘텐츠가 캐싱되었음을 확인할 수 있습니다. 로그를 검사하기 전에 앱에 응답을 두 번 이상 요청했는지 확인하세요.

콘솔

GCP Console에서 로깅 메뉴의 로그 페이지로 이동합니다.

로그 페이지로 이동

첫 번째 드롭다운 메뉴에서 Cloud HTTP 부하 분산기를 선택합니다.

가장 최근 로그 항목을 펼치고 항목의 httpRequest 필드를 펼칩니다.

httpRequest 필드에서 cacheHittrue임을 확인할 수 있습니다.

httpRequest: {
cacheHit:  true
cacheLookup:  true
...

gcloud

gcloud logging read \
    'logName="projects/[PROJECT_ID]/logs/requests"' \
    --limit 2

여기서 [PROJECT_ID]는 프로젝트 ID입니다.

출력에서 캐시에 있음을 확인할 수 있습니다.

httpRequest:
cacheHit: true
cacheLookup: true

제한사항

Cloud CDN 및 Cloud Identity-Aware Proxy는 동일한 HTTP(S) 부하 분산 백엔드 서비스에 대해 사용 설정할 수 없습니다.

문제해결

BackendConfig를 찾을 수 없음

이 오류는 서비스 포트에 대해 BackendConfig가 서비스 주석에 지정되었지만 실제 BackendConfig 리소스를 찾을 수 없을 때 발생합니다. 이 문제는 개발자가 BackendConfig 리소스를 전혀 만들지 않았거나, 잘못된 네임스페이스로 만들었거나, 서비스 주석에서 참조 철자를 잘못 쓴 경우에 발생할 수 있습니다.

kubectl get event
KIND    ... SOURCE
Ingress ... loadbalancer-controller

MESSAGE
Error during sync: error getting BackendConfig for port 80 on service “default/my-service”:
no BackendConfig for service port exists

Cloud CDN 및 Cloud IAP가 모두 사용 설정됨

이 오류는 BackendConfig에서 Cloud IAP 및 Cloud CDN을 모두 사용 설정한 경우에 발생합니다.

kubectl get event
KIND    ... SOURCE
Ingress ... loadbalancer-controller

MESSAGE
Error during sync: BackendConfig default/config-default is not valid:
iap and cdn cannot be enabled at the same time.

콘텐츠가 캐시되지 않음

콘텐츠가 캐시되지 않는 것으로 확인되면, 콘텐츠 캐시를 사용하도록 애플리케이션이 올바르게 구성되었는지 확인하세요. 자세한 내용은 cacheability를 참조하세요.

삭제

이 페이지의 연습을 완료한 후에는 다음 단계에 따라 자신의 계정에 원치 않는 비용이 발생하지 않도록 리소스를 삭제합니다.

이 연습을 위해 만든 Kubernetes 객체를 삭제합니다.

kubectl delete ingress my-ingress --namespace cdn-how-to
kubectl delete service my-service --namespace cdn-how-to
kubectl delete backendconfig my-backend-config --namespace cdn-how-to
kubectl delete deployment my-deployment --namespace cdn-how-to
kubectl delete namespace cdn-how-to

정적 외부 IP 주소를 삭제합니다.

gcloud compute addresses delete cdn-how-to-address --global

다음 단계

이 페이지가 도움이 되었나요? 평가를 부탁드립니다.

다음에 대한 의견 보내기...

Kubernetes Engine