💨

Dockerの開発環境

2022/07/19に公開

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をGemfileGemfile.lockをコンテナに入れて、必要な依存ライブラリをインストールしてbundle installしています。ARGのapp_nameには利用するrailsアプリ名を入れてください。

Discussion