ティーポットは珈琲を淹れられない

ソフトウェアエンジニアK5のブログ

ローカルDocker環境でSQSのモックElasticMQを利用する

2020年10月18日

AWS 環境で動作させるシステムの開発をしていて、ローカルの Docker 環境に SQS と同じ API で動作するモックを用意したくて ElasticMQ を利用してみました。

Docker イメージは幾つかありますが、roribio16/alpine-sqsを利用しました。

docker-compose.yml の用意

docker-compose の設定は以下のようにしました。 Node.js 環境も dokcer-compose で用意しておきます。

docker-compose.yml
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 のコンテナを指すように設定するのがポイントです。

send.js
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/ にアクセスすると、管理画面でキューにメッセージが来ていることが確認できます。 (ただこの管理画面、キューからメッセージを削除しても削除したものも表示されます。それはそれで便利なんですが。)

次はポーリングを仕掛けて受信してみましょう。

receive.js
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

受信できればオッケーです。


  1. alpine を使っているのは、本番環境の Fargate 用コンテナをサイズの小さい alpine で作るつもりでいて、開発環境も同じに合わせたかったからです。debian を使った方が色々とカスタマイズが楽だと思います。


© 2016-2020 K5