いまさらDockerでRails(API)+Rails(worker)+SQS+MySQLの環境を構築してみた
PICK UP POST

いまさらDockerでRails(API)+Rails(worker)+SQS+MySQLの環境を構築してみた

皆さんこんにちは。
料理好きエンジニアの金子です。

普段はiOSの開発メインですが、あるときにRailsのAPIをローカル環境で動かす必要があり、その際に環境構築が結構大変だったので時間短縮を目指してDockerを使って構築してみました。

ちなみにDockerはいままで触ったことはありませんので初Dockerです。

今回はDocker for Macで構築してみました。

Docker for Macのインストール

Docker for Macはhomebrew-caskでインストールすると楽にできます。

brew cask install docker

docker-composeは便利だった

Docker単体でも環境構築できますが、Dockerは1コンテナ1プロセスと言われているのもあり、環境を構築するとなると複数コンテナの管理が必要になってきます。
複数コンテナの管理はdocker-composeを使うと楽です。
具体的には、各コンテナの設定値を1つのyamlファイルで管理でき、コンテナの起動や停止などをまとめて行うことができます。

Docker-composeは、Docker for Macをインストールすると使えるようになりますので、Docker for Macを使う場合別途インストールは不要です。

今回の構成では、docker-compose.ymlは以下のようになります。

version: '3.2'
services:
  fake_sqs:
    image: feathj/fake-sqs
    container_name: fake_sqs_container
    ports:
      - "9494:9494"
    environment:
      VIRTUAL_HOST: "fake_sqs"
    networks:
      - default
  db:
    image: mysql
    container_name: db_container
    command: mysqld --default-authentication-plugin=mysql_native_password
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
    networks:
      - default
    volumes:
      - type: bind
        source: ${DOCKER_VOLUME_PATH}/hoge-db
        target: /var/lib/mysql
      - ./docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d
  api:
    build:
      context: .
      dockerfile: Dockerfile-dev
    container_name: api_container
    command: bundle exec rails s -p 3000 -b 0.0.0.0
    ports:
      - "3000:3000"
    environment:
      RAILS_ENV: development
      AWS_REGION: ${HOGE_AWS_REGION}
      AWS_ACCESS_KEY_ID: ${HOGE_AWS_ACCESS_KEY_ID}
      AWS_SECRET_ACCESS_KEY: ${HOGE_AWS_SECRET_ACCESS_KEY}
    networks:
      - default
    volumes:
      - .:/app
  app:
    build:
      context: .
      dockerfile: Dockerfile-dev
    container_name: app_container
    command: bundle exec shoryuken -R -C config/shoryuken.yml
    environment:
      RAILS_ENV: development
      AWS_REGION: ${EAP_AWS_REGION}
      AWS_ACCESS_KEY_ID: ${EAP_AWS_ACCESS_KEY_ID}
      AWS_SECRET_ACCESS_KEY: ${EAP_AWS_SECRET_ACCESS_KEY}
    networks:
      - default
    volumes:
      - .:/app

docker-composeのファイルバージョン

version: ‘3.2’ というところは、docker-composeのファイル形式のバージョンを表しています。
設定によっては各バージョン間で書き方が違ってくる場合があります。

サービスの設定

Servicesにあるfake_sqs, db, api, appというところが各サービス用のコンテナです。

fake_sqsの設定解説

  fake_sqs:
    image: feathj/fake-sqs
    container_name: fake_sqs_container
    ports:
      - "9494:9494"
    environment:
      VIRTUAL_HOST: "fake_sqs"
    networks:
      - default

今回構築する環境ではワーカーとしてshoryuken+SQSの構成のため、動作させるにはSQSが必要ですが、開発時はfake_sqsで代用することができます。
fake_sqsのDockerイメージが用意されているため、上記のようにイメージを指定して構築できます。

dbの設定解説

  db:
    image: mysql
    container_name: db_container
    command: mysqld --default-authentication-plugin=mysql_native_password
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
    networks:
      - default
    volumes:
      - type: bind
        source: ${DOCKER_VOLUME_PATH}/hoge-db
        target: /var/lib/mysql
      - ./docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d

DBサーバはDockerのMySQL公式イメージを利用して上記のように設定します。
2018/8/15時点ではMySQL8.0.12がインストールされるようですが、このバージョンは認証方式の違いでいろいろ問題がでるのでcommendのところで「mysql_native_password」を設定して調整しています。

Dockerのコンテナ内のデータはコンテナを落とすと消えてしまいます。
開発で使う場合それだと都合がわるいのですが、MySQL公式イメージには初回起動時にスクリプトを実行する機能があるのでそれを利用することで起動時にデータを投入することができます。
「docker-entrypoint-initdb.d」にスクリプトを入れておくと起動時に実行してくれるので、上記の設定ではローカルのディレクトリにマウントしてスクリプトがあれば起動時に実行できるようにしています。
ただ、データ量が多いと毎回実行するのも大変なので、一度投入したデータは継続して使えるようにvolumesを設定してMySQLのデータディレクトリをホストOSにマウントしています。

apiの設定解説

  api:
    build:
      context: .
      dockerfile: Dockerfile-dev
    container_name: api_container
    command: bundle exec rails s -p 3000 -b 0.0.0.0
    ports:
      - "3000:3000"
    environment:
      RAILS_ENV: development
      AWS_REGION: ${HOGE_AWS_REGION}
      AWS_ACCESS_KEY_ID: ${HOGE_AWS_ACCESS_KEY_ID}
      AWS_SECRET_ACCESS_KEY: ${HOGE_AWS_SECRET_ACCESS_KEY}
    networks:
      - default
    volumes:
      - .:/app

APIサーバはrailsなのでdocker公式イメージの中からrubyのバージョンを合わせたものを使います。
これは環境によってインストールするソフトが変わってくるのでDockerfileに別途定義しています。

FROM ruby:2.4.1

LABEL maintainer="https://github.com/lanchester/HogeFugaPiyo" \
      description="Foo Bar Baz"

ARG UID=991
ARG GID=991
ARG APPGROUP=webapp
ARG APPUSER=webapp

ENV APP_ROOT /app
ENV LANG C.UTF-8

# 公開ポート
EXPOSE 3000

RUN apt-get update && apt-get install -y nodejs build-essential libmagic-dev mysql-client libmysqlclient-dev

# ユーザ追加と権限設定
RUN addgroup --gid ${GID} ${APPGROUP} && adduser --home ${APP_ROOT} --shell /bin/sh --disabled-login --gid ${GID} --uid ${UID} ${APPUSER} \
 && mkdir -p ${APP_ROOT}/public/system ${APP_ROOT}/public/assets ${APP_ROOT}/public/packs \
 && chown -R ${UID}:${GID} ${APP_ROOT}/public

# ソースコードコピー
COPY --chown=webapp:webapp . ${APP_ROOT}

# ユーザ指定
USER ${UID}:${GID}

# 作業ディレクトリ変更
WORKDIR ${APP_ROOT}

RUN bundle install

appの設定解説

  app:
    build:
      context: .
      dockerfile: Dockerfile-dev
    container_name: app_container
    command: bundle exec shoryuken -R -C config/shoryuken.yml
    environment:
      RAILS_ENV: development
      AWS_REGION: ${HOGE_AWS_REGION}
      AWS_ACCESS_KEY_ID: ${HOGE_AWS_ACCESS_KEY_ID}
      AWS_SECRET_ACCESS_KEY: ${HOGE_AWS_SECRET_ACCESS_KEY}
    networks:
      - default
    volumes:
      - .:/app

ワーカーはshoryukenを使用していますが、コードベースはAPIサーバと同じなので同じDockerfileを使用しています。

イメージのビルドとコンテナの起動

Docker-compose.ymlファイルを作ったら以下のコマンドでイメージを作成することができます。

docker-compose build

コンテナの起動は以下のコマンドで行います。

docker-compose up

コンテナの停止は以下のコマンドで行います。

docker-compose down

コンテナの状態を確認する

コンテナの状態を確認するのには以下のコマンドを実行します。

docker ps
CONTAINER ID        IMAGE                  COMMAND                  CREATED             STATUS              PORTS                    NAMES
e0ce6bb83def        mysql                  "docker-entrypoint.s…"   22 hours ago        Up 22 hours         3306/tcp                 db_container
cccf28542f67        hoge_app   "bundle exec shoryuk…"   22 hours ago        Up 22 hours         3000/tcp                 app_container
cf63832f327e        feathj/fake-sqs        "/bin/sh -c /start.sh"   22 hours ago        Up 22 hours         0.0.0.0:9494->9494/tcp   fake_sqs_container
cb251b62456e        hoge_api   "bundle exec rails s…"   22 hours ago        Up 22 hours         0.0.0.0:3000->3000/tcp   api_container

コンテナ上でコマンドを実行する

コンテナを立ち上げた後、例えばDBサーバでMySQLのコマンドを使ってデータを操作する場合など、最初はsshで接続していろいろできると思っていましたが、よく考えたらdockerは1コンテナ1サービスであり、実際にsshdをdockerコンテナで動かすべきでないという議論もあるようでした。
コマンドを実行するのであれば以下のように実行することは可能です。

docker exec -it db_container mysql -uroot -p

上記のコマンドでMySQLクライアントで接続して対話的にコマンドを実行することは可能です。

コンテナ間での通信

同じdocker network内であれば名前解決できるため、APIのdatabase.ymlではホスト名を「db」と指定しています。

TAG

  • このエントリーをはてなブックマークに追加
金子 将範
エンジニア 金子 将範 rubyist

新しいことや難しい課題に挑戦することにやりがいを感じ、安定やぬるい事は退屈だと感じます。 考えるより先に手が動く、肉体派エンジニアで座右の銘は諸行無常。 大事なのは感性、プログラミングにおいても感覚で理解し、感覚で書きます。