kakts-log

技術・エンジニアリング組織などについて調べたことをまとめます

【GKE】 NodePoolのマシンタイプをN1からN4に変える際のポイント

概要

GKEで稼働しているサービスで、コスト・パフォーマンス最適化のために昨年末に東京リージョンでGAとなったN4インスタンスへの利用を検討していて、 N4インスタンスに変更する際のハマリポイントを整理します。

cloud.google.com

マシンタイプの切り替え方法

マシンタイプを切り替える方法は、主に下記2つがあります。

  1. 既存のNodePoolのマシンタイプを変更する方法
  2. 新しく使うマシンタイプを設定したNodePoolを新規で作り、kubectl cordon, drainにより旧NodePoolのNodeから段階的にPodを追い出す方法

ここでは、切り替え次の可用性などを考慮して、2番の方法で検証を進めました。

N4に変える際のポイント

N4から、従来のstandardが使えなくなり、ストレージがhyperdiskのみにしか対応しておりません。 https://cloud.google.com/compute/docs/general-purpose-machines?hl=ja#supported_disk_types_for_n4

これに関係して、一部のStatefulSetリソースに関連したPodが起動せず、eventを確認すると下記のエラーが出ていました。

AttachVolume.Attach failed for volume "pvc-hoge" : rpc error: code = InvalidArgument desc = ControllerPublish not permitted on node "projects/dummy/zones/asia-northeast1-a/instances/gke-dummy-instance-abc" due to backoff condition FailedAttachVolume ...


AttachVolume.Attach failed for volume "pvc-hoge" : rpc error: code = InvalidArgument desc = Failed to Attach: failed when waiting for zonal op: rpc error: code = InvalidArgument desc = operation operation-xxx failed (UNSUPPORTED_OPERATION): [pd-standard, n4-standard-4] features are not compatible for creating instance.

設定内容は下記のyamlマニフェストに記載の通りです。
GKEクラスター内で稼働しているStatefulSetが、StatefulSetに紐づくPersistentVolumeClaimでstandardのストレージクラスを設定しており、N4インスタンスでサポートされなくなったことによりPodの起動時にVolumeを割り当てられなくなったことによりエラーが発生していました。

  volumeClaimTemplates:
    - metadata:
        name: dummy-app-data
        labels:
          app.kubernetes.io/name: dummy-app
          app.kubernetes.io/instance: test
          app.kubernetes.io/component: dummy-app
      spec:
        storageClassName: standard # ここでstandardを指定する
        accessModes:
          - ReadWriteOnce
        resources:
          requests:
            storage: 10Gi

StatefulSetリソースの仕組み上、リソースを登録すると、StatefulSetは作成されたPodに紐づくVolumeを作成するためのPersisitentVolumeClaim(PVC)リソースを作成します。
StatefulSetは直接ボリュームを作成するわけではなく、このPVCリソースの情報をもとに、各KubernetesクラスターでサポートされているPersisitentVolume(PV)が作成されます。

StatefulSetの仕組みについては公式ドキュメントをご確認ください。

同様のエラーに対するGoogleCloudのissue Compute VM Instance (n4-standard-16) with attached... - Google Cloud Community

kubernetes.io

このボリュームのタイプを指定したものがStorageClassというKubernetesのリソースで、各プロバイダーで固有のストレージタイプを定義して割り当てることができます。

kubernetes.io

GKEにおけるStorageClassの利用については下記のドキュメントを確認ください https://cloud.google.com/kubernetes-engine/docs/concepts/persistent-volumes?hl=ja

standardストレージからhyperdiskへのデータの移行

ここで、N4インスタンスを利用するにあたり、Hyperdiskストレージを使うように設定します。 主な手順は以下の通りです。

既存のStatefulSetで新しいPersistentVolumeを紐づけるには

StatefulSetの仕様により、稼働済みのStatefulSetに対して上述したvolumeClaimTemplatesを使うように変更することはできません。
そのため、新しいStatefulSetリソースを用意して、volumeClaimTemplatesの設定で新しいStorageClassを指定して作成する必要があります。

詳細は別途記事にまとめます。

まとめ

GKEにおいてN4マシンタイプを利用する際の注意点として下記の問題があります。

  • N4インスタンスでは従来のPersistentDiskやローカルSSDを利用できず、HyperdiskのHyperdisk Balanced というストレージブロックしか利用できない
    • これに伴い、StatefulSetなど、Volumeにstorageクラスなどを割り当てている場合はPod起動時にボリューム割り当てエラーがでてしまいPodが起動できない

上記の点に対処できれば、それ以外の問題は特になく、以前より新しい世代のcpuを使ったVMへの切り替えにより、クラスターのリソースのコストパフォーマンスを改善できるため、利点が上回るかと思います。

思わぬ問題もあるかもしれないため、当然のことですがマシンタイプ切り替えの際は開発環境などで十分にテストすることが重要です。

[Valkey] valkey-bloom モジュールによるブルームフィルターの利用

概要

今回はValkeyにおいて、ブルームフィルターの機能を有効にする方法をまとめます。

valkey-server起動時にvalkey-bloomというモジュールを指定することで、Valkeyにブルームフィルター機能を追加することができます。

ブルームフィルターについては、以前のまとめた記事がありますのでこちらを参照ください。
kakts.dev

valkey-io/valkey-bloomについて

valkey-bloomは、Valkey公式のリポジトリで管理されているブルームフィルター用のValkey モジュールです。
github.com

Redisのブルームフィルター関連コマンド(BF.*)と互換性があり、Redisから移行した際にもこのモジュールを有効にしていれば使うことができます。 `

Valkeyサーバでブルームフィルターを使えるようにする

Valkeyのサーバでは、デフォルトではブルームフィルターの機能が使えないため、valkey-bloomモジュールを有効にしてBF.*コマンドを使えるようにします。

valkey-bloomモジュールのビルド

ここでは下記環境を前提に解説します。 rustで書かれたモジュールのため、rust関連のコマンドも必要となります。

環境
- ubuntu 22.04
- rustc , cargo: 1.84.0

ここで、valkey-io/valkey-bloomのREADMEに記載の通り、cargo buildを使ってビルドしていきます。

cargo build --all --all-targets  --release

このコマンド実行により、target/release/libvalkey_bloom.so に.soファイルが生成されます。
この.soファイルを、valkey-server起動時にオプションか、valkey.confで指定してあげれば利用可能です。

valkey-bloomモジュールを有効にする

Valkeyのサーバでvalkey-bloomモジュールを有効にする方法は、下記の2つあります。

  • valkey.conf内で loadmodule ディレクティブでビルドしたものを指定
  • valkey-server起動時に --loadmodule オプションで指定
  • valkey-serverを起動した上で、valkeyのクライアントでMODULE LOAD で.soファイルを指定

valkey.confで指定する方法

redis.confのように、Valkeyでも起動時の設定をvalkey.confファイルにまとめることができます。

loadmodule ディレクティブを使って .soファイルのパスを指定してあげます。

loadmodule /path/to/libvalkey_bloom.so

# valkey-server起動
valkey-server /path/to/valkey.conf

valkey-server起動時の--loadmoduleオプションで指定する方法

valkey.confでの指定でなく、--loadmoduleオプションでも指定できます。

valkey-server --loadmodule /path/to/libvalkey_bloom.so

valkeyのクライアントでMODULE LOAD で.soファイルを指定

valkeyのソースコードをビルドした際にvalkey-cliというコマンドも生成されます。 これを使ってvalkeyのサーバに接続したあと、MODULE LOAD /path/to/libvalkey_bloom.so を実行することでモジュールをロードできます。

127.0.0.1:6379> MODULE LOAD /path/to/libvalkey_bloom.so

上記3つの方法のどれかでvalkey-bloomモジュールを有効にすることで、クライアントからBF.*関連のコマンドが使えるようになります。

127.0.0.1:6379> BF.ADD
(error) ERR wrong number of arguments for 'BF.ADD' command

試しにBF.ADDを実行してみると、コマンドが存在することが確認できます。
次は、実際にコマンドを実行してみて、簡単にブルームフィルターの機能を試します。

valkey-bloomモジュールで使えるコマンド

基本的にはredisで元々使えていたブルームフィルター関連のコマンドBF.* と互換性があり、redisのドキュメントの方で詳細を確認できます。

redis.io

2025年1月時点ではvalkey-bloomでは下記コマンドをサポートしています。
- BF.EXISTS - BF.ADD - BF.MEXISTS - BF.MADD - BF.CARD - BF.RESERVE - BF.INFO - BF.INSERT - BF.LOAD

ここでは簡単な使い方をまとめます。

BF.ADD

127.0.0.1:6379> BF.ADD a b
(integer) 1
127.0.0.1:6379> BF.ADD a b
(integer) 0 # key: aに対してbが追加済みのため0
127.0.0.1:6379> BF.ADD a c
(integer) 1

BF.CARD カーディナリティの確認

ここでは、指定したキーのブルームフィルタのカーディナリティ、つまり要素数を確認できます。

127.0.0.1:6379> BF.CARD a
(integer) 2 # key: aに対して b, cというアイテムが追加されているため2

BF.EXISTS 要素がブルームフィルターに存在するかの確認

ブルームフィルターの仕組み上、偽陽性があります。

127.0.0.1:6379> BF.EXISTS a b
(integer) 1 # 存在する
127.0.0.1:6379> BF.EXISTS a d
(integer) 0 # 存在しない

BF.INFO 指定したブルームフィルターに関する情報を確認する

BF.INFOは、下記のように、ブルームフィルターの要素数やキャパシティなどの情報を確認できます。

127.0.0.1:6379> BF.INFO a
 1) Capacity
 2) (integer) 100
 3) Size
 4) (integer) 384
 5) Number of filters
 6) (integer) 1
 7) Number of items inserted
 8) (integer) 2
 9) Expansion rate
10) (integer) 2

こういう感じでvalkey-bloomモジュールをビルドし.soファイルを生成した上でモジュールを有効にし、valkeyクライアントからブルームフィルターの機能を使うことができました。

Cargo.tomlで指定するcrate-typeとcdylibについて

rustにおいて、Cargo.tomlでビルドの成果物としてバイナリや.soなどのライブラリファイルなど様々な形式で出力できますが。この形式は libのcrate_type で指定できます。

...
[lib]
crate-type = ["cdylib"]
...

このcrate-typeと、その中のタイプの一つであるcdylibについてまとめます。

crate-typeとは

Cargo.tomlにおけるcrate-type フィールドは、cargoコマンドによるビルド時に生成されるcrate typeを定義します。

crate-typeフィールドは文字列の配列で指定でき、単一のビルドターゲットに対して複数のcrate タイプを指定できます。

doc.rust-lang.org

バイナリやテスト、ベンチマークの場合はbin を指定します。 そのほかにも、lib rlib dylib staticlib proc-macro が指定できます。
それぞれの詳細についてはrustの公式ドキュメントを確認してください。
doc.rust-lang.org

Cargoのビルドターゲットについての詳細は、下記のCargoに関するドキュメントで確認できます。

doc.rust-lang.org

crate-type : cdylibについて

他の言語で書かれたプログラムや実行ファイルによって FFI(Foreign Function Interface)などによって呼び出されるような動的なシステムライブラリを生成する場合は crate-typeにcdylib を指定します。

これを指定した場合、cargoによってビルドした成果物のファイル形式はOSによって異なります。
例えばLinuxでは*.somacOSでは*.dylibWindowsでは*.dll となります。

(参考) rustにおけるFFI(Foreign Function Interface) について

FFIとは今まで知らなかったのですが、ざっくりいうと、あるプログラム言語で書かれたコードから、別のプログラム言語で書かれた関数などを呼び出す機構のことです。

下記の公式ドキュメントと、ブログ記事が参考になったので読んでみてください。

doc.rust-lang.org

qiita.com