AWSのS3で画像を配信
内容
画像の保存にAWSのS3を使用する
基礎知識
- S3
→安価で耐久性の高いAWSのクラウドストレージサービス
→静的コンテンツの配信やバッチ連携用のファイル置き場、ログ等の出力先、静的ウェブホスティング等で利用する - git-secrets
→AWSが公開しているツールで、commitしようとしたコードをチェックし、パスワードだと推定されるような文字列が含まれている場合は、警告を出して処理が中断してくれる機能 - CloudFront
→高速にコンテンツを配信するサービス(CDNのサービス)
→CloudFrontがあることで、高速化され、S3の負荷が軽減される
→高速(ユーザーから最も近いエッジサーバーから画像を配信する)で、効率的(エッジサーバーでコンテンツのキャッシングを行うので、オリジンサーバーに負荷をかけずに配信できる) - CDN(Content Delivery Network)
→オリジンサーバー(元となる画像を配信するサーバー)上にあるコンテンツを、世界中100箇所以上にあるエッジロケーションにコピーし、そこから配信を行う
S3に画像を保存
手順1 バケットの作成
手順2 セキュリティ対策
- IAMのユーザー→作成済みのIAMユーザーをクリック
- 概要のユーザーARNをコピー
- バケットポリシーを設定するため、S3のバケットを開き、作成したバケットをクリック
- アクセス許可→バケットポリシーの編集→以下のように編集
バケットポリシー
{ "Version": "2012-10-17", "Id": "Policy1544152951996", "Statement": [ { "Sid": "Stmt1544152948221", "Effect": "Allow", "Principal": { "AWS": "①" }, "Action": "s3:*", "Resource": "arn:aws:s3:::②" } ] }
- 「①」の箇所に、先ほどコピーした「ユーザーのARN」を入力
- 「②」の箇所に、作成したバケット名を入力
手順3 本番環境からS3に画像を保存
- S3を使用するために必要なGemfileを導入(Gemfileの一番下に以下を追記)
Gemfile
gem "aws-sdk-s3", require: false
ターミナル
% bundle install
- 画像の保存先を指定するために、production.rbを編集
※現状では画像の保存先が「local」に設定されており、アプリケーション内に画像を保存することを意味しているので、S3に保存されるように設定を変更
config/environments/production.rb.rb
# 元々 config.active_storage.service = :local # 以下のように変更 config.active_storage.service = :amazon
- storage.ymlに以下のコードを追記
config/storage.yml
test: # 省略 lacal: # 省略 amazon: service: S3 region: リージョン名(例:ap-northeast-1 bucket: バケット名 access_key_id: <%= ENV['AWS_ACCESS_KEY_ID'] %> secret_access_key: <%= ENV['AWS_SECRET_ACCESS_KEY'] %>
参考(誤操作で秘密情報をpushしないよう対策)
git-secretsを設定して、セキュリティー対策
- ターミナルから、Homebrewを経由してgit-secretsを導入
ターミナル
% cd ~/ #ホームディレクトリに移動 % brew install git-secrets
- git-secretsが導入できたら、設定を適用したいアプリケーションのディレクトリに移動して、git-secretsを有効化
ターミナル
% cd アプリケーション名 #開発中のアプリに移動 % git secrets --install
ターミナル
% git secrets --register-aws --global
- 実際にどのような設定がされているか確認
ターミナル
% git secrets --list
GitHub Desktopを利用している場合
ターミナル
% sudo cp /usr/local/bin/git-secrets /Applications/GitHub\ Desktop.app/Contents/Resources/app/git/bin/git-secrets # 上記コマンドで「No such file or directory」のエラーがでる場合はGitHub Desktopのバージョンが古い可能性があるので、以下のコマンドを実行 % sudo cp /usr/local/bin/git-secrets /Applications/GitHub\ Desktop.app/Contents/Resources/git/bin/git-secrets
※パスワードは自身のPCにログインする際のパスワード
- 今後作成する全てのリポジトリに、git-secretsが適用されるようにする
ターミナル
% git secrets --install ~/.git-templates/git-secrets % git config --global init.templatedir '~/.git-templates/git-secrets'
CloudFrontを利用して画像を高速配信
手順1 CloudFrontを設定
- CloudFrontのディストリビューションの作成をクリック
- オリジン→オリジンドメインはS3で作成したキャッシュさせたいバケット、オリジンパスは今回は空(指定したディレクトリのみキャッシュさせたい場合は指定)、名前はそのまま、S3バケットアクセスは今回はNoのまま(Cloud Frontのみにアクセスさせたい場合は「Yes」を選択)、オリジンシールドはNoのまま
- Default Cache Behavior→特にいじる必要なし
- 設定→すべてのエッジロケーションを使用するが設定されていればOK→ディストリビューションを作成
手順2 CloudFrontではなく独自ドメインで画像が配信されるように設定
- 作成したCloudFrontのIDをクリック→一般の設定の編集をクリック
- 代替ドメイン名(CNAME)→項目を追加→今回は「static.ドメイン名」というサブドメイン名で配信
- SSL証明書を取得するために「証明書をリクエスト」をクリック
- ドメイン名の追加→「*.myapp.com」「myapp.com」等のように、サブドメイン全てを許容するものとドメイン本体を追加しておく→「次へ」
- DNSの検証→「次へ」
- タグの追加は特に必要ないので「確認」
- 確認して「確定とリクエスト」
- ドメイン名横の三角ボタンを押し、「Route 53でのレコードの作成」→「作成」をクリックして「続行」
- 「SSL証明書」が発行されるまで待ち、発行されたら準備完了
- CloudFrontの画面に戻る→カスタムSSL証明書→*付きのドメイン名を選択→他はそのままで「変更を保存」
手順3 Route 53で独自ドメインとCloudFrontの紐付け
- Route 53のホストゾーンでドメイン名を選択→レコードを作成→レコード名「static」を追加、レコードタイプは「CNAME」、値はCloudFrontのドメイン名を記述→ルーティングポリシーはシンプルで→「レコードを作成」
手順4 Rials側で設定
AWS通信
内容
今回は通信について基礎知識のみまとめる
基礎知識
- プロトコル
→コンピュータ同士がネットワークを利用して通信するために決められた約束事
→メーカーやOSが違うコンピュータ同士が通信するためには同じ仕様でやり取りする必要がある、同じプロトコルを使用するという同意があるからこそ様々なコンピュータ同士が通信できている - TCP/IP
→TCP・IPを中心として、インターネットを構築する上で必要なプロトコル群の総称(インターネットを運用するために開発された)
→上から、アプリケーション同士が会話するアプリケーション層(HTTP、DNS、SSH、SMTP)、データの転送を制御するトランスポート層(TCP、UDP)、IPアドレスを管理し経路選択するネットワーク層(IP、ICMP、ARP)、直接接続された機器同士で通信するネットワークインターフェース層(Ethernet、PPP)、の4階層のモデルがある - HTTP(Hyper Text Transfer Protocol)
→インターネットでHTML等のコンテンツの送受信に用いられる通信の約束事
→クライアントがHTTPリクエストを送り、それに対してサーバーがHTTPレスポンスを返す、そのリクエスト・レスポンスの書き方がHTTPの正体 - TCP(Transmission Control Protocol)
→信頼性のある通信を提供、信頼性のある通信を実現する必要がある場合に使用する
→信頼性を保つために、送信するパケットの順序制御や再送制御を行う - UDP(User Datagram Protocol)
→信頼性のない通信 、高速性やリアルタイム性を重視する通信で使用する
→送信するだけで、パケットが届いたかは保証しない
→動画や電話等、即時性が必要な通信や総パケット数が少ない通信(DNS等)に向いている - IP
→IPの役割は、IPアドレス、終点コンピュータまでのパケット配送(ルーティング)、パケットの分割・再構築処理の3つ
→IPアドレス:ネットワーク上で通信を行う宛先を識別するのに使われる
→ルーティング:宛先IPアドレスのコンピュータまでパケットを届ける
→パケットの分割・再構築処理:各ネットワークインターフェースの最大転送単位より小さくなるようにパケットを分割して送信し、終点コンピュータで再構築する
AWSで無料のSSL証明書を取得
内容
SSL証明書の取得
- AWSサービスの中から、Certificate Managerを選択
- 証明書のプロビジョニングの「今すぐ始める」をクリック
- パブリック証明書のリクエストを選んで「証明書のリクエスト」をクリック
- webサイトで利用予定のドメインを指定して「次へ」をクリック
- DNSの検証で「次へ」をクリック
- タグの作成は任意なので、不要であれば空欄のまま「確認」をクリック
- 内容に誤りがなければ「確定とリクエスト」をクリック
- ドメイン横の三角ボタンをクリックしプルダウンを表示
- ネームサーバーをRoute 53としている場合は、「Route 53でのレコードの作成」をクリックし、「作成」をクリック→成功と表示されればOK
- 「続行」で完了
SSL証明書をELBに設定
いくつか方法があるが今回はELBに設定する、その中でもALBを使用する
- AWSサービスの中から、EC2を選択
- 「ロードバランサー」→「ロードバランサーの作成」を選択
- Application Load Balancerを選択
- 任意の名前を入力
- VPCを選択し、アベイラビリティーゾーンでは2つ以上(1つはWebサーバーのあるゾーン)、サブネットを選択
- 新しいセキュリティグループを作成→セキュリティグループ名を設定し、ポートは80と443でどこからでもアクセス出来るように、0.0.0.0/0, ::/0 を許可する→作成したセキュリティグループを選択
- リスナーの追加でHTTPとHTTPSを選べるので、HTTPSを選択
- Create target group→インスタンスを選択、ターゲットグループに任意の名前を設定、バージョンはHTTP1で「Next」
※プロトコルはHTTP、ポートは80のデフォルト設定でOK→EC2インスタンスとELBはHTTP通信のため
- 「インスタンス」の項目で追加するwebサーバにチェックを入れ、「Include as pending below」をクリックすると、ターゲットにwebサーバのインスタンスが追加される→作成→作成したターゲットを選択
- Default SSL certificateで先程作成した証明書を選択
- 最後に設定が問題ないことを確認し「作成」
- ターゲットグループの一覧からターゲットを確認すると、LB作成前はunusedになっていたが、LB作成後はhealthyになり、アクセスできる状態になった
ロードバランサーとドメインを紐付ける
- Route 53でタイプAのレコードを選択して「レコードの編集」をクリック
- トラフィックのルーティング先でエイリアスをオン
- ALBとCLBへのエイリアス→リージョンを選択→先程作成したロードバランサーを選択→保存
EC2インスタンスのポートを設定
- EC2にはALBからのアクセスのみ許可する場合は、セキュリティグループのインバウンドルールを編集する
以上で「https://〜」のドメインでアクセスすると鍵がかかった状態になっている
証明書情報を見ると、Amazonが認証局になり有効期限が来年になっていることが確認できる
AWSにDockerの環境を構築
内容
AWSのEC2にDockerの環境を構築する
手順1 EC2インスタンスにssh接続
まずキーを他人に不正利用されないように、自分で読み込みだけ可能な設定にしてから接続
自分には読み込みだけじゃなく全権限を与えたい場合は下記の数字を700にする(キーはむしろ変更したくないので読み込みだけ許可の400がいい)
ターミナル
% chmod 400 キーの名前.pem % ssh -i キーの名前.pem ec2-user@パブリックIPアドレス
手順2 AWS(EC2)にDockerをインストール
AWSにDockerをインストールするにはOSはLinux環境が必要となる
下記コマンドを実行
ターミナル
# Dockerをインストール [ec2-user@ip-〜]$ sudo yum install -y docker # Dockerを起動 [ec2-user@ip-〜]$ sudo service docker start # ec2-userをdockerグループに入れる事でdockerコマンドが利用可能になる [ec2-user@ip-〜]$ sudo usermod -a -G docker ec2-user # 一度exitでログアウトし再度sshでログイン # dockerコマンドが利用できるか、docker起動確認の為にinfoコマンドを使い確認 [ec2-user@ip-〜]$ docker info # EC2起動時にDockerを自動で立ち上げる場合は下記コマンド [ec2-user@ip-〜]$ sudo chkconfig docker on
手順3 Docker-composeのインストール
AWSにもDocker-composeをインストール
ターミナル
# docker-composeをインストール [ec2-user@ip-〜]$ sudo curl -L https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose # 下記コマンドで実行できるようにアクセス権を変更 [ec2-user@ip-〜]$ sudo chmod +x /usr/local/bin/docker-compose # 下記コマンドで実行できるかを確認 [ec2-user@ip-〜]$ docker-compose --version
手順4 AWSとGitHubを連携
以下コマンドを実行
ターミナル
# gitをインストール [ec2-user@ip-〜]$ sudo yum install -y git # キーを作成(質問は全てエンター) # -t 暗号化方式を指定 # -b 暗号化強度を指定 [ec2-user@ip-〜]$ ssh-keygen -t rsa -b 4096 # 作成した公開鍵を表示し、コピー [ec2-user@ip-〜]$ cat ~/.ssh/id_rsa.pub
こちらのサイトにアクセス
右上の「new SSH key」をクリック
titleを入力し、keyのところに先ほどコピーした文字列を貼り付ける(ssh-rsa~から)
以下コマンドを実行し、途中yesと入力したら、AWSとgithubの認証が成立
ターミナル
[ec2-user@ip-〜]$ ssh -T git@github.com
以後、AWSインスタンス側から自身のgithubに対し、pull等ができるようになる
手順5 コンテナの構築
構築方法は以下の2通り
- Dockerfileを作成し環境を構築
- docker pullでRails等のイメージを取得してコンテナを作成する方法
今回はDockerfileを作成しつつ環境を構築する方法で進める
※ここから自分のファイル名をmyappに置き換える
1. Dockerfileの修正
ここはローカル用とAWS用で同じコードを使う
前回作成したファイルの記述から変更
Dockerfile
FROM ruby:2.6.5 # これがないとAWSでyarnが使用できない RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \ && echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list RUN apt-get update -qq && apt-get install -y \ build-essential \ libpq-dev \ nodejs \ yarn \ vim WORKDIR /myapp ADD Gemfile /run-share/Gemfile ADD Gemfile.lock /run-share/Gemfile.lock RUN gem install bundler RUN bundle install ADD . /myapp RUN mkdir -p tmp/sockets RUN mkdir -p tmp/pids
NginxのDockerfileは変更なし
nginx_docker/Dockerfile
FROM nginx:1.21.3 RUN rm -f /etc/nginx/conf.d/* ADD nginx.conf /etc/nginx/conf.d/run-share.conf CMD /usr/sbin/nginx -g 'daemon off;' -c /etc/nginx/nginx.conf
2. database.ymlの修正
下記を追加して、本番環境は環境変数から値を読み込むようにする
database.yml
production: <<: *default database: <%= ENV['DB_DATABASE'] %> adapter: mysql2 encoding: utf8 charset: utf8 collation: utf8_general_ci host: <%= ENV['DB_HOST'] %> username: <%= ENV['DB_USERNAME'] %> password: <%= ENV['DB_PASSWORD'] %>
DB_HOSTはRDSのエンドポイント
AWSのRDSダッシュボードのデーターベースをクリックし、一覧から該当のRDSを選択すると確認できる
3. nginx設定ファイルの修正
以下の部分を本番環境用に変更
nginx.conf
server { listen 80; # =========ローカルと本番切り替え=========== server_name 固定IP; # server_name localhost; # ======================================
4. .envファイルに環境変数を設定
2.の環境変数を設定する
5. docker-compose.ymlの修正
dbコンテナは本番環境ではRDS使用で不要のためコメントアウト(appコンテナのdepends_onもまとめて)
commandのbundle exec pumaに-e production を追記して、本番環境でサーバーを立ち上げる
手順6 githubからclone
再度sshログインして、githubからclone(URLはリポジトリを表示したときのURL)
ターミナル
# ルート直下に移動(homeディレクトリでコンテナを展開するとpumaとnginxの連携でエラーが出る場合がある) [ec2-user@ip-〜]$ cd / [ec2-user@ip-〜]$ sudo git clone https://github.com/〇〇〇〇〇〇/〇〇〇〇〇〇 # ディレクトリがあるか確認 [ec2-user@ip-〜]$ ls
手順7 .gitignoreに記載したファイルを転送
現在.gitignoreに記載したファイル(.env master.key)は含まれていないので、ssh通信を用いてローカルからAWSに直接ファイルを転送
ターミナル
# 一旦ログアウトして、ローカルのmyappファイルに移動 [ec2-user@ip-〜]$ exit # scpコマンドを用いて、AWSに.envを転送 # 権限の関係で一旦、ホームディレクトリに転送 % sudo scp -i ~/.ssh/myapp_key.pem .env ec2-user@固定IP:/home/ec2-user/ % sudo scp -i ~/.ssh/myapp_key.pem config/master.key ec2-user@固定IP:/home/ec2-user
再度sshログインし、ファイルが転送できているか確認
ターミナル
[ec2-user@ip-〜]$ cd [ec2-user@ip-〜]$ ls -a
ホームディレクトリに移動して.envとmaster.keyが存在することを確認し、.envとmaster.keyを移動させる
ターミナル
[ec2-user@ip-〜]$ sudo mv .env /myapp [ec2-user@ip-〜]$ sudo mv master.key /myapp/config [ec2-user@ip-〜]$ ls -a /myapp/ [ec2-user@ip-〜]$ ls -a /myapp/config
手順8 コンテナを起動
まずはイメージをビルド
※この時Dockerのサービスが停止していてdockerコマンドが使えなくなっている可能性があるので、その際はsudo service docker start
で再度Dockerを起動させる
ターミナル
[ec2-user@ip-〜]$ cd /myapp [ec2-user@ip-〜]$ docker-compose build
サーバー起動前の準備(プリコンパイル)
ターミナル
[ec2-user@ip-〜]$ docker-compose run app rails assets:precompile RAILS_ENV=production
コンテナを起動
※ここでbundler: failed to load command: puma
というエラーが表示され、appサーバーが起動されない場合がある
これが正解かわからないが、mkdir tmp/sockets
とmkdir tmp/pids
で自分でディレクトリを作成すると解決できた
ターミナル
[ec2-user@ip-〜]$ docker-compose up -d
データベースの作成、マイグレーションファイルの読み込み
ターミナル
[ec2-user@ip-〜]$ docker-compose exec app rails db:create db:migrate RAILS_ENV=production
RDSのデーターベース確認方法
以下のコマンドで実行
ターミナル
mysql -u RDSのユーザー名 -h RDSのエンドポイント -p //パスワードを入力してログイン
Dockerを用いたローカル環境にWebサーバー(nginx)を設置
内容
前回既存のRailsアプリにDockerを導入したが、Webサーバーも設置することにしたのでまとめる
現状
ここにwebコンテナ(nginx)を設置する(ちなみにappサーバーはpumaを設置)
手順1 必要なファイルを作成
既存アプリケーションのルートディレクトリにnginx_dockerフォルダを作成し、その配下にDockerfileとnginx.confファイルを作成
手順2 Dockerfileの編集
app用とnginx用のDockerfileを編集(app用は前回のそのまま)
※ここからアプリ名をmyappとして記述している
Dockerfile
FROM ruby:2.6.5 RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \ && echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list RUN apt-get update -qq && apt-get install -y \ build-essential \ libpq-dev \ nodejs \ yarn WORKDIR /myapp COPY Gemfile ./Gemfile COPY Gemfile.lock ./Gemfile.lock RUN gem install bundler RUN bundle install COPY . /myapp COPY entrypoint.sh /usr/bin/ RUN chmod +x /usr/bin/entrypoint.sh ENTRYPOINT ["entrypoint.sh"] EXPOSE 3000 CMD ["rails", "server", "-b", "0.0.0.0"]
nginx_docker/Dockerfile
FROM nginx:1.21.3 # インクルード用のディレクトリ内を削除 RUN rm -f /etc/nginx/conf.d/* # Nginxの設定ファイルをコンテナにコピー ADD nginx.conf /etc/nginx/conf.d/myapp.conf # ビルド完了後にNginxを起動 CMD /usr/sbin/nginx -g 'daemon off;' -c /etc/nginx/nginx.conf
手順3 nginxの設定ファイル
nginx.conf
# プロキシ先の指定 # Nginxが受け取ったリクエストをバックエンドのpumaに送信 upstream myapp { # ソケット通信したいのでpuma.sockを指定 server unix:///myapp/tmp/sockets/puma.sock; } server { listen 80; # ドメインもしくはIPを指定 server_name localhost [or example.com or 192.168.xx.xx]; access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; # ドキュメントルートの指定 root /myapp/public; client_max_body_size 100m; error_page 404 /404.html; error_page 505 502 503 504 /500.html; try_files $uri/index.html $uri @myapp; keepalive_timeout 5; # リバースプロキシ関連の設定 location @myapp { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_pass http://myapp; } }
手順4 docker-compose.ymlの編集
前回railsコンテナをwebと定義していたがそれをappに変更し、nginxコンテナをwebと定義する
docker-compose.yml
version: '3' services: # Nginxコンテナ定義 web: build: context: ./nginx_docker volumes: - public-data:/myapp/public - tmp-data:/myapp/tmp ports: - 80:80 depends_on: - app # Railsコンテナ定義 app: build: . command: bundle exec puma -C config/puma.rb environment: - MYSQL_HOST=${MYSQL_HOST} - MYSQL_USERNAME=${MYSQL_USERNAME} - MYSQL_PASSWORD=${MYSQL_ROOT_PASSWORD} volumes: - .:/myapp - public-data:/myapp/public - tmp-data:/myapp/tmp - log-data:/myapp/log depends_on: - db tty: true stdin_open: true # MySQLコンテナ定義 db: image: mysql:5.6.51 environment: MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} MYSQL_DATABASE: ${MYSQL_DATABASE} ports: - "4306:3306" volumes: - mysql-data:/var/lib/mysql volumes: public-data: tmp-data: log-data: mysql-data:
手順5 puma.rbの編集
puma.rbの最下部に以下の記述を追加
bind "unix://#{app_root}/tmp/sockets/puma.sock"の部分は、nginx.confのserverと一致するようにする
config/puma.rb
app_root = File.expand_path("../..", __FILE__) bind "unix://#{app_root}/tmp/sockets/puma.sock" stdout_redirect "#{app_root}/log/puma.stdout.log", "#{app_root}/log/puma.stderr.log", true
手順6 database.ymlの編集
Railsはデフォルトで、localhost上でDBが動作するようになっているので、hostを先ほど作成したdbに変更
また、ここにおける「MYSQL_USER」と「MYSQL_PASSWORD」はDBファイルで定義した環境変数名を設定
database.yml
default: &default adapter: mysql2 encoding: utf8 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: <%= ENV.fetch('MYSQL_USER') { 'root' } %> password: <%= ENV.fetch('MYSQL_PASSWORD') { 'password' } %> host: db development: <<: *default database: myapp_development test: <<: *default database: myapp_test
手順7 イメージを作成
docker-compose.ymlで、web・app・dbのbuildに指定されているDockerfileを元にイメージを作成
ターミナル
% docker-compose build
手順8 コンテナを起動
以下のコマンドでコンテナを立ち上げ、コンテナが起動しているのかを確認
ターミナル
% docker-compose up -d % docker-compose ps
手順9 データベースの作成、マイグレーションファイルの読み込み
最後に以下のコマンドでデータベースの作成とマイグレーションファイルの読み込みをする
ターミナル
% docker-compose exec app rails db:create db:migrate
コンテナの停止・削除をしたい時
以下のコマンドを実行
ターミナル
# 停止したい時 % docker-compose stop # 停止・削除したい時 % docker-compose down # volumeも一緒に削除したい時(MySQLのデータもすべて消えるので注意!) % docker-compose down -v
docker-composeによる各種ファイルの変更時
内容
docker-composeによるコンテナ構成後、各種ファイルを変更した時の反映方法についてまとめる
docker-compose.ymlの変更時
- イメージ:再構築の必要なし
- コンテナ:再構築の必要あり
→docker-compose up -d
Dockerfileの変更時
- イメージ:再構築の必要あり
→docker-compose build - コンテナ:再構築の必要あり
→docker-compose up -d
ソースコード等の変更時
- イメージ:再構築の必要あり
→docker-compose build - コンテナ:再構築の必要あり
→docker-compose up -d
既存のRailsアプリにDockerを導入
内容
すでにRailsアプリを作成している段階でDockerも導入したいと考えたので、アプリ作成後からDockerを導入する方法についてまとめる
バージョン
基礎知識
- Dockerfileとは
→Docker imageの設計図で、DockerfileからDocker imageを作る
→INSTRUCTION argumentsの形で書いていく - FROM(instruction)
→ベースとなるイメージを決定
→DockerfileはFROMから書き始める - RUN(instruction)
→Linuxコマンドを実行
→RUNを使うことで好きなようにカスタマイズ
→RUN毎にImage Layerが作られる(RUNをずらっと書いていくとLayerの数が膨大になりimageが大きくなってしまう) - imageのLayer数を最小限にするには?
→Layerを作るのはRUN、COPY、ADDの3つ
→コマンドを&&で繋げる
→バックスラッシュ(\)で改行する - $apt-get
→$apt-get update:新しいパッケージリストを取得、$apt-get install: をインストール - CMD(instruction)
→コンテナのデフォルトのコマンドを記述
→CMD["executable", "params1", "params2"]
→原則Dockerfileの最後に記述
→RUNはLayerを作る、CMDは作らない - COPYとADD(instruction)
→単純にファイルやフォルダをコピーする場合はCOPYを使う
→tarの圧縮ファイルをコピーして解凍したい時はADDを使う(大きいファイルの時) - CMDとENTRYPOINT(instruction)
→ENTRYPOINTでもデフォルトのコマンドを指定することができるが、run時に上書きできない
→ENTRYPOINTがある場合は、CMDは["params1", "params2"]の形を取る
→コンテナをコマンドのように使いたい時に使う - ENV(instruction)
→環境変数を設定する - WORKDIR(instruction)
→Docker instructionの実行ディレクトリを変更する - docker compose
→複数のコンテナを簡単にrunできるDockerのツール
→docker runコマンドが長くなる時や、複数のコンテナをまとめて起動する時に使う
手順1 DockerHubの登録とDockerのインストール
- DockerHubのHPでサインアップ
- 無料の枠を選択
- メールが送られてくるのでログイン
- 「Download the desktop application」でDocker Desktopをダウンロード
- Docker.dmgがダウンロードできたらダブルクリックし、インストール→アプリケーションフォルダに移動
手順2 Dockerfileを作成
既存アプリケーションのルートディレクトリにDockerfileを作成し、下記のように記述
※今回はアプリのディレクトリ名をsample_appとする
Dockerfile
FROM ruby:2.6.5 RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \ && echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list RUN apt-get update -qq && apt-get install -y \ build-essential \ libpq-dev \ nodejs \ yarn WORKDIR /sample_app COPY Gemfile ./Gemfile COPY Gemfile.lock ./Gemfile.lock RUN gem install bundler RUN bundle install COPY . /sample_app COPY entrypoint.sh /usr/bin/ RUN chmod +x /usr/bin/entrypoint.sh ENTRYPOINT ["entrypoint.sh"] EXPOSE 3000 CMD ["rails", "server", "-b", "0.0.0.0"]
手順3 docker-compose.ymlを作成
手順2同様にルートディレクトリにdocker-compose.ymlを作成し、下記のように記述
docker-compose.yml
version: '3' #docker-composeのバージョン services: web: build: . command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'" volumes: - .:/sample_app ports: - 3000:3000 depends_on: - db tty: true stdin_open: true db: image: mysql:5.6.51 #既存アプリとあわせる。ターミナルに[$ mysql --version]で確認 environment: MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} #あなたのパスワード MYSQL_DATABASE: root ports: - "4306:3306" volumes: - ./mysql-confd:/etc/mysql/conf.d volumes: mysql-data:
手順4 config/database.ymlの編集
configディレクトリにあるdatabase.ymlを下記のように編集
config/database.yml
default: &default adapter: mysql2 encoding: utf8mb4 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: root password: <%= ENV.fetch("DATABASE_PASSWORD") %> #あなたのパスワード socket: /tmp/mysql.sock host: db development: <<: *default database: sample_app_development test: <<: *default database: sample_app_test
手順5 .envファイルに環境変数を設定し、.gitignoreに.envを追加
手順6 entrypoint.shを作成
手順2、3同様にルートディレクトリにentrypoint.shを作成し、下記のように記述
entrypoint.sh
#!/bin/bash set -e # Remove a potentially pre-existing server.pid for Rails. rm -f /sample_app/tmp/pids/server.pid # Then exec the container's main process (what's set as CMD in the Dockerfile). exec "$@"
手順7 Dockerイメージの作成
ターミナルで下記のコマンドを実行し、Dockerイメージを作成
ターミナル
sample_app% docker-compose build
手順8 Dockerコンテナを起動
ターミナルで下記のコマンドを実行し、Dockerコンテナを起動 ターミナル
sample_app% docker-compose up -d
手順9 コンテナ内にデータベースを作成する
ターミナルで下記のコマンドを実行し、コンテナ内にデータベースを作成 ターミナル
sample_app% docker-compose run web rails db:create
手順10 作成したデータベースのマイグレーションを実行
ターミナルで下記のコマンドを実行し、データベースのマイグレーションを実行 ターミナル
sample_app% docker-compose run web rails db:migrate
手順11 Gemのインストール(これいらないかも)
ターミナルで下記のコマンドを実行し、Gemをインストール ターミナル
sample_app% docker-compose exec web bundle install
以上で導入完了
localhost:3000に接続するとアプリケーションが表示される(rails sはいらない)
エラー1
手順9のコマンド実行時、以下のエラーが出現
ターミナル
Creating sample_app_web_run ... done warning Integrity check: System parameters don't match error Integrity check failed error Found 1 errors. ======================================== Your Yarn packages are out of date! Please run `yarn install --check-files` to update. ======================================== To disable this check, please change `check_yarn_integrity` to `false` in your webpacker config file (config/webpacker.yml). yarn check v1.22.5 info Visit https://yarnpkg.com/en/docs/cli/check for documentation about this command. ERROR: 1
yarnのパッケージの中に古いものが存在していることが原因のようなので、以下のコマンドを実行してyarnをアップグレードしてみた
ターミナル
% yarn upgrade
しかし同じようなエラーが出たので、再度エラーを確認
ターミナル
To disable this check, please change `check_yarn_integrity` to `false` in your webpacker config file (config/webpacker.yml).
上記のようなエラーが出ていたため、「config/webpacker.yml」ファイルのcheck_yarn_integrity箇所をfalseに変更すれば良いと解釈して、実際に変更してみる
config/webpacker.yml
# Verifies that correct packages and versions are installed by inspecting package.json, yarn.lock, and node_modules check_yarn_integrity: false
上記で解決した