Docker-composeでSinatra + Nginx + MySQL を動かす時のハマりポイント

More than 1 year has passed since last update.

面白法人カヤックさんのインターンで Sinatra + Nginx + MySQL を使った簡易イ〇スタを作りました!後日それをdocker-composeで動かそうとしたときに、docker-compose 周りで死ぬほどハマった上にあんまり解決策出てこず苦労しました。。。

備忘録がてらシェアです!


最終的なdocker-compose.yml

version: "3"

services:
web:
build: .
volumes:
- .:/app
ports:
- "4567:4567"
depends_on:
- db
command: bundle exec ruby myapp.rb -o 0.0.0.0

nginx:
image: nginx:latest
volumes:
- ./conf/nginx.conf:/etc/nginx/nginx.conf
- ./public:/var/www/html
ports:
- "8080:8080"
depends_on:
- web

db:
image: mysql:latest
environment:
MYSQL_ALLOW_EMPTY_PASSWORD: "true"
MYSQL_DATABASE: "latestgram"
MYSQL_USER: "root"
volumes:
- ./sql:/docker-entrypoint-initdb.d
command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci
ports:
- "3306:3306"


1. コンテナ上でSinatraが動かない


状況

ローカル環境では(dockerのホストipがlocalhostの時)localhost:4567でアクセスできるのですが、なぜかコンテナ上で動いている時にアクセスできない・・・

もちろんdocker-compose.ymlにポート解放の記述はあります。


解決策

docker-composeの書き方が悪いのかと思って死ぬほどググりましたが、結局Sinatra側の仕様のようです。

Sinatraがデフォルトでは外部から繋がらなくなってたよ - Qiita

によると


なんとdevelopment環境だと、localhostからのアクセスしか受け付けないのがデフォルトらしい!!


とのこと。

じゃあdockerfileにCMD["bundle", "exec", "ruby", "myapp.rb","-o", "0.0.0.0"]とかdocker-compose.ymlcommand: bundle exec ruby myapp.rb -o 0.0.0.0すればいいのか!

・・・できない!!なぜだああああああ


Sinatra: Configuring Settings

image.png

myapp.rb内でset :bind '0.0.0.0'する方法もあるらしいので試してみる。

・・・なぜか上手くいった!

なぜ上手くいかなかったんだ・・・?


2. 日本語を使う場合にMySQLの文字コードエラー


状況

ローカルのMacOSやWindows(WSL)では日本語を扱えるのに、docker-compose up すると

Incorrect string value: '\xE3\x81\x82' for column ...

とか

Illegal mix of collations (latin1_swedish_ci,IMPLICIT) and (utf8mb4_general_ci,COERCIBLE) for operation '='

が出る


解決策

デフォルトの文字コードを設定する必要があるそうです

MySQLのIllegal mix of collations (latin1_swedish_ci,IMPLICIT)のエラーについて - 文系プログラマによるTIPSブログ

docker-composeに

command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci

を追加しましょう。

そして、忘れてはいけないのがすでに起動しているMySQLコンテナを破棄してdocker-compose upすること

こうしないと、変更前のコンテナ使ってしまうので同じエラー出ます

これに気づかずに2時間くらい消費したので、みなさんは私の屍を超えていってください・・・orz

docker ps -a

CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9d1e9aac7bd1 hoge "bundle exec ruby my…" 10 minutes ago Up 10 minutes 0.0.0.0:4567->4567/tcp fugafuga

こんな感じで出てくるので、CONTAINER IDを参照して

docker rm 出てきたIDでいけます!

ちなみにdocker-compose.yml内で自分で作成したDockerfileがある場合は、Dockerfileを編集した際にdockerイメージをbuildし直さないといけないので注意です。

docker-compose buildでいいと思います。


3. nginxやmysqlにdockerのホストIPを伝えたり、コンテナ経由でアクセス

WindowsではDocker Quickstart Terminalを使っていて私の環境では192.168.99.100でコンテナにアクセス出来ます。

しかしMacでDocker for Macなどを使ってターミナル上で作業する場合はlocalhostでのアクセスになります。

またnginxコンテナ→sinatraコンテナへアクセスする場合にはコンテナ通信用のipアドレスを割り当てないといけません。


mysql接続

docker-compose.ymlでmysqlコンテナのサービス名をdbにしているので、それを使ってアクセスできます!

    def db_connect()

client = Mysql2::Client.new(
:host => 'db',
:port => '3306',
:username => 'root',
:password => '',
:database => 'latestgram',
:encoding => 'utf8mb4',
:datatbase_timezone => :local
)
return client
end


nginx.conf

同様に、Sinatraコンテナのサービス名webを使います。

また、dockerのホストipは$hostで設定可能です。(これに気づくのに苦労しました・・・)

worker_processes  1;

events {
worker_connections 1024;
}

http {
include mime.types;
default_type application/octet-stream;

sendfile on;

keepalive_timeout 65;

gzip on;

upstream latestgram{
server web:4567;
}

server {
listen 8080;
server_name $host;
root /var/www/html;

proxy_set_header Host $host:8080;
proxy_set_header X-Forwarded-For http://latestgram:4567;
proxy_set_header X-Forwarded-Host $host:8080;
proxy_set_header X-Forwarded-Server $host:8080;

location / {
proxy_pass http://latestgram;
root /var/www/html;
}

# redirect server error pages to the static page /50x.html
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}


作ったもの

・・・というわけで作ったものはこちらです!

メンターの方がしっかりサポートしていただいて1週間で形にできました!

cloneしてdocker-compose upで一発起動しますb

GitHub - koyo-miyamura/latestgram: 最新50件表示する簡易画像投稿サービス

image