Docker備忘録

自分の備忘録用です:santa_tone1:

#MacOSでのDockerインストール手順
[Docker公式サイト](https://hub.docker.com/editions/community/docker-ce-desktop-mac)からSignUpをクリックしてアカウント作成
（DockerHubとは、世界中の人が作ったイメージが公開されているWebサービス。 自分で作ったイメージを公開することもできる。）

<img width="1332" alt="スクリーンショット 2020-04-19 13.52.18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580388/429e4ec3-db71-3624-21e1-11f952ac71f6.png">

トップページからGet started with Docker Desktopをクリック
<img width="1135" alt="スクリーンショット 2020-04-19 13.54.53.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580388/6867edab-c5e3-b7fb-1bf8-a076ffaf0f07.png">

手順に従って、Download Docker Desktop for MacをクリックしてDockerをインストール

<img width="1044" alt="68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3538303338382f65363631383330352d663236662d373763362d343666312d3463343935343833633135662e706e67.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580388/1b83bbfc-eb0e-0980-c116-99056483816d.png">




<img width="726" alt="スクリーンショット 2020-04-19 13.59.15.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580388/37e7491d-9f39-56ca-0884-932bd173b10b.png">

手順通りにターミナルにコマンドを実行していく。

<img width="1009" alt="スクリーンショット 2020-04-19 14.03.51.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580388/7ce6ca45-f5d2-d0c6-7f6b-a64d55572271.png">

最初のコンテナを作成するために必要なリポジトリをクローン

```terminal
git clone https://github.com/docker/doodle.git
```

コンテナに必要な全てのファイルとコードを提供するDockerイメージをビルドして、タグを付ける

```terminal
cd doodle/cheers2019 && docker build -t アカウント名/cheers2019 .
```

最初のコンテナを実行

```terminal
docker run -it --rm アカウント名/cheers2019
```

DockerHubでイメージを共有すべくDockerHubにプッシュ（プッシュしなくていい場合はスキップ）

```terminal
docker login && docker push アカウント名/cheers2019
```

View my repositoryをクリックしてDockerHubにリンク

<img width="829" alt="スクリーンショット 2020-04-19 14.14.16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580388/34f354b0-cbb4-89f2-7801-57716b9b0306.png">

DockerHubの検索欄にビルドしたいイメージに関する言語を入力すれば、使い方等の説明付きでイメージが公開されている。

<img width="1302" alt="スクリーンショット 2020-04-19 14.17.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580388/23ab1201-519a-cb36-4603-32b80e7c839c.png">

<img width="1317" alt="スクリーンショット 2020-04-19 14.19.11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580388/8372aaa1-d537-7028-b146-50a69cf8b939.png">



#RailsでのDoker環境構築手順
[こちらの記事を参考にしてます](https://qiita.com/azul915/items/5b7063cbc80192343fc0#dockerfile%E3%82%84docker-composeyml%E3%81%AE%E5%A4%89%E6%9B%B4%E3%82%92%E5%8F%8D%E6%98%A0rails%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E3%82%92%E5%86%8D%E8%B5%B7%E5%8B%95)

①ディレクトリ作成

```terminal
$ mkdir 任意のディレクトリ名
$ cd 作成したディレクトリ名
```

②Dockerfileの作成

```dockerfile

FROM ruby:2.5.3

# 必要なパッケージのインストール
RUN apt-get update -qq && \
    apt-get install -y build-essential \ 
                       libpq-dev \        
                       nodejs           

# 作業ディレクトリの作成、設定
RUN mkdir /app_name 
##作業ディレクトリ名をAPP_ROOTに割り当てて、以下$APP_ROOTで参照
ENV APP_ROOT /app_name 
WORKDIR $APP_ROOT

# ホスト側（ローカル）のGemfileを追加する（ローカルのGemfileは【３】で作成）
ADD ./Gemfile $APP_ROOT/Gemfile
ADD ./Gemfile.lock $APP_ROOT/Gemfile.lock

# Gemfileのbundle install
RUN bundle install
ADD . $APP_ROOT
```

③Gemfileを作成

```terminal
source 'https://rubygems.org'
gem 'rails', '5.2.2' 
```
（rails new により『gem 'rails'』が二重に存在しているとエラーを起こすので、そのようなエラーが出た際は重複していないか確認）

④空のGemfile.lockを作成

```terminal
$ touch Gemfile.lock
```

⑤docker-compose.ymlを作成

```docker-compose.yml
version: '3'
services:
  db:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: root
    ports:
      - "3306:3306"

  web:
    build: .
    command: rails s -p 3000 -b '0.0.0.0'
    volumes:
      - .:/app_name
    ports:
      - "3000:3000"
    links:
      - db
```

⑥rails newを実行

```terminal
$ docker-compose run web rails new . --force --database=mysql --skip-bundle
```

⑦database.ymlのpasswordとhostを修正

```database.yml
default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: password # docker-compose.ymlのMYSQL_ROOT_PASSWORDと同じ名前に変更
  host: db # docker-compose.ymlのservice名と同じ名前に変更
```

⑧Dockerを起動する（実行する際のカレントディレクトリに注意すること）

```terminal
$ docker-compose build

$ docker-compose up -d
```
⑨データベースを作成

```terminal
$ docker-compose run web rails db:create
```

⑩ブラウザでlocalhost:3000にアクセスしてサーバーの起動を確認
<img width="846" alt="スクリーンショット 2020-04-19 14.40.39.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580388/380f1ccb-a092-f9b9-fbd4-8b21c6deea6e.png">


#Dockerに関するコマンド

イメージのダウンロード

```terminal
docker pull イメージのオプションやタグ名等を追加
```

全てのサービスをビルド

```terminal
docker-compose build
```

サービス名を指定してビルド

```terminal
docker-compose build rails
```

全てのサービスを起動

```terminal
docker-compose up

デーモン状態で起動
docker-compose up -d
```
全てのサービスを停止

```terminal
docker-compose stop
サービス名を指定して停止
docker-compose stop nginx
```



サーバーを停止

```terminal
docker-compose down
```
サーバを再起動

```terminal
$ docker-compose up --build
```
bundle install

```terminal
#docker-compose run {サービス名} {任意のコマンド}
$ docker-compose run web bundle install
```

ローカルからMySQLコンテナに接続

```terminal
$ mysql -u root -p -h localhost -P 3306 --protocol=tcp
```



起動中のコンテナを確認

```terminal
$ docker ps
```

停止中のコンテナを確認

```terminal
$ docker ps -a
```

コンテナの削除

```terminal
$ docker rm コンテナID
```
コンテナIDの一覧を表示　

```terminal
docker ps -a -q
```

コンテナ全削除

```terminal
$ docker rm `docker ps -a -q`
```






#ユーザーログイン機能
##Gemの追加手順
gemを追記したら、再度build（新規gemのみを構築する処理を記述しないと全ての構築をしているので時間は掛かる）してgemを読み込み、コンテナを起動させた状態でbundle installする。
その後、dockerをリスタートする。

```terminal
$ docker-compose build
$ docker-compose run web bundle install
$ docker-compose restart web
```



上記のGemの追加手順を参考に、Gemfileにコメントアウトで記述されている「gem 'bcrypt'」をbundleinstallする。

##モデルの作成
ユーザー登録に必要なuserモデルを下記コマンドで生成する。

例

```terminal
$ docker-compose exec web rails g model モデル名 カラム名:データ型
$ docker-compose exec web rails db:migrate
``` 


「password_digest」カラムに暗号化されたパスワードが入る仕組みなので、カラム名は変更しない。
（バックスラッシュはMacのキーボードだと「optionキー　＋　￥」で入力出来る。）

```terminal
$ docker-compose exec web \     
> rails g model user name:string email:string password_digest:string
```
マイグレーションファイルを修正してマイグレートを実行してテーブル作成。

```rb
class CreateUsers < ActiveRecord::Migration[6.0]
  def change
    create_table :users do |t|
      t.string :name, null: false
      t.string :email, null: false
      t.string :password_digest, null: false

      t.timestamps
    end
    add_index :users, :name, unique: true
    add_index :users, :email, unique: true
  end
end
```

```terminal
docker-compose exec web rails db:migrate
```


もし、マイグレートに不具合が生じて、諸々確認したい場合は、

```terminal
docker-compose exec web rails db:migrate:status マイグレーションステータスを確認したい      
docker-compose exec web rails db:rollback　マイグレーションファイルをロールバックしたい
docker-compose exec web rake db:migrate:reset　テーブルのレコードを空にしたい      
docker-compose exec web rake db:drop　データベース自体を削除したい
docker-compose exec web rake db:create　再びデータベース構築したい
```

また、Ruby2.7になって出る警告として下記の場合は、deprecated とは、「非推奨である」という意味であり、このような警告が出る理由は、Ruby 2.6系から2.7へのアップデートでの仕様変更によるもので、具体的にはキーワード引数の代わりにハッシュを渡すと警告が出るようになっている。

```terminal
warning: Using the last argument as keyword parameters is deprecated; maybe ** should be added to the call
```
解決策としては、下記例の様にハッシュオブジェクトの前に**をつけること。

```rb
buy_burger('cheese', **params)
```

##ユーザーモデルの設定

```rb
class User < ApplicationRecord
  has_secure_password #モデルが持つメソッドを呼び、入力されたパスワードと確認用で入力されたパスワードが一致していれば、password_digestカラムに暗号化された文字列が入る仕様が組み込まれている

  validates :name, #カラムにバリデーションをかける。
    presence: true, #ユーザー名の入力を必須とする
    uniqueness: true, #属性の値が一意（unique）であり、ユーザー名が重複出来ないようにする
    length: { maximum: 16 }, #ユーザー名を最大１６文字までにする
    format: {
      with: /\A[a-z0-9]+\z/, #正規表現により入力文字を判定させる
      message: 'は小文字英数字で入力してください' #判定結果により出るエラーメッセージを指定する
    }

  validates :password,
    length: { minimum: 8} #パスワードを最小８文字し、空のパスワードを許容しないようにすることで「presence: true」の記述が不要に出来る

  validates :email,
    uniqueness: {
      case_sensitive: false #大文字小文字の違いを確認するデフォルト制約をfalseにする
    }, 
    format: {
      with: /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i,
      message: 'メールアドレスを入力してください'
    }
end
```
##ja.ymlファイルの初期設定

①　application.rbファイルを編集して、日本語ファイルを利用する設定を行う

```config/application.rb
class Application < Rails::Application
  config.time_zone = 'Tokyo'
  config.active_record.default_timezone = :local

  
  #　追記(設定必須) 
  config.i18n.default_locale = :ja #デフォルトのlocaleを日本語(:ja)にする
  #　追記(設定必須)
  config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}').to_s] #i18nの複数ロケールファイルが読み込まれるようpathを通す 
end
```
②　gem導入

```Gemfile
gem 'rails-i18n'
```

作成後、反映させるためにRailsを再起動する

```terminal
docker-compose restart web
```


③　ja.ymlファイルを作成する。

中身は下記Githubを参考
[https://github.com/svenfuchs/rails-i18n/blob/master/rails/locale/ja.yml]


```config/locales/ja.yml
--
  ja:
    activerecord:
      errors:
        messages:
          record_invalid: 'バリデーションに失敗しました: %{errors}'
          restrict_dependent_destroy:
            has_one: "%{record}が存在しているので削除できません"
            has_many: "%{record}が存在しているので削除できません"
    date:
      abbr_day_names:
      - 日
      - 月
#以下省略
```


④　変更確認

```terminal
rails r "puts I18n.default_locale"

ja #enからjaになっていればOK
```


##コントローラーの作成
ユーザーのセッション情報を作成・削除を行うためのコントローラーを作成する。

例

```terminal
$ docker-compose exec web rails g コントローラー名 アクション名（付けなくても良い）
$ docker-compose exec web rails g controller maps index

「docker-compose exec」は、コンテナが起動している時に使用するコマンド
```

セッションズコントローラーは、ユーザーのセッション管理のみを行うために作成するので、viewファイルを作成しないためにも「--skip-template-engine」を追記する。
また、ユーザーIDを削除してログアウト機能を実装するためにも「destroy」アクションを作成する。
このコントローラーの実装により、セッション情報のユーザーIDからユーザーを検索して、ログインの有無を判断させる。


```terminal
docker-compose exec web \                                     
> rails g controller sessions create destroy --skip-template-engine
```

次に、
・ルートとなるトップページを用意するためのHomeコントローラー
・Userコントローラー
を作成する。

```terminal
docker-compose exec web \                                     
> rails g controller home index

indexアクションのみを作成
```

```terminal
docker-compose exec web \                                     
> rails g controller user new create me

ユーザーの作成ページを表示するnewアクション
登録ユーザー保管のためのcreateアクション
ログイン中のユーザーのマイページを表示するためのmeアクション
を作成する。
```

```rb
class UserController < ApplicationController
  def new
    @user = User.new(flash[:user])　#form_withにより新規登録情報はcreateアクションに移行する
  end

  def create
    user = User.new(user_params)
    if user.save
      flash[:success] = "ユーザを登録しました"
      session[:user_id] = user.id
      redirect_to mypage_path
    else
      flash[:user] = user
      flash[:error_messages] = user.errors.full_messages
      redirect_back fallback_location: 'http://localhost'
    end
  end

  def me
    
  end

  private

  def user_params
    params.require(:user).permit(:name, :email, :password, :password_confirmation)
  end
end
```

##ルーティングの設定　

```root.rb
Rails.application.routes.draw do
  get 'mypage', to: 'user#mypage' #表示するためのgetメソッドでURLを「mypage」に設定し、該URLをリクエストした際はuserコントローラーのmeアクションを実行する
  post 'login', to: 'sessions#create' #登録ユーザーを保存するためのpostメソッドでURLを「login」に設定
  delete 'logout', to: 'sessions#destroy' #ユーザーIDを削除するためのdeleteメソッドでURLを「logouut」に設定　
  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
  root 'home#index' 
  resources :user, only: %i[new create]
end
```

##ビューの作成

ユーザー登録用のフォームを作成していく。

```html.erb
<%= render 'shared/error_messages' %>

<%= form_with model: @user, url: user_index_path, local: true do |f| %>
  <div class="form-group">
    <%= f.label :name, 'ユーザー名' %>
    <%= f.text_field :name, class: 'form-control' %>
  </div>
  <div class="form-group">
    <%= f.label :email, 'メールアドレス' %>
    <%= f.email_field :email, class: 'form-control' %>
  </div>
  <div class="form-group">
    <%= f.label :password, 'パスワード' %>
    <%= f.password_field :password, class: 'form-control' %>
  </div>
  <div class="form-group">
    <%= f.label :password_confirmation, 'パスワード（確認）' %>
    <%= f.password_field :password_confirmation, class: 'form-control' %>
  </div>

  <%= f.submit '作成', class: 'btn btn-primary' %>
<% end %>
```

##binding.pryを実行

gemを導入

```Gemfile
gem 'pry-rails'
```

ユーザー登録時のuserパラメーター群の中身を確認してみる

```rb
def mypage
  binding.pry #今回は、登録後に遷移するマイページ用のアクションに記述    
end
```
ターミナルでattachコマンドを入力

```terminal
docker attach コンテナ名
```
ユーザー登録を実行すると、そこでサーバーが止まるのでパラメーターの中身を確認出来る
<img width="1433" alt="スクリーンショット 2020-04-30 21.22.26.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580388/2dd4678c-9321-2357-dd4e-3f7396c4b387.png">

パラメータ表示後、binding.pryの適用が表示される。
<img width="253" alt="スクリーンショット 2020-04-30 21.23.26.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580388/2948b2a0-6e4c-d1d6-c086-4e3d656115b9.png">
セッション情報も確認出来る。

```terminal
[1] pry(#<UserController>)> session
=> #<ActionDispatch::Request::Session:0xb540 not yet loaded>
[2] pry(#<UserController>)> session[:user_id]
=> 4
```
binding.pryを削除してexitで抜ける。

#Deviseの導入手順


はじめにdevise 関連ファイルを生成することができるようにする。

```terminal
$ docker-compose build
```

次にDeviseをインストールして、devise.rbとdevise.en.ymlの２つのファイルを生成する。

```terminal
$ docker-compose run --rm web rails g devise:install
      create  config/initializers/devise.rb
      create  config/locales/devise.en.yml
===============================================================================

Some setup you must do manually if you haven't yet:

  1. Ensure you have defined default url options in your environments files. Here
     is an example of default_url_options appropriate for a development environment
     in config/environments/development.rb:

       config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

     In production, :host should be set to the actual host of your application.
 
  2. Ensure you have defined root_url to *something* in your config/routes.rb.
     For example:

       root to: "home#index"

  3. Ensure you have flash messages in app/views/layouts/application.html.erb.
     For example:

       <p class="notice"><%= notice %></p>
       <p class="alert"><%= alert %></p>

  4. You can copy Devise views (for customization) to your app by running:

       rails g devise:views

===============================================================================
```

【上記説明の和訳】
　

1.　 環境ファイルにデフォルトのURLオプションが定義されていることを確認してください。 
　　以下は、開発環境に適したdefault_url_optionsの例です。
　　本番環境では、ホストをアプリケーションの実際のホストに設定する必要があります。


```terminal 
config / environments / development.rb
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
```
  
2.　config / routes.rbでroot_urlを* something *に定義していることを確認してください。
　　例えば、root to: "home#index"です。

3.　app / views / layouts / application.html.erbにフラッシュメッセージがあることを確認します。
　　例えば下記のとおりです。　

```html.erb
  <p class="notice"><%= notice %></p>
  <p class="alert"><%= alert %></p>
```

4.　次のコマンドを実行することで、（カスタマイズ用の）Deviseビューをアプリにコピーできます。 

```terminal
rails g devise:view
```

上記１のとおり、デフォルトのURL設定を追記する。

```development.rb
Rails.application.configure do
 
  # Default URL
  config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
end
```
ルートの設定をする。


#RSpecの導入

新たなGemを追加（今回はRspec）

```ruby
group :development, :test do
  gem 'rspec-rails'
end
```
　
ターミナルでサービス起動
（ただし、このコマンドの場合は全てのサービスを起動させるので時間が掛かる）

```terminal
$ docker-compose up -d --build
$ docker-compose exec web rails generate rspec:install
```

<img width="243" alt="スクリーンショット 2020-04-19 15.22.42.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580388/bbbde79c-8268-00c3-2dcd-ca2e2ef43d5a.png">

上記出力がされればOK　↑


ちなみにgemを追加する際に追加したgemのみインストールする方法　↓

docker-compose.ymlの編集

```docker-compose.yml
version: "3"
services:
  app:
    build: .
    volumes:
      - .:/app
      - bundle_path:/bundle # 名前付きvolumeのbundle_pathを設定し、トップレベルのvolumesに追加
    environment:
      - BUNDLE_PATH=/bundle # environmentを使用し、BUNDLE_PATHを設定


        #途中省略

volumes:
  bundle_path: # 追加
```

gemのcache作成

```terminal
$ docker-compose app bundle install
```
コンテナ停止

```terminal
$ docker-compose down
```
新しいGemfileを追記してインストール

```terminal
$ docker-compose run app bundle install
```

コンテナ再起動

```terminal
$ docker-compose up
```

Rspec実行方法

```terminal
$ docker-compose exec web rspec
```
テストを記述していなければ下記のように出力される　↓　

<img width="527" alt="スクリーンショット 2020-04-19 15.25.41.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580388/50b25772-f583-7da0-cce5-a273507713c3.png">