データ基盤 データエンジニアリング Airbyte

Airbyte実行環境をKubernetesとTerraformで再構築して得たもの

データ基盤 データエンジニアリング Airbyte

技術部データ基盤チームに所属している@tosh2230です。

2023年後半から、ELTツールであるAirbyte Self-Managed(Community)版を本格的に活用していくことにしました。実行環境やその運用を一新しましたので、かいつまんでご紹介します。

  1. Airbyteに期待する役割
  2. データ転送対象
  3. Airbyte Self-Managed or Airbyte Cloud
  4. 実行環境の構築
    1. Kubernetes,Helm,Kustomize
    2. マニフェストファイルの生成
    3. Helm chartカスタマイズの具体例
  5. 設定情報の管理
    1. Terraform
    2. Octavia CLIからの方針転換
    3. 環境分離
    4. 設定情報の変更
    5. 開発環境での検証と本番環境への反映
  6. 実行環境を再構築して得たもの
    1. バージョンアップのしやすさ
    2. 気軽にデータソースを追加できる安心感
    3. 属人化の解消(予定)と技術スタックの統一
  7. 今後の課題

Airbyteに期待する役割

Airbyteを導入した目的は、SaaSからGoogle BigQueryへのデータ転送です。

Airbyteには豊富なコネクタがあるうえに、スキーマの自動認識や差分転送機能、パーティション設定、APIリクエスト制限に合わせた待機処理など、便利な機能が備わっています。これらを活用することで、データソースを追加する工数の削減が期待できます。

冒頭で「本格的に」と書きましたが、実は2021年からAirbyteを本番環境で運用しています。紹介している記事はこちらです。

ペパボのデータ基盤『Bigfoot』におけるAirbyteの本番運用

データ転送対象

これまでのZendesk Talkに加えて、新たにSalesforce,Zendesk Support,Zendesk Chatの3つを転送対象にしました。転送頻度は1時間おきです。

  • Salesforce
  • Zendesk Support
  • Zendesk Chat
  • Zendesk Talk

追加した3つはいずれも、ペパボのデータ活用の中核をなすデータソースです。データの可用性を担保するうえで、Google Compute EngineでのDocker Composeという既存の構成で要件を満たすのは厳しいと考えて、実行環境から再検討することにしました。

Airbyte Self-Managed or Airbyte Cloud

今回、Airbyteを自社で管理することを選びましたが、Airbyte Cloudというマネージドサービスもあります。費用はデータ転送量・行数による従量課金制です。

Airbyteの実行基盤を管理しなくてよい点は魅力的ではあるものの、今後社内での利用シーンが広がっていくことを考えると、ペパボがもっているプライベートクラウドで稼働させることによるコストメリットが大きいと考えました。

実行環境の構築

Kubernetes,Helm,Kustomize

Airbyte実行環境は、オンプレミスなプライベートクラウドに構築しているKubernetesクラスタです。環境構築にあたっては、公開されているHelm chartを利用しています。

Chartには、Airbyteを動かすために必要なリソースが定義されていますが、追加したいリソースやカスタマイズしたい設定がありました。そこでhelm templateコマンドでマニフェストファイルを生成したうえで、Kustomizeでリソースの追加やパッチの適用を行う方式にしました。

利用しているバージョンは下記のとおりです。

  • Airbyte: v0.50.31
  • Helm chart: v0.49.5

マニフェストファイルの生成

マニフェストファイル関連のディレクトリの構成は下記のようにしています(一部省略)。本番環境と開発環境を構築します。

$ tree .
.
├── base
├── overlays
│   ├── development
│   │   ├── from_helm
│   │   │   ├── airbyte
│   │   │   │   ├── charts
│   │   │   │   └── templates
│   │   │   └── kustomization.yaml
│   │   ├── kustomization.yaml
│   │   └── patches
│   └── production
│       ├── from_helm
│       │   ├── airbyte
│       │   │   ├── charts
│       │   │   └── templates
│       │   └── kustomization.yaml
│       ├── kustomization.yml
│       └── patches
└── values.yaml

下記のコマンドを実行することで、Helm chartからマニフェストファイルを生成しています。

rm -rf overlays/production/from_helm
helm template airbyte airbyte/airbyte -n prod \
  -f values.yaml \
  --output-dir overlays/production/from_helm
cd overlays/production/from_helm && rm -f kustomization.yaml && \
  kustomize create --autodetect --recursive

マニフェストファイルからリソースを更新するのは、Argo CDによるGitOpsで行っています。mainブランチへのマージによって、Kubernetesクラスタを更新します。

Helm chartカスタマイズの具体例

先に述べた、chartへのカスタマイズの具体例をいくつか挙げます。

Ingress

Airbyte環境へ安全にアクセスできるようにIngressを設置しています。Web UIにはoauth2-proxyによる認証、Web APIではIP認証を行っています。

Secrets

マニフェストで必要となる秘匿情報ではSealed Secretsを利用しています。秘匿情報には、Airbyteデータベースとして設置しているPostgreSQLへのログイン情報や、Google CloudのCredentialsなどがあります。

airbyte-api-server

Airbyte v0.50.31には、Airbyteコンポーネントのひとつであるairbyte-api-serverINTERNAL_API_URLという環境変数がありますが、この環境変数がchartに反映されていないというIssueが報告されています。利用していたchartのバージョンはこの問題に該当していましたので、環境変数を追加するパッチを適用しています1

airbyte-bootloader

利用可能なコネクタの一覧であるコネクタカタログは、chartのデフォルト設定では固定されています。これはつまり、Airbyte本体をバージョンアップしないとコネクタカタログが更新されないということを指します。

コネクタカタログの更新を担当するのはairbyte-bootloaderです。下記のように、bootloaderコンテナの環境変数に対してパッチを当てることで最新のコネクタカタログを取得し、Airbyte本体をバージョンアップすることなく新しいコネクタバージョンを選べるようになります2

- op: add
  path: /spec/containers/0/env/-
  value:
    name: CONNECTOR_REGISTRY_SEED_PROVIDER
    valueFrom:
      configMapKeyRef:
        name: airbyte-airbyte-env
        key: CONNECTOR_REGISTRY_SEED_PROVIDER
---
apiVersion: v1
kind: ConfigMap
metadata:
  (中略)
data:
  CONNECTOR_REGISTRY_SEED_PROVIDER: remote

ここまで、あたかも自分で構築したかのように書きましたが、やったのはほとんど@pyamaです。私はApproveボタンを押しました。

設定情報の管理

続いて、Airbyteの設定情報をどのように管理しているかをご紹介します。

Terraform

Airbyteには主に3つの設定情報があります。Source,Destination,Connectionです。

  • Source: データ取得元の種類と接続情報
  • Destination: データ送信先の種類と接続情報
  • Connection: SourceとDestinationを組み合わせた転送設定

これらの管理をTerraformで行っています。公式のTerraform Providerが公開されていますので、ありがたく活用しています。利用しているバージョンは、現時点で最新のv0.3.7です。

Octavia CLIからの方針転換

当初、設定情報の管理は Airbyte 独自の管理ツールであるOctavia CLIを使っていたのですが、一連の作業の中でOctavia CLIが今後メンテナンスされない方針であることに気づき、Terraformによる管理に切り替えました。

Note: This tutorial leverages Octavia CLI, which is an alpha unofficial CLI that won't be maintained. Since the publication of this tutorial, Airbyte has released an official Terraform Provider, which we would advise to use instead of the CLI.

環境分離

上述したように、Airbyteの実行環境として本番環境と開発環境の2つを構築しています。両環境の設定をどのように管理するかを検討した結果、環境ごとにディレクトリやtfstateを分けることにしました。

$ tree -a .
.
├── development
│   ├── .env
│   ├── connections.tf
│   ├── destinations.tf
│   ├── sources.tf
│   ├── terraform.tf
│   ├── variables.tf
│   └── workspaces.tf
└── production
    ├── .env
    ├── connections.tf
    ├── destinations.tf
    ├── sources.tf
    ├── terraform.tf
    ├── variables.tf
    └── workspaces.tf

他には、Terraformのworkspacesを使う案がありました。前提として、両環境には転送頻度や検証作業の都合で設定が異なる箇所があります。Workspacesで環境を分けると、条件分岐が複数発生して可読性が下がるおそれがありました。加えて、Airbyte設定情報の総コード行数はそこまで多くはないため、2環境分のコード重複は許容できると判断しました。

設定情報の変更

設定情報は、基本的にGitHub Actionsで変更しています。Pull requestがmainブランチへマージされるとterraform applyが行われます。

terraform planはCIにて実行されますが、ローカルでも実行できると便利です。ただし、SourceやDestionationの設定で秘匿情報を扱いますので、何らかの方法で埋め込む必要があります。もともと秘匿情報を管理するツールとして1Passwordを使っていたため、1Password CLIを使うことにしました。

例として、Terraform変数google_cloud_sa_keyへ秘匿情報を埋め込むことを考えます。

$ cat development/variables.tf
variable "google_cloud_sa_key" {
  type      = string
  sensitive = true
  default   = ""
}

.envファイルで、Terraform変数に対応する形で秘匿情報への参照URIをセットします。このURIは、1Passwordのアイテムで「秘密参照をコピーする」を選ぶと取得できます。

$ cat development/.env
TF_VAR_google_cloud_sa_key="op://bigfoot/1234567890/credentials.json"

この.envファイルをop runコマンドのenv-fileオプションを経由して渡すと、秘匿情報がセットされた状態でplanが実行されます。

$ op run --env-file=.env --no-masking -- terraform plan

開発環境での検証と本番環境への反映

動作検証を目的に試行錯誤するのは、Web UIから行うのが便利だと思います。新しいデータソースを追加する場合、開発環境での動作検証から本番環境への反映までを下記の流れで行っています。

  1. 開発環境のWeb UIでSource,Destionation,Connectionの設定を行う
  2. Connectionのsyncを実行し、期待どおりにデータを転送できているかを確認する
  3. 動作確認を終えたら、Terraformのimportブロックを使って開発環境のTerraformコードをつくる
  4. 開発環境にapplyする
  5. 開発環境のTerraformコードをもとに、本番環境のコードを書く
  6. 本番環境にapplyする

この手順で進めることで、本番環境と開発環境で差分が発生しにくいうえに、コミットとして変更履歴が残るのが良いと思っています。

実行環境を再構築して得たもの

バージョンアップのしやすさ

Docker Composeの時代にAirbyteのバージョンアップを行ったときは、「やってみないとわからないですね…」となりがちで、手順の作成や準備に一定の時間が必要でした。KubernetesとTerraformの構成に変わってからは、コードの差分で変更内容を把握しやすくなりました。万が一の切り戻しも素早く行えるため、気持ちを楽にして作業できます。加えて、Argo CDによりコンポーネントが視覚化されたことで、問題が発生した時にどこがあやしいかを特定しやすくなりました。

また、Airbyteの良いところのひとつに、コネクタの独立性が高いことが挙げられます。コネクタの実態はDocker imageなので、Airbyte本体への依存が抑えられているためです。コネクタバージョンのみを変えて検証できるので、動作検証での原因切り分けがしやすくなっています。

Airbyteは活発に開発が行われているために、リリース頻度は比較的高い印象です。バージョンアップしやすい構成にできましたので、新機能による恩恵を早く受けられます。時にはセキュリティアップデートを即座に適用することで、安心・安全な環境を維持することにもつながります。

気軽にデータソースを追加できる安心感

Airbyteのようなソフトウェアを使えば、追加の実装なしでデータウェアハウスへデータを転送する機能を得られます。ただ実際には、データソースが増えていくにつれて、多数のsync処理をお互いが干渉することなくスケールする実行環境が求められるようになるかと思います。Kubernetesにしたことで、リソースを柔軟にコントロール可能な安定した実行環境にできました。

実際に、SalesforceとZendeskをデータソースとして追加する過程で実行環境に関する問題はほとんど起きませんでした。Airbyteを上手に使うことでデータ転送にかける時間を減らし、データを活用する工程に注力していきたいものです。

属人化の解消(予定)と技術スタックの統一

先に書いたように、本番環境に期待する状態をコードにしましたので、これからは変更履歴を残せます。「なぜこの設定になっているのか」を把握しやすくなり、変更をpull requestで行うことから属人化の解消が期待できます。これは、現在のチームメンバーだけでなく、将来新しく加わる方々がキャッチアップするときにも嬉しいはずです。

また今回使っているソフトウェアは、ペパボでよく使われているものばかりです。ハードウェアも社内リソースを活用しました。社内でよく使われている技術を用いて実装することで、アーキテクチャを説明するときの共通言語が増えます。データ基盤を身近に感じてもらうという効果も期待しています。

今後の課題

いまのところ見えている課題もいくつかあります。

  • コネクタの新バージョンがリリースされたことに気づけない
  • 使用するコネクタバージョンの管理と更新が手動

前者についてはいずれ解決できそうですが、後者については良い方法を思いついていません。

使用するコネクタバージョンはWeb UIで変更できますが、APIは公開されていないようです。本番環境と開発環境で指定しているコネクタのバージョンが異なるケースが起こりがちなので、何かしらの方法で管理したいと思っています。理想としては、APIが公開されてTerraformで管理できるようになると、さらに便利になりそうです。


  1. このIssueはchart v0.50.10で修正されたとのことです。次のバージョンアップの際に検証してみようと思います。 

  2. 詳しい内容は Airbyteで最新のconnector registry seedを参照する をご参照ください。