Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ソフトウェアエンジニアにとってサステナブルなIaCを実現するための取り組み

Kazuki Aizawa
November 11, 2022

 ソフトウェアエンジニアにとってサステナブルなIaCを実現するための取り組み

CloudNative Days Tokyo 2022 プレイベント

Infrastructure as Codeによる構成管理は、品質の向上とリリースの高速化のために非常に有用ですが、ソフトウェアの成長とともにパラメータ管理が複雑化し、コードの見通しが悪くなるといった問題が発生します。
NTTコミュニケーションズでは、この問題を解決しつつ、ソフトウェアのインフラストラクチャ構成とそれをデプロイするワークフローを統一的なインターフェースで定義できる独自のIaC実装をCUE言語を利用して開発しました。
本セッションでは、この独自のIaC実装であるCloud Native Adapterについて、実例を交えながらご紹介します。

Kazuki Aizawa

November 11, 2022
Tweet

Other Decks in Technology

Transcript

  1. © NTT Communications Corporation All Rights Reserved. 1 自己紹介 會澤

    一輝 NTTコミュニケーションズ ソフトウェアエンジニア • 2021年 入社 • 社内・NTTグループ会社へ DevOps導入支援 • DevOpsプラットフォーム Qmonus Value Stream 開発 https://github.com/kaz130
  2. © NTT Communications Corporation All Rights Reserved. 2 じめに DevOpsプラットフォームをNTTグループに提供しています

    • アプリ開発者がアプリケーション実装に集中してもらうために、クラウド・インフラ構成を簡単に作 る仕組みを提供したい • 変化するインフラを前提としたCloud Nativeなアプリケーションを継続開発するために、インフラを コード化(Inftastructure as Code、以下IaC)していくことが必要 • IaC実装を効果的に再利用して、素早くアーキテクチャとCI/CDを作れる仕組みを内製 継続的に変更を加えていく際に、メンテナンスしやすい Inftastructure as Codeと ? プラットフォームチーム 再利用 クラウド・インフラ構成 プラクティスをまとめた IaC実装 アプリ開発チーム アプリ開発チーム アプリ開発チーム As a Service提供
  3. © NTT Communications Corporation All Rights Reserved. 3 アジェンダ •

    IaCにおけるインターフェースが抱える課題 • IaCへ CUE言語によるアプローチ • CUE言語とCloud Native Adapter
  4. © NTT Communications Corporation All Rights Reserved. 4 IaCを分解して考える Feedback

    loop Test Workflow User Interface どうやってインフラをコード定義するか。 どうやってインフラに設定を適用するか(順序)。 どうやってインフラが正常か確認するか。 どうやってインフラを観察し期待値に収束させるか。 User Infrastructure Infrastructure as Code 4
  5. © NTT Communications Corporation All Rights Reserved. 5 インターフェースにフォーカスを当てる 


    Feedback loop Test Workflow User Interface どうやってインフラをコード定義するか。 どうやってインフラに設定を適用するか(順序)。 どうやってインフラが正常か確認するか。 どうやってインフラを観察し期待値に収束させるか。 User Infrastructure Infrastructure as Code 5
  6. © NTT Communications Corporation All Rights Reserved. 6 IaCにおけるUser Interfaceに対するアプローチ

    IaCで 、インフラストラクチャ リソース構成と設定 期待値をコードで定義する KubernetesにおけるIaCとして、YAMLベース インターフェスを提供する例 Helm: • Kubernetes用パッケージマネージャ • Helm Chartによるテキストテンプレート機能を提供 Kustomize: • Kubernetesクラスタ リソースを管理 • overlay機能により構成をカスタマイズ
  7. © NTT Communications Corporation All Rights Reserved. 7 IaCにおけるUser Interface

    課題 IaCをメンテナンスする、すなわち継続的に変更を加えていく際に以下 課題があると考え た ① 事前に検査できない ② 見通しが悪い ③ プロジェクト間で 再利用が難し い 課題
  8. © NTT Communications Corporation All Rights Reserved. 8 課題① コード 堅牢性

    • HelmとKustomize どちらも、Kubernetesに適用してみないとAPI違反に気付けない • Kustomizeで規模が大きくなるにつれ、断片化された Overlayコンフィグを結合した後 マニフェ ストがAPI違反しているか目で見つける が難しい • IaCを実装を変更する際に、開発者 手元でエラーを検出・修正できない 生産性が低い ① 事前に検査できない apiVersion: apps/v1 kind: Deployment metadata: name: app01 spec: template: spec: containers: - name: test apiVersion: apps/v1 kind: Deployment metadata: name: app01 spec: template: containers: - image: testimage 階層が違う 適用時にエラー に気づく patch base
  9. © NTT Communications Corporation All Rights Reserved. 9 ② 見通しが悪い

    課題② コード 保守性 • パラメータが増えた Helm、Overlayコンフィグが増えた Kustomize それぞれについて、特定 値/コンフィグがどこで設定されたか追いかける が辛い • 設定した値/コンフィグが意図せず上書きされる • リファクタリングするにも大工事になりがち ◦ 例:「20,000+行 manifestをリファクタリングして分かったKustomize 美しきアーキテクチャと拡張性」Cloud Native Days Tokyo 2021, Hiroshi Hayakawa deployment/ base/ deployment.yaml service.yaml ... env/ prod/ deployment-patch.yaml service-patch.yaml ...
  10. © NTT Communications Corporation All Rights Reserved. 10 ③ プロジェクト間で

    再利用が難しい 課題③ コード 再利用性 • 既にあるIaC 良いプラクティスだけを抽出し再利用する が難しい ◦ Helm 全てを1つ パッケージにまとめるしかない ◦ Kustomizeで共通分を切り出して整理すると、見通し 悪さを加 させてしまう • 結果、既存プロジェクト YAMLをコピーすることから始め、プロジェクトごとにサイロで YAML ファイルを管理することになる • バグ修正や構成 改善を複数プロジェクトに渡って適用する が難しくなる プロジェクトA プロジェクトA IaC修正を他プロジェクトに水 平展開したい プロジェクトB プロジェクトC
  11. © NTT Communications Corporation All Rights Reserved. 11 課題 まとめ: YAMLエンジニア問題

    HelmやKustomizeそれぞれ 課題というより 、YAMLがソフトウェアエンジニアが扱うインターフェース として適していないと考える ① 事前に検査できない ② 見通しが悪い ③ プロジェクト間で 再利用が難し い 課題 ソフトウェアエンジニアにとって継続開発し やすい、データ記述言語を選定
  12. © NTT Communications Corporation All Rights Reserved. 12 CUE言語 スケーラブルにデータ/コンフィグを検証、生成するため

    データ記述言語 • Types are Values ◦ 値と型を区別しない ◦ 型による制約や検査がシンプルに記述できる • 制約によるデータ生成 ◦ CUE 継承 ような仕組みを持たず、パラメータ 上書きを許容しない ◦ 結合 順序に関係なく一貫した結果を生成できる • Go APIやProtocol Buffers, OpenAPI をサポート
  13. © NTT Communications Corporation All Rights Reserved. 13 Kubernetes manifest

    CUE言語による表現 apiVersion: "apps/v1" kind: "Deployment" metadata: { name: "nginx-deployment" labels: app: "nginx" } spec: { replicas: 3 selector: matchLabels: app: "nginx" template: { metadata: labels: app: "nginx" spec: containers: [{ name: "nginx" image: "nginx:1.14.2" ports: [{ containerPort: 80 }] }] } } apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment labels: app: nginx spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.14.2 ports: - containerPort: 80 cue export cue import Kubernetesドキュメント から引用
  14. © NTT Communications Corporation All Rights Reserved. 14 CUE言語によるデータ 記述

    apiVersion: "apps/v1" kind: "Deployment" metadata: { name: "nginx-deployment" labels: app: "nginx" } spec: { replicas: 3 selector: matchLabels: app: "nginx" template: { metadata: labels: app: "nginx" spec: containers: [{ name: "nginx" image: "nginx:1.14.2" ports: [{ containerPort: 80 }] }] } } “Key: Value” 形でデータを記述 “{ }” を使ってデータ構 を表現 単一 値 記述で “{ }” を 省略可能
  15. © NTT Communications Corporation All Rights Reserved. 15 Types are

    Values spec: { replicas: >=1 & <5 selector: matchLabels: app: string template: { metadata: labels: app: string spec: containers: [{ name: string image: string ports: [{ containerPort: int | *80 }, ...] }, ...] } } データ定義と同じように制約を記述 デフォルト値を指定 型や具体的な数値による制約
  16. © NTT Communications Corporation All Rights Reserved. 16 Types are

    Values $ cue eval deployment.cue replicas: invalid value 3 (out of bound >5): ./deployment.cue:2:11 ./deployment.cue:3:11 replicas: int replicas: >5 replicas: 3 cue eval 矛盾した制約 エラーとして出力される % cue eval deployment.cue replicas: 3 replicas: int replicas: >2 replicas: 3 cue eval データを評価することで、定義に矛盾がないか検証され、 制約を満たす具体的な値が出力される
  17. © NTT Communications Corporation All Rights Reserved. 17 API Schema

    Validation # カレントディレクトリでgo moduleを初期化 $ go mod init example.com # Kubernetes APIを取得 $ go get k8s.io/api/apps/v1 # Go APIからCUEのスキーマを作成 $ cue get go k8s.io/api/apps/v1 cue.mod/ └── gen/ └── k8s.io/ ├── api/ │ ├── apps/ │ └── core/ └── apimachinery/ └── pkg/ import ( "k8s.io/api/apps/v1" ) deployments: [_name=string]: v1.#Deployment & { _image: string _port: int ... } スキーマをimportして validation
  18. © NTT Communications Corporation All Rights Reserved. 18 API Schema

    Validationによるコード 検査 ① 事前に検査できない ① 型・スキーマによる検査 課題 NTTコム アプローチ • Kubernetes API Schemaを使ってエンジニア 手元で生成するマニフェストを事前に検 査する • 型、制約、値を全て同じ文法で記述できるため、検査 ため コードを追加したとしても シンプル
  19. © NTT Communications Corporation All Rights Reserved. 19 CUE言語によるTemplatingとComposition deployments:

    nginx: { _image: "nginx:1.14.2" _port: 80 } パラメータを変数化し、テン プレートとして利用 別 モジュールでテンプレートに存在しないパラメータを追加 (composite) deployments: [_name=string]: { _image: string _port: int metadata: { name: _name + "-deployment" labels: app: _name } spec: { replicas: 3 selector: matchLabels: app: _name ... } } deployments: nginx: apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment labels: app: nginx spec: replicas: 3 selector: matchLabels: app: nginx ... template: spec: containers: - env: - name: NGINX_HOST value: example.com deployments: nginx: spec: template: spec: containers: [{ env: [{ name: "NGINX_HOST" value: "example.com" }] }]
  20. © NTT Communications Corporation All Rights Reserved. 20 ② シンプルにコンフィグを分割した

    モジュール構成 ② 見通しが悪い Compositionとモジュール化によるコード管理 課題 NTTコム アプローチ • 機能分担や意図/コンテクストごとに小さいモジュールに分割し、コンフィグ 結合をシン プルに記述していくことで、見通し 良いモジュール構成を確立 • 言語仕様として、値 上書きを認めていないため、意図しない結合を排除できる
  21. © NTT Communications Corporation All Rights Reserved. 21 デモ: CUE言語によるマニフェスト生成 Kubernetes

    Manifest cue export kubectl apply • CUE言語を使ってマニフェストを記述 • Kubernetesにデプロイ
  22. © NTT Communications Corporation All Rights Reserved. 22 ここまで 課題とそ

    解決方法 CUE言語を活用することで、コード 堅牢性と保守性を向上させた 次いで、CUE言語を最大限活かしつつ、IaC実装を効果的に再利用するため 仕組みを導 入したい ① 事前に検査できない ② 見通しが悪い ③ プロジェクト間で 再利用が難し い ① 型・スキーマによる検査 ② シンプルにコンフィグを分割した モジュール構成 CUE言語 課題 NTTコム アプローチ CUE言語を活かした仕組みが 欲しい
  23. © NTT Communications Corporation All Rights Reserved. 23 2つ アプローチによる再利用可能なIaC実装

    パッケージ化 1. インターフェース規約 導入 2. パッケージ化されたIaC実装を読み出し、パラメータを埋め込む独自方式 実装 NTTコム 独自方式: Cloud Native Adapter Cloud Native Adapter すぐに使い出しできるプラクティスをまと めたIaC実装
  24. © NTT Communications Corporation All Rights Reserved. 24 課題 •

    IaC実装方法がプロジェクトごとに異なる場合、そ IaC実装をインフラに適用する手続きもプロジェク トごとに異なってしまう → CUE実装 インターフェース規約を導入 Cloud Native Adapter インターフェース規約 parameters: { k8sNamespace: string } resources: { deployment: { apiVersion: "apps/v1" kind: "Deployment" metadata: { name: "test" namespace: parameters.k8sNamespace } ... { } Cloud Native Adapter 規約例 • マニフェストを生成する際に受け取るパラメータを `parameters` フィールドで宣言する • 作成するインフラストラクチャを `resources` フィー ルドに列挙する • 実行するパイプラインを `pipelines` フィールドで宣 言する
  25. © NTT Communications Corporation All Rights Reserved. 25 Adapterによるインフラとワークフロー 宣言

    resources: { gcpPublicIp: ... gcpSeculityPolicy: ... k8sService: ... k8sIngress: ... } pipelines: { deploy: { tasks: { applyManifest: ... testApi: ... } } } # infrastructure configuration provider: kubernetes apiVersion: apps/v1 kind: Deployment spec: minReadySeconds: 60 replicas: 1 ... --- provider: kubernetes apiVersion: cloud.google.com/v1 kind: BackendConfig spec: connectionDraining: drainingTimeoutSec: 300 ... --- # CI/CD operations apiVersion: tekton.dev/v1beta1 kind: Pipeline metadata: name: deploy spec: tasks: - name: applyManifest taskRef: name: applyManifest params: - name: namespace value: $(params.namespace) ... — apiVersion: tekton.dev/v1beta1 kind: Task ... Cloud Native Adapter Cloud Native Adapterをコンパイルし てマニフェストを生成
  26. © NTT Communications Corporation All Rights Reserved. 26 課題 •

    他 エンジニアが実装したIaCを、アプリ開発者が使い始めるまで 手続きが煩雑 → インターフェース規約にしたがって実装された IaC 読み出しとコンパイル機能を導入 Adapter 読み出しとコンパイル 利用するCloud Native Adapterを宣言するConfig例 マニフェスト params: - name: k8sNamespace type: string modules: - name: qmonus.net/adapter/official revision: v0.1.0 designPatterns: - pattern: qmonus.net/adapter/official/k8s/simple params: k8sNamespace: $(params.k8sNamespace) 再利用可能な Cloud Native Adapter コンパイル 読み出し コンパイル 条件 参照
  27. © NTT Communications Corporation All Rights Reserved. 27 再利用可能な形にモジュールとして分割された Adapterを再利用

    • 分割されたモジュールを選択・結合して利用可能 • CUE言語により、結合 順序によらず一貫したマニフェストを生成 composites: [ { pattern: api.DesignPattern params: ... }, { pattern: containerSecurity.DesignPattern params: ... } ] name: "GKE API Adapter" resources: { gcpPublicIp: ... gcpSeculityPolicy: ... k8sService: ... k8sIngress: ... } name: "Container Security Adapter" pipelines: { scan: { tasks: ... } } Adapterにおけるモジュール 分割・結合
  28. © NTT Communications Corporation All Rights Reserved. 28 Cloud Native

    Adapterによるシステム 構築 「インフラストラクチャ構成」と「ワークフロー」を統一的なインターフェースで提供 コンフィグをパッケージ化されたモジュールとして分割・結合して再利用できる Container Security Cloud Native Adapter Uptime Check Cloud Native Adapter GKE API Cloud Native Adapter Infrastructure Configuration Build Scan CI/CD Pipeline Release Check
  29. © NTT Communications Corporation All Rights Reserved. 29 デモ: Cloud Native

    Adapterを利用したデプロイ Cloud Native Adapter Kubernetes Manifest Public API Cloud Native Adapter Composite • モジュール化された Adapterを使ってインフラを構築 • クラウド環境にアプリケーションをデプロイ kubectl apply
  30. © NTT Communications Corporation All Rights Reserved. 30 まとめ: 課題とそ アプローチ

    CUE言語とCloud Native Adapterにより、サステナブルなIaC実装と活用を実現 ① 事前に検査できない ② 見通しが悪い ③ プロジェクト間で 再利用が難し い ① 型・スキーマによる検査 ② シンプルにコンフィグを分割した モジュール構成 ③ 独自 パッケージと利用する仕 組み Cloud Native Adapter CUE言語 課題 NTTコム アプローチ 開発者にとってメンテナンスしやすいIaC インターフェースが必要
  31. © NTT Communications Corporation All Rights Reserved. 31 Qmonus Value

    Stream アプリをユーザへ提供するまで バリューストリームを最大化するDevOpsプラットフォーム • Cloud Native Adapterを利用したアプリケーション デリバリ・運用をサポート • 複数 アプリケーション・ワークフローを一元管理
  32. © NTT Communications Corporation All Rights Reserved. 32 We are

    hiring
 プロダクト志向で、DevOpsプラットフォーム = Qmonus Value Streamを一緒に開発し てくれるメンバーを募集しています!