Skip to content

Infrastructure Adapterへの変換

本章では、Qmonus Value Streamにおいて、持ち込みのKubernetesのManifestからInfrastructure Adapterを生成し、持ち込みのアプリケーションをデプロイする手順を解説します。

本チュートリアルを実施する前に、Getting Started(GCP / Azure)、Cloud Native Adapterの拡張(GCP / Azure)、AssemblyLineの拡張(GCP / Azure)が完了していることをご確認ください。

なお、GCPについては(~2023/06) 初めてのQmonus Value Stream ~GCP編~を前提とします。

チュートリアルの流れは以下の通りです。

  • Qmonus Value Stream CLIのqvsctl adapter importコマンドを使用してサンプルのManifestからInfrastructure Adapterを生成し、パラメータ化を行います。
  • AssemblyLineを実行し、Infrastructure Adapterで定義したリソースとコンテナイメージ(=AssemblyLineの拡張(GCP / Azure)で持ち込みのコンテナレジストリにPushしたイメージ)がデプロイされていることを確認します。

本章で使用するサンプルManifestでデプロイされるアプリケーションは、以下の図に示すように、Kubernetes DeploymentリソースとService(type: NodePort)リソース、Ingressリソースで構成されるHTTP APIサーバです。Getting Started(GCP / Azure)で使用した環境のKubernetesクラスタをお使いください。

Infrastructure Adapter

0. サンプルManifestの準備

本チュートリアルでは、持ち込みのKubernetesのManifestからInfrastructure Adapterを生成してQmonus Value Streamを実行することを想定し、サンプルのManifestを使用して手順を解説します。

準備として、まずはサンプルのManifestを作成します。
Kubernetes Ingress、Service、Deploymentのリソース群を定義します。
${your_manifest_dir}はManifest管理用のディレクトリ等、任意のパスに置き換えてください。

また、Azure/AKSの場合のみ48-49行目のannotationsを追加してください。

bash
# 任意のManifestの管理ディレクトリのパスを定義します
your_manifest_dir=/path/to/dir

# 作業ディレクトリの作成
mkdir ${your_manifest_dir}/qvsctl_import_sample

# ingress, service, deploymentのリソース群Manifestを作成する
vim ${your_manifest_dir}/qvsctl_import_sample/manifests.yml
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-demo
  namespace: REPLACE_NS
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-demo
  template:
    metadata:
      labels:
        app: nginx-demo
    spec:
      containers:
      - name: nginx-demo
        image: REPLACE_IMAGE
        ports:
        - containerPort: 80
        resources:
          requests:
            cpu: 5m
            memory: 32Mi
          limits:
            cpu: 10m
            memory: 64Mi
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-demo
  namespace: REPLACE_NS
spec:
  type: NodePort
  ports:
  - port: 80
    targetPort: 80
  selector:
    app: nginx-demo
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-demo
  namespace: REPLACE_NS
  #Azure環境の場合のみannotationsを追加する
  annotations:
    kubernetes.io/ingress.class: azure/application-gateway

spec:
  rules:
    - http:
        paths:
          - path: /*
            pathType: ImplementationSpecific
            backend:
              service:
                name: nginx-demo
                port:
                  number: 80

1. Infrastructure Adapterの生成(CLI)

サンプルのManifestからInfrastructure Adapterを生成し、使用しているローカルリポジトリへ出力します。使用するリポジトリは、Cloud Native Adapterの拡張(GCP / Azure)の事前準備で作成したものを使用します。

bash
# ローカルリポジトリへ移動
cd applications-qvs-demo

# 本チュートリアル用のブランチをチュートリアルのブランチから作成
git checkout -b import-infrastructure-adapter getting-started

# 作業ディレクトリへ移動
cd .valuestream

# qvsctl adapter import コマンドを使用してManifestからInfrastructure Adapterを生成し、ローカルリポジトリへ出力
qvsctl adapter import -f ${your_manifest_dir}/qvsctl_import_sample/manifests.yml -o local/main.cue

2. Infrastructure Adapterのパラメータ化(CLI)

出力されたInfrastructure Adapterに対し、生成元のManifestへ割り当てていたパラメータを継承します。 ここでは、Deployment、Service、Ingressに使用されるk8sNamespaceとDeploymentで使用されるimageを、それぞれInfrastructure AdapterのパラメータとしてInfrastructure Adapter定義内に宣言しています。 また、package にはアプリケーションに対するKubernetesリソースとしてyourappというpackage名を入力しています。

bash
# Infrastructure Adapterをパラメータ化する
vim local/main.cue
yaml
-package REPLACE_ME
+package yourapp

DesignPattern: {
-    name:        "REPLACE_ME"
-    description: "REPLACE_ME"
+    name:        "yourapp"
+    description: "Application for importation of Infrastructure Adapter tutorial."
+
+    parameters: {
+        k8sNamespace: string
+        imageName: string
+    }
+
    resources: {
        app: {
            resource0: {
                apiVersion: "apps/v1"
                kind:       "Deployment"
                metadata: {
                    name:      "nginx-demo"
-                    namespace: "REPLACE_NS"
+                    namespace: parameters.k8sNamespace
                }
                spec: {
                    replicas: 1
                    selector: {
                        matchLabels: {
                            app: "nginx-demo"
                        }
                    }
                    template: {
                        metadata: {
                            labels: {
                                app: "nginx-demo"
                            }
                        }
                        spec: {
                            containers: [{
                                name:  "nginx-demo"
-                                image: "REPLACE_IMAGE"
+                                image: parameters.imageName
                                ports: [{
                                    containerPort: 80
                                }]
                                resources: {
                                    requests: {
                                        cpu:    "5m"
                                        memory: "32Mi"
                                    }
                                    limits: {
                                        cpu:    "10m"
                                        memory: "64Mi"
                                    }
                                }
                            }]
                        }
                    }
                }
            }
            resource1: {
                apiVersion: "v1"
                kind:       "Service"
                metadata: {
                    name:      "nginx-demo"
-                    namespace: "REPLACE_NS"
+                    namespace: parameters.k8sNamespace
                }
                spec: {
                    type: "NodePort"
                    ports: [{
                        port:       80
                        targetPort: 80
                    }]
                    selector: {
                        app: "nginx-demo"
                    }
                }
            }
            resource2: {
                apiVersion: "networking.k8s.io/v1"
                kind:       "Ingress"
                metadata: {
                    name: "nginx-demo"
-                    namespace: "REPLACE_NS"
+                    namespace: parameters.k8sNamespace
                }
                spec: {
                    rules: [{
                        http: {
                            paths: [{
                                path:     "/*"
                                pathType: "ImplementationSpecific"
                                backend: {
                                    service: {
                                        name: nginx-demo"
                                        port: {
                                            number: 80
                                        }
                                    }
                                }
                            }]
                        }
                    }]
                }
            }
        }
    }
}
yaml
package yourapp

DesignPattern: {
    name:        "yourapp"
    description: "Application for importation of Infrastructure Adapter tutorial."

    parameters: {
        k8sNamespace: string
        imageName: string
    }

    resources: {
        app: {
            resource0: {
                apiVersion: "apps/v1"
                kind:       "Deployment"
                metadata: {
                    name:      "nginx-demo"
                    namespace: parameters.k8sNamespace
                }
                spec: {
                    replicas: 1
                    selector: {
                        matchLabels: {
                            app: "nginx-demo"
                        }
                    }
                    template: {
                        metadata: {
                            labels: {
                                app: "nginx-demo"
                            }
                        }
                        spec: {
                            containers: [{
                                name:  "nginx-demo"
                                image: parameters.imageName
                                ports: [{
                                    containerPort: 80
                                }]
                                resources: {
                                    requests: {
                                        cpu:    "5m"
                                        memory: "32Mi"
                                    }
                                    limits: {
                                        cpu:    "10m"
                                        memory: "64Mi"
                                    }
                                }
                            }]
                        }
                    }
                }
            }
            resource1: {
                apiVersion: "v1"
                kind:       "Service"
                metadata: {
                    name:      "nginx-demo"
                    namespace: parameters.k8sNamespace
                }
                spec: {
                    type: "NodePort"
                    ports: [{
                        port:       80
                        targetPort: 80
                    }]
                    selector: {
                        app: "nginx-demo"
                    }
                }
            }
            resource2: {
                apiVersion: "networking.k8s.io/v1"
                kind:       "Ingress"
                metadata: {
                    name: "nginx-demo"
                    namespace: parameters.k8sNamespace
                }
                spec: {
                    rules: [{
                        http: {
                            paths: [{
                                path:     "/*"
                                pathType: "ImplementationSpecific"
                                backend: {
                                    service: {
                                        name: "nginx-demo"
                                        port: {
                                            number: 80
                                        }
                                    }
                                }
                            }]
                        }
                    }]
                }
            }
        }
    }
}

3. QVS Configの修正(CLI)

AssemblyLineの拡張(GCP / Azure)で使用したQVS Configを修正します。
ここでは、手順2で作成したInfrastructure Adapter yourappをコンパイルするように指定しています。 19-22行目ではデプロイ先クラスタの環境とあっていることを確認してください。

bash
vim qvs.yaml
yaml
params:
  - name: k8sNamespace
    type: string
  - name: imageName
    type: string

modules:
  - name: github.com/qmonus/sample
    local:
      path: . # relative path to qvs.yaml

designPatterns:
-  - pattern: github.com/qmonus/sample/local
+  - pattern: github.com/qmonus/sample/local:yourapp
    params:
      k8sNamespace: $(params.k8sNamespace)
      imageName: $(params.imageName)

# デプロイ先クラスタがGKEの場合
  - pattern: qmonus.net/adapter/official/pipeline/build:buildkitGcp
# デプロイ先クラスタがAKSの場合
  - pattern: qmonus.net/adapter/official/pipeline/build:buildkitAzure

  - pattern: qmonus.net/adapter/official/pipeline/deploy:simple
yaml
params:
  - name: k8sNamespace
    type: string
  - name: imageName
    type: string

modules:
  - name: github.com/qmonus/sample
    local:
      path: . # relative path to qvs.yaml

designPatterns:
  - pattern: github.com/qmonus/sample/local:yourapp
    params:
      k8sNamespace: $(params.k8sNamespace)
      imageName: $(params.imageName)

# デプロイ先クラスタがGKEの場合
  - pattern: qmonus.net/adapter/official/pipeline/build:buildkitGcp
# デプロイ先クラスタがAKSの場合
  - pattern: qmonus.net/adapter/official/pipeline/build:buildkitAzure

  - pattern: qmonus.net/adapter/official/pipeline/deploy:simple

リモートリポジトリに変更を反映します。

bash
# リモートリポジトリにpushする
git add qvs.yaml local/main.cue
git commit -m "Infrastructre Adapter Import QVS Tutorial"
git push origin import-infrastructure-adapter

4. AssemblyLineの実行(GUI)

登録したAssemblyLineを実行し、yourapp Adapterを使って、Simple APIアプリケーションをKubernetesにデプロイします。

  1. Qmonus Value StreamのGUIの左メニューより、AssemblyLineを選択します。
  2. 画面中央に表示される staging-deploy を選択します。
  3. Pipelines (Stages) に表示されている build,deploy カードを選択し、それぞれ全てのパラメータが埋まっていることを確認します。
  4. 以下のInput Parameterを入力し、 RUN ボタンを押下してCI/CDを開始します。
    • gitRevision: import-infrastructure-adapter

5. デプロイされたサンプルアプリケーションの確認(CLI)

Kubernetesにアクセスして、デプロイに成功したリソースとアプリケーションを確認します。 デプロイ完了後、Ingressが機能するまでに時間がかかりますので、5分ほどお待ちして確認ください。 以下の手順では、Kubeconfigをoutput.kubeconfig.yamlとしていますが、適宜ご利用しているKubeconfig名に読み替えて実行してください。

bash
# デプロイしたDeploymentを確認する
kubectl --kubeconfig output.kubeconfig.yaml get deployment
NAME         READY   UP-TO-DATE   AVAILABLE   AGE
nginx-demo  1/1     1            1

# デプロイしたServiceを確認する
kubectl --kubeconfig output.kubeconfig.yaml get service
NAME         TYPE           CLUSTER-IP       EXTERNAL-IP    PORT(S)        AGE
nginx-demo   NodePort                      <none>         80:xxxxx/TCP

# デプロイしたIngressを確認する(機能するまでに時間がかかるので、5分程待って実行)
kubectl --kubeconfig output.kubeconfig.yaml get ingress
NAME            CLASS    HOSTS         ADDRESS          PORTS   AGE
nginx-demo      <none>   *             ${external_ip}   80

# 上記IngressにアサインされたEXTERNAL-IPにアクセス
curl http://${external_ip}; echo

解説

本チュートリアルでは、Qmonus Value Stream CLIのqvsctl adapter importコマンドを用いて、サンプルのKubernetes ManifestからInfrastructure Adapterを生成出来ることを確認しました。このように、Kubernetes Manifestを既に利用している場合は、同一のリソースを提供するCloud Native Adapterのフォーマットに簡単に変換できます。 詳細については、Kubernetes ManifestからInfrastructure Adapterへの変換を参照してください。