Rails
docker
ElasticMQ
docker-compose
shoryuken

docker-composeでShoryukenのローカル開発環境を構築するのに嵌った


tl;dr


  • ローカルでShoryukenの開発をするためにSQSのmockとなるものをたてたい


    • 簡単のためにdocker-composeを使いたい



  • SQSの代替としてElasticMQを使う


    • motoやlocalstackだと罠がある




Shoryukenをローカル開発するときの問題点

Shoryukenを起動するにはSQSに繋ぐ必要がありますがローカルからAWSに繋げたくないので、SQSコンパチのミドルウェアをなんらかローカルで起動する必要がありまが、Shoryukenのwikiをみるとmotoを使えばできるよ、と書いてあります。

たしかにmotoをインストールして、そこにつなぐようにすればローカルで開発できますが、開発環境構築に手間がかかってしまうので、やっぱりdocker-compose up一発で済ませたいところです。


Dockerでmotoを使う上での問題点

docker-composeするためにmotoのDockerイメージがほしいわけなんですが、motoのofficialなイメージはありません。1

なにかいいのないかな?って思ってたところにlocalstackの存在を思いだしました。

こちらはofficialなイメージが存在します。

いい感じです。


localstackとdocker-compose upの問題点

localstackのrepositoryにはdocker-compose.ymlがおいてあるので、これを参考にShoryuken workerとlinkさせればうまくいきそうです。

以下のような感じでしょうか。


docker-compose.yml

version: '3.2'

services:
worker:
build: .
command: ["shoryuken", "-C", "config/shoryuken.yml"]
tmpfs:
- /app/tmp
volumes:
- .:/app
- bundle_install:/usr/local/bundle
depends_on:
- sqs
environment:
RAILS_ENV: ${RAILS_ENV:-development}
SQS_URL: http://sqs:4576

sqs:
image: localstack/localstack
environment:
- SERVICES=sqs
- DOCKER_HOST=unix:///var/run/docker.sock
ports:
- 4576:4576
volumes:
- localstack:/tmp/localstack
- /var/run/docker.sock:/var/run/docker.sock

volumes:
bundle_install:
localstack:


しかしながら、これでdocker-compose upしてもworkerがSQSに接続できず、起動しません。

どうやらlocalstackはcontainerが立ち上がってすぐにSQSに繋げるわけではなく、container起動後指定したSERVICES起動していく仕組み2らしく、depends_onを指定していてもworkerから繋げません。

Shoryukenは起動時にSQSに接続して、queueが存在するかどうか確認してエラーだったら落ちてしまうのでこれだと使えません。

試してないですが、これはmotoも同じ3(たぶん)なので、別の手段を考える必要があります。

(追記)

Dockerのofficialドキュメントに記述がありました。

wait-if-forなどでwrapすることで、TCPコネクションをみて起動するのがよさそうです。

これだとlocalstackでもいけるかも。(confのmount次第)


ElasticMQを使う

localstackのSQS部分はElasitcMQを起動しているんですが、localstackを挟まずに直でElasticMQを使うようにしてみます。

結論として、これならdepends問題は解消されます。

ElasitcMQのDockerイメージはs12v/elasticmqを使うことにします。


docker-compose.yml

version: '3.2'

services:
worker:
build: .
command: ["shoryuken", "-C", "config/shoryuken.yml"]
tmpfs:
- /app/tmp
volumes:
- .:/app
- bundle_install:/usr/local/bundle
depends_on:
- sqs
environment:
RAILS_ENV: ${RAILS_ENV:-development}
SQS_URL: http://sqs:9324

sqs:
image: s12v/elasticmq
ports:
- 9324:9324

volumes:
bundle_install:


実はこれでもだめで、SQS自体には繋げるのですがまだcreate queueされてないのでやはりworkerが落ちてしまうのです。

worker起動前にcreate queueの処理を挟むか?とか考えますが、他にいい方法はないのでしょうか?


elasticmq.confをmountして解決する

色々ググってMocking SQS with ElasticMQ and docker-composeという記事を発見4しました。


Done! Enjoy your queue on port 9324! Happy messaging!

Not so fast, we are still not done here: as we are most likely using elasticMQ for testing, we also do not want to manually create our queues. We can provide a config file describing the queues we want to be in place:


ってことでconfig fileをおいておけばqueueが勝手に作られるらしい。

以下のようなconfigを用意します。


elasticmq.conf

node-address {

protocol = http
host = sqs
port = 9324
context-path = ""
}
rest-sqs {
enabled = true
bind-port = 9324
bind-hostname = "0.0.0.0"
sqs-limits = strict
}
generate-node-address = false
queues {
default{ }
}

queuesの中に作っておきたいqueue5を書いておくのと、node-address.hostにdocker-compose経由で参照するhost名指定します。

そしてこれをmountする。


docker-compose.yml

version: '3.2'

services:
worker:
build: .
command: ["shoryuken", "-C", "config/shoryuken.yml"]
tmpfs:
- /app/tmp
volumes:
- .:/app
- bundle_install:/usr/local/bundle
depends_on:
- sqs
environment:
RAILS_ENV: ${RAILS_ENV:-development}
SQS_URL: http://sqs:9324

sqs:
image: s12v/elasticmq
ports:
- 9324:9324
volumes:
- ./config/elasticmq.conf:/etc/elasticmq/elasticmq.conf

volumes:
bundle_install:


$ docker-compose up -d

$ aws --endpoint-url=http://localhost:9324 sqs list-queues
{
"QueueUrls": [
"http://sqs:9324/queue/default"
]
}

無事workerも起動しました:smile:





  1. 野良イメージはありますが、野良なのであんまり使いたくない 



  2. docker-composeのlogをみるとわかる。ちなみにSQS起動後 aws --endpoint-url=http://localhost:4576 sqs list-queues とかすると普通に繋げる 



  3. localstack同様に複数のAWS Serviceを起動するものなので 



  4. インターネッツは偉大 



  5. shoryuken.ymlに書いておくqueue