🍓

ラズパイ×KEDAでサーバーレス入門

2021/12/19に公開
3

今回はサーバーレスの学習を兼ねて、KEDAをラズベリーパイ上で構築し、イベント駆動型サービスを開発/構築しました。

サーバーレスを支える技術

イベント駆動(Event-driven)とは、例えばボタンが押される(イベントが発生する)と処理が実行される(駆動する)という事象のことで、このような仕組み全般をイベント駆動型アーキテクチャとかいいます。

近日のキーワードになっているサーバーレス・コンピューティングですが、これを実現する手段として、インフラのイベント駆動化が注目されている感じ(だと思っている)です。

具体的なサービスを挙げるとAWS Lambda(Amazon)、Azure Functions(Microsoft)などです。FaaS(Function as a Service)とよび、コードの実行をサービスとして提供しています。このサービスのバックグラウンドにイベント駆動化されたインフラがいます。

イベントが発生したらユーザのコードを実行する環境をデプロイされます。このため開発者は毎回、クリーンな実行環境を用意し直したり、サーバをプロビジョニングしたりする必要がありません。基盤としては、従来のようにユーザがサーバを占有しないため、純粋な開発においてはマシンリソースを大きく節約することができます。

そしてこのイベントが発生したらユーザのコードを実行する環境をデプロイの部分に、インフラをイベント駆動化する技術であるKnativeやKEDAがいます。

KEDA

KEDAは端的にいうと、k8s上で動作するイベント駆動型のオートスケーラーです。
https://keda.sh
主な機能はイベントの受信Podのオートスケールになります。

恐ろしくシンプルなのですが、例えば

  • ユーザからRESTが送られてきたらPodを起動したい
  • CPUやRAM使用率が上がったらPodを減らしたい
  • Kafkaへのmessage量が一定以上になったらmessageを処理するPodをスケールダウンしたい

などが実現可能です。ちなみにCNCF(Cloud Native Computing Foundation:コンテナ技術についての技術を推進していこうとしている財団)に加入しました。

KEDA for arm64(RaspberryPi)

KEDA公式はaarch64(arm系アーキテクチャ)には対応していただけない様子...だったのですが、最近はCNCFのバックアップがあり、前向きに検討され始めてきていました!
https://github.com/kedacore/keda/issues/779

ただし現状では、まだ内部の開発者(mohsinonxrm氏)が提供しているだけで、最新バージョン2.5.0は使えず、2.4.0が提供されています。
→現在(2021-12-19)は2.6.0が最新で、2.5.0がmohsinonxrm氏によって提供されていました。
https://hub.docker.com/r/mohsinonxrm/keda

上記の現状のため少なくとも正式リリースまでは、自分でビルドする方法を知っておく必要があるなということで、今回はRaspberryPi上でKEDAをビルドしてしまいました。

ビルド方法

KEDAのリポジトリにDockerfileがあり、想定される環境下であれば問題なくビルドできるというものなのですが
https://github.com/kedacore/keda/blob/main/Dockerfile
RaspberryPiではそうもいかなかったです。issueやmohsinonxrmの資料を参考に、RaspberryPiでも動作するDockerfileを作成しました。

keda(manager)

コードをgit cloneして持ってくること、ARCH=arm、make実行前にgo mod tidyしている以外はほぼ内容同じです。

keda/dockerfile
FROM golang:1.17.3 as builder

ENV DEBIAN_FRONTEND=noninteractive
ENV TZ=Asia/Tokyo
WORKDIR /workspace

ENV ARCH=arm
RUN git clone -b v2.5.0 https://github.com/kedacore/keda.git && \ 
    cd keda && \ 
    go mod tidy && \ 
    make manager

FROM gcr.io/distroless/static:nonroot
WORKDIR /
COPY --from=builder --chown=nonroot:nonroot /workspace/keda/bin/keda .
USER nonroot:nonroot
ENTRYPOINT ["/keda", "--zap-log-level=info", "--zap-encoder=console"]

バージョンの異なる内容が必要な場合はリポジトリのDockerfileを参照して書き直してください。

keda-metrics-apiserver(adapter)

Metrics APIトリガーを利用するのに必要になります。make buildであればkeda(manager)もbinに出力されるので、実はimageに大きな違いがなく、最低1つのdockerイメージでデプロイできたりします。

それでも分けているのは、結局デプロイ時にyamlで設定を作成する必要があり、KEDAのアップデートが速いことを考えると、削減できるリソースが管理コストに見合わないためです。

keda-metrics-apiserver/dockerfile
FROM golang:1.17.3 as builder

ENV DEBIAN_FRONTEND=noninteractive
ENV TZ=Asia/Tokyo
WORKDIR /workspace

ENV ARCH=arm
RUN git clone -b v2.5.0 https://github.com/kedacore/keda.git && \ 
    cd keda && \ 
    go mod tidy && \ 
    make adapter
RUN mkdir -p /apiserver.local.config/certificates && \ 
    chmod -R 777 /apiserver.local.config

FROM gcr.io/distroless/static:nonroot
WORKDIR /
COPY --from=builder --chown=nonroot:nonroot /workspace/keda/bin/keda-adapter .
COPY --from=builder --chown=nonroot:nonroot /apiserver.local.config  /apiserver.local.config
USER nonroot:nonroot
ENTRYPOINT ["/keda-adapter", "--secure-port=6443", "--logtostderr=true", "--v=0"]

バージョンの異なる内容が必要な場合はリポジトリのDockerfile.adapterを参照して書き直してください。

デプロイ方法(kustomize)

https://github.com/kedacore/keda/releases/tag/v2.5.0
kedaのリリースからダウンロードできるYamlファイル(本記事ではkeda-2.5.0.yaml)を、以下のファイルと同じディレクトリに配置します。

manifests/keda/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
  - ../base
images:
  - name: ghcr.io/kedacore/keda-metrics-apiserver:2.5.0
    newName: registry.neko.lab:5005/root/serverless/keda-metrics-apiserver 
    newTag: latest
  - name: ghcr.io/kedacore/keda:2.5.0
    newName: registry.neko.lab:5005/root/serverless/keda
    newTag: latest

nameにはkeda-2.5.0.yamlで指定されているimageと同じ値を、newNamenewTagは自身の設定を記載します。レジストリにイメージをPush完了したらkubectl apply -k manifests/keda/でk8s上にデプロイできます。

以上でkedaの構築は完了です。

KEDAの使用例

KEDAのデプロイだけではおもしろくないので実際に便利そうなものを作ってみました。
RESTサーバにyoutubeのurlをPOSTすると、サーバにダウンロードしてくれる機構(ydl-sserver)です。youtube-dlを利用しています。

https://github.com/nkte8/serverless

KEDAはこちらが用意したMetricsサーバの特定URLに対して定期的に結果を取得しており、ここで得られる値によってスケジュールを行います。

ydl-serverはcurlにより動画URLをリクエストをされた時だけkubernetesにPodをスケジュールするため、基本的に動作リソースはmetricsサーバのみです。

リクエスト数頻度に合わせてPodのスケジュール数を変更するため、ピーク時に多くのPodを、リクエスト数が少ないときは少しずつ処理を実行します。

終わりに

一時期Knativeを学んでいたのですが、CNCFから外れるということで、KEDAに移りました。初めの頃はあまり理解できていなかったことも、きちんと使えるようになると色々わかってきていい感じです。

初めの章の説明ですが、私もサーバーレス初心者なので、なにか間違っていたり見当違いなことを言っているかもしれません。
なにかございましたら、よろしければご指摘いただいて、是非修正させてください。

参考

https://github.com/kedacore/keda/blob/main/BUILD.md
https://github.com/kedacore/keda/blob/main/Dockerfile.adapter
https://hub.docker.com/r/mohsinonxrm/keda-metrics-apiserver
https://github.com/kedacore/keda/discussions/2183

Discussion

ねこのねこの

本記事内の備考程度ではありますが、ここ最近はmohsinonxrm氏の精力的な行動によってarm用イメージが提供され、新しめなKEDAをRaspberryPiで動かせたりします。
自分でビルドするのが億劫であれば彼のイメージをお借りして、以下をapply -kでも良いと思いました。

resources:
  - https://github.com/kedacore/keda/releases/download/v2.5.0/keda-2.5.0.yaml
images:
  - name: ghcr.io/kedacore/keda-metrics-apiserver:2.5.0
    newName: mohsinonxrm/keda-metrics-apiserver
    newTag: 2.5.0
  - name: ghcr.io/kedacore/keda:2.5.0
    newName: mohsinonxrm/keda
    newTag: 2.5.0