目次


IBM Cloud Kubernetes Service 上で Ambassador API ゲートウェイを実行する

Kubernetes クラスター内でトラフィックを転送およびフィルタリングする方法を学ぶ

Comments

Ambassador は、Envoy 上に構築された Kubernetes ネイティブの API ゲートウェイ・テクノロジーです。このチュートリアルでは、Ambassador をセットアップし、そこに IBM Cloud Kubernetes Service (IKS) を統合した後、Ambassador の使用例を簡単に説明します。使用方法と構成に関する詳細は、Ambassador Web サイト上の信頼できるドキュメントを参照してください。

Ambassador の役割は、Kubernetes クラスター内に入ってくるトラフィックを転送およびフィルタリングすることです。Web リクエストは Ambassador を経由して Kubernetes 内の正しいバックエンド・デプロイメントに転送されます。つまり、Ambassador が LoadBalancer の外部 IP を引き継ぎます。このようなトラフィック処理を行うソフトウェアは、Kubernetes Ingress、IKS Application Load Balancer (ALB)、Istio-ingressgateway をはじめ、他にも数多くあります。クラスター・スタックのこの部分では、業界がこの分野での開発を繰り返す中で、多くのイノベーションが生まれているのです。

他のツールとの簡単な比較

Ambassador と Istio-ingressgateway は両方とも Envoy (https://www.envoyproxy.io/) を採用しています。一方、IKS ALB は Nginx を採用し、その構成には Kubernetes Ingress が使用されます。Kubernetes Ingress は単なる API に過ぎませんが、デフォルトの実装は Nginx に基づきます。ほとんどの場合、いずれのツールを使用するのでも一般的なエッジ・ロード・バランサーの処理 (書き換え、SSL ターミネーション/アップグレード、ヘッダー管理、トラフィック分割など) を行うことができます。Ambassador と istio-ingressgateway は Envoy を使用することから、gRPC のサポートが強化されますが、これらのツールの間での真の違いは構成の柔軟性と表現力にあります。Ingress 構成の大部分は API レイヤー (Kubernetes 内のアップストリーム) から抜け切れていないので、一般的なアクションのほとんど (書き換えなど) はベンダー固有の拡張機能として行われます。Istio-ingressgateway は gateway という名前の CRD を使用して構成を提供します。一方、この後わかるように Ambassador は Kubernetes サービス上で yaml を直接アノテーションに埋め込み、その yaml を外部公開用として識別して構成を提供します。

インストールと構成

Ambassador Web サイト上にある公式のクイック・スタートは、IKS 上で非常に役立つガイドです。このチュートリアルでは基本的な機能にとどまらずに、Ambassador にさらに IKS 自動 DNS 名と自動 Let's Encrypt SSL 証明書を統合します。このチュートリアルの前に Ambassador をインストールした場合は、必ず完全にアンインストールしてから手順を開始してください。

  1. ソース・コードを取得します。
    $ git clone https://gitlab.com/nibalizer/ambassador-iks
    $ cd ambassador-iks
  2. Ambassador の yaml 構成を適用します。
    $ kubectl apply -f ambassador-rbac.yaml
    service/ambassador-admin created
    clusterrole.rbac.authorization.k8s.io/ambassador created
    serviceaccount/ambassador created
    clusterrolebinding.rbac.authorization.k8s.io/ambassador created
      deployment.extensions/ambassador created

    これにより、サービス、ClusterRole、ServiceAccount、 ClusterRoleBinding、デプロイメントが作成されます。ClusterRole と ClusterRoleBinding には名前空間がありませんが、他のリソースは kube-system 名前空間内に作成されます。名前空間によって、リソースが分離されるとともに、既存の IKS 構成と統合しやすくなります。
  3. デーモンが起動していることを確認します。ポッドが Status: Running になっていれば、起動していることになります。
    $ kubectl -n kube-system get pod -l service=ambassador
    NAME                         READY   STATUS    RESTARTS   AGE
    ambassador-f6b9b96cc-49854   1/1     Running   0          4h8m
    ambassador-f6b9b96cc-5t2bl   1/1     Running   0          4h8m
    ambassador-f6b9b96cc-9jw4f   1/1     Running   0          4h8m
  4. Ambassador のデプロイメントの内容を調べます (簡潔明瞭にするために、出力を一部削除しています)。
    $ kubectl -n kube-system get -o yaml deploy/ambassador
    yaml
    apiVersion: extensions/v1beta1
    kind: Deployment
    metadata:
      annotations:
        deployment.kubernetes.io/revision: "2"
      creationTimestamp: "2019-03-27T16:26:10Z"
      generation: 2
      labels:
        service: ambassador
      name: ambassador
      namespace: kube-system
      resourceVersion: "56509"
      selfLink:/apis/extensions/v1beta1/namespaces/kube-system/deployments/ambassador
      uid: 08058fd9-50ad-11e9-851d-da993851ee33
    spec:
      progressDeadlineSeconds: 2147483647
      replicas: 3
      revisionHistoryLimit: 10
      selector:
        matchLabels:
          service: ambassador
      strategy:
        rollingUpdate:
          maxSurge: 1
          maxUnavailable: 1
        type: RollingUpdate
      template:
        metadata:
          annotations:
            consul.hashicorp.com/connect-inject: "false"
            sidecar.istio.io/inject: "false"
          creationTimestamp: null
          labels:
            service: ambassador
        spec:
          containers:
          - env:
              - name: AMBASSADOR_NAMESPACE
              value: default
            image: quay.io/datawire/ambassador:0.51.2
            imagePullPolicy: IfNotPresent
            livenessProbe:
              failureThreshold: 3
              httpGet:
                path:/ambassador/v0/check_alive
                port: 8877
                scheme: HTTP
              initialDelaySeconds: 30
              periodSeconds: 3
              successThreshold: 1
              timeoutSeconds: 1
            name: ambassador
            ports:
            - containerPort: 80
              name: http
              protocol: TCP
            - containerPort: 443
              name: https
              protocol: TCP
            - containerPort: 8877
              name: admin
              protocol: TCP
            readinessProbe:
              failureThreshold: 3
              httpGet:
                path:/ambassador/v0/check_ready
                port: 8877
                scheme: HTTP
              initialDelaySeconds: 30
              periodSeconds: 3
              successThreshold: 1
              timeoutSeconds: 1
            resources:
              limits:
                cpu: "1"
                memory: 400Mi
              requests:
                cpu: 200m
                memory: 100Mi
            terminationMessagePath:/dev/termination-log
            terminationMessagePolicy: File
          dnsPolicy: ClusterFirst
          restartPolicy: Always
          schedulerName: default-scheduler
          securityContext: {}
          serviceAccount: ambassador
          serviceAccountName: ambassador
    status:
      availableReplicas: 3
      conditions:
      readyReplicas: 3
      replicas: 3
      updatedReplicas: 3

    まず注目すべき点は、名前空間とラベルです。このデプロイメントは kube-system 名前空間内で実行されいて、service: ambassador というラベルが付けられています。
    metadata:
      generation: 2
      labels:
        service: ambassador
      name: ambassador
      namespace: kube-system

    次に注目すべき点は、スキャン対象の Ambassador の名前空間をデフォルトの名前空間に設定していることです。別の名前空間内でアプリを実行する必要がある場合は、その名前空間でデフォルト名前空間を置き換えて構成します。
    - env:
      - name: AMBASSADOR_NAMESPACE
        value: default

    最後に指摘する点として、サービス・アカウントの構成もこの出力で確認できます。Ambassador はこのサービス・アカウントを使用して Kubernetes API に接続し、サービスとその他のオブジェクトの変更を監視します。
    serviceAccount: ambassador
    serviceAccountName: ambassador

    ClusterRoleBinding の内容と、さらに重要なことに ClusterRole の内容も調べることができます。
    $ kubectl get ClusterRole/ambassador -o yaml
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
      annotations:
      creationTimestamp: "2019-03-27T16:26:10Z"
      name: ambassador
      resourceVersion: "52692"
      selfLink:/apis/rbac.authorization.k8s.io/v1/clusterroles/ambassador
      uid: 07d033bd-50ad-11e9-851d-da993851ee33
    rules:
    - apiGroups:
      - ""
      resources:
      - namespaces
      - services
      - secrets
      verbs:
      - get
      - list
      - watch

    上記の出力から、ServiceAccount にはすべての名前空間、サービス、シークレットに対する getwatchlist 処理の実行権限が付与されることがわかります。これらの処理を実行できなければ、Ambassador は SSL の機密データをシークレットから抽出することも、サービス・オブジェクトの変更を監視して、構成をプライマリー・デーモンに適用することもできません。

    次のステップでは、Kubernetes 内で LoadBalancer タイプのサービスを構成し、Ambassador デプロイメントの外部トラフィックを受け入れられるようにします。クイック・スタート・ガイドでは専用のカスタム・サービスを作成していますが、ここではそうではなく、IKS ALB で現在使用している既存のサービスを再利用します。こうすれば、すでにクラスターの DNS 名に割り当てられた IP を使用できます。

  5. 既存のクラスターとネットワークのセットアップを調べます。
    $ ibmcloud ks cluster get nibz-nightly-2019-03-26
    Retrieving cluster nibz-nightly-2019-03-26...
    OK
    
    Name:                   nibz-nightly-2019-03-26   
    ID:                     c1961757afbb44aba41ab089562bba91   
    State:                  normal   
    Created:                2019-03-26T08:02:42+0000   
    Location:               wdc06   
    Master URL:             https://c1.us-east.containers.cloud.ibm.com:30437   
    Master Location:        Washington D.C.   
    Master Status:          Ready (12 hours ago)   
    Ingress Subdomain:      nibz-nightly-2019-03-26.us-east.containers.appdomain.cloud   
    Ingress Secret:         nibz-nightly-2019-03-26   
    Workers:                3   
    Worker Zones:           wdc06   
    Version:                1.12.6_1546   
    Owner:                  skrum@us.ibm.com   
    Monitoring Dashboard:   -   
    Resource Group ID:      2a926a9173174d94a6eb13284e089f88   
    Resource Group Name:    default   
    $ host nibz-nightly-2019-03-26.us-east.containers.appdomain.cloud
    nibz-nightly-2019-03-26.us-east.containers.appdomain.cloud has address 169.63.132.38
    $ kubectl get svc -n kube-system
    NAME                                             TYPE           CLUSTER-IP       EXTERNAL-IP     PORT(S)                      AGE
    kube-dns                                         ClusterIP      172.21.0.10      <none>          53/UDP,53/TCP                12h
    kubernetes-dashboard                             ClusterIP      172.21.207.120   <none>          443/TCP                      12h
    metrics-server                                   ClusterIP      172.21.226.71    <none>          443/TCP                      12h
    public-crc1961757afbb44aba41ab089562bba91-alb1   LoadBalancer   172.21.197.63    169.63.132.38   80:31574/TCP,443:31121/TCP   12h

    上記の出力から、クラスター nibz-nightly-2019-03-26.us-east.containers.appdomain.cloud に生成されたドメイン名がすでに ALB LoadBalancer の外部 IP (この例では svc/public-crc1961757afbb44aba41ab089562bba91-alb1) にマッピングされていることがわかります。

    手順を進めるには、この LoadBalancer の背後にある、IBM が管理する ALB を無効にする必要があります。

  6. ALB 名を取得します。
    $ kubectl get svc -n kube-system | grep alb
    public-crc1961757afbb44aba41ab089562bba91-alb1   LoadBalancer   172.21.197.63    169.63.132.38   80:31574/TCP,443:31121/TCP   13h
  7. 環境変数を設定します。
    $ ALB_ID=$(kubectl get svc -n kube-system | grep alb | cut -d " " -f 1)
    $ echo $ALB_ID 
    public-crc1961757afbb44aba41ab089562bba91-alb1
  8. ALB を無効にします。
    $ ibmcloud ks alb configure --albID $ALB_ID --disable-deployment
    Configuring ALB...
    OK
    IKS_BETA_VERSION=1.0 コマンドの構造に注目してください (従来の方法では ibmcloud ks alb-configure となります)。

    これらのポッドが停止するまではしばらく時間がかかるので、辛抱強く待ってください。

  9. ALB ポッドが削除されるまでモニタリングします。
    $ kubectl get pods -n kube-system | grep alb
    public-crc1961757afbb44aba41ab089562bba91-alb1-89d685cfb-fvvpl   4/4     Running            0          13h
    public-crc1961757afbb44aba41ab089562bba91-alb1-89d685cfb-h6z5p   4/4     Running            0          13h
    
    $ kubectl get pods -n kube-system | grep alb
  10. kube-system から svc/ambassador を削除します (存在する場合)。
    $ kubectl -n kube-system delete svc/ambassador
  11. IBM 提供の ALB サービスを見つけます。
    $ kubectl -n kube-system get svc| grep alb
    public-cr1d251d6b8c9f4ab093405333a4570d83-alb1   LoadBalancer   172.21.138.109   169.63.140.238   80:30549/TCP,443:30345/TCP   8h
    $ kubectl -n kube-system get svc| grep alb | cut -d " " -f 1
    public-cr1d251d6b8c9f4ab093405333a4570d83-alb1
  12. 環境変数を設定します。
    $ ALB_SVC=$(kubectl -n kube-system get svc| grep alb | cut -d " " -f 1)
    $ echo $ALB_SVC 
    public-cr1d251d6b8c9f4ab093405333a4570d83-alb1
  13. ALB_SVC を編集します。
    $ kubectl -n kube-system edit svc/${ALB_SVC}

    以下のコードを見つけます。
    selector:
      app: public-cr1d251d6b8c9f4ab093405333a4570d83-alb1

    次のように変更します。
    selector:
      service: ambassador

    Ambassador がインストールされました!次は、単純なテスト用アプリケーションをデプロイしてテストを行います。
    $ kubectl apply -f qotm.yaml 
    service/qotm created
    deployment.extensions/qotm created
    qotm 構成に含まれるサービス内で、Ambassador の構成を確認できます。Ambassador は qotm サービスを /qotm/ で公開しているはずです。Ambassador ポッドは kube-system 名前空間内で実行されているため、この名前空間を qotmservice エントリー (13 行目) に指定する必要があります。
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: qotm
      annotations:
        getambassador.io/config: |
          ---
          apiVersion: ambassador/v1
          kind: Mapping
          name: qotm_mapping
          prefix:/qotm/
          service: qotm.default
    spec:
      selector:
        app: qotm
      ports:
      - port: 80
        name: http-qotm
        targetPort: http-api

    それでは、テストしましょう!
  14. curl を使用して、デプロイしたサービスをテストします。
    $ curl -I nibz-nightly-2019-03-27.us-east.containers.appdomain.cloud/qotm/
    
    HTTP/1.1 200 OK
    content-type: application/json
    content-length: 172
    server: envoy
    date: Wed, 27 Mar 2019 23:02:17 GMT
    x-envoy-upstream-service-time: 3

    上記の出力から、200 OK レスポンスが返されたこと、サーバーが Envoy であること、そしてすべてが問題なく機能していることを確認できます。

Ambassador で SSL を使用できるようにする

DNS 名Let's Encrypt 証明書は、IBM Cloud によって自動的に作成されます。通常、この 2 つを使用するのは IBM ALB ですが、この例では Ambassador で使用します。IBM Cloud で使用する DNS はすでにセットアップしてあるので、Ambassador で SSL 証明書を使用してみましょう。

証明書は、デフォルト名前空間内のシークレットに格納されています。該当するシークレットの名前はクラスター名と同じです。

$ kubectl get secret | grep Opaque
nibz-nightly-2019-03-27                Opaque
  1. openssl を使用して証明書の内容を調べます。
    $ kubectl get secret nibz-nightly-2019-03-27 -o yaml | grep tls.crt: | cut -d " " -f 4 | base64 -d | openssl x509 -text -noout -in - 
    Certificate:
        Data:
            Version: 3 (0x2)
            Serial Number:
                04:80:c8:b2:e1:e0:f6:02:29:ff:57:e6:f6:15:a7:8b:6f:72
            Signature Algorithm: sha256WithRSAEncryption
            Issuer: C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
            Validity
                Not Before:M ar 27 07:28:45 2019 GMT
                Not After : Jun 25 07:28:45 2019 GMT
            Subject: CN = nibz-nightly-2019-03-27.us-east.containers.appdomain.cloud
            Subject Public Key Info:
                Public Key Algorithm: rsaEncryption
                    RSA Public-Key: (2048 bit)
                    Modulus:

TLS を Ambassador に対して有効にするには、ALB サービス定義を再度変更する必要があります。

  1. ALB_SVC を編集します。
    $ kubectl -n kube-system edit svc/${ALB_SVC}
  2. annotations セクション内に getambassador.io/config セクションを追加します。
    注: nibz-nightly-2019-03-27 ではなく実際のクラスター名を使用する必要があります。実際のクラスター名はデフォルト名前空間内のシークレットを参照するため、末尾に .default が必要です。
    apiVersion: v1
    kind: Service
    metadata:
      annotations:
        getambassador.io/config: |
          ---
          apiVersion: ambassador/v1
          kind: Module
          name: tls
          config:
            server:
              enabled: True
              redirect_cleartext_from: 80
              secret: nibz-nightly-2019-03-27.default
        service.kubernetes.io/ibm-ingress-controller-public: 169.63.140.238
        service.kubernetes.io/ibm-load-balancer-cloud-provider-zone: wdc06
      creationTimestamp: "2019-03-27T08:23:25Z"

    これで、SSL が有効になります!
  3. もう一度、curl を使用してテストします。
    $ curl -Li nibz-nightly-2019-03-27.us-east.containers.appdomain.cloud/qotm/
    HTTP/1.1 301 Moved Permanently
    location: https://nibz-nightly-2019-03-27.us-east.containers.appdomain.cloud/qotm/
    date: Wed, 27 Mar 2019 17:45:52 GMT
    server: envoy
    content-length: 0
    
    HTTP/1.1 200 OK
    access-control-allow-credentials: true
    access-control-allow-origin: *
    content-type: text/html; charset=utf-8
    date: Wed, 27 Mar 2019 17:45:52 GMT
    server: envoy
    content-length: 9593
    x-envoy-upstream-service-time: 4

    成功です!ポート 80 からポート 443 への 301 リダイレクト・レスポンスが返されました。また、ポート 443 上のサービスに有効な x509 証明書があることも確認できました。

Ambassador を使用する

Ambassador を使用して実際の処理を行いましょう!Ambassador は多数の構成方法をサポートしているので、メイン・サイト (https://www.getambassador.io) 上に用意されているドキュメントを確認することをお勧めします。ここでは初の Ambassador 操作体験として、qotm アプリにアクセスするときにレスポンス・ヘッダーを追加する例を紹介します。この単純な例については、このリンク先の Web サイトで説明しています。次の構成を qotm サービス・エントリーの Ambassador アノテーションに追加します。

  1. qotm サービス・オブジェクトを編集します。
    $ kubectl edit svc/qotm
  2. 次のコードを Ambassador 構成に追加します。
    add_response_headers:
      x-test-static: Ambassador on IKS

    リソースに変更を加えるには、kubectl apply -f httbin-headers.yaml を使用することもできます。

    変更後の構成をテストしましょう。

    $ curl -LI nibz-nightly-2019-03-27.us-east.containers.appdomain.cloud/qotm/
    HTTP/1.1 301 Moved Permanently
    location: https://nibz-nightly-2019-03-27.us-east.containers.appdomain.cloud/qotm/
    date: Wed, 27 Mar 2019 18:10:45 GMT
    server: envoy
    transfer-encoding: chunked
    
    HTTP/1.1 200 OK
    access-control-allow-credentials: true
    access-control-allow-origin: *
    content-length: 9593
    content-type: text/html; charset=utf-8
    date: Wed, 27 Mar 2019 18:10:45 GMT
    server: envoy
    x-envoy-upstream-service-time: 4
    x-test-static: Ambassador on IKS

レスポンス・ヘッダーの末尾に x-test-static が追加されていることに注目してください。

このチュートリアルでは、IBM Cloud Kubernetes Service 上で Ambassador をセットアップする方法を説明しました。また、基本を超えて組み込み DNS と TLS 証明書の機能も統合しました。さらに詳細を学ぶには、Ambassador Web サイトに用意されているガイドに従ってください。また、Ambassador をベースに作成された Seldon などのツールを試すことも一考です。

alb-disable の裏技を見つけて文書化してくれた Gregory Hanson、そして優れたドキュメントの数々を作成した Ambassador の優秀な開発者たちに感謝の言葉を贈ります。

参考資料:

  • https://www.ibm.com/blogs/bluemix/2018/09/transitioning-your-service-mesh-from-ibm-cloud-kubernetes-service-ingress-to-istio-ingress/
  • https://www.getambassador.io/user-guide/getting-started/#1-deploying-ambassador
  • https://www.getambassador.io/reference/running/#namespaces
  • https://github.com/datawire/ambassador/blob/master/ambassador/kubewatch.py
  • https://www.getambassador.io/user-guide/grpc
  • https://www.getambassador.io/user-guide/tls-termination/
  • https://medium.com/@ArpadKun/ibm-cloud-kubernetes-service-ingress-alb-cheat-sheet-1-basics-4fbc1c86b886

ダウンロード可能なリソース


コメント

コメントを登録するにはサインインあるいは登録してください。

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Cloud computing
ArticleID=1066489
ArticleTitle=IBM Cloud Kubernetes Service 上で Ambassador API ゲートウェイを実行する
publish-date=08212019