TopicとSubscription作成を内包したCloud PubSub エミュレータのDocker Imageを作る
動機
GCPのCloud PubSubは、テスト用にlocal emulatorを提供しており、gcloud cliより以下のコマンドで起動することができます。
gcloud beta emulators pubsub start --project=PUBSUB_PROJECT_ID [options]
このままcloud sdkを用いてtopicとsubscriptionを作成してテストをすることもできますが、docker-composeを用いたintegration test等と組み合わせるとテストを実行する前にtopicとsubscriptionを用意したり、既に存在する場合は作成をskipしたりといったhelperを書く必要がでてきます。
こうした苦労をなくすために、image起動時にあらかじめ指定したtopicとsubscriptionを作成した状態でpubsub emulatorが起動するようなDockerfileを作成しました。
Dockerfile
FROM gcr.io/google.com/cloudsdktool/cloud-sdk:367.0.0-emulators
RUN apt-get update && \
apt-get install -y git python3-pip netcat && \
git clone https://github.com/googleapis/python-pubsub.git
ENV PROJECT_ID=emulator \
TOPIC_ID=event-topic \
SUBSCRIPTION_ID=event-subscription \
PUSH_ENDPOINT=http://host.docker.internal:3000
WORKDIR /python-pubsub/samples/snippets
RUN pip3 install virtualenv && \
virtualenv env && \
. env/bin/activate && \
pip3 install -r requirements.txt
COPY ./entrypoint.sh ./
EXPOSE 8085
ENTRYPOINT ["./entrypoint.sh"]
entrypoint.sh
#!/bin/bash
set -em
export PUBSUB_PROJECT_ID=$PROJECT_ID
export PUBSUB_EMULATOR_HOST=0.0.0.0:8085
gcloud beta emulators pubsub start --project=$PUBSUB_PROJECT_ID --host-port=$PUBSUB_EMULATOR_HOST --quiet &
while ! nc -z localhost 8085; do
sleep 0.1
done
. env/bin/activate
python3 publisher.py $PUBSUB_PROJECT_ID create $TOPIC_ID
python3 subscriber.py $PUBSUB_PROJECT_ID create-push $TOPIC_ID $SUBSCRIPTION_ID $PUSH_ENDPOINT
fg %1
解説
Dockerfile
Dockerfileでは、cloud-sdk-dockerのemulatorが内包されたimageを使用しています。image tagの一覧はregistryから確認できます。
FROM gcr.io/google.com/cloudsdktool/cloud-sdk:367.0.0-emulators
image起動時にpubsubのtopicとsubscriptionの作成をcloud sdkを介して行う必要があるため、pythonのサンプルプロジェクトをcloneし、同時にpython3とnetcatをinstallしています。
RUN apt-get update && \
apt-get install -y git python3-pip netcat && \
git clone https://github.com/googleapis/python-pubsub.git
環境変数で作成するtopic idや、subscriptionのpush endpointを指定しています。
ENV PROJECT_ID=emulator \
TOPIC_ID=event-topic \
SUBSCRIPTION_ID=event-subscription \
PUSH_ENDPOINT=http://host.docker.internal:3000
cloneしたpythonのサンプルプロジェクトの/python-pubsub/samples/snippets
をworking dirに設定し、依存関係のinstallを行っています。
WORKDIR /python-pubsub/samples/snippets
RUN pip3 install virtualenv && \
virtualenv env && \
. env/bin/activate && \
pip3 install -r requirements.txt
ref: https://maku77.github.io/python/env/venv.html
後述するentrypoint.sh
ファイルをcopyし、entrypointで実行しています。
COPY ./entrypoint.sh ./
EXPOSE 8085
ENTRYPOINT ["./entrypoint.sh"]
entrypoint.sh
shellにはbashを指定し、-mでjob controlを有効にしています。
#!/bin/bash
set -em
pubsub emulatorが読み込む環境変数をexportしています。
export PUBSUB_PROJECT_ID=$PROJECT_ID
export PUBSUB_EMULATOR_HOST=0.0.0.0:8085
後でtopicやsubscriptionの作成を行うため、pubsub emulatorをバックグラウンドで起動し、netcat
を使用してlocalhost:8085
がlistenするまで待機しています。末尾の&
によりバックグラウンドで起動されます。
gcloud beta emulators pubsub start --project=$PUBSUB_PROJECT_ID --host-port=$PUBSUB_EMULATOR_HOST --quiet &
while ! nc -z localhost 8085; do
sleep 0.1
done
pythonのサンプルプロジェクトで提供されているpublisher.py
とsubscriber.py
を実行し、topicとsubscriptionを作成しています。今回はpush subscriptionを作成してるので、push endpointも指定しています。
. env/bin/activate
python3 publisher.py $PUBSUB_PROJECT_ID create $TOPIC_ID
python3 subscriber.py $PUBSUB_PROJECT_ID create-push $TOPIC_ID $SUBSCRIPTION_ID $PUSH_ENDPOINT
最後にfg
で先ほどbackgroundに移行させたemulatorの起動プロセスをforegroundに移行させます。これにより最終的にemulatorのプロセスがdocker image起動後に持続することになります。
fg %1
docker-compose.yaml
最後に、作成したpubsub emulatorのimageを使用したサンプルのdocker-compose.yamlを紹介します。
環境変数のPUSH_ENDPOINT
でhost.docker.internal
を指定することで、他にdocker-composeで起動しているサービスに対してhostのnetworkを通じてpush requestを送ることができます。
ref: https://qiita.com/skobaken/items/03a8b9d0e443745862ac
version: '3.8'
services:
pubsub:
image: {buildしたimage}:latest
restart: always
environment:
- PROJECT_ID=emulator
- TOPIC_ID=event-topic-local
- SUBSCRIPTION_ID=event-subscription-local
- PUSH_ENDPOINT=http://host.docker.internal:3000/example
extra_hosts:
- host.docker.internal:host-gateway
ports:
- 8085:8085
Discussion