エッジからメッシュへ: GKE Ingress を介したサービス メッシュ アプリケーションの公開

このチュートリアルでは、Anthos Service Mesh と Cloud Load Balancing を組み合わせて、サービス メッシュ内のアプリケーションをインターネット クライアントに公開する方法について説明します。

Anthos Service Mesh は Istio をベースにしたマネージド サービス メッシュで、セキュリティが強化された、観測可能で標準化された通信レイヤをアプリケーションに提供します。Anthos Service Mesh、Traffic Director、Istio のいずれを使用する場合でも、サービス メッシュは、メッシュ内で通信しているクライアントに包括的な通信プラットフォームを提供します。ただし、メッシュ外にあるクライアントをメッシュ内でホストされているアプリケーションに接続する方法は課題にあります。

アプリケーションは、クライアントの場所に応じてさまざまな方法でクライアントに公開できます。このチュートリアルでは、ロードバランサをサービス メッシュと統合するために Cloud Load Balancing と Anthos Service Mesh を組み合わせることにより、アプリケーションをクライアントに公開する方法について説明します。このチュートリアルは、Anthos Service Mesh を実行する上級者を対象としていますが、取り扱う内容は Istio on Google Kubernetes Engine に対しても有効です。

Mesh Ingress ゲートウェイ

Istio 0.8 では Mesh Ingress ゲートウェイが導入されました。これは、サービス メッシュ外からのトラフィックに公開されるポートの専用プロキシを提供します。これらのメッシュの上りプロキシでは、アプリケーションのルーティング動作とは別に L4 の露出動作を制御できます。このプロキシでは、アプリケーション サイドカーに到達する前に、メッシュ外部トラフィックにルーティングとポリシーを適用することもできます。Mesh Ingress は、メッシュ内のノードに到達した際のトラフィック処理を定義しますが、外部コンポーネントはトラフィックが最初にメッシュに到着する方法を定義する必要があります。

この外部トラフィックを管理するには、メッシュ外のロードバランサが必要です。このチュートリアルでは、GKE Ingress リソースを通じてプロビジョニングされた Google Cloud Load Balancing を使用して、デプロイを自動化します。この設定の標準的な例は、(Google Cloud の場合は)公開 TCP/UDP ロードバランサをデプロイする外部負荷分散サービスです。このロードバランサは、GKE クラスタの NodePort を参照します。これらの NodePort は、下流のメッシュ サイドカー プロキシにトラフィックをルーティングする Istio Ingress ゲートウェイ ポッドを公開します。次の図は、このトポロジを示しています。内部プライベート トラフィックの負荷分散は、内部 TCP/UDP ロードバランサをデプロイする点を除いて、このアーキテクチャと類似しています。

外部ロードバランサは、外部クライアントを Ingress ゲートウェイ プロキシ経由でメッシュにルーティングします。

Mesh Ingress ゲートウェイで L4 の負荷分散を使用すると、次のような利点があります。

  • この設定により、ロードバランサのデプロイが簡略化されます。
  • ロードバランサは、クラスタの変更、ノードの停止、プロセス停止が発生したときに、安定した仮想 IP(VIP)、ヘルスチェック、信頼性の高いトラフィック分散を提供します。
  • すべてのルーティング ルール、TLS 終端、トラフィック ポリシーは、Mesh Ingress ゲートウェイの 1 つの場所で処理されます。

GKE Ingress とサービス

クラスタ外部のクライアントには、さまざまな方法でアプリケーションへのアクセスを提供できます。次の表に、Google Cloud のロードバランサのデプロイに使用できる Kubernetes のプリミティブを示します。アプリケーションをクライアントに公開するために使用すべきロードバランサの種類は、主に次のような点によって決まります: クライアントが外部か内部か、どのようなプロトコルのサポートが必要か、サービス メッシュが複数の GKE クラスタにまたがるか、または単一のクラスタに含まれているか。

次の表に示すロードバランサのタイプはすべて、ユースケースに応じてメッシュでホストされているアプリケーションを公開できます。

GKE リソース クラウドベースのロードバランサ 特性
外部 HTTP(S) 負荷分散での Ingress 外部 HTTP(S) ロードバランサ

Google エッジ接続拠点(PoP)の L7 プロキシ

パブリック VIP

グローバル スコープ

単一クラスタ

内部 HTTP(S) 負荷分散での Ingress 内部 HTTP(S) ロードバランサ

Virtual Private Cloud(VPC)ネットワーク内の L7 プロキシ

プライベート VIP

リージョン スコープ

単一クラスタ

外部 LoadBalancer サービス 外部 TCP/UDP ロードバランサ

Google エッジ接続拠点での L4 パススルー

パブリック VIP

リージョン スコープ

単一クラスタ

内部 LoadBalancer サービス 内部 TCP / UDP ロードバランサ

VPC ルーティング ネットワークの L4 パススルー

プライベート VIP

リージョン スコープ

単一クラスタ

複数クラスタ Ingress(複数クラスタ、外部 Ingress) 外部 HTTP(S) ロードバランサ

Google エッジ接続拠点の L7 プロキシ

パブリック VIP

グローバル スコープ

複数クラスタ

Anthos Service Mesh のデフォルトのロードバランサは外部 TCP/UDP ロードバランサですが、このチュートリアルでは、外部 HTTP(S) 負荷分散を使用してデプロイする外部 HTTP(S) バランサを中心に説明します。外部 HTTP(S) ロードバランサは、Identity-Aware Proxy(IAP)、Google Cloud Armor、Cloud CDN などのエッジサービスと、グローバルに分散されたエッジプロキシのネットワークと統合します。次のセクションでは、2 つのレイヤからなる HTTP 負荷分散を使用する際のアーキテクチャとメリットについて説明します。

Cloud Ingress と Mesh Ingress

Mesh Ingress レイヤとともに外部 L7 負荷分散をメッシュ外にデプロイすると、特にインターネット トラフィックに大きなメリットがあります。Anthos Service Mesh と Istio Ingress ゲートウェイはメッシュ内の高度なルーティングとトラフィック管理を提供しますが、一部の機能はネットワークのエッジで提供されます。Google Cloud の外部 HTTP(S) 負荷分散を介したインターネット エッジ ネットワークを活用すると、メッシュベースの Ingress よりも、パフォーマンス、信頼性、セキュリティ関連の大きな利点が得られます。これには、次のような利点があります。

この L7 負荷分散の外部レイヤは、Mesh Ingress で使用されるセルフホストのプロキシではなく、クラウド管理ロードバランサ上に構築されるため、「Cloud Ingress」と呼ばれます。Cloud Ingress と Mesh Ingress を組み合わせる場合、Google Cloud インフラストラクチャとメッシュの補完機能を活用します。次の図は、Cloud Ingress と Mesh Ingress を組み合わせて、インターネット トラフィックの 2 つの負荷分散レイヤとして機能する方法を示しています。

Cloud Ingress は、VPC ネットワーク経由でメッシュへの外部トラフィックのためのゲートウェイとして機能します。

このトポロジでは、Cloud Ingress レイヤがサービス メッシュの外部からのトラフィックを参照し、そのトラフィックを Mesh Ingress レイヤに転送します。その後、この Mesh Ingress レイヤはメッシュでホストされるアプリケーション バックエンドにトラフィックを転送します。

Cloud Ingress と Mesh Ingress のトポロジ

このセクションでは、各 Ingress レイヤを一緒に使用するときに補完する役割について説明します。これらの役割は詳細なルールではなく、各レイヤのメリットを使用するガイドラインです。このパターンのバリエーションは、ユースケースによって異なります。

  • Cloud Ingress。Mesh Ingress レイヤと組み合わせて使用する場合、Cloud Ingress レイヤはエッジ セキュリティとグローバル負荷分散に最適です。Cloud Ingress レイヤには DDoS 対策、クラウド ファイアウォール、認証、暗号化サービスがエッジにおいて統合されているため、このレイヤはメッシュ外で上記サービスを実行することに優れています。ルーティング ロジックは通常、このレイヤで比較的単純ですが、マルチクラスタ環境やマルチリージョン環境では、ロジックがより複雑になる可能性があります。インターネットに接続するロードバランサの重要な機能のため、Cloud Ingress レイヤはインフラストラクチャ チームが管理します。このチームはインターネット上でのアプリケーションの公開方法や保護方法について独占的に制御します。この制御により、このレイヤはデベロッパー主導のインフラストラクチャよりも柔軟性や動的性能が低くなります。このことは、このレイヤへの管理者アクセスを提供する対象と提供方法に影響する可能性があります。
  • Mesh Ingress。Cloud Ingress と組み合わせて使用する場合、Mesh Ingress レイヤはアプリケーションに近い柔軟なルーティングを可能とします。このような柔軟性があるため、複雑なルーティング ロジックやアプリケーション レベルの可視性のために、Mesh Ingress は Cloud Ingress より優れています。Ingress レイヤを分離することで、アプリケーション オーナーは他のチームに影響を与えずにこのレイヤを直接制御できます。L7 ロードバランサの代わりに L4 ロードバランサを介してサービス メッシュ アプリケーションを公開する場合、アプリケーションを保護するために、メッシュ内の Mesh Ingress レイヤでクライアント TLS を終了する必要があります。

ヘルスチェック

L7 負荷分散の 2 つのレイヤを使用する複雑さの 1 つは、ヘルスチェックです。各ロードバランサを構成して、次のレイヤの健全性を確認して、トラフィックを受信できるようにする必要があります。次の図のトポロジは、Cloud Ingress によって Mesh Ingress プロキシのヘルスチェックを行う方法と、返されたメッシュでアプリケーション バックエンドの健全性を確認する方法を示しています。

Cloud Ingress は Mesh Ingress のヘルスチェックを行い、Mesh Ingress はアプリケーション バックエンドのヘルスチェックをチェックします。

このトポロジの考慮事項は次のとおりです。

  • Cloud Ingress。このチュートリアルでは、Ingress で Google Cloud ロードバランサを構成し、公開されたヘルスチェック ポートで Mesh Ingress プロキシの健全性を確認します。メッシュ プロキシがダウンしている場合、またはクラスタ、メッシュ、リージョンが利用できない場合、Google Cloud ロードバランサはこの状態を検出し、メッシュ プロキシにトラフィックを送信しません。
  • Mesh Ingress。メッシュ アプリケーションでは、バックエンドでヘルスチェックを直接実行し、負荷分散とトラフィック管理をローカルで実行できます。

セキュリティ

前述のトポロジにはいくつかのセキュリティ要素が含まれます。最も重要な要素の 1 つは、暗号化の構成と証明書のデプロイです。外部 HTTP(S) 負荷分散の Ingress は、Google マネージド証明書と緊密に統合されています。この統合により、公開証明書が自動的にプロビジョニングされ、ロードバランサに紐づけられ、宣言型 GKE Ingress インターフェースを通じて証明書の更新とローテーションが行われます。インターネット クライアントは、公開証明書に対する認証を行い、Virtual Private Cloud(VPC)の最初のホップとして外部ロードバランサに接続します。

Google Front End(GFE)と Mesh Ingress プロキシの間にあるネクストホップは、デフォルトで暗号化されます。GFE とバックエンド間のネットワーク レベルの暗号化は自動的に適用されます。ただし、セキュリティ要件によって、プラットフォーム オーナーが暗号鍵の所有権を保持していると判断された場合、クラスタ Ingress(GFE)と Mesh Ingress(Envoy プロキシ インスタンス)の間で TLS 暗号化による HTTP/2 を有効にできます。このパスで TLS 暗号化による HTTP/2 を有効にすると、GFE は認証されないため、自己署名証明書または公開証明書を使用してトラフィックを暗号化できます。暗号化の追加レイヤについては、このガイドで説明します。証明書の誤処理を防ぐため、パブリック ロードバランサには他の場所の公開証明書を使用しないでください。代わりに、サービス メッシュで別個の証明書を使用することをおすすめします。

サービス メッシュで TLS が強制されている場合、すべてのトラフィックはサイドカー プロキシとMesh Ingress との間で暗号化されます。次の図は、クライアントから Google Cloud ロードバランサへの、ロードバランサから Mesh Ingress プロキシ、および Ingress プロキシからサイドカー プロキシへの HTTPS 暗号化を示しています。

セキュリティは、メッシュ外のマネージド証明書と、メッシュ内の内部証明書を使用して実装されます。

目標

  • Google Cloud に Google Kubernetes Engine(GKE)クラスタをデプロイします。
  • Istio ベースの Anthos Service Mesh を GKE クラスタにデプロイします。
  • パブリック HTTPS トラフィックを終了し、そのトラフィックをサービス メッシュでホストされるアプリケーションに転送するように GKE Ingress を構成します。
  • インターネット上のクライアントに公開する GKE クラスタに Online Boutique アプリケーションをデプロイします。

費用

このチュートリアルでは、課金対象である次の Google Cloud コンポーネントを使用します。

料金計算ツールを使うと、予想使用量に基づいて費用の見積もりを生成できます。 新しい Google Cloud ユーザーは無料トライアルをご利用いただける場合があります。

このチュートリアルを終了した後、作成したリソースを削除すると、それ以上の請求は発生しません。詳細については、クリーンアップをご覧ください。

始める前に

  1. Google Cloud Console の [プロジェクト セレクタ] ページで、Google Cloud プロジェクトを選択または作成します。

    プロジェクト セレクタに移動

  2. Cloud プロジェクトに対して課金が有効になっていることを確認します。プロジェクトに対して課金が有効になっていることを確認する方法を学習する

  3. Cloud Console で、Cloud Shell をアクティブにします。

    Cloud Shell をアクティブにする

    このチュートリアルでは、Cloud Shell からすべてのターミナル コマンドを実行します。

  4. デフォルトの Google Cloud プロジェクトを設定します。

    export PROJECT=$(gcloud info --format='value(config.project)')
    export PROJECT_NUMBER=$(gcloud projects describe ${PROJECT} --format="value(projectNumber)")
    gcloud config set project ${PROJECT}
    
  5. 作業ディレクトリを作成します。

    mkdir -p ${HOME}/edge-to-mesh
    cd ${HOME}/edge-to-mesh
    export WORKDIR=`pwd`
    

    チュートリアルを完了したら、作業ディレクトリを削除できます。

GKE クラスタの作成

このチュートリアルで説明されてる機能には、GKE クラスタ バージョン 1.16 以降が必要です。

  1. Cloud Shell で、新しい kubeconfig ファイルを作成します。この手順により、既存の(デフォルト)kubeconfig ファイルと競合しなくなります。

    touch edge2mesh_kubeconfig
    export KUBECONFIG=${WORKDIR}/edge2mesh_kubeconfig
    
  2. GKE クラスタの環境変数を定義します。

    export CLUSTER_NAME=edge-to-mesh
    export CLUSTER_LOCATION=us-west1-a
    
  3. Google Kubernetes Engine API を有効にします。

    gcloud services enable container.googleapis.com
    
  4. GKE クラスタを作成する。

    gcloud container clusters create ${CLUSTER_NAME} \
        --machine-type=e2-standard-4 \
        --num-nodes=4 \
        --zone ${CLUSTER_LOCATION} \
        --enable-ip-alias \
        --workload-pool=${PROJECT}.svc.id.goog \
        --release-channel rapid
    
  5. クラスタが実行されていることを確認します。

    gcloud container clusters list
    

    出力は次のようになります。

    NAME          LOCATION    MASTER_VERSION    MASTER_IP      MACHINE_TYPE   NODE_VERSION      NUM_NODES  STATUS
    edge-to-mesh  us-west1-a  1.21.5-gke.1302   35.233.195.59  e2-standard-4  1.21.5-gke.1302   4          RUNNING
    
  6. クラスタに接続します。

    gcloud container clusters get-credentials ${CLUSTER_NAME} --zone ${CLUSTER_LOCATION} --project ${PROJECT}
    

サービス メッシュのインストール

  1. Cloud Shell にAnthos Service Mesh のインストール ファイルをダウンロードします。

    GKE への Anthos Service Mesh のインストールの手順に沿って、Google 提供のスクリプトを使用して Anthos Service Mesh をインストールします。

    次に例を示します。

    ./asmcli install \
        --project_id ${PROJECT} \
        --cluster_name ${CLUSTER_NAME} \
        --cluster_location ${CLUSTER_LOCATION} \
        --enable_all
    
  2. すべてのデプロイが稼働していることを確認します。

    kubectl wait --for=condition=available --timeout=600s deployment --all -n istio-system
    kubectl wait --for=condition=available --timeout=600s deployment --all -n asm-system
    

    出力は次のようになります。

    deployment.apps/istiod-asm-1112-17 condition met
    deployment.apps/canonical-service-controller-manager condition met
    

GKE Ingress をデプロイする

次の手順では、GKE の Ingress コントローラを介して外部 HTTP(S) ロードバランサをデプロイします。Ingress リソースは、ロードバランサ、TLS 証明書、バックエンド ヘルスチェックのプロビジョニングを自動化します。また、Cloud Endpoints を使用して、アプリケーションのパブリック DNS 名が自動的にプロビジョニングされます。

Ingress ゲートウェイをインストールする

セキュリティのベスト プラクティスとして、Ingress ゲートウェイは、コントロール プレーンとは異なる Namespace にデプロイすることをおすすめします。

  1. Cloud Shell で、専用の asm-ingress Namespace を作成します。

    kubectl create namespace asm-ingress
    
  2. asm-ingress Namespace に名前空間ラベルを追加します。

    export ASM_REVISION=$(kubectl get deploy -n istio-system \
        -l app=istiod \
        -o jsonpath={.items[*].metadata.labels.'istio\.io\/rev'}'{"\n"}')
    kubectl label namespace asm-ingress istio-injection- istio.io/rev=${ASM_REVISION} --overwrite
    

    出力は次のようになります。

    label "istio-injection" not found.
    namespace/asm-ingress labeled
    

    asm-ingress 名前空間にラベルを付けると、アプリケーションのデプロイ時に Envoy サイドカー プロキシを自動挿入するよう Istio に指示します。ASM インストール ガイドで説明されているように、適用する istio.io/rev ラベルが、インストールした ASM のバージョンと一致していることを確認してください。

  3. 次のコマンドを実行して、Deployment マニフェストを ingress-deployment.yaml として作成します。

    cat <<EOF > ingress-deployment.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: asm-ingressgateway
      namespace: asm-ingress
    spec:
      selector:
        matchLabels:
          asm: ingressgateway
      template:
        metadata:
          annotations:
            # This is required to tell Anthos Service Mesh to inject the gateway with the
            # required configuration.
            inject.istio.io/templates: gateway
          labels:
            asm: ingressgateway
        spec:
          containers:
          - name: istio-proxy
            image: auto # The image will automatically update each time the pod starts.
            resources:
              limits:
                cpu: 2000m
                memory: 1024Mi
              requests:
                cpu: 100m
                memory: 128Mi
          serviceAccountName: asm-ingressgateway
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
      name: asm-ingressgateway
      namespace: asm-ingress
    rules:
    - apiGroups: [""]
      resources: ["secrets"]
      verbs: ["get", "watch", "list"]
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
      name: asm-ingressgateway
      namespace: asm-ingress
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: Role
      name: asm-ingressgateway
    subjects:
      - kind: ServiceAccount
        name: asm-ingressgateway
    ---
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: asm-ingressgateway
      namespace: asm-ingress
    EOF
    

    この Deployment には、RoleRoleBinding が関連付けられた独自の ServiceAccount があり、これによりゲートウェイが証明書にアクセスできます。

  4. クラスタに ingress-deployment.yaml をデプロイして Deployment リソースを作成します。

    kubectl apply -f ingress-deployment.yaml
    

    出力は次のようになります。

    deployment.apps/asm-ingressgateway configured
    role.rbac.authorization.k8s.io/asm-ingressgateway configured
    rolebinding.rbac.authorization.k8s.io/asm-ingressgateway configured
    serviceaccount/asm-ingressgateway created
    

    すべてのデプロイが稼働していることを確認します。

    kubectl wait --for=condition=available --timeout=600s deployment --all -n asm-ingress
    

    出力は次のようになります。

    deployment.apps/asm-ingressgateway condition met
    
  5. 次のコマンドを実行して、Service マニフェストを ingress-service.yaml として作成します。

    cat <<EOF > ingress-service.yaml
    apiVersion: v1
    kind: Service
    metadata:
      name: asm-ingressgateway
      namespace: asm-ingress
      annotations:
        cloud.google.com/neg: '{"ingress": true}'
        cloud.google.com/backend-config: '{"default": "ingress-backendconfig"}'
        cloud.google.com/app-protocols: '{"https":"HTTP2"}' # HTTP/2 with TLS encryption
      labels:
        asm: ingressgateway
    spec:
      ports:
      # status-port exposes a /healthz/ready endpoint that can be used with GKE Ingress health checks
      - name: status-port
        port: 15021
        protocol: TCP
        targetPort: 15021
      # Any ports exposed in Gateway resources should be exposed here.
      - name: http2
        port: 80
      - name: https
        port: 443
      selector:
        asm: ingressgateway
      type: ClusterIP
    EOF
    

    この Service には、デプロイ時に Ingress ロードバランサのパラメータを設定する、次のアノテーションがあります。

    • cloud.google.com/backend-config は、BackendConfig というカスタム リソースの名前を指します。Ingress コントローラは、BackendConfig を使用して Google Cloud BackendService リソースにパラメータを設定します。このリソースは、次のステップで Google Cloud ヘルスチェックのカスタム パラメータを定義するために使用します。
    • cloud.google.com/neg: '{"ingress": true}' は、コンテナ ネイティブの負荷分散の Ingress バックエンド(この場合は Mesh Ingress プロキシ)を有効にします。これらのバックエンドでは、より効率的で安定した負荷分散を実現するために、インスタンス グループではなくネットワーク エンドポイント グループ(NEG)を使用します。
    • cloud.google.com/app-protocols: '{"https":"HTTP2"}' は、暗号化の追加レイヤために外部 HTTP(S) 負荷分散の Ingress外部 HTTP(S) 負荷分散の概要で説明されているように、TLS で HTTP2 を使用してサービス メッシュの Ingress ゲートウェイに接続するように GFE に指示します。
  6. クラスタに ingress-service.yaml をデプロイして Service リソースを作成します。

    kubectl apply -f ingress-service.yaml
    

    出力は次のようになります。

    service/asm-ingressgateway created
    

バックエンド サービスの設定を適用

  1. Cloud Shell で次のコマンドを実行して、BackendConfig マニフェストを ingress-backendconfig.yaml として作成します。

    cat <<EOF > ingress-backendconfig.yaml
    apiVersion: cloud.google.com/v1
    kind: BackendConfig
    metadata:
      name: ingress-backendconfig
      namespace: asm-ingress
    spec:
      healthCheck:
        requestPath: /healthz/ready
        port: 15021
        type: HTTP
      securityPolicy:
        name: edge-fw-policy
    EOF
    

    BackendConfig は、Ingress 負荷分散のバックエンド パラメータを定義するカスタム リソース定義(CRD)です。GKE Ingress で構成できるバックエンドとフロントエンドのパラメータの一覧については、Ingress 機能をご覧ください。

    このチュートリアルでは、BackendConfig マニフェストで Mesh Ingress プロキシのカスタム ヘルスチェックを指定します。Anthos Service Mesh と Istio は、サイドカー プロキシのヘルスチェック/healthz/ready パスのポート 15021 で公開します。Mesh Ingress プロキシのサービスポート(443)とヘルスチェック ポート(15021)は異なるため、カスタム ヘルスチェック パラメータが必要です。GKE Ingress は、BackendConfig の次のヘルスチェック パラメータを使用して、Google Cloud ロードバランサのヘルスチェックを構成します。また、さまざまな種類のネットワーク攻撃から負荷分散トラフィックを保護するセキュリティ ポリシーも参照できます。

    • healthCheck.port は、各ポッドの IP アドレスの Google Cloud ロードバランサでヘルスチェックを受け取るポートを定義します。
    • healthCheck.requestPath は、指定されたポートでヘルスチェックを受け取る HTTP パスを定義します。
    • type は、ヘルスチェックのプロトコル(この場合は HTTP)を定義します。
    • securityPolicy.name は、Cloud Armor セキュリティ ポリシーの名前です。
  2. クラスタに ingress-backendconfig.yaml をデプロイして BackendConfig リソースを作成します。

    kubectl apply -f ingress-backendconfig.yaml
    

    出力は次のようになります。

    backendconfig.cloud.google.com/ingress-backendconfig created
    

    Ingress リソースがデプロイされるまで、BackendConfig パラメータと asm-ingressgateway Service アノテーションは Google Cloud ロードバランサには適用されません。Ingress デプロイは、これらのすべてのリソースを結び付けます。

セキュリティ ポリシーの定義

Google Cloud Armor の DDoS 防御とカスタマイズ可能なセキュリティ ポリシーは、Ingress リソースを介してロードバランサに接続できます。次の手順では、事前構成されたルールを使用してクロスサイト スクリプティング(XSS)攻撃をブロックするセキュリティ ポリシーを作成します。このルールは、既知の攻撃の署名と一致するトラフィックをブロックしますが、他のすべてのトラフィックを許可します。ワークロードに応じて、環境に異なるルールが適用される場合があります。

  1. Cloud Shell で、edge-fw-policy という名前のセキュリティ ポリシーを作成します。

    gcloud compute security-policies create edge-fw-policy \
        --description "Block XSS attacks"
    
  2. 事前構成された XSS フィルタを使用するセキュリティ ポリシー ルールを作成します。

    gcloud compute security-policies rules create 1000 \
        --security-policy edge-fw-policy \
        --expression "evaluatePreconfiguredExpr('xss-stable')" \
        --action "deny-403" \
        --description "XSS attack filtering"
    

edge-fw-policy は前のセクションの ingress-backendconfig によって参照されました。Ingress リソースがデプロイされると、このセキュリティ ポリシーをロードバランサにバインドして、asm-ingressgateway Service のバックエンドを保護します。

IP アドレス指定と DNS の設定

  1. Cloud Shell で、Google Cloud ロードバランサのグローバル静的 IP を作成します。

    gcloud compute addresses create ingress-ip --global
    

    この静的 IP は Ingress リソースによって使用され、外部ロードバランサが変更されても、IP を同じままにできます。

  2. 静的 IP アドレスを取得します。

    export GCLB_IP=$(gcloud compute addresses describe ingress-ip --global --format=json | jq -r '.address')
    echo ${GCLB_IP}
    

    Ingress IP との安定した理解しやすいマッピングを作成するには、パブリック DNS レコードが必要です。任意の DNS プロバイダと自動化を使用できます。このチュートリアルでは、マネージド DNS ゾーンを作成する代わりに Endpoints を使用します。Endpoints は、パブリック IP 用に無料の Google 管理 DNS レコードを提供します。

  3. 次のコマンドを実行して、dns-spec.yaml という名前の YAML 仕様ファイルを作成します。

    cat <<EOF > dns-spec.yaml
    swagger: "2.0"
    info:
      description: "Cloud Endpoints DNS"
      title: "Cloud Endpoints DNS"
      version: "1.0.0"
    paths: {}
    host: "frontend.endpoints.${PROJECT}.cloud.goog"
    x-google-endpoints:
    - name: "frontend.endpoints.${PROJECT}.cloud.goog"
      target: "${GCLB_IP}"
    EOF
    

    YAML 仕様では、frontend.endpoints.${PROJECT}.cloud.goog の形式でパブリック DNS レコードが定義されます。${PROJECT} は一意のプロジェクト番号です。

  4. Cloud プロジェクトに dns-spec.yaml ファイルをデプロイします。

    gcloud endpoints services deploy dns-spec.yaml
    

    出力は次のようになります。

    Operation finished successfully. The following command can describe the Operation details:
     gcloud endpoints operations describe operations/rollouts.frontend.endpoints.edge2mesh.cloud.goog:442b2b38-4aee-4c60-b9fc-28731657ee08
    
    Service Configuration [2021-11-14r0] uploaded for service [frontend.endpoints.edge2mesh.cloud.goog]
    

    IP と DNS が構成されたので、Ingress フロントエンドを保護するための公開証明書を生成できます。GKE Ingress は Kubernetes リソースとして Google マネージド証明書をサポートしており、宣言型の方法でプロビジョニングできます。

TLS 証明書をプロビジョニングする

  1. Cloud Shell で次のコマンドを実行して、ManagedCertificate マニフェストを managed-cert.yaml として作成します。

    cat <<EOF > managed-cert.yaml
    apiVersion: networking.gke.io/v1
    kind: ManagedCertificate
    metadata:
      name: gke-ingress-cert
      namespace: asm-ingress
    spec:
      domains:
        - "frontend.endpoints.${PROJECT}.cloud.goog"
    EOF
    

    この YAML ファイルでは、Endpoints を通じて作成された DNS 名が公開証明書をプロビジョニングするように指定します。Google がこれらの公開証明書のライフサイクルを完全に管理するため、ユーザーの直接介入なしに、定期的に自動生成およびローテーションされます。

  2. GKE クラスタに managed-cert.yaml ファイルをデプロイします。

    kubectl apply -f managed-cert.yaml
    

    出力は次のようになります。

    managedcertificate.networking.gke.io/gke-ingress-cert created
    
  3. ManagedCertificate リソースを調べて、証明書の生成の進行状況を確認します。

    kubectl describe managedcertificate gke-ingress-cert -n asm-ingress
    

    出力は次のようになります。

    Name:         gke-ingress-cert
    Namespace:    asm-ingress
    Labels:       <none>
    Annotations:  kubectl.kubernetes.io/last-applied-configuration:
                    {"apiVersion":"networking.gke.io/v1","kind":"ManagedCertificate","metadata":{"annotations":{},"name":"gke-ingress-cert","namespace":"...
    API Version:  networking.gke.io/v1
    Kind:         ManagedCertificate
    Metadata:
      Creation Timestamp:  2020-08-05T20:44:49Z
      Generation:          2
      Resource Version:    1389781
      Self Link:           /apis/networking.gke.io/v1/namespaces/asm-ingress/managedcertificates/gke-ingress-cert
      UID:                 d74ec346-ced9-47a8-988a-6e6e9ddc4019
    Spec:
      Domains:
        frontend.endpoints.edge2mesh.cloud.goog
    Status:
      Certificate Name:    mcrt-306c779e-8439-408a-9634-163664ca6ced
      Certificate Status:  Provisioning
      Domain Status:
        Domain:  frontend.endpoints.edge2mesh.cloud.goog
        Status:  Provisioning
    Events:
      Type    Reason  Age   From                            Message
      ----    ------  ----  ----                            -------
      Normal  Create  44s   managed-certificate-controller  Create SslCertificate mcrt-306c779e-8439-408a-9634-163664ca6ced
    

    証明書の準備ができると、Certificate StatusActive になります。

Ingress リソースをデプロイする

  1. Cloud Shell で次のコマンドを実行して、Ingress マニフェストを ingress.yaml として作成します。

    cat <<EOF > ingress.yaml
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: gke-ingress
      namespace: asm-ingress
      annotations:
        kubernetes.io/ingress.allow-http: "false"
        kubernetes.io/ingress.global-static-ip-name: "ingress-ip"
        networking.gke.io/managed-certificates: "gke-ingress-cert"
        kubernetes.io/ingress.class: "gce"
    spec:
      defaultBackend:
        service:
          name: asm-ingressgateway
          port:
            number: 443
      rules:
      - http:
          paths:
          - path: /*
            pathType: ImplementationSpecific
            backend:
              service:
                name: asm-ingressgateway
                port:
                  number: 443
    EOF
    

    このマニフェストでは、上記のすべてのリソースを関連付ける Ingress リソースが定義されています。このマニフェストでは、次のフィールドを指定します。

    • kubernetes.io/ingress.allow-http: "false" は、Google Cloud ロードバランサのポート 80 で HTTP トラフィックを無効にします。ポート 443 は HTTPS をリッスンし、ポート 80 が無効になっているため、クライアントが暗号化されていないトラフィックに接続すると実質的に防止されます。
    • kubernetes.io/ingress.global-static-ip-name: "ingress-ip" は、以前に作成した IP アドレスをロードバランサにリンクします。このリンクを使用すると、IP アドレスをロードバランサとは別に作成でき、ロードバランサのライフサイクルとは別に再利用できます。
    • networking.gke.io/managed-certificates: "gke-ingress-cert" はこのロードバランサを、以前に Google が管理する SSL 証明書リソースにリンクします。
  2. クラスタに ingress.yaml をデプロイします。

    kubectl apply -f ingress.yaml
    
  3. Ingress リソースを調べて、ロードバランサのデプロイの進行状況を確認します。

    kubectl describe ingress gke-ingress -n asm-ingress
    

    出力は次のようになります。

    ...
    Annotations:
      ingress.kubernetes.io/https-forwarding-rule:       k8s2-fs-fq3ng2uk-asm-ingress-gke-ingress-qm3qqdor
      ingress.kubernetes.io/ssl-cert:                    mcrt-306c779e-8439-408a-9634-163664ca6ced
      networking.gke.io/managed-certificates:            gke-ingress-cert
      kubernetes.io/ingress.global-static-ip-name:  ingress-ip
      ingress.gcp.kubernetes.io/pre-shared-cert:    mcrt-306c779e-8439-408a-9634-163664ca6ced
      ingress.kubernetes.io/backends:               {"k8s-be-31610--07bdde06b914144a":"HEALTHY","k8s1-07bdde06-asm-ingress-asm-ingressgateway-443-228c1881":"HEALTHY"}
      ingress.kubernetes.io/forwarding-rule:        k8s2-fr-fq3ng2uk-asm-ingress-gke-ingress-qm3qqdor
      ingress.kubernetes.io/https-target-proxy:     k8s2-ts-fq3ng2uk-asm-ingress-gke-ingress-qm3qqdor
      ingress.kubernetes.io/target-proxy:           k8s2-tp-fq3ng2uk-asm-ingress-gke-ingress-qm3qqdor
      ingress.kubernetes.io/url-map:                k8s2-um-fq3ng2uk-asm-ingress-gke-ingress-qm3qqdor
    ...
    

    Ingress リソースは、ingress.kubernetes.io/backends アノテーションでバックエンドが HEALTHY と示されている場合に使用できます。アノテーションには、バックエンド サービス、SSL 証明書、HTTPS ターゲット プロキシなど、プロビジョニングされたさまざまな Google Cloud リソースの名前も表示されます。

自己署名 Ingress ゲートウェイ証明書をインストールする

次の手順では、GFE がサービス メッシュの Ingress ゲートウェイへの TLS 接続を確立できるようにする証明書を(Kubernetes secret リソースとして)生成し、インストールします。Ingress ゲートウェイ証明書の要件の詳細については、セキュア バックエンド プロトコルに関する検討事項ガイドをご覧ください。

  1. Cloud Shell で、openssl を使用して秘密鍵と証明書を作成します。

    openssl req -new -newkey rsa:4096 -days 365 -nodes -x509 \
     -subj "/CN=frontend.endpoints.${PROJECT}.cloud.goog/O=Edge2Mesh Inc" \
     -keyout frontend.endpoints.${PROJECT}.cloud.goog.key \
     -out frontend.endpoints.${PROJECT}.cloud.goog.crt
    
  2. asm-ingress 名前空間に Secret を作成します。

    kubectl -n asm-ingress create secret tls edge2mesh-credential \
     --key=frontend.endpoints.${PROJECT}.cloud.goog.key \
     --cert=frontend.endpoints.${PROJECT}.cloud.goog.crt
    

外部ロード バランシング用 Ingress ゲートウェイを構成する

次の手順では、asm-ingress Namespace に共有 Gateway リソースを作成します。ゲートウェイは通常、プラットフォーム管理者か、ネットワーク管理者チームが所有します。そのため、Gateway リソースは、プラットフォーム管理者が所有する asm-ingress Namespace に作成され、独自の VirtualService エントリを介して他の Namespace で使用できます。

  1. Cloud Shell で次のコマンドを実行して、Gateway マニフェストを ingress-gateway.yaml として作成します。

    cat <<EOF > ingress-gateway.yaml
    apiVersion: networking.istio.io/v1alpha3
    kind: Gateway
    metadata:
        name: asm-ingressgateway
        namespace: asm-ingress
    spec:
      selector:
        asm: ingressgateway
      servers:
      - port:
          number: 443
          name: https
          protocol: HTTPS
        hosts:
        - "*" # IMPORTANT: Must use wildcard here when using SSL, see note below
        tls:
          mode: SIMPLE
          credentialName: edge2mesh-credential
    EOF
    

    なお、Gatewayhosts フィールドには、ワイルドカード「*」のエントリを使用する必要があります。GCLB では、バックエンドへの SNI 拡張機能を使用しません。ワイルドカード エントリを使用すると、暗号化されたパケット(GCLB から)が ASM Ingress ゲートウェイに送信されます。ASM Ingress ゲートウェイでは、パケットを復号し、HTTP ホストヘッダー(復号されたパケット内)を使用して(VirtualService エントリに基づいて)ルーティングの判断を行います。

  2. クラスタに ingress-gateway.yaml をデプロイします。

    kubectl apply -f ingress-gateway.yaml
    

    出力は次のようになります。

    gateway.networking.istio.io/asm-ingressgateway created
    

Online Boutique サンプル アプリケーションをインストールする

  1. Cloud Shell で、専用の onlineboutique Namespace を作成します。

    kubectl create namespace onlineboutique
    
  2. onlineboutique Namespace に名前空間ラベルを追加します。

    export ASM_REVISION=$(kubectl get deploy -n istio-system \
        -l app=istiod \
        -o jsonpath={.items[*].metadata.labels.'istio\.io\/rev'}'{"\n"}')
    kubectl label namespace onlineboutique istio-injection- istio.io/rev=${ASM_REVISION} --overwrite
    

    出力は次のようになります。

    label "istio-injection" not found.
    namespace/onlineboutique labeled
    

    onlineboutique Namespace にラベルを付けると、アプリケーションのデプロイ時に Envoy サイドカー プロキシを自動挿入するよう Istio に指示します。ASM インストール ガイドで説明されているように、適用する istio.io/rev ラベルが、インストールした ASM のバージョンと一致していることを確認してください。

  3. Online Boutique のサンプルアプリの Kubernetes YAML ファイルをダウンロードします。

    curl -LO \
        https://raw.githubusercontent.com/GoogleCloudPlatform/microservices-demo/master/release/kubernetes-manifests.yaml
    
  4. Online Boutique アプリをデプロイします。

    kubectl apply -f kubernetes-manifests.yaml -n onlineboutique
    

    出力は次のようになります。

    deployment.apps/frontend created
    service/frontend created
    service/frontend-external created
    ...
    
  5. すべてのデプロイが稼働していることを確認します。

    kubectl get pods -n onlineboutique
    

    出力は次のようになります。

    NAME                                     READY   STATUS    RESTARTS   AGE
    adservice-d854d8786-fjb7q                2/2     Running   0          3m
    cartservice-85b5d5b4ff-8qn7g             2/2     Running   0          2m59s
    checkoutservice-5f9bf659b8-sxhsq         2/2     Running   0          3m1s
    ...
    
  6. 次のコマンドを実行して、VirtualService マニフェストを frontend-virtualservice.yaml として作成します。

    cat <<EOF > frontend-virtualservice.yaml
    apiVersion: networking.istio.io/v1alpha3
    kind: VirtualService
    metadata:
      name: frontend-ingress
      namespace: onlineboutique
    spec:
      hosts:
      - "frontend.endpoints.${PROJECT}.cloud.goog"
      gateways:
      - asm-ingress/asm-ingressgateway
      http:
      - route:
        - destination:
            host: frontend
            port:
              number: 80
    EOF
    

    なお、VirtualService は、アプリケーションの Namespace(onlineboutique)に作成されることに注意してください。通常、アプリケーション オーナーは、frontend アプリケーションにルーティングするトラフィックとその方法を決定して構成し、VirtualService がアプリケーション オーナーによってデプロイされるようにします。

  7. クラスタに frontend-virtualservice.yaml をデプロイします。

    kubectl apply -f frontend-virtualservice.yaml
    

    出力は次のようになります。

    virtualservice.networking.istio.io/frontend-virtualservice created
    
  8. 次のリンクにアクセスします。

    echo "https://frontend.endpoints.${PROJECT}.cloud.goog"
    

    Online Boutique のフロントエンドが表示されます。

    Online Boutique のホームページに表示される商品。

  9. 証明書の詳細を表示するには、ブラウザのアドレスバーの [サイト情報を表示]、[Certificate (Valid)] の順にクリックします。

    証明書ビューアには、証明書の有効期限や証明書の発行者など、マネージド証明書の詳細が表示されます。

これで、サービス メッシュでホストされるアプリケーションのフロントエンドとして機能するグローバル HTTPS ロードバランサが作成されました。

クリーンアップ

チュートリアルが完了したら、Google Cloud で作成したリソースをクリーンアップして、今後料金が発生しないようにします。プロジェクトを完全に削除するか、クラスタ リソースを削除してからクラスタを削除できます。

プロジェクトの削除

  1. Cloud Console で [リソースの管理] ページに移動します。

    [リソースの管理] に移動

  2. プロジェクト リストで、削除するプロジェクトを選択し、[削除] をクリックします。
  3. ダイアログでプロジェクト ID を入力し、[シャットダウン] をクリックしてプロジェクトを削除します。

個々のリソースの削除

このチュートリアルで使用した Cloud プロジェクトを残しておく場合は、個々のリソースを削除します。

  1. Ingress リソースを削除します。

    kubectl delete -f ingress.yaml
    
  2. マネージド証明書を削除します。

    kubectl delete -f managed-cert.yaml
    
  3. Endpoints DNS エントリを削除します。

    gcloud endpoints services delete "frontend.endpoints.${PROJECT}.cloud.goog"
    

    出力は次のようになります。

    Are you sure? This will set the service configuration to be deleted, along
    with all of the associated consumer information. Note: This does not
    immediately delete the service configuration or data and can be undone using
    the undelete command for 30 days. Only after 30 days will the service be
    purged from the system.
    
  4. 続行を確認するメッセージが表示されたら、「Y」と入力します。

    出力は次のようになります。

    Waiting for async operation operations/services.frontend.endpoints.edge2mesh.cloud.goog-5 to complete...
    Operation finished successfully. The following command can describe the Operation details:
     gcloud endpoints operations describe operations/services.frontend.endpoints.edge2mesh.cloud.goog-5
    
  5. 静的 IP アドレスを削除します。

    gcloud compute addresses delete ingress-ip --global
    

    出力は次のようになります。

    The following global addresses will be deleted:
    
     - [ingress-ip]
    
  6. 続行を確認するメッセージが表示されたら、「Y」と入力します。

    出力は次のようになります。

    Deleted
    [https://www.googleapis.com/compute/v1/projects/edge2mesh/global/addresses/ingress-ip].
    
  7. GKE クラスタを削除します。

    gcloud container clusters delete $CLUSTER_NAME --zone $CLUSTER_LOCATION
    

次のステップ