ローカルDocker環境でSQSのモックElasticMQを利用する
AWS 環境で動作させるシステムの開発をしていて、ローカルの Docker 環境に SQS と同じ API で動作するモックを用意したくて ElasticMQ を利用してみました。
Docker イメージは幾つかありますが、roribio16/alpine-sqsを利用しました。
docker-compose.yml の用意
docker-compose の設定は以下のようにしました。 Node.js 環境も dokcer-compose で用意しておきます。
version: '3.7'
services:
# Node.js環境。開発時のnpmコマンド実行はここで行う。
node:
image: node:12.18.3-alpine3.12
volumes:
- ./:/project:delegated
tty: true
working_dir: /project
environment:
# AWS-SDKを動作させるのにダミーでいいので設定しておく必要がある
AWS_REGION: ap-northeast-1
AWS_ACCESS_KEY_ID: local
AWS_SECRET_ACCESS_KEY: dummy
# 入力キュー
# SQS互換のElasticMQを利用
input_queue:
image: roribio16/alpine-sqs
ports:
# 管理画面へアクセスするポート
- 9325:9325
この alpine-sqs というイメージは default という名前のキューが最初から作成された状態で起動してくれます。
Node.js 環境の用意
コンテナを起動しておきましょう。
$ docker-compose up -d
node コンテナに入って作業します。alpine 版を使ってるので bash が入っていなくて sh を指定します1。
$ docker-compose exec node sh
ここからは node コンテナ内でのコマンド実行の場合は、先頭を $ ではなく # で表します。
package.json を作成します。中身は適当でいいです。
# npm init
AWS SDK をインストールします。
$ npm install aws-sdk
AWS SDK でのアクセス
まず送信用のスクリプトを作成します。 endpoint に用意した ElasticMQ のコンテナを指すように設定するのがポイントです。
const AWS = require('aws-sdk');
const endpointUrl = 'http://input_queue:9324';
const queueUrl = endpointUrl + '/queue/default';
const sqs = new AWS.SQS({
apiVersion: '2012-11-05',
endpoint: endpointUrl,
});
const params = {
// Remove DelaySeconds parameter and value for FIFO queues
DelaySeconds: 10,
MessageAttributes: {
Title: {
DataType: 'String',
StringValue: 'The Whistler',
},
Author: {
DataType: 'String',
StringValue: 'John Grisham',
},
WeeksOn: {
DataType: 'Number',
StringValue: '6',
},
},
MessageBody: 'Information about current NY Times fiction bestseller for week of 12/11/2016.',
QueueUrl: queueUrl,
};
sqs.sendMessage(params, function (err, data) {
if (err) {
console.log('Error', err);
} else {
console.log('Success', data.MessageId);
}
});
node コンテナ上で実行してみます。
# node send.js
ホスト側のブラウザで http://localhost:9395/ にアクセスすると、管理画面でキューにメッセージが来ていることが確認できます。 (ただこの管理画面、キューからメッセージを削除しても削除したものも表示されます。それはそれで便利なんですが。)
次はポーリングを仕掛けて受信してみましょう。
const AWS = require('aws-sdk');
const endpointUrl = 'http://input_queue:9324';
const queueUrl = endpointUrl + '/queue/default';
const sqs = new AWS.SQS({
apiVersion: '2012-11-05',
endpoint: endpointUrl,
});
async function poll() {
const params = {
QueueUrl: queueUrl,
MaxNumberOfMessages: 10,
WaitTimeSeconds: 20,
MessageAttributeNames: ['Title', 'Author', 'WeeksOn'],
};
return new Promise((resolve, reject) => {
sqs.receiveMessage(params, (err, data) => {
if (err) {
console.error(err);
reject(err);
} else {
console.log(data);
resolve(data);
}
});
});
}
async function main() {
const data = await poll();
}
main();
node コンテナ上で実行します。
# node receive.js
受信できればオッケーです。
-
alpine を使っているのは、本番環境の Fargate 用コンテナをサイズの小さい alpine で作るつもりでいて、開発環境も同じに合わせたかったからです。debian を使った方が色々とカスタマイズが楽だと思います。
↩