네트워크 프록시로 외부 액세스가 가능한 GKE 비공개 클러스터 만들기

GKE 비공개 클러스터를 만들면 공개 인터넷에서 클러스터의 마스터 노드에 액세스할 수 없습니다. 하지만 액세스할 수 있어야 관리할 수 있습니다. 이 가이드에서는 비공개 IP 공간에서 만들고 호스트하는 프록시를 통할 경우를 제외하고는 네트워크 외부에서 마스터에 액세스할 수 없도록 GKE 비공개 클러스터의 마스터를 구성하는 방법을 보여줍니다.

클러스터에서 내부 부하 분산기를 통해 Kubernetes Service를 라우팅하는 대신 프록시를 구성할 수 있습니다. 그러면 gcloud container clusters get-credentials를 사용하여 사용자 인증 정보를 가져오고, 보안 연결을 통해 마스터에 액세스할 수 있습니다.

목표

  • 최소한의 외부 액세스만 가능한 GKE 비공개 클러스터를 만듭니다.
  • 프록시를 실행하기 위한 Docker 이미지를 만들고 배포합니다.
  • 프록시에 액세스하기 위한 Kubernetes Service를 만듭니다.
  • 클러스터에 대한 다른 모든 외부 액세스를 삭제합니다.

비용

이 가이드에서는 다음과 같이 비용이 청구될 수 있는 Google Cloud Platform 구성요소를 사용합니다.

이 솔루션의 예상 비용은 하루에 약 $2.42입니다.

시작하기 전에

  1. Select or create a Google Cloud Platform project.

    Go to the Manage resources page

  2. 프로젝트에 결제가 사용 설정되어 있는지 확인하세요.

    결제 사용 설정 방법 알아보기

  3. 다음과 같은 구성을 갖춘 클라이언트 머신이 있는지 확인합니다.
    • 처음에 클러스터에 액세스하기 위한 알려진 외부 IP 주소. 프록시가 설정된 후에는 CIDR 범위에 대한 액세스 권한을 제공하기 때문에 일시적으로만 필요합니다. 대표적인 예는 외부 IP 주소가 있는 Compute Engine 가상 머신입니다. 클러스터를 만들고 포드 및 서비스를 배포하기 위한 권한도 있어야 합니다.
    • gcloud auth configure-docker를 사용하여 gcr.io에 설치되고 인증된 Docker

이 가이드를 마친 후에 계속 비용이 청구되지 않도록 하려면 만든 리소스를 삭제하면 됩니다. 자세한 내용은 삭제를 참조하세요.

비공개 클러스터 만들기

첫 번째 단계는 이 가이드에 사용할 비공개 클러스터를 만들거나 선택하는 것입니다.

사용하기를 원하는 클러스터가 이미 있는 경우에는 클러스터를 만드는 단계를 건너뛸 수 있지만, 클라이언트 머신에서 몇 가지 초기 액세스 형태를 구성해야 합니다.

  1. 클러스터를 만들려면 다음 명령어를 실행합니다. [YOUR_CLIENT_IP_ADDRESS]에는 클라이언트의 라우팅 가능한 외부 IP 주소 또는 넷블록을 사용합니다.

    gcloud beta container clusters create frobnitz  \
        --zone=us-central1-c \
        --master-ipv4-cidr=172.16.0.64/28 \
        --enable-ip-alias \
        --private-cluster\
        --create-subnetwork=""  \
        --master-authorized-networks [YOUR_CLIENT_IP_ADDRESS]/32 \
        --enable-master-authorized-networks

    이 명령어는 frobnitz라는 이름의 GKE 비공개 클러스터를 마스터 인증 네트워크 세트와 함께 만들어서 클라이언트 머신만 액세스할 수 있도록 허용합니다.

  2. 대신, 기존 클러스터가 있고 이에 대한 액세스 권한을 부여하려면 다음 명령어를 실행합니다. [YOUR_CLIENT_IP_ADDRESS]에는 클라이언트의 라우팅 가능한 외부 IP 주소 또는 넷블록을 사용합니다. [CLUSTER_NAME]은 기존 클러스터의 이름입니다.

    gcloud beta container clusters update [CLUSTER_NAME] \
        --zone [CLUSTER_ZONE] \
        --enable-master-authorized-networks \
        --master-authorized-networks=[YOUR_CLIENT_IP_ADDRESS]/32

Docker 이미지 만들기

다음 단계를 따라 Kubernetes API 서버의 전달 프록시 역할을 하는 k8s-api-proxy,라는 Kubernetes API 프록시 이미지를 빌드하세요.

  1. 클라이언트 머신에서 디렉토리를 만들고 해당 디렉토리로 이동합니다.

    mkdir k8s-api-proxy && cd k8s-api-proxy

  2. Dockerfile을 만듭니다. 다음 구성은 Privoxy 프록시가 있는 간단한 컨테이너 배포인 Alpine에서 컨테이너를 만듭니다. 또한 Dockerfile은 컨테이너 초기화를 위한 curljq를 설치하고, 필요한 구성 파일을 추가하고, 포트 8118을 GKE에 내부적으로 노출하고, 시작 스크립트를 추가합니다.

    FROM alpine
    RUN apk add -U curl privoxy jq && \ mv /etc/privoxy/templates /etc/privoxy-templates && \ rm -rf /var/cache/apk/* /etc/privoxy/* && \ mv /etc/privoxy-templates /etc/privoxy/templates ADD --chown=privoxy:privoxy config \ /etc/privoxy/ ADD --chown=privoxy:privoxy k8s-only.action \ /etc/privoxy/ ADD --chown=privoxy:privoxy k8s-rewrite-external.filter \ /etc/privoxy/ ADD k8s-api-proxy.sh /
    EXPOSE 8118/tcp
    ENTRYPOINT ["./k8s-api-proxy.sh"]

  3. k8s-api-proxy 디렉토리에서 config 파일을 만들고 다음 콘텐츠를 추가합니다.

    # Allow Kubernetes API access only
    actionsfile /etc/privoxy/k8s-only.action
    # Rewrite https://CLUSTER_IP to https://kubernetes.default
    filterfile /etc/privoxy/k8s-rewrite-external.filter
    # Don't show the pod name in errors
    hostname k8s-privoxy
    # Bind to all interfaces, port :8118
    listen-address  :8118
    # User cannot click-through a block
    enforce-blocks 1
    # Allow more than one outbound connection
    tolerate-pipelining 1

  4. 같은 디렉토리에서 k8s-only.action 파일을 만들고 다음 콘텐츠를 추가합니다. CLUSTER_IPk8s-api-proxy.sh가 실행될 때 대체됩니다.

    # Block everything...
    {+block{Not Kubernetes}}
    /
    # ... except the external k8s endpoint, which you rewrite (see # k8s-rewrite-external.filter). {+client-header-filter{k8s-rewrite-external} -block{Kubernetes}} CLUSTER_IP/

  5. k8s-rewrite-external.filter 파일을 만들고 다음 콘텐츠를 추가합니다. CLUSTER_IPk8s-api-proxy.sh가 실행될 때 대체됩니다.

    CLIENT-HEADER-FILTER: k8s-rewrite-external\
     Rewrite https://CLUSTER_IP/ to https://kubernetes.default/
    s@(CONNECT) CLUSTER_IP:443\
     (HTTP/\d.\d)@$1 kubernetes.default:443 $2@ig

  6. k8s-api-proxy.sh 파일을 만들고 다음 콘텐츠를 추가합니다.

    #!/bin/sh
    set -o errexit set -o pipefail set -o nounset
    # Get the external cluster IP EXTERNAL_IP=$(curl -SsL --insecure https://kubernetes.default/api | jq -r '.serverAddressByClientCIDRs[0].serverAddress')
    # Replace CLUSTER_IP in the rewrite filter and action file sed -i "s/CLUSTER_IP/${EXTERNAL_IP}/g"\ /etc/privoxy/k8s-rewrite-external.filter sed -i "s/CLUSTER_IP/${EXTERNAL_IP}/g"\ /etc/privoxy/k8s-only.action
    # Start Privoxy un-daemonized privoxy --no-daemon /etc/privoxy/config

  7. k8s-api-proxy.sh를 실행 파일로 만듭니다.

    chmod +x k8s-api-proxy.sh

  8. 컨테이너를 빌드하고 프로젝트에 푸시합니다. [YOUR_PROJECT]는 프로젝트의 ID로 대체합니다.

    docker build -t gcr.io/[YOUR_PROJECT]/k8s-api-proxy:0.1 .
    docker push gcr.io/[YOUR_PROJECT]/k8s-api-proxy:0.1

이미지 및 서비스 배포

  1. 방금 만든 컨테이너를 노출하는 Kubernetes 배포를 만듭니다. [YOUR_PROJECT]에는 프로젝트 ID를 사용합니다.

    kubectl run k8s-api-proxy \
        --image=gcr.io/[YOUR_PROJECT]/k8s-api-proxy:0.1 \
        --port=8118

  2. 같은 디렉토리에서 내부 부하 분산기를 위한 ilb.yaml 파일을 만들고 다음을 복사해 붙여넣습니다.

    apiVersion: v1
    kind: Service
    metadata:
      labels:
        run: k8s-api-proxy
      name: k8s-api-proxy
      namespace: default
      annotations:
        cloud.google.com/load-balancer-type: "Internal"
    spec:
      ports:
      - port: 8118
        protocol: TCP
        targetPort: 8118
      selector:
        run: k8s-api-proxy
      type: LoadBalancer

  3. 내부 부하 분산기를 배포합니다.

    kubectl create -f ilb.yaml

  4. 서비스를 확인하고 IP 주소를 기다립니다.

    kubectl get service/k8s-api-proxy

    다음과 같이 출력됩니다. 외부 IP가 보이면 프록시가 준비된 것입니다.

    NAME            TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
    k8s-api-proxy   LoadBalancer   10.24.13.129   10.24.24.3    8118:30282/TCP   2m

    이 단계에 있는 외부 IP 주소가 프록시 주소입니다.

  5. 테스트할 클러스터의 마스터 IP 주소를 확인합니다.

    gcloud container clusters list

    결과에서 클러스터의 MASTER_IP 값을 메모합니다.

    NAME      LOCATION       MASTER_VERSION  MASTER_IP       MACHINE_TYPE   NODE_VERSION  NUM_NODES  STATUS
    frobnitz  us-central1-c  1.9.7-gke.3     35.188.209.220  n1-standard-1  1.9.7-gke.3   3          RUNNING

  6. 프록시가 사용 가능한지 확인하려면 같은 네트워크에서 Compute Engine 인스턴스를 만들고, SSH로 액세스하고, 프록시를 확인합니다. [YOUR_SUBNET], [YOUR_PROXY][MASTER_IP]에는 이전에 얻은 값을 사용합니다.

    gcloud compute instances create \
        --subnet=[YOUR_SUBNET] proxy-test
    gcloud compute ssh proxy-test -- \
        curl --insecure -x [YOUR_PROXY]:8118 https://[MASTER_IP]/api

  7. kubectl 명령어가 어디에서든지 내부 부하 분산기에 도달할 수 있도록 https_proxy 환경 변수를 HTTP 프록시로 설정합니다. [YOUR_PROXY]에는 이전 단계에서 얻은 외부 IP 주소를 사용합니다.

    export https_proxy=[YOUR_PROXY]:8118

  8. 프록시 및 https_proxy 변수를 테스트합니다.

    kubectl get pods

삭제

이 가이드에서 사용한 리소스 비용이 Google Cloud Platform 계정에 청구되지 않도록 하는 방법은 다음과 같습니다.

  • 클러스터를 삭제합니다.
  • Compute Engine 인스턴스를 위해 생성된 모든 외부 IP 주소를 삭제합니다.

클러스터 삭제

클러스터를 이 가이드에서만 사용하기 위해 만들었고 다른 목적으로 사용하기를 원치 않는 경우에는 삭제할 수 있습니다. 클라이언트 머신의 명령줄에서 다음 명령어를 실행합니다.

gcloud beta container clusters delete frobnitz \
    --zone us-central1-c

외부 IP 주소 및 인스턴스 삭제

처음에 외부에서 액세스하기 위한 Compute Engine 인스턴스를 만든 경우에는 해당 인스턴스 그리고 관련된 모든 외부 IP를 삭제합니다.

만든 인스턴스의 이름을 찾아서 삭제합니다.

gcloud compute instances list
gcloud compute instances delete [NAME]

마찬가지로 예약된 외부 주소를 조회하여 삭제합니다.

gcloud compute addresses list
gcloud compute addresses delete [NAME]

다음 단계

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

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