6月 2021|sitateru tech blog

sitateru tech blog

シタテルの技術やエンジニアの取り組みを紹介するテックブログです。

2021年6月17日木曜日

AWS App Mesh をEKSで試してみた(仮想ルーター、仮想サービス)

前回に続き、EKS上でのAWS App Meshをやっていきます。
今回は、仮想ルーターと仮想サービスです。
前回作った仮想ノードにアクセスするには仮想ルーターか仮想ゲートウェイが必要になるので、いよいよメッシュができていきます💪

あまりしっかり説明されたドキュメントが見つからず経験ベースな部分が多いので、正しい説明になっているかどうか怪しい部分もありますがご了承ください🙇‍


  1. 仮想ルーター作成

仮想ノードへトラフィックを振り分ける仮想ルーターを作成します。
振り分け先は weightedTargetsvirtualNodeRef.name で仮想ノード名を指定します。
プロトコルはHTTPにしましたが、他にもGRPC, HTTP2, TCPが設定できるようです。

apiVersion: appmesh.k8s.aws/v1beta2
kind: VirtualRouter
metadata:
  namespace: mesh-test
  name: vrouter-1
spec:
  listeners:
    - portMapping:
        port: 80
        protocol: http
  routes:
    - name: route-1
      httpRoute:
        match:
          prefix: /
        action:
          weightedTargets:
            - virtualNodeRef:
                name: vnode-1
              weight: 1
            - virtualNodeRef:
                name: vnode-2
              weight: 1

  1. 仮想サービス用サービス作成

仮想サービスの実体にするserviceを作成します。
selecter は、仮想サービスを介してアクセスする先のpodが全て含まれるように指定する必要があるみたいです。
今回の例だと、仮想サービス → 仮想ルーター(vrouter-1) → 仮想ノード(vnode-1, vnode-2) というトラフィックの流れになるので、vnode-1とvnode-2の実体になるpodに app: sample1 のラベルをつけてあります。

apiVersion: v1
kind: Service
metadata:
  name: svc-v
  namespace: mesh-test
  labels:
    app: sample1
spec:
  type: ClusterIP
  selector:
    app: sample1
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

  1. 仮想サービス作成

先の svc-v を実体とする仮想サービスを作成します。
name は上で仮想サービス用に作ったサービス名と等しくする必要があるみたいです。
provider には仮想サービスを通してアクセスする先を指定を指定します。単一のvirtualNodeかvirtualRouterを選択できるので、トラフィックを複数ノードに分けたいならvirtualRouter、分けなくていいならvirtualNodeにするとよさそうです。

apiVersion: appmesh.k8s.aws/v1beta2
kind: VirtualService
metadata:
  namespace: mesh-test
  name: svc-v
spec:
  provider:
    virtualRouter:
      virtualRouterRef:
        name: vrouter-1

  1. 仮想サービスをバックエンドに設定

作った仮想サービスにアクセスするには、「仮想ノードのバックエンド」にその仮想サービスを指定する必要があります。
仮想ノードのyamlで、backendsに仮想サービスを追加しておきます。

apiVersion: appmesh.k8s.aws/v1beta2
kind: VirtualNode
metadata:
  name: vnode-x
  namespace: mesh-test
spec:
  # 主要部分は省略
  backends:
    - virtualService:
        virtualServiceRef:
          name: svc-v

仮想ノード化されたPodから仮想サービスへリクエストを送ると、
ルーティングに従ったレスポンスが返ってくるはずです。

$ kubectl exec -it somepod-524b1761b4-vg8kw -- bash
root@somepod-524b1761b4-vg8kw:/# curl svc-v.mesh-test.svc.cluster.local

いろいろ試してみたところ、「バックエンドにその仮想サービスを指定したpod」で「仮想サービス名.名前空間.svc.cluster.localへトラフィックを送る」場合に仮想サービスで設定したトラフィック振り分けが行われる仕様のようです。
それ以外の条件、例えばバックエンドを指定していないpodからのリクエストや仮想サービス名だけのホスト名にトラフィックを送る($ curl svc-v)場合は(仮想ではない)Serviceの svc-v に行くようです。
なかなかややこしいですね。

, , ,

2021年6月3日木曜日

AWS App Mesh をEKSで試してみた(準備~仮想ノードまで)

突然ですが、AWS App Meshは皆さんお使いでしょうか?
AWS製のサービスメッシュ構築サービスですね。

サービスメッシュといえばIstioが有名ですが、AWS App MeshはAWS製だけあってEKSはもちろんEC2やECSのインスタンス・コンテナもメッシュに組み込むことができるのが強みという印象です。

そんなApp MeshをEKS上でいろいろと実験してみたので、自分の理解の反芻のためにもまとめてみたいと思います。

試した環境は kubernetes 1.20, App Meshコントローラ 1.3.0 でした。


  1. 準備

ドキュメントに従ってコントローラをインストールします。

Getting started with AWS App Mesh and Kubernetes - AWS App Mesh

手順はドキュメントの通りなのでここでは書きませんが、完了するとappmesh-systemネームスペースでコントローラのポッドができていました。

$ kubectl get pod -n appmesh-system
NAME                                  READY   STATUS    RESTARTS   AGE
appmesh-controller-6c55b46558-8s363   1/1     Running   0          1d

  1. mesh作成

メッシュを作成します。
egressFilter はメッシュ内部から外部へのアクセスを許可するかどうかですね。許可しない場合はDROP_ALLにします。
namespaceSelecter も何でもいいので書いておきましょう。

apiVersion: appmesh.k8s.aws/v1beta2
kind: Mesh
metadata:
  name: mesh-1
spec:
  egressFilter:
    type: ALLOW_ALL
  namespaceSelector:
    matchLabels:
      mesh: sitateru-mesh

  1. namespace作成

メッシュのリソースを配置するネームスペースを宣言します。
上のMeshで指定した namespaceSelector とラベルを合わせておきましょう。
App Meshの機能を使うにはappmesh.k8s.aws/sidecarInjectorWebhook をenabledにしてEnvoyサイドカーが入れられるようにしておく必要があります。

apiVersion: v1
kind: Namespace
metadata:
  name: mesh-test
  labels:
    mesh: mesh-1
    appmesh.k8s.aws/sidecarInjectorWebhook: enabled

  1. サービスアカウント作成

IAMで以下のポリシーを作成します。
今回は動作検証なので mesh-1 メッシュの全ての仮想ノードと仮想ゲートウェイに対して StreamAggregatedResources を許可していますが、実使用の際には適宜リソース名を指定するほうが望ましいですね。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "appmesh:StreamAggregatedResources",
            "Resource": [
                "arn:aws:appmesh:ap-northeast-1:111122223333:mesh/mesh-1/virtualNode/*",
                "arn:aws:appmesh:ap-northeast-1:111122223333:mesh/mesh-1/virtualGateway/*"
            ]
        }
    ]
}

続いてこのポリシーをアタッチしたサービスアカウントをEKSクラスターに作成します。

$ eksctl create iamserviceaccount \
    --cluster test-cluster \
    --namespace mesh-test \
    --name appmesh-proxyauth \
    --attach-policy-arn arn:aws:iam::111122223333:policy/appmesh-proxyauth \
    --override-existing-serviceaccounts \
    --approve

  1. 仮想ノード用サービス作成

仮想ノードの実体にするdeploymentとserviceを作成します。コンテナイメージは何でもいいのですが、今回はただのnginxにしています。
serviceAccountName には👆で作成したサービスアカウント名を指定します。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-1
  namespace: mesh-test
  labels:
    app: sample0
spec:
  selector:
    matchLabels:
      app: sample0
  template:
    metadata:
      labels:
        app: sample0
        server: nginx
    spec:
      serviceAccountName: appmesh-proxyauth
      containers:
        - name: nginx
          image: nginx:1.19.0
          ports:
          - containerPort: 80
          resources:
            limits:
              cpu: 10m
              memory: 10Mi
---
apiVersion: v1
kind: Service
metadata:
  name: svc-1
  namespace: mesh-test
  labels:
    app: sample0
spec:
  selector:
    app: sample0
    server: nginx
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

  1. 仮想ノード作成

今作ったsvc-1 を実体とする仮想ノードを作成します。
serviceDiscovery で仮想ノードとする実体を指定するのですが、ここでは目的のサービスのDNSホスト名( サービス名.名前空間.svc.cluster.local )を指定します。

ServiceとPodに対するDNS | Kubernetes

ちなみにDNSではなくCloud Mapを使って指定することもできるみたいです。

apiVersion: appmesh.k8s.aws/v1beta2
kind: VirtualNode
metadata:
  name: vnode-1
  namespace: mesh-test
spec:
  podSelector:
    matchLabels:
      app: sample0
  listeners:
    - portMapping:
        port: 80
        protocol: http
  serviceDiscovery:
    dns:
      hostname: svc-1.mesh-test.svc.cluster.local

うまくできていればAWSコンソールでもメッシュや仮想ノードが表示されているはずです。

できていない場合は appmesh-controller ポッドのログを見れば何かわかるかもしれないのでチェックしてみてください。


そこそこ長くなってきたのでここまでにしようと思います。
ここまで作ったものだけではぜんぜんサービスメッシュになっていないのですが、続きは近いうちにまた書きます!

ちなみに、メッシュのリソース作成はkubernetes的にはカスタムリソースの作成になっています。
そのカスタムリソースの定義は👇なので、yamlをどう書けばいいのかこちらを見つつやるのがいいのではないかと思います!

eks-charts/crds.yaml at master · aws/eks-charts


, , ,