tjinjin's blog

インフラ要素多めの個人メモ

ローカル環境でRailsアプリをdockerで動かしてみる

About

そろそろやっておきたいと思ったので試しました。

環境

$ docker -v
Docker version 1.13.1, build 092cba3
$ docker-compose -v
docker-compose version 1.11.1, build 7c5d5e4

検証

基本的にドキュメントを見ながら作りました。アレンジした部分とかもあったので、一部修正しつつやりました。

Quickstart: Compose and Rails - Docker

適当なRailsアプリを作る

db接続必須なアプリを作ります。

$ gem install rails
$ rails new . -d postgresql
$ rails g scaffold Member name:string comment:text

試しにローカルで動かすには

$ rails db:setup
$ rails s

でサーバが起動します(postgresqlがローカルで動いていれば)。

Dockerfileを作る

次にドキュメント見つつ、dockerファイルを作ります。

FROM ruby:2.4.0
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs
RUN mkdir /myapp
WORKDIR /myapp
ADD Gemfile /myapp/Gemfile
ADD Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
ADD . /myapp

nokogiriのinstallが長い。。。これでアプリのdocker化の準備ができました。

docker-compose.ymlを作る

次にdocker-compose.ymlを作成します。とりあえず動くレベルであれば下記のようなファイルで出来ました。

version: '2'
services:
  db:
    image: postgres
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
  web:
    build: .
    command: bash -c "sleep 3 && bundle exec rails db:setup && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/myapp
    ports:
      - "3000:3000"
    depends_on:
      - db

docker-hubで用意されているpostgresはローカル外からの接続はパスワード認証(md5)になっています。事前にユーザを作るためにはenviromentを設定し、指定したユーザで接続できるようにしておく必要があります。従って、アプリのconfig/database.ymlを修正しておきます。

default: &default
  adapter: postgresql
  encoding: unicode
  database: dockerized-rails_development
  username: postgres
  password: postgres
  host: db

また、先程のcommandのところでsleep 3しているのは、db側が起動しきらない状態でdb:setupが実行されるのを防ぐためです。

https://hub.docker.com/_/postgres/

はまったところ

よくわからないけど、突然動かなくなる現象

コード何も変わってないのになんで動かなくなるの?って現象に複数回遭遇したの辛かったです(ヽ´ω`)

  • tmp/pids/server.pidが削除されなくてwebが起動しない(これはまだマシ
  • webサーバからdbサーバへの名前解決ができなくてpostgresへ接続できなくなる

なんというか、試しに遊ぼうと思ったところでこれ食らうと辛い。下記のエラーはpostgresのimageを1回消したら直りました。

いろいろ調べると根本的な原因は不明なのですが、docker-compose up時にクラスタ?用のbridgeを作ってそこにエントリを追加することで名前解決できるようですが、そこがうまくいかなくなっていたようです。下記はうまく言っているときのパターンです。

$ docker network inspect dockerizedrails_default
[
    {
        "Name": "dockerizedrails_default",
        "Id": "401cbf3c701784ed8fd9204c621b100204fa71e1030c515ac62a3bf522d0acd4",
        "Created": "2017-02-13T14:55:07.449826039Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.19.0.0/16",
                    "Gateway": "172.19.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Containers": {
            "7198b19232101a6e9a7d47323671936462b1d84629d8ed23f14edc96f48add27": {
                "Name": "dockerizedrails_db_1",
                "EndpointID": "fbbafefd89123131d180a8c783ca5cc432a65eb6ba7a7d243bb0ef1ca1b200bc",
                "MacAddress": "02:42:ac:13:00:02",
                "IPv4Address": "172.19.0.2/16",
                "IPv6Address": ""
            },
            "b7fdfec2847f015975457920c97c6b278e8fc69860ee9b479a3bfdc53480c17c": {
                "Name": "dockerizedrails_web_1",
                "EndpointID": "01d495e58753902424cd71ef1564341df48ef0264f804d2bc9f8a73a648fa560",
                "MacAddress": "02:42:ac:13:00:03",
                "IPv4Address": "172.19.0.3/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]

なんか名前解決してくれそうなものがありますね。

まとめ

久しぶりにdocker触り始めたので、しっかり基礎からやっていきます!

蛇足

network周りが気になったのでもうちょっと調べました。

$ docker exec -ti dockerizedrails_web_1 ping db
PING db (172.19.0.2): 56 data bytes
64 bytes from 172.19.0.2: icmp_seq=0 ttl=64 time=0.073 ms
64 bytes from 172.19.0.2: icmp_seq=1 ttl=64 time=0.105 ms

digをコンテナに入れてみると

root@b7fdfec2847f:/myapp# dig db

; <<>> DiG 9.9.5-9+deb8u9-Debian <<>> db
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 13249
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;db.                            IN      A

;; ANSWER SECTION:
db.                     600     IN      A       172.19.0.2

おお、名前引けてる。これはどこで管理しているのか。。。

# cat /etc/resolv.conf
nameserver 127.0.0.11
options ndots:0

127.0.0.11っていうのは何やつなんだろう?🤔

きっとlibnetwork当たりでやってるんだろうなってところで一旦諦めました。。。たぶん内部DNSを自前実装しているのかな。

docker/network.go at master · docker/docker · GitHub

参考

Dockerのブリッジ・ネットワークでのコンテナ間名前解決がどうなっているのか見てみた - Qiita