Service と Ingress を作成する

このドキュメントでは、Google Distributed Cloud のユーザー、ハイブリッド、またはスタンドアロン クラスタで Kubernetes Ingress オブジェクトを作成する方法について説明します。1 つの Ingress は 1 つ以上の Service オブジェクトに関連付けられます。それぞれの Service オブジェクトは、Pod のセットに関連付けられます。

Deployment を作成する

Deployment のマニフェストを次に示します。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-deployment
spec:
  selector:
    matchLabels:
      greeting: hello
  replicas: 3
  template:
    metadata:
      labels:
        greeting: hello
    spec:
      containers:
      - name: hello-world
        image: "gcr.io/google-samples/hello-app:2.0"
        env:
        - name: "PORT"
          value: "50000"
      - name: hello-kubernetes
        image: "gcr.io/google-samples/node-hello:1.0"
        env:
        - name: "PORT"
          value: "8080"

この演習を進めるにあたって、この Deployment のマニフェストについて次のことを理解しておくことが重要です。

  • Deployment に属する各 Pod には greeting: hello ラベルが付いています。

  • 各 Pod には 2 つのコンテナがあります。

  • env フィールドは、hello-app コンテナは TCP ポート 50000 でリッスンし、node-hello コンテナは TCP ポート 8080 でリッスンするように指定します。hello-app の場合、ソースコードを見ると PORT 環境変数の効果がわかります。

このマニフェストを hello-deployment.yaml という名前のファイルにコピーして Deployment を作成します。

kubectl apply --kubeconfig CLUSTER_KUBECONFIG -f hello-deployment.yaml

CLUSTER_KUBECONFIG は、クラスタの kubeconfig ファイルの名前に置き換えます。

Service を使用して Deployment を公開する

クライアントが Deployment の Pod にリクエストを安定して送信するには、Service を作成します。

Deployment をクラスタ内のクライアントに公開する Service のマニフェストは次のとおりです。

apiVersion: v1
kind: Service
metadata:
  name: hello-service
spec:
  type: ClusterIP
  selector:
    greeting: hello
  ports:
  - name: world-port
    protocol: TCP
    port: 60000
    targetPort: 50000
  - name: kubernetes-port
    protocol: TCP
    port: 60001
    targetPort: 8080

マニフェストを hello-service.yaml という名前のファイルにコピーして、Service を作成します。

kubectl apply --kubeconfig CLUSTER_KUBECONFIG -f hello-service.yaml

CLUSTER_KUBECONFIG は、クラスタの kubeconfig ファイルの名前に置き換えます。

Service を表示します。

kubectl --kubeconfig CLUSTER_KUBECONFIG get service hello-service --output yaml

出力には、Service に対して指定された clusterIP の値が表示されます。例:

apiVersion: v1
kind: Service
metadata:
  annotations:
    ...
spec:
  clusterIP: 10.96.14.249
  clusterIPs:
  - 10.96.14.249
  ipFamilies:
  - IPv4
  ipFamilyPolicy: SingleStack
  ports:
  - name: world-port
    port: 60000
    protocol: TCP
    targetPort: 50000
  - name: kubernetes-port
    port: 60001
    protocol: TCP
    targetPort: 8080
  selector:
    greeting: hello
  sessionAffinity: None
  type: ClusterIP
status:
  loadBalancer: {}

上述の出力では、ports フィールドは ServicePort オブジェクトの配列であり、1 つは world-port、もう 1 つは kubernetes-port という名前です。Service フィールドの詳細については、Kubernetes ドキュメントの ServiceSpec をご覧ください。

クライアントが Service を呼び出す方法は次のとおりです。

  • world-port の使用: クラスタノードのいずれかで実行されているクライアントが、portclusterIP にリクエストを送信します。この例では、10.96.14.249:60000 です。リクエストは、targetPort 上のメンバー Pod に転送されます。この例では、POD_IP_ADDRESS:50000 です。

  • kubernetes-port の使用: クラスタノードのいずれかで実行されているクライアントが、portclusterIP にリクエストを送信します。この例では、10.96.14.249:60001 です。リクエストは、targetPort 上のメンバー Pod に転送されます。この例では、POD_IP_ADDRESS:8080 です。

Ingress コンポーネント

Ingress に関連する一部のクラスタ コンポーネントは次のとおりです。

  • istio-ingress Deployment。これは上り(内向き)プロキシです。上り(内向き)プロキシは、Ingress オブジェクトで指定されたルールに従ってトラフィックを内部 Service に転送します。

  • istio-ingress Service。この Service は、istio-ingress Deployment を公開します。

  • istiod Deployment。これは上り(内向き)コントローラです。上り(内向き)コントローラは、Ingress オブジェクトの作成を監視し、それに応じて Ingress プロキシを構成します。

これらのクラスタ内 Istio コンポーネントはすべて、gke-system Namespace にインストールされます。この Namespace は、Istio / Cloud Service Mesh の完全なインストールと競合しません。

Ingress を作成する

Ingress のマニフェストを次に示します。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
spec:
  rules:
  - http:
      paths:
      - path: /greet-the-world
        pathType: Exact
        backend:
          service:
            name: hello-service
            port:
              number: 60000
      - path: /greet-kubernetes
        pathType: Exact
        backend:
          service:
            name: hello-service
            port:
              number: 60001

このマニフェストを my-ingress.yaml という名前のファイルにコピーし、次のようにして Ingress を作成します。

kubectl apply --kubeconfig CLUSTER_KUBECONFIG -f my-ingress.yaml

ユーザー クラスタを作成する場合は、クラスタ構成ファイルで loadbalancer.ingressVIP の値を指定します。この IP アドレスは、クラスタ ロードバランサ上に構成されます。Ingress を作成すると、Ingress には、その外部 IP アドレスと同じ VIP が付与されます。

クライアントがユーザー クラスタの上り(内向き)VIP にリクエストを送信すると、そのリクエストはロードバランサに転送されます。ロードバランサは、istio-ingress Service を使用してユーザー クラスタで実行される Ingress プロキシにリクエストを転送します。Ingress プロキシは、リクエスト URL のパスに応じて、異なるバックエンドにリクエストを転送するように構成されています。

/greet-the-world パス

Ingress マニフェストで、パス /greet-the-worldserviceName: hello-serviceservicePort: 60000 に関連付けられていることを示すルールを確認できます。hello-service Service の world-port セクションの port 値が 60000 であることを思い出してください。

- name: world-port
    port: 60000
    protocol: TCP
    targetPort: 50000

Ingress サービスが、リクエストを clusterIP:50000 に転送します。その後、リクエストは、hello-service Service のメンバー Pod のいずれかに送信されます。送信された Pod 内のポート 50000 でリッスンするコンテナに、Hello World! メッセージが表示されます。

/greet-kubernetes パス

Ingress マニフェストで、パス /greet-kubernetesserviceName: hello-serviceservicePort: 60001 に関連付けられていることを示すルールを確認できます。hello-service Service の kubernetes-port セクションの port 値が 60001 であることを思い出してください。

- name: kubernetes-port
    port: 60001
    protocol: TCP
    targetPort: 8080

Ingress サービスはリクエストを clusterIP: 8080 に転送します。その後、リクエストは、hello-service Service のメンバー Pod のいずれかに送信されます。送信された Pod 内のポート 8080 でリッスンするコンテナに、Hello Kubernetes! メッセージが表示されます。

Ingress をテストする

/greet-the-world パスを使用して Ingress をテストします。

curl CLUSTER_INGRESS_VIP/greet-the-world

CLUSTER_INGRESS_VIP は、Ingress の外部 IP アドレスに置き換えます。

出力には、Hello, world! メッセージが表示されます。

Hello, world!
Version: 2.0.0
Hostname: ...

/greet-kubernetes パスを使用して Ingress をテストします。

curl CLUSTER_INGRESS_VIP/greet-kubernetes

出力には、Hello, Kubernetes! メッセージが表示されます。

Hello Kubernetes!

バンドルされた Ingress を無効にする

Google Distributed Cloud にバンドルされた Ingress 機能は上り(内向き)機能のみをサポートしています。Istio または Cloud Service Mesh と統合することも選択できます。これらのプロダクトには、相互 TLS(mTLS)、サービス間の認証を管理する機能、ワークロードのオブザーバビリティなど、完全に機能するサービス メッシュの追加の利点があります。Istio または Cloud Service Mesh と統合する場合は、バンドルされた Ingress 機能を無効にすることをおすすめします。

バンドルされた Ingress を有効または無効にするには、クラスタ構成ファイルの spec.clusterNetwork.bundledIngress フィールドを使用します。このフィールドは、バージョン 1.13.0 以降のクラスタでのみ使用できます。bundledIngress フィールドはデフォルトで true になり、生成されたクラスタ構成ファイルには存在しません。このフィールドは可変で、バージョン 1.13.0 以降のクラスタを作成または更新するときに変更できます。このフィールドは、クラスタをバージョン 1.13.0 以降にアップグレードするときにも指定できます。

次のクラスタ構成ファイルのサンプルは、バンドルされた Ingress 機能を無効にするようにクラスタを構成する方法を示しています。

apiVersion: v1
kind: Namespace
metadata:
  name: cluster-hybrid-basic
---
apiVersion: baremetal.cluster.gke.io/v1
kind: Cluster
metadata:
  name: hybrid-basic
  namespace: cluster-hybrid-basic
spec:
  type: hybrid
  profile: default
  anthosBareMetalVersion: 1.13.0
  gkeConnect:
    projectID: project-fleet
  controlPlane:
    nodePoolSpec:
      nodes:
      - address: 10.200.0.2
  clusterNetwork:
    bundledIngress: false
    pods:
      cidrBlocks:
      - 192.168.0.0/16
    services:
      cidrBlocks:
      - 10.96.0.0/20
...

Ingress 用に HTTPS を設定する

クライアントからの HTTPS リクエストを受け入れるには、Ingress プロキシは証明書を持っていなければなりません。これにより、適切な送信先であることをクライアントに示すことができます。このプロキシには、HTTPS handshake を実行するための秘密鍵も必要です。

以下の例では、次のエンティティを使用します。

  • Ingress プロキシ: HTTPS handshake に加わり、パケットを hello-service Service のメンバー Pod に転送します。

  • hello-service Service のドメイン: Example Org の altostrat.com

手順は次のとおりです。

  1. ルート証明書と秘密鍵を作成します。この例では、Root CA Example Org の root.ca.example.com のルート認証局を使用します。

    openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj \
        '/O=Root CA Example Inc./CN=root.ca.example.com' -keyout root-ca.key \
        -out root-ca.crt
    
  2. 証明書署名リクエストを作成します。

     openssl req -out server.csr -newkey rsa:2048 -nodes -keyout server.key -subj \
         "/CN=altostrat.com/O=Example Org"
    
  3. Ingress プロキシのサービス証明書を作成します。

    openssl x509 -req -days 365 -CA root-ca.crt -CAkey root-ca.key -set_serial 0 \
        -in server.csr -out server.crt
    

    これで、次の証明書と鍵が作成されました。

    • root-ca.crt: ルート CA の証明書
    • root-ca.key: ルート CA の秘密鍵
    • server.crt: Ingress プロキシの証明書を提供
    • server.key: Ingress プロキシの秘密鍵
  4. サービス提供側の証明書と鍵を保持する Kubernetes Secret を作成します。

    kubectl create secret tls example-server-creds --key=server.key --cert=server.crt \
        --namespace gke-system
    

    生成された Secret の名前は example-server-creds です。

Deployment と Service を作成する

このガイドの HTTP 部分で Deployment と Service を作成した場合は、そのままにしておきます。作成していない場合は、HTTP 用の手順に沿って作成します。

Ingress を作成する

HTTP の部分で Ingress をすでに作成している場合は、その Ingress を削除して続行します。

Ingress を削除します。

kubectl --kubeconfig CLUSTER_KUBECONFIG delete ingress my-ingress

以前に作成した Service のトラフィックを処理するには、tls セクションを持つ新しい Ingress を作成します。これにより、クライアントと上り(内向き)プロキシ間の HTTPS が有効になります。

Ingress のマニフェストを次に示します。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress-2
spec:
  tls:
  - hosts:
    - altostrat.com
    secretName: example-server-creds
  rules:
  - host: altostrat.com
    http:
      paths:
      - path: /greet-the-world
        pathType: Exact
        backend:
          service:
            name: hello-service
            port:
              number: 60000
      - path: /greet-kubernetes
        pathType: Exact
        backend:
          service:
            name: hello-service
            port:
              number: 60001

このマニフェストを my-ingress-2.yaml という名前のファイルに保存して、Ingress を作成します。

kubectl apply --kubeconfig CLUSTER_KUBECONFIG -f my-ingress-2.yaml

テストして確認します。

  • /greet-the-world パスをテストします。

    curl -v --resolve altostrat.com:443:CLUSTER_INGRESS_VIP\
        https://altostrat.com/greet-the-world \
        --cacert root-ca.crt
    

    出力:

    Hello, world!
    Version: 2.0.0
    Hostname: hello-deployment-5ff7f68854-wqzp7
    
  • /greet-kubernetes パスをテストします。

    curl -v --resolve altostrat.com:443:CLUSTER_INGRESS_VIP \
        https://altostrat.com/greet-kubernetes --cacert root-ca.crt
    

    出力:

    Hello Kubernetes!
    

LoadBalancer Service を作成する

LoadBalancer タイプの Service は、クラスタ外部にワークロードを公開する別の方法です。LoadBalancer タイプの Service を作成する手順と例については、アプリケーションのデプロイの LoadBalancer タイプの Service の作成をご覧ください。

クリーンアップ

Ingress を削除します。

kubectl --kubeconfig CLUSTER_KUBECONFIG delete ingress INGRESS_NAME

INGRESS_NAME は、Ingress の名前(my-ingressmy-ingress-2 など)に置き換えます。

Service を削除します。

kubectl --kubeconfig CLUSTER_KUBECONFIG delete service hello-service

Deployment を削除します。

kubectl --kubeconfig CLUSTER_KUBECONFIG delete deployment hello-deployment

LoadBalancer Service を削除します。

kubectl --kubeconfig CLUSTER_KUBECONFIG delete service service-does-not-use-nodeports