🐳

Kind で KEDA + Localstack(SQS) が可能になっていた

2023/02/22に公開

概要

EKS 上で動く、API からキューに情報を積み、SQS をトリガーとしてコンテナを起動させる非同期処理を開発していたのですが、ローカルで完結する環境の構築をしました。
これを実現するために KEDA を利用していたのですが、v2.8 までは LocalStack へアクセスする方法がなく、やむなく AWS 上に作成した SQS を利用していました。
しかし、ローカルで完結しないことに違和感を感じていた中、ふと調べてみると LocalStack を利用可能な変更が マージ されていたので、さっそく試してみました。

LocalStack の起動

Docker Compose を利用しました。手軽にまずは起動したかったためです。

version: '3.8'

services:
  localstack:
    image: localstack/localstack:1.3.1
    environment:
      - SERVICES=sqs,s3
      - DEFAULT_REGION=ap-northeast-1
    volumes:
      - ./docker-entrypoint-init.d:/docker-entrypoint-initaws.d
      - localstack-data:/var/lib/localstack:delegated
    ports:
      - 4566:4566

volumes:
  localstack-data:

起動時に Queue も作成したかったため初期化スクリプトを利用しています。

#!/bin/bash

awslocal sqs create-queue --queue-name localstack.fifo --attributes FifoQueue=true,ContentBasedDeduplication=true

Queue の名前は http://{LocalStack の参照名}:4566/000000000000/localstack.fifo となります。

API から Enqueue

Go で実装しました。

func Enqueue() () {
	sess, err := session.NewSession(&aws.Config{
	// ホストマシーンの場合は http://localhost:4566
	// Kind の場合は http://host.docker.internal:4566
	// Docker Compose の場合は下記
		Endpoint: "http://localstack:4566",
	})
	if err != nil {
		// do something
	}

	svc := sqs.New(sess)

	_, err = svc.SendMessage(&sqs.SendMessageInput{
		QueueUrl: aws.String("http://localstack:4566/000000000000/localstack.fifo")
		// ...
	})

	if err != nil {
		// do something
	}
}

コンテナの実行環境でダミーの認証情報を環境変数をセットすれば良いだけなので、AWS 上の SQS を参照するより複雑さがなくなります。

export AWS_ACCESS_KEY_ID="dummy"
export AWS_SECRET_ACCESS_KEY="dummy"
export AWS_SESSION_TOKEN="dummy"

KEDA でポーリング

ScaledJob の定義をします。ScaledObject でも設定は大きく変わらないと思います。

apiVersion: v1
kind: Secret
metadata:
  name: aws-secrets
data:
  AWS_ACCESS_KEY_ID: ZHVtbXk=              # dummy
  AWS_SECRET_ACCESS_KEY: ZHVtbXk=          # dummy
  AWS_DEFAULT_REGION: YXAtbm9ydGhlYXN0LTE= # ap-northeast-1
---
apiVersion: keda.sh/v1alpha1
kind: TriggerAuthentication
metadata:
  name: keda-trigger-auth-aws-credentials
spec:
  secretTargetRef:
    - parameter: awsAccessKeyID
      name: aws-secrets
      key: AWS_ACCESS_KEY_ID
    - parameter: awsSecretAccessKey
      name: aws-secrets
      key: AWS_SECRET_ACCESS_KEY
---
apiVersion: keda.sh/v1alpha1
kind: ScaledJob
metadata:
  name: scaled-job
  labels:
    keda: sqs
spec:
  jobTargetRef:
    completions: 1
    backoffLimit: 2
    template:
      metadata:
        labels:
          keda: sqs
      spec:
        containers:
          - name: job
            image: job:latest
            envFrom:
              - secretRef:
                  name: job
        restartPolicy: Never
  pollingInterval: 30
  successfulJobsHistoryLimit: 2
  failedJobsHistoryLimit: 2
  triggers:
    - type: aws-sqs-queue
      authenticationRef:
        name: keda-trigger-auth-aws-credentials
      metadata:
        queueURL: http://host.docker.internal:4566/000000000000/localstack.fifo
        queueLength: "5"
        awsRegion: "ap-northeast-1"
        awsEndpoint: "http://host.docker.internal:4566"

KEDA のデプロイは Kustomize でさくっとできます。
KEDA によりスケールされたコンテナで SQS から Dequeue や Delete ができるように、secretGenerator で認証情報を作成しコンテナの環境変数にセットします。

resources:
- https://github.com/kedacore/keda/releases/download/v2.9.3/keda-2.9.3.yaml
- scalejob.yaml
secretGenerator:
- literals:
  - AWS_ACCESS_KEY_ID=dummy
  - AWS_SECRET_ACCESS_KEY=dummy
  - AWS_SESSION_TOKEN=dummy
  name: job

ExternalName で LocalStack の CNAME を作成すると http://localstack:4566 で名前解決できるので統一感がでます。

apiVersion: v1
kind: Service
metadata:
  name: localstack
spec:
  externalName: host.docker.internal
  type: ExternalName

まとめ

ローカル環境で動作確認が完結するので良い感じです!
AWS 上に SQS を構築すると費用も発生しますし、保守の手間や複数名での開発でのコンフリクトに煩わされる可能性がありますが、その懸念も払拭できます!
ぜひお試しを!

Discussion