Dockerの開発環境
dockerのフォルダ構成
.
├── docker-compose.yml
└── dockerfiles
├── rails
│ ├── Dockerfile
│ └── app_folder
└── nginx
├── Dockerfile
└── nginx_conf
├── nginx.conf
└── server.conf
フォルダ構成
フォルダ構成はdocker-composeを中心に構築をするようなディレクトリ設計になっています。
dockerfilesの中にrails, nginxというようにアプリ、ミドルウェアで分けています。こうする理由は、アプリ、ミドルウェアごとに分けることで問題が起こっても切り分けと、修正箇所を分けやすくするためです。
例えば、500系の問題が起こったとしたら、まずrailsとnginxに目が行きます。すると、ここでnginxでの問題か、railsでの問題かの検証をするはずです。nginxとrailsを同じフォルダで整理なしに構築をしていた場合、今nginxの作業をしているのか、railsの作業をしているのかがわからなくなります。これを回避するためにあえてrailsとnginxのフォルダを分けています。
この構造ならば、修正するときにもnginxをいじっているのか、railsをいじっているのかが一目瞭然となっているので修正時のミスを減らす効果があります。
docker-compose.ymlの内容
version: '3'
services:
nginx:
container_name: nginx
build: ./dockerfiles/nginx
depends_on:
- api
tty: true
volumes:
- type: bind
source: ./dockerfiles/nginx/nginx_config/nginx.conf
target: /etc/nginx/nginx.conf
- type: bind
source: ./dockerfiles/nginx/nginx_config/server.conf
target: /etc/nginx/conf.d/default.conf
ports:
- "8000:80"
api:
container_name: api
build: ./dockerfiles/rails
depends_on:
- posgresql
tty: true
restart: always
working_dir: /${app名}
command: bundle exec rails s -p 3000 -b '0.0.0.0'
volumes:
- type: bind
source: ./dockerfiles/rails/${app名}
target: /${app名}
expose:
- '3000'
ports:
- '3000:3000'
posgresql:
container_name: posgresql_db
image: postgres:14.2
volumes:
- db_data:/var/lib/pgsql
# - ./sql_folder:/docker-entrypoint-initdb.d
restart: always
environment:
POSTGRES_PASSWORD: admin
POSTGRES_USER: admin
POSTGRES_DB: ${app名}_development
ports:
- "5432:5432"
volumes:
db_data:
上記では、nginx, api, postgresqlを使った構成となっています。nginxにはconfを付けていて、apiにはrailsを、postgresqlには起動時に必要なファイルを明記しています。
${app名}
には使うrailsアプリ名を入れてください。
docker-composeの各要素
image
dockerが格納されているimageを記述します。imageをそのまま持ってくるのは、nginx, memcached, mysql, etcのミドルウェアを呼び出します。
主な用途として、docker-composeのみの記述で利用できるimageの場合にimageの要素に記述します。
image: ${コンテナイメージ}:${ラベル}
build
dockerfileが格納されているパスを記述します。自身で作ったdockerfileを呼び出します。
主な用途として、アプリケーションで必要な環境を整備するときにbuildを使い、コンテナを作成します。
独自の環境の場合はDockerfileを利用してください。
build: ${ dockerfileが格納されているフォルダパス }
depends-on
依存するコンテナを指定します。指定することで、自動でコンテナからコンテナへのネットワークを作成することができます。
オンプレ環境の場合は、mysqlの場合ローカルホストを指定してつなげますが、dockerの場合はdocker間ネットワークでつなげます。
依存するコンテナが分かっていてネットワークをつなげる場合、依存先のサービス名を指定してください。
depends-on:
- ${ 依存するサービス名 }
volumes
ボリュームは、コンテナが依存するファイル、フォルダを指定します。ボリュームを設定することにより、コンテナにデータを流し込むことができます。
volumeの種類にはvolumeとbindがあります。volumeはコンテナが作成されたら実行している間はコンテナ内のvolumeを変更することはできませんが、bindは元となるフォルダを変更をしたらコンテナも変更をかけることができます。
volumeはテスト、本番環境下で使って、bindは開発環境で使うようにしてください。
構文
volumes:
- ${追加するファイルパス、フォルダパス}:${追加するコンテナ内のパス}
- type: bind
source: ${追加するファイルパス、フォルダパス}
target: ${追加するコンテナ内のパス}
ports
portsはコンテナと外部ポートをつなげます。ウェブサイトのように外部にポートを開ける必要のある場合に使います。
外部に公開されてしまうため、SQLのように機密性の高いデータを扱う場合は外部に開けないでください。
ports:
- ${外部に開けるポート番号}:${内部のポート番号}
expose
exposeはコンテナ間で通信をするポートを開けます。例えば、localhost:3000をローカルでつなげたい場合は3000を指定してポートを開けます。
mysqlのように外部と通信させずにローカルで通信を完結させたい場合に使います。
expose:
- ${ コンテナ間で開けるポート番号 }
restart
restartはコンテナが終了したときに再起動するかの記述をします。
開発環境下であるのなら、alwaysにしてください。
noはリスタートをしません。
on-failureは回数分リスタートを行います。
alwaysは常に再起動を行います。
unless-stoppedはDocker デーモンの停止前にコンテナが停止上状態になっていた場合を除き、常に再起動を行います。
restart: ${ no/on-failure/always/unless-stopped }
参考資料: http://docs.docker.jp/engine/reference/run.html#restart-policies-restart
tty
コンテナに標準出力を許可する。
ttyを許可をすると/bin/bashでコンテナに入ることができる。
開発時にはtrueにして、テスト/本番環境はfalseにする。
tty: ${ true/false }
work_dir
commandの実行パスを記述する。
実行するディレクトリがある場合に使うようにしましょう。
work_dir: ${ 実行するパス }
command
最終的に実行するコマンドを記述する。
command: ${ 実行コマンド }
enviroment
環境変数を設定する。
environment:
- ${ 環境変数名 }:${ 環境変数の値 }
Dockerfileと直下のファイルの内容
Dockerfileの各要素
RUN
コンテナ構築時に実行するコマンドを記述します。
linuxの場合は/bin/sh -c
がデフォルトで、windowsの場合はcmd /S /C
がデフォルトで実行されます。/bin/sh
以外にも設定を変更をすれば/bin/bash
のように変更をすることができます。
このRUN
はなるべく1行でまとめてください。そうしないと、コンテナの起動が遅れてしまいます。
RUN: ${ 実行コマンド }
COPY
copyはそのままフォルダをコンテナに入れる。無圧縮でコピーされます。特別な場合がない限り、COPYを利用してコンテナにファイル、フォルダを入れてください。
COPY: ${ ソースパス } ${ ターゲットパス }
CMD
コンテナ実行時にデフォルトで実行するコマンドをします。RUNと同じで/bit/sh -c
と同じで、docker run
の実行時にコマンドが実行されます。
CMD: ${ 実行コマンド }
nginx
nginxのconf
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
nginx.conf
server{
listen 80;
location /api {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS, PUT, DELETE";
add_header Access-Control-Allow-Headers "Origin, Authorization, Accept, Cache-Control, Content-Type";
proxy_pass http://api:3000/;
}
# location / {
# proxy_pass http://api:3000/;
# }
}
server.conf
上記はhttpで接続できる設定となっています。server.confの/apiはrailsをapiとして運用したときにapiとfrontのurlを分けるために分けています。これは開発環境下でのみを想定した設定となっています。
rails
FROM ruby:3.1.1-buster
ARG app_name=${アプリ名}
RUN mkdir /myapp
COPY ./${app_name}/Gemfile /${app_name}/Gemfile
COPY ./${app_name}/Gemfile.lock /${app_name}/Gemfile.lock
WORKDIR /${app_name}
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev
RUN bundle install
COPY ./${app_name}/ /${app_name}
上記はRailsをGemfile
とGemfile.lock
をコンテナに入れて、必要な依存ライブラリをインストールしてbundle install
しています。ARGのapp_nameには利用するrailsアプリ名を入れてください。
Discussion