Edited at

マイクロサービス用APIGateway Ambassadorを使ってみた

この記事はKubernetes2 Advent Calendar 5日目の記事です。


概要

Ambassadorはマイクロサービス用のAPIGatewayです。

この記事は公式ドキュメントを参照しながら使用した時の検証ログです。


主な機能

おおまかな3つの機能を有しています。



  • AWS APIGatewayのようなAPIGatewayのホスティング機能


  • Kongのような昔からある伝統的なAPIGateway機能

  • NginxやHAProxy、Envoy、KubernetesのIngressContollerのようなProxy機能

具体的に機能を掘り下げると、

開発者(Dev)の観点としては下記に特徴があります。


  • Opsを必要とさず、サービスを外部公開する事が可能

  • 細かなルーティング制御、正規表現ベースのルーティング、ホストルーティングなどが可能

  • 認証

  • gRPC、HTTP/2をサポート

  • カナリアリリース

  • シャドートラッキング機能(後でデモでやります)

  • 特定のサービスへのL7トラフィックの透過的な監視

運用者(Ops)の観点としては下記に特徴があります。


  • ルーティングとスケーリングをEnvoyとKubernetesに依存しているので、展開と操作が簡単

  • TLSTerminationとリダイレクトを広範囲に運用可能

  • トラブルシューティング時に統合的に診断する事が可能

  • 複数の異なるバージョンのAmbassadorを運用出来て、簡単にテスト、更新する事が可能


  • Istioと連携してサービスメッシュ化が可能

内部実装としては下記の特徴があります。

Ambassadorは、Kubernetesを最大限に利用し、

信頼性(reliability), 可用性(availability), スケーラビリティ(scalability)を担保しています。

状態管理の為に、Ambassador自身でデータベースのようなストレージを必要とせず、Kubernetes内に全ての状態管理を維持しています。

Ambassadorをスケールする時は、KubernetesのReplicasetでレプリカ数を変更するか、

horizontal pod autoscalerを利用する事で簡単にスケール事が可能となっています。

又、EnvoyProxyを使用して、全てのトラフィックのルーティングとプロキシーをしています。

より細かな詳細は下記ドキュメントを参照してみて下さい。


インストール

RBACが有効の場合と、無効の場合の2つのmanifestが用意されています。

下記では、使用しているkubernetes clusterではRBACが有効でしたので、

RBAC有効のmanifestをapplyしています。

$ kubectl apply -f https://getambassador.io/yaml/ambassador/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

下記は、applyしたmanifest(ambassador-rbac.yaml)です。

---

apiVersion: v1
kind: Service
metadata:
labels:
service: ambassador-admin
name: ambassador-admin
spec:
type: NodePort
ports:
- name: ambassador-admin
port: 8877
targetPort: 8877
selector:
service: ambassador
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: ambassador
rules:
- apiGroups: [""]
resources:
- services
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources:
- configmaps
verbs: ["create", "update", "patch", "get", "list", "watch"]
- apiGroups: [""]
resources:
- secrets
verbs: ["get", "list", "watch"]
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: ambassador
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: ambassador
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: ambassador
subjects:
- kind: ServiceAccount
name: ambassador
namespace: default
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: ambassador
spec:
replicas: 3
template:
metadata:
annotations:
sidecar.istio.io/inject: "false"
labels:
service: ambassador
spec:
serviceAccountName: ambassador
containers:
- name: ambassador
image: quay.io/datawire/ambassador:0.40.2
resources:
limits:
cpu: 1
memory: 400Mi
requests:
cpu: 200m
memory: 100Mi
env:
- name: AMBASSADOR_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
ports:
- name: http
containerPort: 80
- name: https
containerPort: 443
- name: admin
containerPort: 8877
livenessProbe:
httpGet:
path: /ambassador/v0/check_alive
port: 8877
initialDelaySeconds: 30
periodSeconds: 3
readinessProbe:
httpGet:
path: /ambassador/v0/check_ready
port: 8877
initialDelaySeconds: 30
periodSeconds: 3
restartPolicy: Always

色々とYAMLでリソースが記載されてますが、簡単に説明すると下記になります。


  1. ambassadorというServiceAccountを作成

  2. services・configmaps・secretsを最低限操作可能な権限が付与したClusterRoleを作成

  3. ClusterRoleBindingで、1と2を関連付け

  4. ambassadorコンテナを定義したPod(コンテナPort80・443・8877)を作成

  5. 4のPodをReplicaSet3でDeploymentを作成

  6. NodePortとして5に関連付けてServiceを作成

6で作成したServiceリソースはNodePortとして作成されていますので、

LB経由にしたい場合は、下記のServiceリソースを適用する必要があります。

---

apiVersion: v1
kind: Service
metadata:
name: ambassador
annotations:
metallb.universe.tf/address-pool: public # 自前環境ではMetalLBを使用しているのでMetalLB用のannotationを追加しています
spec:
type: LoadBalancer
ports:
- port: 80
selector:
service: ambassador

上記Serviceリソースをapplyします。

$  kubectl apply -f ambassador-service.yaml

service/ambassador created

全体として下記が作成されました。

ubectl get pod,deployment,svc

NAME READY STATUS RESTARTS AGE
pod/ambassador-65cc86c8f9-76x47 1/1 Running 0 5m
pod/ambassador-65cc86c8f9-bdtcc 1/1 Running 0 5m
pod/ambassador-65cc86c8f9-qpfwz 1/1 Running 0 5m

NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
deployment.extensions/ambassador 3 3 3 3 5m

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/ambassador LoadBalancer 10.105.219.17 192.168.10.254 80:32764/TCP 10s
service/ambassador-admin NodePort 10.107.84.219 <none> 8877:30675/TCP 5m


RouteService

インストールが済んだので、ルーティング機能を試してみようと思います。


デモ1: 外部webサービスへルーティングしてみる

httpbin.orgという、REST-APIでリクエストしたHTTPメソッドをレスポンスしてくれる外部webサービスにルーティングしてみます。

まず、httpbin.orgに直接curlしてみます。

$ curl httpbin.org/get

{
"args": {},
"headers": {
"Accept": "*/*",
"Connection": "close",
"Host": "httpbin.org",
"User-Agent": "curl/7.54.0"
},
"origin": "xxx.xxx.xxx.xxx",
"url": "http://httpbin.org/get"
}

こちらのレクエストのheaders、originIP、urlがJSONとしてレスポンスされてきました。

それでは、Ambassadorを経由して、httpbin.orgにリクエストしてみます。

Ambassadorのルーティング設定を定義します。

$ cat httpbin.yaml

---
apiVersion: v1
kind: Service
metadata:
name: httpbin
annotations:
getambassador.io/config: |
---
apiVersion: ambassador/v0
kind: Mapping
name: httpbin_mapping
prefix: /httpbin/
service: httpbin.org:80
host_rewrite: httpbin.org
spec:
ports:
- name: httpbin
port: 80

上記manifest(httpbin.yaml)をapplyします。

$ kubectl apply -f httpbin.yaml

service/httpbin created

上記で作成したAmbassadorを確認してみます。

kubectl get svc -o wide ambassador

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
ambassador LoadBalancer 10.105.219.17 192.168.10.254 80:32764/TCP 77m service=ambassador

192.168.10.254:80で公開されました。

それでは、Ambassadorのルーティング経由でhttpbin.orgに転送されるか確認してみます。

$ curl 192.168.10.254/httpbin/get

{
"args": {},
"headers": {
"Accept": "*/*",
"Connection": "close",
"Host": "httpbin.org",
"User-Agent": "curl/7.54.0",
"X-Envoy-Expected-Rq-Timeout-Ms": "3000",
"X-Envoy-Original-Path": "/httpbin/get"
},
"origin": "xxx.xxx.xxx.xxx",
"url": "http://httpbin.org/get"
}

Ambassadorのルーティング経由でhttpbin.orgに転送されています。

Ambassadorは、内部でEnvoyProxyを使用して、

全てのトラフィックのルーティングとプロキシーをしているので、

Envoyが付加したヘッダーが確認出来るかと思います。


デモ2: KubernetesのServiceにルーティングしてみる

デモ1では外部webサービス(httpbin.org)にルーティングしましたが、

次はKubernetes内で動作している内部webサービスに転送してみます。

今回使用する内部webサービスは、任意の引用符をレスポンスしてくれるQuote of the Moment Serviceという簡単なwebサービスを使用して、

Kubernetes内で動作しているwebサービスにルーティングしてみます。

今度はKubernetes内で動作しているwebサービなので、

Ambassadorのルーティング設定と、webサービスに必要なリソースも定義します。

$ cat qotm.yaml

---
apiVersion: v1
kind: Service
metadata:
name: qotm
annotations:
getambassador.io/config: |
---
apiVersion: ambassador/v0
kind: Mapping
name: qotm_mapping
prefix: /qotm/
service: qotm
spec:
type: LoadBalancer
selector:
app: qotm
ports:
- port: 80
name: http-qotm
targetPort: http-api
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: qotm
spec:
replicas: 1
strategy:
type: RollingUpdate
template:
metadata:
labels:
app: qotm
spec:
containers:
- name: qotm
image: datawire/qotm:1.1
ports:
- name: http-api
containerPort: 5000
resources:
limits:
cpu: "0.1"
memory: 100Mi

上記manifest(qotm.yaml)をapplyします。

$ kubectl apply -f qotm.yaml

service/qotm created
deployment.extensions/qotm created

必要なリソースが起動したか確認してみます。

$ kubectl get pod,deployment,svc

NAME READY STATUS RESTARTS AGE
pod/qotm-74849778b7-w7hcb 1/1 Running 0 3s

NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
deployment.extensions/qotm 1 1 1 1 3s

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/qotm ClusterIP 10.111.129.26 <none> 80/TCP 4s

それでは、Ambassadorのルーティング経由でKubernetes内で動作しているwebサービスに転送されているか確認してみます。

$ curl -X GET http://192.168.10.254/qotm/

{
"hostname": "qotm-74849778b7-lhjj4",
"ok": true,
"quote": "A principal idea is omnipresent, much like candy.",
"time": "2018-12-03T08:06:45.780997",
"version": "1.1"
}

Ambassador経由で、Serviceリソース(qotm)にルーティングされ、

レスポンスが返却されている事が確認出来ました。


Ambassador's manifests

デモ1,デモ2のServiceリソースのmanifestの記載通り、

AmbassadorのmanifestはKubernetes Serviceリソースのannotationに記載します。

annotations:

getambassador.io/config: |
---
apiVersion: ambassador/v0
kind: Mapping
name: qotm_mapping
prefix: /qotm/
service: qotm

又、AmbassadorのServiceリソースもKubernetesのServiceリソースと同じく、

用途によって種類があり、下記のようなServiceリソースが用意されています。

下記、AmbassadorのServiceリソースです。

Serviceリソース名
概略

Module
 Ambassadorの全体設定を定義に使用します。AmbassadorのListenPortの定義、liveness_probe、readiness_probeの有効無効化、CORSの設定などの定義が出来ます。

AuthService
外部認証サービスの設定を定義に使用します。SSO認証プロトコル(OAuth、OpenID Connect...)などの認証やベーシック認証だけでなく、レート制限を超える認証要求を拒否したり、指定のURLに認証を入れたりする事が出来ます

RateLimitService
大量のリクエストで後負荷になった場合、カスケード障害を防止する為にリクエスト制限をかける時に使用します。EnvoyのGlobal rate limitingを利用しています。

TracingService
Zepkinなどを使用して分散トレーシングをする時に使用します。

Mapping
トラフィックをkubernetesのserviceにルーティングする時に使用します。Ambassadorを利用する時には、このMappingを1つ以上定義する必要があります。(上記デモで使用しました)

上記の中で、デモで使用したMappingの別の機能、Traffic Shadowingを試してみたいと思います。


Traffic Shadowing

Traffic Shadowingは、Mapping Serviceの機能の1つで、

Ambassadorに転送されたトラフィックを非同期にコピーして、違うサービスにトラフィックを送信する機能です。

コピーした同じトラフィックを利用している為、コピーしたトラフィックを処理しているサービス側にバグがあった場合でも本番環境にまったく影響を与えません(コピーしたトラックを処理しているサービスのレスポンスは破棄されます)。

その為、リリース前のサービスに、コピーしたトラフィックを非同期に流して、本番環境のトラフィックを利用したデバッグ作業や、Diffyを使用したリグレッションテストなどが容易に出来るようになり、従来のBlue-Greenデプロイメントやカナリアリリースを利用したテスト手法とはまた違ったアプローチでデプロイ&テストをする事が可能になります。

shadowing.png

引用: Traffic Shadowing | Ambassador

それでは、Traffic Shadowingのデモをしてみたいと思います。

デモシナリオとして、デモ2で使用したQuote of the Moment Serviceをアップデートしてみたいと思います。

デモ2で使用したwebサービスはバージョン1.1で、最新のバージョン1.3にアップデートしたいと思いますが、

その前に本番環境のトラフィックで動作確認がしたく、Traffic Shadowingで最新バージョンのサービスにもトラフィックを転送して動作確認してみようと思います。


デモ3: Traffic Shadowingを試してみる

最新バージョンのQuote of the Moment Serviceリソースを定義します。

---

apiVersion: v1
kind: Service
metadata:
name: qotm-shadow
annotations:
getambassador.io/config: |
---
apiVersion: ambassador/v0
kind: Mapping
name: qotm_shadow_mapping
prefix: /qotm/
service: qotm-shadow
shadow: true
spec:
selector:
app: qotm-shadow
ports:
- port: 80
name: http-qotm-shadow
targetPort: http-api
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: qotm-shadow
spec:
replicas: 1
strategy:
type: RollingUpdate
template:
metadata:
labels:
app: qotm-shadow
spec:
containers:
- name: qotm-shadow
image: datawire/qotm:1.3
ports:
- name: http-api
containerPort: 5000
resources:
limits:
cpu: "0.1"
memory: 100Mi

Traffic Shadowingを有効にするには、Ambassadorのmanifestに 「shadow: true」を追記するだけです。

apiVersion: ambassador/v0

kind: Mapping
name: qotm_shadow_mapping
prefix: /qotm/
service: qotm-shadow
shadow: true

上記manifest(qotm-shadow.yaml)をapplyします。

kubectl apply -f qotm-shadow.yaml

service/qotm-shadow created
deployment.extensions/qotm-shadow created

Traffic Shadowing出来ているか確認してみます。

デモ2で使用したバージョン1.1のサービスアプリケーションにcurlしてみます。

 curl -X GET http://192.168.10.254/qotm/

{
"hostname": "qotm-74849778b7-lhjj4",
"ok": true,
"quote": "Nihilism gambles with lives, happiness, and even destiny itself!",
"time": "2018-12-03T08:16:23.689394",
"version": "1.1"
}

レスポンスの値を見るとバージョンは1.1です。

では、Traffic Shadowingの設定をしたバージョン1.3の方にもトラフィックが転送されているか確認してみます。

kubectl logs -f qotm-shadow-5f598d844f-j42qv

2018-12-03 08:09:49 QotM 1.3 INFO: initializing on qotm-shadow-5f598d844f-j42qv:5000
2018-12-03 08:09:50 QotM 1.3 INFO: * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
2018-12-03 08:09:50 QotM 1.3 INFO: * Restarting with stat
2018-12-03 08:09:54 QotM 1.3 INFO: initializing on qotm-shadow-5f598d844f-j42qv:5000
2018-12-03 08:09:54 QotM 1.3 WARNING: * Debugger is active!
2018-12-03 08:09:54 QotM 1.3 INFO: * Debugger PIN: 199-342-250

2018-12-03 08:16:23 QotM 1.3 DEBUG: GET /: session None, username None, handler statement
2018-12-03 08:16:23 QotM 1.3 INFO: 10.244.2.37 - - [03/Dec/2018 08:16:23] "GET / HTTP/1.1" 200 -

以上のように、バージョン1.1のサービスアプリケーションの影響を与えず、

バージョン1.3のサービスアプリケーションにもコピーしたトラフィックが転送されている事が確認出来ました。


AuthService

デモ1では、外部webサービス(httpbin.org)にルーティング設定をしましたが、

現状では、Serviceリソースを経由して不特定多数に利用されてしまいます。

運営者に迷惑をかけない様、AuthServiceに簡単なベーシック認証をかけてみます。


デモ4: ベーシック認証してみる

認証をかけるには、AuthService manifestを使用します。

利用するBasic認証モジュールは、ambassador-auth-httpbasicを利用します。

ambassador-auth-httpbasicのmanifestをapplyします。

kubectl apply -f https://raw.githubusercontent.com/datawire/ambassador-auth-httpbasic/master/manifests/ambassador-auth-httpbasic.yaml

以下のリソースが生成されます。

cat ambassador-auth-httpbasic.yaml

---
apiVersion: v1
kind: Service
metadata:
name: ambassador-auth
spec:
type: ClusterIP
ports:
- name: http-api
port: 80
targetPort: http-api
selector:
app: ambassador-auth-httpbasic

---
apiVersion: v1
kind: Secret
metadata:
name: ambassador-auth-httpbasic
type: Opaque
data:
users.yaml: "YWRtaW46CiAgaGFzaGVkX3Bhc3N3b3JkOiAiJDJiJDEyJG1XcXZVT1pRb3d2aks4WFBtT3VPdk9XUFBnVVYyZDY0TWw0OXJPRXpmQWw4TUpYWjNaUFJLIgo="

---
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: ambassador-auth-httpbasic
spec:
replicas: 1
strategy:
type: RollingUpdate
selector:
matchLabels:
app: ambassador-auth-httpbasic
template:
metadata:
labels:
app: ambassador-auth-httpbasic
spec:
containers:
- name: ambassador-auth-httpbasic
image: quay.io/datawire/ambassador-auth-httpbasic:0.1.1
ports:
- name: http-api
containerPort: 5000
volumeMounts:
- name: ambassador-auth-httpbasic
mountPath: /var/lib/ambassador/auth-httpbasic
readOnly: true
volumes:
- name: ambassador-auth-httpbasic
secret:
secretName: ambassador-auth-httpbasic
items:
- key: users.yaml
path: users.yaml

ベーシック認証のid:pwは、SecretsをVolumeリソースとして参照しており、

ダウンロードしてきたままのmanifestでは下記が入ります。

$ echo "YWRtaW46CiAgaGFzaGVkX3Bhc3N3b3JkOiAiJDJiJDEyJG1XcXZVT1pRb3d2aks4WFBtT3VPdk9XUFBnVVYyZDY0TWw0OXJPRXpmQWw4TUpYWjNaUFJLIgo=" | base64 --decode

admin:
hashed_password: "$2b$12$mWqvUOZQowvjK8XPmOuOvOWPPgUV2d64Ml49rOEzfAl8MJXZ3ZPRK"

実際に運用する際は、このSecretsを更新することになります。

デモ1で使用したServiceリソースにAuthService manifestを追加します。

$  cat httpbin.yaml

---
apiVersion: v1
kind: Service
metadata:
name: httpbin
annotations:
getambassador.io/config: |
---
apiVersion: ambassador/v0
kind: AuthService
name: authentication
auth_service: "ambassador-auth:80"
path_prefix: "/extauth"
---
apiVersion: ambassador/v0
kind: Mapping
name: httpbin_mapping
prefix: /httpbin/
service: httpbin.org:80
host_rewrite: httpbin.org
spec:
ports:
- name: httpbin
port: 80

上記manifest(httpbin.yaml)をapplyします。

$ kubectl apply -f httpbin.yaml

kubectl apply -f httpbin.yaml
service/httpbin configured

それでは、ベーシック認証が入ったか確認してみます。

 curl -v  http://192.168.10.254/httpbin-innode/get

* Trying 192.168.10.254...
* TCP_NODELAY set
* Connected to 192.168.10.254 (192.168.10.254) port 80 (#0)
> GET /httpbin-innode/get HTTP/1.1
> Host: layback-lab.com
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 401 Unauthorized
< server: envoy
< date: Mon, 03 Dec 2018 09:02:33 GMT
< www-authenticate: Basic realm="Authentication Required"
< content-type: text/html; charset=utf-8
< content-length: 0
< x-envoy-upstream-service-time: 1
<
* Connection #0 to host 192.168.10.254 left intact

レスポンスが401 Unauthorizedになりました。

www-authenticateレスポンスヘッダーにType Basicがあることが確認出来ます。

ベーシック認証が有効になっている事が確認出来ました。

次に、認可可能か確認してみます。

$ curl -v -u admin:admin http://192.168.10.254/httpbin/get

* Trying 192.168.10.254...
* TCP_NODELAY set
* Connected to 192.168.10.254 (192.168.10.254) port 80 (#0)
* Server auth using Basic with user 'admin'
> GET /httpbin/get HTTP/1.1
> Host: layback-lab.com
> Authorization: Basic YWRtaW46YWRtaW4=
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 200 OK
< server: envoy
< date: Mon, 03 Dec 2018 09:04:53 GMT
< content-type: application/json
< content-length: 356
< access-control-allow-origin: *
< access-control-allow-credentials: true
< via: 1.1 vegur
< x-envoy-upstream-service-time: 337
<
{
"args": {},
"headers": {
"Accept": "*/*",
"Authorization": "Basic YWRtaW46YWRtaW4=",
"Connection": "close",
"Host": "httpbin.org",
"User-Agent": "curl/7.54.0",
"X-Envoy-Expected-Rq-Timeout-Ms": "3000",
"X-Envoy-Original-Path": "/httpbin/get"
},
"origin": "xxx.xxx.xxx.xxx",
"url": "http://httpbin.org/get"
}
* Connection #0 to host 192.168.10.254 left intact

正常に認可されました。

上記のように、認証のロジックは外部のServiceリソース(ambassador-auth-httpbasic)にカプセル化されているので、様々なユースケースの認証をサポートできるようになっています(OAuth,OpenIDConnect etc...)。

又、RateLimit前にフィルターとして実行するなど、他のAmbassador Serviceリソースと連携して使用する時には、ambassador-auth-httpbasicのようなAuthServiceリソースは、リクエスト時に最初に呼び出される様な設計になっています。


おまけ: Diagnostics

Ambassadorには標準で簡単なダッシュボード機能が備わっています。

kubectl get pod

NAME READY STATUS RESTARTS AGE
ambassador-65cc86c8f9-76x47 1/1 Running 0 11h
ambassador-65cc86c8f9-bdtcc 1/1 Running 0 11h
ambassador-65cc86c8f9-qpfwz 1/1 Running 0 11h

ubectl port-forward ambassador-65cc86c8f9-76x47 8877

Forwarding from 127.0.0.1:8877 -> 8877
Forwarding from [::1]:8877 -> 8877

プラウザでlocalhost:8877に閲覧してみます。

Ambassador Diagnostic Overview.png

KubernetesDashboardの様な豪華ではありませんが、

Podのトラブルシューティングや、ルーティングの確認などには重宝するのではないでしょうか。


まとめ

APIGateway Ambassadorを使ってみました。

Ambassador自体を運用する手間が少ない点(Kubernetes依存の為)や、

設定をKubernetesのannotationに定義する点(Dev寄りな設計思想)などを考慮すると、

例えば、Strangler Patternとして、巨大なモノリスサービスからマイクロサービスへ移行する際、DevとOpsが分離していないチーム体制だった時に、AmsassadorはAPIGatewayとして採用する選択肢の1つになるのではないかと思います。

サービスメッシュ定義後、Ambassadorはサービスメッシュとはまた違った解釈で、マイクロサービスの問題を解決しています。

公式のブログにそのへんの補足が記載されておりますので、良ければ参照してみて下さい。


Appendix