外部トラフィック向けKubernetesサービス

KubernetesのExternalNameサービスと、エンドポイントを持つKubernetesサービスを使用すると、外部サービスへのローカルDNS *エイリアス*を作成できます。このDNSエイリアスは、ローカルサービスのDNSエントリと同じ形式を持ちます。つまり、`<サービス名>.<名前空間名>.svc.cluster.local`です。DNSエイリアスは、ワークロードに*場所の透過性*を提供します。ワークロードは、ローカルサービスと外部サービスを同じ方法で呼び出すことができます。ある時点で外部サービスをクラスタ内にデプロイすることにした場合、そのKubernetesサービスをローカルバージョンを参照するように更新するだけで済みます。ワークロードは変更なしで動作を続けます。

このタスクは、外部サービスへのアクセスのためのこれらのKubernetesメカニズムがIstioでも引き続き機能することを示しています。実行する必要がある唯一の設定手順は、Istioの相互TLS以外のTLSモードを使用することです。外部サービスはIstioサービスメッシュの一部ではないため、Istioの相互TLSを実行できません。外部サービスのTLS要件と、ワークロードが外部サービスにアクセスする方法に応じて、TLSモードを設定する必要があります。ワークロードがプレーンHTTPリクエストを発行し、外部サービスがTLSを要求する場合は、IstioによるTLS発信を実行することを検討してください。ワークロードが既にTLSを使用している場合、トラフィックは既に暗号化されているため、Istioの相互TLSを無効にするだけです。

このタスクの例ではHTTPプロトコルを使用していますが、外部トラフィックのKubernetesサービスは他のプロトコルでも機能します。

開始前に

  • インストールガイドの手順に従ってIstioをセットアップします。

  • リクエストを送信するためのテストソースとして使用するために、curlサンプルアプリをデプロイします。自動サイドカーインジェクションを有効にしている場合は、次のコマンドを実行してサンプルアプリをデプロイします。

    Zip
    $ kubectl apply -f @samples/curl/curl.yaml@
    

    それ以外の場合は、次のコマンドを使用してサイドカーを手動で挿入してから、curlアプリケーションをデプロイします。

    Zip
    $ kubectl apply -f <(istioctl kube-inject -f @samples/curl/curl.yaml@)
    
  • ソースポッドの名前を格納するために、SOURCE_POD環境変数を設定します。

    $ export SOURCE_POD=$(kubectl get pod -l app=curl -o jsonpath={.items..metadata.name})
    
  • Istioの制御を受けないソースポッドの名前空間を作成します。

    $ kubectl create namespace without-istio
    
  • without-istio名前空間にcurlサンプルを起動します。

    Zip
    $ kubectl apply -f @samples/curl/curl.yaml@ -n without-istio
    
  • リクエストを送信するには、ソースポッドの名前を格納するためにSOURCE_POD_WITHOUT_ISTIO環境変数を作成します。

    $ export SOURCE_POD_WITHOUT_ISTIO="$(kubectl get pod -n without-istio -l app=curl -o jsonpath={.items..metadata.name})"
    
  • Istioサイドカーが挿入されていないこと、つまりポッドにコンテナが1つしかないことを確認します。

    $ kubectl get pod "$SOURCE_POD_WITHOUT_ISTIO" -n without-istio
    NAME                     READY   STATUS    RESTARTS   AGE
    curl-66c8d79ff5-8tqrl    1/1     Running   0          32s
    

外部サービスへのアクセスのためのKubernetes ExternalNameサービス

  1. デフォルトの名前空間に、httpbin.orgのKubernetes ExternalNameサービスを作成します。

    $ kubectl apply -f - <<EOF
    kind: Service
    apiVersion: v1
    metadata:
      name: my-httpbin
    spec:
      type: ExternalName
      externalName: httpbin.org
      ports:
      - name: http
        protocol: TCP
        port: 80
    EOF
    
  2. サービスを観察します。クラスタIPがないことに注意してください。

    $ kubectl get svc my-httpbin
    NAME         TYPE           CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
    my-httpbin   ExternalName   <none>       httpbin.org   80/TCP    4s
    
  3. Istioサイドカーのないソースポッドから、Kubernetesサービスのホスト名を使用してhttpbin.orgにアクセスします。Kubernetesのサービスに関するDNS形式、つまり`<サービス名>.<名前空間>.svc.cluster.local`を使用していることに注意してください。

    $ kubectl exec "$SOURCE_POD_WITHOUT_ISTIO" -n without-istio -c curl -- curl -sS my-httpbin.default.svc.cluster.local/headers
    {
      "headers": {
        "Accept": "*/*",
        "Host": "my-httpbin.default.svc.cluster.local",
        "User-Agent": "curl/7.55.0"
      }
    }
    
  4. この例では、暗号化されていないHTTPリクエストがhttpbin.orgに送信されます。例のためだけに、TLSモードを無効にし、外部サービスへの暗号化されていないトラフィックを許可します。現実的なシナリオでは、Istioによる外部TLS発信を実行することをお勧めします。

    $ kubectl apply -f - <<EOF
    apiVersion: networking.istio.io/v1
    kind: DestinationRule
    metadata:
      name: my-httpbin
    spec:
      host: my-httpbin.default.svc.cluster.local
      trafficPolicy:
        tls:
          mode: DISABLE
    EOF
    
  5. Istioサイドカーのあるソースポッドから、Kubernetesサービスのホスト名を使用してhttpbin.orgにアクセスします。Istioサイドカーによって追加されたヘッダー(例:X-Envoy-Peer-Metadata)に注意してください。また、Hostヘッダーがサービスのホスト名と等しいことにも注意してください。

    $ kubectl exec "$SOURCE_POD" -c curl -- curl -sS my-httpbin.default.svc.cluster.local/headers
    {
      "headers": {
        "Accept": "*/*",
        "Content-Length": "0",
        "Host": "my-httpbin.default.svc.cluster.local",
        "User-Agent": "curl/7.64.0",
        "X-B3-Sampled": "0",
        "X-B3-Spanid": "5795fab599dca0b8",
        "X-B3-Traceid": "5079ad3a4af418915795fab599dca0b8",
        "X-Envoy-Peer-Metadata": "...",
        "X-Envoy-Peer-Metadata-Id": "sidecar~10.28.1.74~curl-6bdb595bcb-drr45.default~default.svc.cluster.local"
      }
    }
    

Kubernetes ExternalNameサービスのクリーンアップ

$ kubectl delete destinationrule my-httpbin
$ kubectl delete service my-httpbin

エンドポイントを持つKubernetesサービスを使用して外部サービスにアクセスする

  1. セレクタのないWikipediaのKubernetesサービスを作成します。

    $ kubectl apply -f - <<EOF
    kind: Service
    apiVersion: v1
    metadata:
      name: my-wikipedia
    spec:
      ports:
      - protocol: TCP
        port: 443
        name: tls
    EOF
    
  2. サービスのエンドポイントを作成します。WikipediaのIPアドレス範囲リストからいくつかのIPを選択します。

    $ kubectl apply -f - <<EOF
    kind: Endpoints
    apiVersion: v1
    metadata:
      name: my-wikipedia
    subsets:
      - addresses:
          - ip: 198.35.26.96
          - ip: 208.80.153.224
        ports:
          - port: 443
            name: tls
    EOF
    
  3. サービスを観察します。wikipedia.orgにアクセスするために使用できるクラスタIPがあることに注意してください。

    $ kubectl get svc my-wikipedia
    NAME           TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
    my-wikipedia   ClusterIP   172.21.156.230   <none>        443/TCP   21h
    
  4. Istioサイドカーのないソースポッドから、KubernetesサービスのクラスタIPを使用してwikipedia.orgにHTTPSリクエストを送信します。curl--resolveオプションを使用して、クラスタIPでwikipedia.orgにアクセスします。

    $ kubectl exec "$SOURCE_POD_WITHOUT_ISTIO" -n without-istio -c curl -- curl -sS --resolve en.wikipedia.org:443:"$(kubectl get service my-wikipedia -o jsonpath='{.spec.clusterIP}')" https://en.wikipedia.org/wiki/Main_Page | grep -o "<title>.*</title>"
    <title>Wikipedia, the free encyclopedia</title>
    
  5. この場合、ワークロードはwikipedia.orgにHTTPSリクエスト(オープンTLS接続)を送信します。トラフィックはワークロードによって既に暗号化されているため、Istioの相互TLSを安全に無効にすることができます。

    $ kubectl apply -f - <<EOF
    apiVersion: networking.istio.io/v1
    kind: DestinationRule
    metadata:
      name: my-wikipedia
    spec:
      host: my-wikipedia.default.svc.cluster.local
      trafficPolicy:
        tls:
          mode: DISABLE
    EOF
    
  6. Istioサイドカーのあるソースポッドから、KubernetesサービスのクラスタIPを使用してwikipedia.orgにアクセスします。

    $ kubectl exec "$SOURCE_POD" -c curl -- curl -sS --resolve en.wikipedia.org:443:"$(kubectl get service my-wikipedia -o jsonpath='{.spec.clusterIP}')" https://en.wikipedia.org/wiki/Main_Page | grep -o "<title>.*</title>"
    <title>Wikipedia, the free encyclopedia</title>
    
  7. アクセスが実際にクラスタIPによって実行されていることを確認します。curl -vの出力に「Connected to en.wikipedia.org (172.21.156.230)」という文があることに注意してください。これは、サービスの出力にクラスタIPとして表示されたIPが言及されています。

    $ kubectl exec "$SOURCE_POD" -c curl -- curl -sS -v --resolve en.wikipedia.org:443:"$(kubectl get service my-wikipedia -o jsonpath='{.spec.clusterIP}')" https://en.wikipedia.org/wiki/Main_Page -o /dev/null
    * Added en.wikipedia.org:443:172.21.156.230 to DNS cache
    * Hostname en.wikipedia.org was found in DNS cache
    *   Trying 172.21.156.230...
    * TCP_NODELAY set
    * Connected to en.wikipedia.org (172.21.156.230) port 443 (#0)
    ...
    

エンドポイントを持つKubernetesサービスのクリーンアップ

$ kubectl delete destinationrule my-wikipedia
$ kubectl delete endpoints my-wikipedia
$ kubectl delete service my-wikipedia

クリーンアップ

  1. curlサービスをシャットダウンします。

    Zip
    $ kubectl delete -f @samples/curl/curl.yaml@
    
  2. without-istio名前空間内のcurlサービスをシャットダウンします。

    Zip
    $ kubectl delete -f @samples/curl/curl.yaml@ -n without-istio
    
  3. without-istio名前空間を削除します。

    $ kubectl delete namespace without-istio
    
  4. 環境変数をアンセットします。

    $ unset SOURCE_POD SOURCE_POD_WITHOUT_ISTIO
    
この情報は役に立ちましたか?
改善のための提案はありますか?

ご意見ありがとうございます!