dockerとdocker composeでwebアプリをdocker化する方法

初めに!

Dockerは軽量で高速に動作するコンテナ型仮想環境用ツールです。
従来の開発ではアプケーション開発と並行して環境構築を1から行う必要がありました。
しかしDockerを利用することで環境の一括管理することができ、大幅な効率化が図れます。
さらにDockerを利用することで他の開発者と環境を共有やバージョン管理を行うことで開発環境の標準化が行えるようになります。
よってDockerは現代の開発環境に必要不可欠な存在となっているのです。

目的

  • dockerとdocker-composeを使用してRailsアプリケーションとPostgressを簡単にセットアップし、実行していきます。

前提条件

  • まずはDockerとDocker Hubがインストールされていることが前提で進めていきます。
    まだの方は公式サイトインストールを行なってください。

大まかな方針

  1. Railsで記述したファイルを自分の環境に用意する。
  2. Dockerfileとdocker-compose.ymlの準備。
  3. database.ymlの追記。
  4. アプリケーションの実行。

手順

Railsで記述したファイルを自分の環境に用意する。

  • docker化するアプケーションを用意していきましょう!

  • 私は以下のものcloneしてwebアプリを用意しました。

$ git clone https://github.com/ihatov08/rails7_docker_template

Dockerfileとdocker-compose.ymlの準備。

  • 今回はRailsとPostgresSQLの2つのコンテナを使用するので
    docker-compose.ymlを使用します。

Dockerfile

FROM ruby:3.2.2
RUN apt-get update && apt-get install -y \
    build-essential \
    libpq-dev \ 
    nodejs \
    postgresql-client \
    yarn
RUN mkdir workdir
WORKDIR /workdir
ADD Gemfile /workdir/Gemfile
ADD Gemfile.lock /workdir/Gemfile.lock
RUN bundle install
ADD . /workdir/

docker-compose.yml

version: '12'
services:
  db:
    image: postgres
    environment:
      POSTGRES_PASSWORD: trust
  web:
    build: .
    command: /bin/sh -c "rm -f tmp/pids/server.pid && rails db:migrate && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/workdir
    ports:
      - "3000:3000"
    depends_on:
      - db
  tty: true
    stdin_open: true
  • 今回はPOSTGRES_PASSWORD:trustにしているが本来はPOSTGRES_PASSWORD:値にはきちんとパスワードを入力した方が良い。

テータベースに接続

  • docker-compose.ymlのサービスの定義を合わせるためにconfig/database.ymlを変更していきます。

  • config/database.ymlはデータベース設定についての詳細が記載されているファイル。

config/database.yml

default: &default
  adapter: postgresql
  encoding: unicode 
  host: db
  username: postgres
  password:
  pool: 5

データベースを作成する。

  • 初回のみ実行する。
$ docker-compose run web rake db:create
  • dbの中に新たなデータベースが作成される。

アプリケーションの起動

$ docker-compose up 
  • ブラウザにてhttp://localhost:3000/を入力するとアプリケーションが立ち上がります。

結語

  • 複数のコンテナを利用してアプリケーションを立ち上げる場合はdocker-composeを利用する。

  • docker-compose.ymlにはサービス定義部分に必要な数のコンテナ名を記述する。

  • アプリケーションとデータベースを接続を行うためにconfig/database.ymlを変更する。

Puma caught this error: Cannot load database configuration: key not found: "DATABASE_PASSWORD" (KeyError)について

初めに!

  • 学習中に躓いたところをアウトプットしていきます。

概要

  • dockerを使用してRailsアプリケーションとDBをセットして立ち上げることを目的としています。

問題点

  • docker-compose upをしてブラウザでポート3000にアクセスするとエラーが生じた。

エラー内容

ブラウザに表示されたエラー

ターミナルに現れたエラー
web-1  | 2024-04-26 09:07:20 +0000 Rack app ("GET /" - (192.168.65.1)): #<KeyError:"Cannot load database configuration:\nkey not found: \"DATABASE_PASSWORD\"">

関連ファイル

docker-compose.yml
version: '12'
volumes:
  db-data:
  
services:
  db:
    image: postgres
    volumes:
      - 'db-data:/var/lib/postgresql/data'

  web:
    build: .
    command: /bin/sh -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/workdir
    environment:
      - 'POSTGRES_PASSWORD=password'
    ports:
      - "3000:3000"
    depends_on:
      - db
    links:
      - db
    tty: true
    stdin_open: true
database.yml
default: &default
  adapter: postgresql
  encoding: unicode
  host: db
  username: postgres
  port: 5432
  password: <%= ENV.fetch("DATABASE_PASSWORD") %> 
  # For details on connection pooling, see Rails configuration guide
  # https://guides.rubyonrails.org/configuring.html#database-pooling
  pool: 5

エラーの原因の予想

  • docker-compose.ymlのDATABASE_PASSWORDに関連する場所に原因がある。

  • database.ymlのpasswordがうまく機能していない。

原因

  • docker-compose.ymlのenviromentのPOSTGRES_PASSWORD=passwordをDATABASE _PASSWORDに変更
version: '12'
volumes:
  db-data:
  
services:
  db:
    image: postgres
    volumes:
      - 'db-data:/var/lib/postgresql/data'

  web:
    build: .
    command: /bin/sh -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/workdir
    environment:
      - 'DATABASE_PASSWORD=password'
    ports:
      - "3000:3000"
    depends_on:
      - db
    links:
      - db
    tty: true
    stdin_open: true

結語

  • 今回起こったエラーはdocker-compose.ymlのenvironmentの環境変数がきちんと設定されていなかったことで生じた。

docker-compose build時に services.db.environment must be a mappingというエラーが生じる。

初めに

  • 学習中のエラーを自分でまとめてみました

  • なるべくわかりやすく説明していこうと思います。

背景

  • dockerを利用して、Railsアプリケーションとpostgresをセットアップをして実行する。

  • docker-compose buildの際にエラーが生じた。

docker-compose.yml
version: '12'
volumes:
  db-data:
services:
  db:
    image: postgres
    environment:
      POSTGRES_PASSWORD:password
    volumes:
      - 'db-data:/var/lib/postgresql/data'

  web:
    build: .
    command: /bin/sh -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/workdir
    ports:
      - "3000:3000"
    depends_on:
      - db
    tty: true
    stdin_open: true
database.yml
default: &default
  adapter: postgresql
  encoding: unicode
  host: db
  user: postgres
  port: 5432
  password: <%= ENV.fetch("DATABASE_PASSWORD") %> 
  # For details on connection pooling, see Rails configuration guide
  # https://guides.rubyonrails.org/configuring.html#database-pooling
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>

エラー内容

validating /Users/seinokyouhei/Desktop/practice/rails7_docker_template/docker-compose.yml: services.db.environment must be a mapping
  • docker-compose.ymlのservices、db、enviromentの部分でエラーが生じていることがわかる。

  • mappingはenviromentのキーと値の組み合わせ構造のこと

  • つまり組み合わせ構造が間違っていると予想ができる。

解決策

  • enviromentの構造に-が抜けていたため。
改善後のdocker-compose.yml
version: '12'
volumes:
  db-data:
services:
  db:
    image: postgres
    environment:
      - POSTGRES_PASSWORD:password
    volumes:
      - 'db-data:/var/lib/postgresql/data'

  web:
    build: .
    command: /bin/sh -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/workdir
    ports:
      - "3000:3000"
    depends_on:
      - db
    tty: true
    stdin_open: true

結語

  • ymlではオブジェクトや辞書型データのキーと値の組み合わせ構造のことをマッピングと呼ぶ

  • must be a mappingはymlの構造上のエラーである。

docker-compose up後に自動でwebコンテナがexitedになる

初めに

  • 学習中に生じたエラーについて解決方法のプロセスを記述していこうと思います。

問題

  • docker-compose up後にRailsサーバーが立ち上がるようにしたいが、立ち上がらない。

  • 原因としてはweb側のコンテナが勝手にExitedされているから。

logを確認してみる。

web-1  | => Booting Puma
web-1  | => Rails 7.0.6 application starting in development 
web-1  | => Run `bin/rails server --help` for more startup options
web-1  | Exiting
web-1  | A server is already running. Check /workdir/tmp/pids/server.pid.
web-1 exited with code 1
  • A server is already running. Check /workdir/tmp/pids/server.pid.の部分でまだ立ち上げていないのに、サーバーが立ち上がっていると表示されている。

原因

  • 以前に起動した時に作成されたserver.pidというファイルが残ってしまったため。

  • サーバ起動のたびにserver.pidの削除を行う。

解決方法

  1. rm tmp/pids/server.pidを実行する。

  2. 問題は解決するが、いちいちコマンドを実行しなければいけないので面倒である。

  3. docer-compose.ymlの修正を行う。

修正前

version: '12'
services:
  db:
    image: postgres
  web:
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes:
      - .:/workdir
    ports:
      - "3000:3000"
    depends_on:
      - db

修正後

version: '12'
services:
  db:
    image: postgres
  web:
    build: .
    command: /bin/sh -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/workdir
    ports:
      - "3000:3000"
    depends_on:
      - db
  • これで次回起動してもrm tmp/pids/server.pidを実行しなくても良くなる。

結語

  • server.pidが作成されると次にサーバーを起動しても勝手にexitedされてしまう。

  • server.pidを削除することで解消される。

  • 毎回起動前にserver.pidを削除するのは手間なのでdocker-compose.ymlを修正する。

クィックスタート: Compose と Rails!を行った時の生じたエラーや用語のまとめ

初めに

  • クィックスタート: Compose と Railsを実際に行って躓いたところや、わからないことをまとめてみました。

  • 同じように悩んでいる方に向けて書きます。

  • 間違っていることを発信いる場合はコメントなどで教えていただけると幸いです。

クィックスタート: Compose と Railsの最終目的

  • docker-composeを使用して簡易的にrailsを立ち上げてみる。

  • 使用するアプリケーションはrails

  • データベースは,postresSQL。

初めにクイックスタートの通りファイルを作成し、記述を行う。

  • quick-startフォルダを作成し移動する。
mkdir quick-start
cd mkdir
  • quick-startフォルダ内に移動してDockerfile,Gemfile,Gemfile.lockを作成。
touch Dockerfile Gemfile Gemfile.lock
Dockerfile
FROM ruby:2.3.3
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
Gemfile
source 'https://rubygems.org'
gem 'rails', '5.0.0.1'
  • docker-compose.ymlを作成して記述を行う。
touch docker-compose.yml
docker-compose.yml
version: '3'
services:
  db:
    image: postgres
  web:
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes:
      - .:/myapp
    ports:
      - "3000:3000"
    depends_on:
      - db
Dockerfileとは?
  • FROM, RUN, CMD, EXPOSE, ENV, ADD, および COPYといったドッカーコンストラクションを利用して記述する。

  • Dockerfileの最初にはFROMを使用してビルドプロセスのイメージを作成する。

Gemfileとは?
  • Railsで必要となる道具をリストアップしてまとめたファイル。

  • 一括でインストールしたり、バージョンを揃えることができるので開発がスムーズになる。

  • gemfile内の内容を変更したり、追加したらbundle installを行う。

Gemfile.lockとは?
  • プロジェクトに使用されているgemの正確なバージョン記載がされている。

  • bundle install後に記述が追加される。

プロジェクトのひな型を作成する。

  • docker-compose run web rails new . --force --database=postgresqlを実行する。

    コマンドの解説
  • docker-compose run はdocker-compose.ymlをベースとして実行を行う。

  • webは docker-compose.ymlに記述されているサービス名で、webアプリケーションのサーバを実行するサービスを指す。

  • rails new .はコンテナ内の作業ディレクトリ内で新しいアプリケーションを立ち上げると言う意味を示す。

オプションの解説
  • --force は新しいrailsアプリケーションが立ち上がるときに強制的に上書きを行う。

  • --database=postgresqlrailsアプリケーションが立ち上がるとPostgresSQLに接続を行うように設定される。またこのオプションによりconfig/database.yml ファイルが PostgreSQL の接続設定で初期化される。

エラー1

  • ERROR [web 2/8] RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejsが生じる。
    エラー内容
 > [web 2/8] RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs:               
14.59 W: Failed to fetch http://security.debian.org/dists/jessie/updates/main/binary-amd64/Packages  404  Not Found [IP: 151.101.2.132 80]                                                                          
14.59                                                                                                     
14.59 W: Failed to fetch http://deb.debian.org/debian/dists/jessie/main/binary-amd64/Packages  404  Not Found
14.59 
14.59 W: Failed to fetch http://deb.debian.org/debian/dists/jessie-updates/main/binary-amd64/Packages  404  Not Found
14.59 
14.59 E: Some index files failed to download. They have been ignored, or old ones used instead.
------
ruby:2.3.3のバージョンが古いのでパッケージのダウンロード先が見つからないと仮定する。
  • ruby:2.3.3→ruby:2.5に変えてみる。

  • docker-compose run web rails new . --force --database=postgresqlがうまく走る。

ファイル一覧を確認する。

total 64
-rw-r--r--@  1 seinokyouhei  staff   219  4 18 18:29 Dockerfile
-rw-r--r--@  1 seinokyouhei  staff  1738  4 18 18:31 Gemfile
-rw-r--r--@  1 seinokyouhei  staff  4827  4 18 18:32 Gemfile.lock
-rw-r--r--   1 seinokyouhei  staff   374  4 18 18:31 README.md
-rw-r--r--   1 seinokyouhei  staff   227  4 18 18:31 Rakefile
drwxr-xr-x@ 10 seinokyouhei  staff   320  4 18 18:32 app
drwxr-xr-x@  8 seinokyouhei  staff   256  4 18 18:33 bin
drwxr-xr-x@ 14 seinokyouhei  staff   448  4 18 18:32 config
-rw-r--r--   1 seinokyouhei  staff   130  4 18 18:31 config.ru
drwxr-xr-x@  3 seinokyouhei  staff    96  4 18 18:32 db
-rw-r--r--@  1 seinokyouhei  staff   210  4 18 12:07 docker-compose.yml
drwxr-xr-x@  4 seinokyouhei  staff   128  4 18 18:32 lib
drwxr-xr-x@  3 seinokyouhei  staff    96  4 18 18:32 log
drwxr-xr-x@  9 seinokyouhei  staff   288  4 18 18:32 public
drwxr-xr-x@  9 seinokyouhei  staff   288  4 18 18:32 test
drwxr-xr-x   4 seinokyouhei  staff   128  4 18 18:31 tmp
drwxr-xr-x@  3 seinokyouhei  staff    96  4 18 18:32 vendor
  • コンテナ側で作成されたファイルの所有者は全てrootユーザによって実行されているのでrootになる。

指定したディレクトリとその中の全てのファイルおよびサブディレクトリの所有者とグループを、実行ユーザーのものに変更

  • sudo chown -R $USER:$USER .を実行する。

コマンドの解説

sudo
  • 通常のユーザーが管理者権限を使ってコマンドを実行するために使用。

    chown
  • ファイルやディレクトリの所有者とグループを変更するための使用する。

-R オプション
  • recursivenの略で再帰的という意味を示す。(フィードバック)

  • chownの下に指定したファイルやディレクトリに対して再帰的に所有者の変更を行う。

$USER:$USER
  • $USERという環境変数はログインしたユーザーのユーザー名を格納している。

  • $USER:$USERとすることで所有者とグループの所有者を現在の所有者にする。

  • 最初の$USERが新しい所有者を指定して、後の$USERが新しいグループを指定する。

.
  • 現在使用しているカレントディレクトリのことを示す。

  • 現在のディレクトリとその中に入っているファイルやサブディレクトリの所有者を実行中のユーザーに変更する。

プロジェクトの再ビルド

  • rals newを行った際にdcokerfileやGemfileの内容が変更されたので再度docker-compose buildを行う。
$ docker-compose build

データベースの接続設定

  • Dockerコンテナーを使用して PostgreSQL データベースと接続を行う。

  • config/database.ymlの変更を行う。

config/database.yml
default: &default
  adapter: postgresql
  encoding: unicode
  host: db
  username: postgres
  password:
  pool: 5

development:
  <<: *default
  database: myapp_development


test:
  <<: *default
  database: myapp_test
  • docker-compose upを実行する。

エラー2

  • Error: Database is uninitialized and superuser password is not specified.というエラーが生じる。
db-1   | Error: Database is uninitialized and superuser password is not specified.
db-1   |        You must specify POSTGRES_PASSWORD to a non-empty value for the
db-1   |        superuser. For example, "-e POSTGRES_PASSWORD=password" on "docker run".
db-1   | 
db-1   |        You may also use "POSTGRES_HOST_AUTH_METHOD=trust" to allow all
db-1   |        connections without a password. This is *not* recommended.
db-1   | 
db-1   |        See PostgreSQL documentation about "trust":
db-1   |        https://www.postgresql.org/docs/current/auth-trust.html
  • データベースが初期化されておらず、スパーユーザーパスワードが指定されていないから起きたエラー。

  • POSTGRES_PASSWORDには、superuserに対して空でない値を指定する必要があります。例えば "docker run "で"-e POSTGRES_PASSWORD=password "と指定する。

  • "POSTGRES_HOST_AUTH_METHOD=trust を使用すればパスワードを指定する必要はないが推奨はされない

  • 今回はパスワードを設定しない方法で行う。

  • 本来はきちんと環境変数の値を入れるが、今回はアプリケーションを立ち上げることを目的としているために、省略します。

docker-compose.ymlに追加

version: '3'
services:
  db:
    image: postgres
      environment:**
      POSTGRES_HOST_AUTH_METHOD: trust**
  web:
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes:
      - .:/myapp
    ports:
      - "3000:3000"
    depends_on:
      - db
  • 追加後docker-compose upを行うと無事実行ができました。

データベースの作成を行う。

  • コンテナーと PostgreSQL データベースの接続ができた。

  • docker-compose run web rake db:createを実行するしてデータベースを生成する。

  • 以下のメッセージが表示されてデータベースが無事に作成されたことがわかった。

Created database 'myapp_development'
Created database 'myapp_test'

docker-compose run web rake db:createコマンドの解説。

  • docker-compose runはdocker-compose.ymlに記述されているアプリケーションやデータベースを立ち上げ、コマンドを実行する。

  • webはdocker-compose.ymlに記述されているアプリケーションのこと。今回はRails

  • rakeはRailsのタスクランナーでrake db:createでRailsに関連づけられたデータベースを作成する。config/database.ymlに設定されたデータに基づいて実行される。

Rails の「ようこそ」ページの確認

  • docker-compose upを実行する。

  • ブラウザで確認するためにhttp://localhost:3000にアクセスする。

結語

  • 今回docker-composeを使用してRailsのアプケーションを立ち上げたが、コードの関するエラーはもちろんのこと、Railsのバージョン管理に関しても学習しなければいけないと感じました。

  • Rails、dockerの公式ドキュメントを英語で読むことも非常に重要であると感じました。

SSHについて

初めに!

  • 学習途中で疑問に思ったことを調べ、そのことについてアウトプットしていきます。

  • dockerを勉強してからよくSSH接続を行うためにこれを利用してきちんと理解していく。

SSHとは

  • secure shellの略語で通信内容を暗号化して読み取られないようにするためのプトロコル。

sshの接続の流れを見てみる

  1. クライアント側で秘密キーと公開キーを作成する。

  2. 接続する先のサーバーに公開キーを送る。

  3. クライアント側からサーバー側にSSH接続を行いたい旨を伝える

  4. サーバー側で乱数を生成し、乱数(セッションキー)と公開キーを使用して暗号を作成してクライアント側に暗号を送る。

  5. クライアント側で秘密キーと暗号を使って復号して乱数を取り出す。

  6. クライアント側は乱数からハッシュ値を生成してサーバー側に送る。

  7. サーバー側も生成した乱数からハッシュ値を生成する。

  8. クライアント側とサーバー側が生成したハッシュ値を比較して合致しているか確認する。

秘密キーと公開キーについて

秘密キー
  • 秘密キーはクライアント側が持っているキーで他人に知られてはいけない。

  • 暗号化された通信を解読する際に使用される

公開キー
  • 公開キーはサーバー側に送られるキー。

  • クライアントの身元を確認するために使用される。

  • 秘密キーと公開キーは対になっていて公開キーで暗号化されたデータは秘密キーによってのみ解読することができる。

乱数と公開キーを使用して暗号を作成する

  • サーバ側は乱数を生成し、受け取った公開キーと一緒に使用することで暗号を生成する。

  • 暗号は秘密キーがなければ解読がでいない。解読することで乱数を取り出せる。

クライアント側とサーバー側のハッシュ値の比較

  • クライアント側はサーバー側から送られた暗号から得られた乱数からハッシュ値を生成。

  • サーバー側がサーバー側が生成した乱数からハッシュ値を生成する。

  • どちらも同じハッシュ値であれば承認がされる。

結語

  • SSHは通信情報を暗号化して第三者に情報を抜き取られないようにする仕組み。

  • 秘密キーと公開キーを生成し、それらを使用してクライアント側とサーバ側の確証を行う。

docker hubを利用してhello-worldというimageをpullする

初めに

  • 学習した内容をアウトプットするために書いていきます。

手順

  • コンテナにログイン

  • docker pull hello-wroldを打ってhello-worldをホストにプルする

  • docker imagesで確認

コンテナにログインをする。

  • docker loginのコマンドを打つ

  • インタネットに接続かつdockerが起動しているかをきちんと確認を行う。

  • loginできればLogin Succeededがターミナルで表示される。

docker pull hello-wroldを打ってhello-worldをホストにプルする

  • docker pull を打つことでimageをdocker hubからpullする。

  • 今回はhello-worldという画像をpullしたいのでdocker pull hello-worldとする。

    * docker imagesで確認

  • docker imagesでpullしたhello-worldを確認する。

REPOSITORY                   TAG       IMAGE ID              CREATED         SIZE
hello-world                    latest    d2c94e258dcb   11 months ago   13.3kB
  • TAGは何も指定してなければlatestになる。

結語

  • ホストにdocker hubからimageをpullするにはdocker pull を入力すれば引っ張って来れる。

  • pullした後に確認のためにdocker imagesを入力してきちんとpullできているか確認を行う。