OCI Service MeshでBookInfoアプリケーションを動かしてみる

# はじめに

先日OCI(Oracle Cloud Infrastructure)でマネージドService Meshのサービスがリリースされました！
その名もOracle Cloud Infrastructure(OCI) Service Mesh!!(そのまま...!!)

この記事ではService Mesh界隈ではお馴染み？のBookInfoアプリケーションを利用してOCI Service MeshのHello Worldをやっていきます。

# 事前準備

準備事項は以下です。

* 動的グループとポリシー
    * OCI Service Meshや証明書サービスに関連する動的グループとポリシーを作成
   
* 証明書サービス
    * 認証局
        * Mesh内の通信に利用する証明書を動的に発行するために利用
    * 証明書
        * Ingress Gateway用の証明書

* Oracle Container Engine for Kubernetes(OKE)
    * OSOK(Oracle Service Operator for Kubernetes)のインストール
    * メトリクスサーバのインストール

## 動的グループとポリシーの作成

まず、OCI Service Meshに必要な動的グループとポリシーを作成していきます。
動的グループについては[こちら](https://docs.oracle.com/ja-jp/iaas/Content/Identity/Tasks/managingdynamicgroups.htm)、ポリシーについては[こちら](https://docs.oracle.com/ja-jp/iaas/Content/Identity/Concepts/policies.htm)をご確認ください。
今回は、ご自身のコンパートメントに対してはフル権限(`to manage all-resources in compartment`)がある前提とします。

今回作成する動的グループのルールは以下です。

今回は、`MeshDynamicGroup`として以下のルールを作成します。

```sh
ANY {instance.compartment.id = '<ご自身のコンパートメントID>'}
```

```sh
ANY {resource.type='certificateauthority', resource.type='certificate'}
```

動的グループを作成したら、以下のポリシーを作成します。

```sh
Allow dynamic-group MeshDynamicGroup to use keys in compartment <ご自身のコンパートメント名>
Allow dynamic-group MeshDynamicGroup to manage objects in compartment <ご自身のコンパートメント名>
Allow dynamic-group MeshDynamicGroup to manage service-mesh-family in compartment <ご自身のコンパートメント名>
Allow dynamic-group MeshDynamicGroup to read certificate-authority-family in compartment <ご自身のコンパートメント名>
Allow dynamic-group MeshDynamicGroup to use certificate-authority-delegates in compartment <ご自身のコンパートメント名>
Allow dynamic-group MeshDynamicGroup to manage leaf-certificate-family in compartment <ご自身のコンパートメント名>
Allow dynamic-group MeshDynamicGroup to manage certificate-authority-associations in compartment <ご自身のコンパートメント名>
Allow dynamic-group MeshDynamicGroup to manage certificate-associations in compartment <ご自身のコンパートメント名>
Allow dynamic-group MeshDynamicGroup to manage cabundle-associations in compartment <ご自身のコンパートメント名>
```

これで、動的グループとポリシーの作成は完了です。

## 証明書サービス

証明書サービスの構築は割愛します。
[こちら](https://qiita.com/Skogkatter112/items/da7847861c203fdab8ee)をご確認ください。

## OKEクラスタ

### クラスタの作成

OKEの構築も割愛します（サボりすぎ...)
[こちら](https://oracle-japan.github.io/ocitutorials/cloud-native/oke-for-commons/)をご確認ください。

### OSOKのインストール

OCI Service Meshでは、Kubernetes Operatorとして[OSOK(Oracle Service Operator for Kubernetes)](https://github.com/oracle/oci-service-operator)を利用します。

OSOKをインストールするためには、Operator SDKとオペレータ・ライフサイクル・マネージャ(OLM)のインストールが必要です。

Operator SDKとオペレータ・ライフサイクル・マネージャ(OLM)のインストールはOCIチュートリアルに手順があるので、[こちら](https://oracle-japan.github.io/ocitutorials/cloud-native/oke-for-intermediates/#3-1-operator-sdk%E3%81%8A%E3%82%88%E3%81%B3%E3%82%AA%E3%83%9A%E3%83%AC%E3%83%BC%E3%82%BF%E3%83%A9%E3%82%A4%E3%83%95%E3%82%B5%E3%82%A4%E3%82%AF%E3%83%AB%E3%83%9E%E3%83%8D%E3%83%BC%E3%82%B8%E3%83%A3olm%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)を参考に実施してください。

Operator SDKとオペレータ・ライフサイクル・マネージャ(OLM)のインストールが完了したら、以下のコマンドを実行し、OSOK用のNamespaceを作成します。

```sh
kubectl create ns oci-service-operator-system
```

次にOSOKをインストールします。 

```sh
operator-sdk run bundle iad.ocir.io/oracle/oci-service-operator-bundle:1.1.0 -n oci-service-operator-system --timeout 5m
```

以下のように出力され、OSOKがインストールされます。

```sh
INFO[0036] Successfully created registry pod: iad-ocir-io-oracle-oci-service-operator-bundle-X-X-X 
INFO[0036] Created CatalogSource: oci-service-operator-catalog 
INFO[0037] OperatorGroup "operator-sdk-og" created      
INFO[0037] Created Subscription: oci-service-operator-vX-X-X-sub 
INFO[0040] Approved InstallPlan install-tzk5f for the Subscription: oci-service-operator-vX-X-X-sub 
INFO[0040] Waiting for ClusterServiceVersion "oci-service-operator-system/oci-service-operator.vX.X.X" to reach 'Succeeded' phase 
INFO[0040]   Waiting for ClusterServiceVersion "oci-service-operator-system/oci-service-operator.vX.X.X" to appear 
INFO[0048]   Found ClusterServiceVersion "oci-service-operator-system/oci-service-operator.vX.X.X" phase: Pending 
INFO[0049]   Found ClusterServiceVersion "oci-service-operator-system/oci-service-operator.vX.X.X" phase: InstallReady 
INFO[0053]   Found ClusterServiceVersion "oci-service-operator-system/oci-service-operator.vX.X.X" phase: Installing 
INFO[0066]   Found ClusterServiceVersion "oci-service-operator-system/oci-service-operator.vX.X.X" phase: Succeeded 
INFO[0067] OLM has successfully installed "oci-service-operator.vX.X.X"
```

### メトリクスサーバのインストール

OCI Service Meshでは、HPA(Horizontal Pod Autoscaler)を利用してIngress Gateway(後述)がスケールするので、メトリクスサーバをインストールしておきます。

```sh
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/high-availability.yaml
```

これで事前準備は完了です！

# OCI Service Meshの構築

ここからはOCI Service Meshを構築していきます。

構築に入る前にOCI Service Meshで登場するリソースを確認していきます。

まずはこちらですが、一般的なService Meshのイメージです。
![スクリーンショット 2022-05-26 10.25.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40392/26b26286-0d64-a948-ae2d-e8b39e925d73.png)

これを実現するために、OCI Service Meshでは以下のリソースを構築します。(これから構築するBookInfoアプリケーションを例にしたものです)

![スクリーンショット 2022-05-26 10.26.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40392/974b3d8c-c8dd-244c-e69a-99ad79454851.png)

この絵に登場するリソースは以下のような関係になっています。

![スクリーンショット 2022-05-26 10.27.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40392/628dc8f9-907a-8a52-64c0-d9da7c65a919.png)

各リソースを簡単に説明します。

* Mesh:サービスメッシュ全体を表すリソース
* Virtual Service:サービスメッシュ内の仮想サービス
* Virtual Deployment:Virtual Serviceに紐づける仮想デプロイメント
* Virtual Service Route Table:Virtual Service内のトラフィックルール。IstioでいうDestination Ruleのような存在。
* Ingress Gateway:メッシュ外からメッシュ内への通信を制御するGateway。IstioのIngress Gatewayとほぼ同じ。
* Ingress Gateway Route Table:Ingress Gatewayのトラフィックルール。
* Access Policy:Virtual Serviceに対するアクセス制御。

細かくみると他にもリソースがあるのですが、主なリソースだけピックアップしています。

では、実際にOCI Service Meshの環境を構築していきます。
今回はBookInfoアプリケーションを利用したService Mesh環境を構築していきます。

まず最初にBookInfoアプリケーション用のNamespaceを作成します。

```sh
kubectl create namespace bookinfo
```

次にbookinfo Namespaceに対して、OCI Service Meshを有効にするラベルを付与します。

```sh
kubectl label namespace bookinfo servicemesh.oci.oracle.com/sidecar-injection=enabled
```

BookInfoアプリケーションの標準リソースを作成します。

```yaml:bookinfo.yaml
##################################################################################################
# Details service
##################################################################################################
apiVersion: v1
kind: Service
metadata:
  name: details
  namespace: bookinfo
  labels:
    app: details
    service: details
spec:
  ports:
  - port: 9080
    name: http
  selector:
    app: details
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: bookinfo-details
  namespace: bookinfo
  labels:
    account: details
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: details-v1
  namespace: bookinfo
  labels:
    app: details
    version: v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: details
      version: v1
  template:
    metadata:
      labels:
        app: details
        version: v1
    spec:
      serviceAccountName: bookinfo-details
      containers:
      - name: details
        image: docker.io/istio/examples-bookinfo-details-v1:1.16.2
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 9080
        securityContext:
          runAsUser: 1000
---
##################################################################################################
# Ratings service
##################################################################################################
apiVersion: v1
kind: Service
metadata:
  name: ratings
  namespace: bookinfo
  labels:
    app: ratings
    service: ratings
spec:
  ports:
  - port: 9080
    name: http
  selector:
    app: ratings
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: bookinfo-ratings
  namespace: bookinfo
  labels:
    account: ratings
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ratings-v1
  namespace: bookinfo
  labels:
    app: ratings
    version: v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: ratings
      version: v1
  template:
    metadata:
      labels:
        app: ratings
        version: v1
    spec:
      serviceAccountName: bookinfo-ratings
      containers:
      - name: ratings
        image: docker.io/istio/examples-bookinfo-ratings-v1:1.16.2
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 9080
        securityContext:
          runAsUser: 1000
---
##################################################################################################
# Reviews service
##################################################################################################
apiVersion: v1
kind: Service
metadata:
  name: reviews
  namespace: bookinfo
  labels:
    app: reviews
    service: reviews
spec:
  ports:
  - port: 9080
    name: http
  selector:
    app: reviews
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: bookinfo-reviews
  namespace: bookinfo
  labels:
    account: reviews
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: reviews-v1
  namespace: bookinfo
  labels:
    app: reviews
    version: v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: reviews
      version: v1
  template:
    metadata:
      labels:
        app: reviews
        version: v1
    spec:
      serviceAccountName: bookinfo-reviews
      containers:
      - name: reviews
        image: docker.io/istio/examples-bookinfo-reviews-v1:1.16.2
        imagePullPolicy: IfNotPresent
        env:
        - name: LOG_DIR
          value: "/tmp/logs"
        ports:
        - containerPort: 9080
        volumeMounts:
        - name: tmp
          mountPath: /tmp
        - name: wlp-output
          mountPath: /opt/ibm/wlp/output
        securityContext:
          runAsUser: 1000
      volumes:
      - name: wlp-output
        emptyDir: {}
      - name: tmp
        emptyDir: {}
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: reviews-v2
  namespace: bookinfo
  labels:
    app: reviews
    version: v2
spec:
  replicas: 1
  selector:
    matchLabels:
      app: reviews
      version: v2
  template:
    metadata:
      labels:
        app: reviews
        version: v2
    spec:
      serviceAccountName: bookinfo-reviews
      containers:
      - name: reviews
        image: docker.io/istio/examples-bookinfo-reviews-v2:1.16.2
        imagePullPolicy: IfNotPresent
        env:
        - name: LOG_DIR
          value: "/tmp/logs"
        ports:
        - containerPort: 9080
        volumeMounts:
        - name: tmp
          mountPath: /tmp
        - name: wlp-output
          mountPath: /opt/ibm/wlp/output
        securityContext:
          runAsUser: 1000
      volumes:
      - name: wlp-output
        emptyDir: {}
      - name: tmp
        emptyDir: {}
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: reviews-v3
  namespace: bookinfo
  labels:
    app: reviews
    version: v3
spec:
  replicas: 1
  selector:
    matchLabels:
      app: reviews
      version: v3
  template:
    metadata:
      labels:
        app: reviews
        version: v3
    spec:
      serviceAccountName: bookinfo-reviews
      containers:
      - name: reviews
        image: docker.io/istio/examples-bookinfo-reviews-v3:1.16.2
        imagePullPolicy: IfNotPresent
        env:
        - name: LOG_DIR
          value: "/tmp/logs"
        ports:
        - containerPort: 9080
        volumeMounts:
        - name: tmp
          mountPath: /tmp
        - name: wlp-output
          mountPath: /opt/ibm/wlp/output
        securityContext:
          runAsUser: 1000
      volumes:
      - name: wlp-output
        emptyDir: {}
      - name: tmp
        emptyDir: {}
---
##################################################################################################
# Productpage services
##################################################################################################
apiVersion: v1
kind: Service
metadata:
  name: productpage
  namespace: bookinfo
  labels:
    app: productpage
    service: productpage
spec:
  ports:
  - port: 9080
    name: http
  selector:
    app: productpage
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: bookinfo-productpage
  namespace: bookinfo
  labels:
    account: productpage
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: productpage-v1
  namespace: bookinfo
  labels:
    app: productpage
    version: v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: productpage
      version: v1
  template:
    metadata:
      labels:
        app: productpage
        version: v1
    spec:
      serviceAccountName: bookinfo-productpage
      containers:
      - name: productpage
        image: docker.io/istio/examples-bookinfo-productpage-v1:1.16.2
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 9080
        volumeMounts:
        - name: tmp
          mountPath: /tmp
        securityContext:
          runAsUser: 1000
      volumes:
      - name: tmp
        emptyDir: {}
---
```

次にOCI Service Meshを構成するためのリソースを作っていきます。
なお、Manifestの中でアプリケーションのホスト名が定義されていますが、今回は`service-mesh.com`とします。
あとでhostsファイルを編集します。

```yaml:bookinfo_mesh.yaml
---
kind: Mesh
apiVersion: servicemesh.oci.oracle.com/v1beta1
metadata:
  name: bookinfo
  namespace: bookinfo
spec:
  compartmentId: <xxxxxxxxxxxxxxxxxxxxxxxx>
  certificateAuthorities:
    - id: <xxxxxxxxxxxxxxxxxxxxxxxx>
  mtls:
    minimum: PERMISSIVE
---
##################################################################################################
# Details service
##################################################################################################
kind: VirtualService
apiVersion: servicemesh.oci.oracle.com/v1beta1
metadata:
  name: details
  namespace: bookinfo
spec:
  mesh:
    ref:
      name: bookinfo
  defaultRoutingPolicy:
    type: UNIFORM
  compartmentId: <xxxxxxxxxxxxxxxxxxxxxxxx>
  hosts:
    - details
    - details:9080
---
kind: VirtualDeployment
apiVersion: servicemesh.oci.oracle.com/v1beta1
metadata:
  name: details-v1
  namespace: bookinfo
spec:
  virtualService:
    ref:
      name: details
  compartmentId: <xxxxxxxxxxxxxxxxxxxxxxxx>
  listener:
    - port: 9080
      protocol: HTTP
  accessLogging:
    isEnabled: true
  serviceDiscovery:
    type: DNS
    hostname: details
---
apiVersion: servicemesh.oci.oracle.com/v1beta1
kind: VirtualServiceRouteTable
metadata:
  name: details-route-table
  namespace: bookinfo
spec:
  compartmentId: <xxxxxxxxxxxxxxxxxxxxxxxx>
  virtualService:
    ref:
      name: details
  routeRules:
    - httpRoute:
        destinations:
          - virtualDeployment:
              ref:
                name: details-v1
            weight: 100
---
##################################################################################################
# Ratings service
##################################################################################################
kind: VirtualService
apiVersion: servicemesh.oci.oracle.com/v1beta1
metadata:
  name: ratings
  namespace: bookinfo
spec:
  mesh:
    ref:
      name: bookinfo
  defaultRoutingPolicy:
    type: UNIFORM
  compartmentId: <xxxxxxxxxxxxxxxxxxxxxxxx>
  hosts:
    - ratings
    - ratings:9080
---
kind: VirtualDeployment
apiVersion: servicemesh.oci.oracle.com/v1beta1
metadata:
  name: ratings-v1
  namespace: bookinfo
spec:
  virtualService:
    ref:
      name: ratings
  compartmentId: <xxxxxxxxxxxxxxxxxxxxxxxx>
  listener:
    - port: 9080
      protocol: HTTP
  accessLogging:
    isEnabled: true
  serviceDiscovery:
    type: DNS
    hostname: ratings
---
apiVersion: servicemesh.oci.oracle.com/v1beta1
kind: VirtualServiceRouteTable
metadata:
  name: ratings-route-table
  namespace: bookinfo
spec:
  compartmentId: <xxxxxxxxxxxxxxxxxxxxxxxx>
  virtualService:
    ref:
      name: ratings
  routeRules:
    - httpRoute:
        destinations:
          - virtualDeployment:
              ref:
                name: ratings-v1
            weight: 100
---
##################################################################################################
# Reviews service
##################################################################################################
kind: VirtualService
apiVersion: servicemesh.oci.oracle.com/v1beta1
metadata:
  name: reviews
  namespace: bookinfo
spec:
  mesh:
    ref:
      name: bookinfo
  defaultRoutingPolicy:
    type: UNIFORM
  compartmentId: <xxxxxxxxxxxxxxxxxxxxxxxx>
  hosts:
    - reviews
    - reviews:9080
---
kind: VirtualDeployment
apiVersion: servicemesh.oci.oracle.com/v1beta1
metadata:
  name: reviews-v1
  namespace: bookinfo
spec:
  virtualService:
    ref:
      name: reviews
  compartmentId: <xxxxxxxxxxxxxxxxxxxxxxxx>
  listener:
    - port: 9080
      protocol: HTTP
  accessLogging:
    isEnabled: true
  serviceDiscovery:
    type: DNS
    hostname: reviews
---
kind: VirtualDeployment
apiVersion: servicemesh.oci.oracle.com/v1beta1
metadata:
  name: reviews-v2
  namespace: bookinfo
spec:
  virtualService:
    ref:
      name: reviews
  compartmentId: <xxxxxxxxxxxxxxxxxxxxxxxx>
  listener:
    - port: 9080
      protocol: HTTP
  accessLogging:
    isEnabled: true
  serviceDiscovery:
    type: DNS
    hostname: reviews
---
kind: VirtualDeployment
apiVersion: servicemesh.oci.oracle.com/v1beta1
metadata:
  name: reviews-v3
  namespace: bookinfo
spec:
  virtualService:
    ref:
      name: reviews
  compartmentId: <xxxxxxxxxxxxxxxxxxxxxxxx>
  listener:
    - port: 9080
      protocol: HTTP
  accessLogging:
    isEnabled: true
  serviceDiscovery:
    type: DNS
    hostname: reviews
---
apiVersion: servicemesh.oci.oracle.com/v1beta1
kind: VirtualServiceRouteTable
metadata:
  name: reviews-route-table
  namespace: bookinfo
spec:
  compartmentId: <xxxxxxxxxxxxxxxxxxxxxxxx>
  virtualService:
    ref:
      name: reviews
  routeRules:
    - httpRoute:
        destinations:
          - virtualDeployment:
              ref:
                name: reviews-v1
            weight: 50
          - virtualDeployment:
              ref:
                name: reviews-v2
            weight: 25
          - virtualDeployment:
              ref:
                name: reviews-v2
            weight: 25
---
##################################################################################################
# Productpage services
##################################################################################################
kind: VirtualService
apiVersion: servicemesh.oci.oracle.com/v1beta1
metadata:
  name: productpage
  namespace: bookinfo
spec:
  mesh:
    ref:
      name: bookinfo
  defaultRoutingPolicy:
    type: UNIFORM
  compartmentId: <xxxxxxxxxxxxxxxxxxxxxxxx>
  hosts:
    - productpage
    - productpage:9080
---
kind: VirtualDeployment
apiVersion: servicemesh.oci.oracle.com/v1beta1
metadata:
  name: productpage
  namespace: bookinfo
spec:
  virtualService:
    ref:
      name: productpage
  compartmentId: <xxxxxxxxxxxxxxxxxxxxxxxx>
  listener:
    - port: 9080
      protocol: HTTP
  accessLogging:
    isEnabled: true
  serviceDiscovery:
    type: DNS
    hostname: productpage
---
apiVersion: servicemesh.oci.oracle.com/v1beta1
kind: VirtualServiceRouteTable
metadata:
  name: productpage-route-table
  namespace: bookinfo
spec:
  compartmentId: <xxxxxxxxxxxxxxxxxxxxxxxx>
  virtualService:
    ref:
      name: productpage
  routeRules:
    - httpRoute:
        destinations:
          - virtualDeployment:
              ref:
                name: productpage
            weight: 100
---
kind: IngressGateway
apiVersion: servicemesh.oci.oracle.com/v1beta1
metadata:
  name: bookinfo-ingress-gateway
  namespace: bookinfo
spec:
  compartmentId: <xxxxxxxxxxxxxxxxxxxxxxxx>
  mesh:
    ref:
      name: bookinfo
  hosts:
    - name: ochacafeHost
      hostnames:
        - service-mesh.com
      listeners:
        - port: 9080
          protocol: HTTP
          tls:
            serverCertificate:
              ociTlsCertificate:
                certificateId: <xxxxxxxxxxxxxxxxxxxxxxxx>
            mode: TLS
  accessLogging:
    isEnabled: true
---
apiVersion: servicemesh.oci.oracle.com/v1beta1
kind: IngressGatewayRouteTable
metadata:
  name: bookinfo-ingress-gateway-route-table
  namespace: bookinfo
spec:
  compartmentId: <xxxxxxxxxxxxxxxxxxxxxxxx>
  ingressGateway:
    ref:
      name: bookinfo-ingress-gateway
  routeRules:
    - httpRoute:
        ingressGatewayHost:
          name: ochacafeHost
        destinations:
          - virtualService:
              ref:
                name: productpage
---
kind: AccessPolicy
apiVersion: servicemesh.oci.oracle.com/v1beta1
metadata:
  name: bookinfo-policy
  namespace: bookinfo
spec:
  mesh:
    ref:
      name: bookinfo
  compartmentId: <xxxxxxxxxxxxxxxxxxxxxxxx>
  rules:
    - action: ALLOW
      source:
        virtualService:
          ref:
            name: productpage
      destination:
        virtualService:
          ref:
            name: details
    - action: ALLOW
      source:
        virtualService:
          ref:
            name: productpage
      destination:
        virtualService:
          ref:
            name: reviews
    - action: ALLOW
      source:
        virtualService:
          ref:
            name: reviews
      destination:
        virtualService:
          ref:
            name: ratings
    - action: ALLOW
      source:
        ingressGateway:
          ref:
            name: bookinfo-ingress-gateway
      destination:
        virtualService:
          ref:
            name: productpage
---
```

このファイルでは以下の3点を編集します。

```yaml
compartmentId: <xxxxxxxxxxxxxxxxxxxxxxxx>
```

はご自身のコンパートメントIDに差し替えてください。

```yaml
  certificateAuthorities:
    - id: <xxxxxxxxxxxxxxxxxxxxxxxx>
```

ここは、事前準備で作成した認証局のOCIDに差し替えてください。

```yaml
      listeners:
        - port: 9080
          protocol: HTTP
          tls:
            serverCertificate:
              ociTlsCertificate:
                certificateId: <xxxxxxxxxxxxxxxxxxxxxxxx>
```

ここは、事前準備で作成した証明書のOCIDに差し替えてください。

次に、2つ目のファイルで作成した`VirtualDeployment`と`Virtual Service`をバインドするためのリソースを作成します。
前述したリソースでは登場していないリソースが出てきますが、「`VirtualDeployment`と`Virtual Service`をバインドするための役割なんだな〜」くらいの理解で問題ありません。

```yaml:binding.yaml
kind: VirtualDeploymentBinding
apiVersion: servicemesh.oci.oracle.com/v1beta1
metadata:
  name: details-binding
  namespace: bookinfo
spec:
  virtualDeployment:
    ref:
      name: details-v1
      namespace: bookinfo
  target:
    service:
      ref:
        name: details
        namespace: bookinfo
---
kind: VirtualDeploymentBinding
apiVersion: servicemesh.oci.oracle.com/v1beta1
metadata:
  name: ratings-v1-binding
  namespace: bookinfo
spec:
  virtualDeployment:
    ref:
      name: ratings-v1
      namespace: bookinfo
  target:
    service:
      ref:
        name: ratings
        namespace: bookinfo
      matchLabels:
        version: v1
---
kind: VirtualDeploymentBinding
apiVersion: servicemesh.oci.oracle.com/v1beta1
metadata:
  name: reviews-v1-binding
  namespace: bookinfo
spec:
  virtualDeployment:
    ref:
      name: reviews-v1
      namespace: bookinfo
  target:
    service:
      ref:
        name: reviews
        namespace: bookinfo
      matchLabels:
        version: v1
---
kind: VirtualDeploymentBinding
apiVersion: servicemesh.oci.oracle.com/v1beta1
metadata:
  name: reviews-v2-binding
  namespace: bookinfo
spec:
  virtualDeployment:
    ref:
      name: reviews-v2
      namespace: bookinfo
  target:
    service:
      ref:
        name: reviews
        namespace: bookinfo
      matchLabels:
        version: v2
---
kind: VirtualDeploymentBinding
apiVersion: servicemesh.oci.oracle.com/v1beta1
metadata:
  name: reviews-v3-binding
  namespace: bookinfo
spec:
  virtualDeployment:
    ref:
      name: reviews-v3
      namespace: bookinfo
  target:
    service:
      ref:
        name: reviews
        namespace: bookinfo
      matchLabels:
        version: v3
---
kind: VirtualDeploymentBinding
apiVersion: servicemesh.oci.oracle.com/v1beta1
metadata:
  name: productpage-binding
  namespace: bookinfo
spec:
  virtualDeployment:
    ref:
      name: productpage
      namespace: bookinfo
  target:
    service:
      ref:
        name: productpage
        namespace: bookinfo
---
```

次に、Ingress Gatewayを担うServiceを作成します。
ここでも、`IngressGatewayDeployment`という前述では解説していないリソースが登場しますが、これはIstioでいうIngress GatewayのProxyのような存在だと考えてください。

```yaml:service.yaml
apiVersion: servicemesh.oci.oracle.com/v1beta1
kind: IngressGatewayDeployment
metadata:
  name: bookinfo-ingress-gateway-deployment
  namespace: bookinfo
spec:
  ingressGateway:
    ref:
      name: bookinfo-ingress-gateway
      namespace: bookinfo
  deployment:
    autoscaling:
      minPods: 1
      maxPods: 1
  ports:
    - protocol: TCP
      port: 9080
      serviceport: 443
  service:
    type: ClusterIP
---
apiVersion: v1
kind: Service
metadata:
  name: bookinfo-ingress
  namespace: bookinfo
  annotations:
    service.beta.kubernetes.io/oci-load-balancer-shape: "flexible"
    service.beta.kubernetes.io/oci-load-balancer-shape-flex-min: "10"
    service.beta.kubernetes.io/oci-load-balancer-shape-flex-max: "100"
spec:
  ports:
    - port: 80
      targetPort: 9080
      name: http
    - port: 443
      targetPort: 9080
      name: https
  selector:
    servicemesh.oci.oracle.com/ingress-gateway-deployment: bookinfo-ingress-gateway-deployment
  type: LoadBalancer
```

それでは作成したManifestを順番に適用していきます。

```sh
kubectl apply -f bookinfo.yaml
kubectl apply -f bookinfo_mesh.yaml
kubectl apply -f binding.yaml
kubectl apply -f service.yaml
```

これで環境構築は完了です。
念のため、Podが全て起動しているかどうかだけ確認しておきます。

```sh
[opc@client ~]$ kubectl get pods -n bookinfo
NAME                                                             READY   STATUS    RESTARTS   AGE
bookinfo-ingress-gateway-deployment-deployment-b6c6d8db6-2fcjd   1/1     Running   0          6d16h
details-v1-5498c86cf5-jdqsx                                      2/2     Running   0          6d16h
productpage-v1-65b75f6885-t5s8q                                  2/2     Running   0          6d16h
ratings-v1-b477cf6cf-pzgm7                                       2/2     Running   0          6d16h
reviews-v1-79d546878f-4gdg2                                      2/2     Running   0          6d16h
reviews-v2-548c57f459-7652d                                      2/2     Running   0          6d16h
reviews-v3-6dd79655b9-v9jx8                                      2/2     Running   0          6d16h
```

アプリケーションにアクセスするにはOCI LoadBalancerを利用するので、以下のコマンドでIPを確認します。  

```sh
[opc@oclient ~]$ kubectl get svc -n bookinfo
NAME                                          TYPE           CLUSTER-IP      EXTERNAL-IP       PORT(S)                      AGE
bookinfo-ingress                              LoadBalancer   10.96.42.109    x.x.x.x           80:30755/TCP,443:32264/TCP   6d16h
bookinfo-ingress-gateway-deployment-service   ClusterIP      10.96.224.188   <none>            443/TCP                      6d16h
details                                       ClusterIP      10.96.251.185   <none>            9080/TCP                     6d16h
productpage                                   ClusterIP      10.96.43.138    <none>            9080/TCP                     6d16h
ratings                                       ClusterIP      10.96.176.181   <none>            9080/TCP                     6d16h
reviews                                       ClusterIP      10.96.182.192   <none>            9080/TCP                     6d16h
```

`bookinfo-ingress`に表示される`EXTERNAL-IP`がLoadBalancerのアドレスになります。
今回は、`https://service-mesh.com`でアクセスしたいので、hostsファイルに以下の列を追記します。

`x.x.x.x  service-mesh.com`

これで`https://service-mesh.com/productpage`にアクセスし、以下のような画面が表示されれば成功です！

![スクリーンショット 2022-05-26 11.38.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40392/c43df332-8360-3052-89fe-e90ca7255250.png)

ちなみにOCIコンソール上から見るとOSOKを利用して各種リソースが作成されていることが確認できます。
逆に言えば、コンソールからリソースを作成すればOSOKがKubernetesクラスタに反映してくれます。

![スクリーンショット 2022-05-26 11.41.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40392/76171ff6-5d03-c10c-beb3-e52dcb4575ad.png)

# まとめ

今回は、OCI Service MeshでBookInfoアプリケーションを動かしてみました。
次回はOCI Service Meshを利用して監視を行ったり、アプリケーションのバージョンに応じてルーティングルールを変更してみたりということをやってみたいと思います。

# 参考記事

https://qiita.com/Skogkatter112/items/da7847861c203fdab8ee

https://docs.oracle.com/en-us/iaas/Content/service-mesh/home.htm

https://oracle-japan.github.io/ocitutorials/cloud-native/oke-for-intermediates/