dockerについて。
インフラ環境を構築するために、Dockerを活用させていくためにも、まず勉強していく必要がある。
今回はそれを学ぶために、自習してきた内容を記録する。
ここの内容を参考にする
https://www.youtube.com/watch?v=lZD1MIHwMBY
環境構築
今回使用するものはこれ。
- iTerm2
- Docker
- VScode
- Git
iterm2のブラウザを開いて、ダウンロードする。zipから、簡単に出すことができる。
これを使って、Linuxとかのコマンドを使う。
VScodeの拡張で便利なのは?
- japaneselanguage
- docker
gitのインストール
ブラウザで検索し、download for mac を押してみる。
Macの場合、Homebrewを使う。
homebrewを使ったら、
brew install git
を用いる。入ったら、
git --version
で、コマンドが表示されたらOK
dockerのインストール
DockerDesktop for mac を用いる。
これをダウンロード。そして、開いていく。
https://www.docker.com/products/docker-desktop
クリックすると起動する。
dockerが既に動いているかを確認するには、上のメニューバーを見ると、クジラが映る。
この状態で、このように打てば、dockerのコマンドがあるのを確認できる。
docker --version
Docker version 20.10.10, build b485636
Linuxを用いる。
dockerにはLinuxコマンドを用いる。
コンピュータやサーバの操作をする時に、使えないと不便。これを知っていれば、Dockerやサーバの操作をする時に便利になる。
一度身につければ、変わらずに使い続けることができる。
dockerは開発環境を整えるもので、OSからコードまでをセットにしたもの。
Docker使う時も、OSはLinuxなので、Linuxを学ぶ必要がある。コマンドを使って。ファイルの一括操作とかができるので、便利らしい。
シェルはLinuxのコマンドを受け取って、結果を出力するためのソフトウェア。
- つまり、ユーザーとLinuxの仲介役である。
- そのコマンドを入力する画面が、ターミナル。
ターミナルはあくまで画面担当。シェルはコマンドを解釈して、Linuxに伝える。
実際にLinuxコマンド使う。
-
lsコマンド。
- 現在いるディレクトリなどの一覧を見ることができる。
-
pwdコマンド
- 今、自分がいるディレクトリを表示
-
cdコマンド
- ディレクトリを移動する。
- 〜ならホームディレクトリ
-
mkdirコマンド
- ディレクトリを作るコマンド
-
mkdir docker
とすると、 - dockerのディレクトリ(フォルダ)を、現在のディレクトリ内に作る。
-
touchコマンド
- 新規の空ファイルを作成することができる。
-
echoコマンド
- echo 'Hello' > tmpとすると、tmpの中にHelloの文字を見れる。
-
catコマンド。ファイルの中身を見る
-
lessコマンド
- lessコマンドは、全画面で文字を表示する。長い時に便利。
- qキーで終了する。
-
mvコマンド(ムーブ)
- ファイル名を変更するコマンド
-
mv tmp tmp1
とすると、 - tmp -> tmp1 に変更される。
-
rm(リムーブ)コマンド
- ファイル名を削除するコマンド
Dockerを使ってみる。
使いながら、仕組みも学ぼう。
以下コマンドを、iterm2にて入力
docker run hello-world
こんな感じで、Hello from Dockerと来ればOK.
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
これは、
もっと具体的な流れ。
クライアント(依頼主)が、
- docker runというコマンドを渡す。
- それをクライアントが、デーモンにコマンドを実行するように伝える。
- それをデーモンが受け取る。
- バックグラウンド上で動作し続けるアプリケーションのこと
- デーモンは、Dockerのイメージをレジストリから引っ張ってくる。(ローカルに持ってきてくれる)
- レジストリは、イメージをオンライン上で保存しておく場所のこと。
- イメージを元に、コンテナを作っていく。
- ターミナルに、コンテナを起動した結果
Hello from Docker
が表示される。
Dockerでアプリを作って実行する。
Dockerというのは、
- イメージと
- コンテナ
の操作になっている。
Dockerを用いる開発の基本の流れはこう。
アプリケーションの用意
Rubyの簡単なサーバを作る。
VScodewを開く。
main.rb
というファイルを作成する。
rubyの、webrick
というものを用いると、簡単にWebサーバーを立ち上げることができる。
ウェブサーバーとは、HTTPリクエストを受け取り、レスポンスを返すサーバーのことである。
require 'webrick'
server = WEBrick::HTTPServer.ner(
DocumentRoot: './',
BindAddress: '0.0.0.0',
Port: 8000
)
server.mount_proc('/') do |req,res|
res.body = 'hello'
end
server.start
トップページが表示されたら、ハローと表示されるファイルである。
Dockerfileを作成する。
Dockerfile
というファイルを作り、以下のように作成
- FROMで、ruby2.7というドッカーのイメージを使うことを指定する。
- RUNという変数で、Linuxのコマンドを指定する。ここでは、ディレクトリを作成する。
- main.rbを、 /var/wwwの下におく。
- CMDで、実行するコマンドを指定する。["ruby","/var/www/main.rb"]で、rubyで、main.rbを実行するということを表す。
イメージを作成する。
ドッカーのイメージの作成は、コマンドで行う。
docker image build -t sample/webrick:latest .
docker image build
は、ドッカーのイメージをビルドする。
-tオプションで、タグを指定する。
ここでは、sample/webrick:latest
というタグを指定する。latestはバージョンの名前とする。
最後の.
で、現在のディレクトリを参照する。つまり、現在のディレクトリのDockerfileを参照するという事。
イメージを作れたかを確認するのは、以下コマンドで確認できる。
docker image ls
こんな感じになる。
itoudaiware@itoudaiwarenoMacBook-Pro docker % docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
sample/webrick latest bd853182e720 About a minute ago 812MB
hello-world latest 18e5af790473 8 weeks ago 9.14kB
また、docker --help
で、コマンドを確認できる。
コンテナ起動
イメージからコンテナの作成&起動をするには、docker container run
を使う。
今回なら、以下コマンドになる。
docker container run -p 8000:8000 --name webrick sample/webrick:latest
解説する。
- docker container runで、作成と起動を同時に行う
- -pで、ポートを指定する。ここでは、ローカルの8000ポート(最初の8000)を、dockerの8000ポート(次の8000)に接続させている。
- ポートは、アプリケーションの宛先みたいなもの。
- コンテナは閉じた環境なので、Dockerの中のポート番号につなげる必要がある。
- 最後に、イメージ名を指定している。
実行すると、こんな感じになる。
うまくできていると思われる。
itoudaiware@itoudaiwarenoMacBook-Pro docker % docker container run -p 8000:8000 --name webrick2 sample/webrick:latest
[2021-11-21 06:19:15] INFO WEBrick 1.6.1
[2021-11-21 06:19:15] INFO ruby 2.7.4 (2021-07-07) [aarch64-linux]
[2021-11-21 06:19:15] INFO WEBrick::HTTPServer#start: pid=1 port=8000
確認するには、自分のブラウザで確認する。localhost:8000(自分のパソコンの8000)
にアクセスする。
こんな感じで確認できる。
コンテナのライフサイクル
まずは、ターミナルでCtrl +C
docker container ls
で、現在起動中のコンテナのリストを見る。
docker container ls -a
で、停止中のものも見る。
コンテナを停止させるコマンドはこれ。
webrickは、コンテナ名
docker container stop webrick
削除させるにはこれ。webrickは、コンテナ名。
docker container rm webrick
また、バックグラウンドでコンテナを実行させるには、-dのオプションを用いる。
これで、ターミナルも使う事ができる。
docker container run -d -p 8000:8000 --name webrick sample/webrick:latest
よく使うコンテナ関連のコマンド
ログ
これは、デバッグや、問題があった時によくみる。
docker container logs webrick(コンテナ名)
これで、コンテナに対するログが見れる。
itoudaiware@itoudaiwarenoMacBook-Pro docker % docker container logs webrick
[2021-11-21 06:32:16] INFO WEBrick 1.6.1
[2021-11-21 06:32:16] INFO ruby 2.7.4 (2021-07-07) [aarch64-linux]
[2021-11-21 06:32:16] INFO WEBrick::HTTPServer#start: pid=1 port=8000
172.17.0.1 - - [21/Nov/2021:06:32:43 UTC] "GET / HTTP/1.1" 200 5
- -> /
172.17.0.1 - - [21/Nov/2021:06:32:50 UTC] "GET / HTTP/1.1" 200 5
- -> /
itoudaiware@itoudaiwarenoMacBook-Pro docker %
別のコマンドを実行する時
docker container exec webrick ruby -v
- exec の後に、コンテナ名を入れる
- その後、実行したいコマンドを入力
- ここではルビーのバージョンを見る。
これで、作ったコンテナの中でコマンドを使う事ができる。
後片付け
pruneというコマンドを用いる。
docker system prune -a
-a を用いると、今使っていないコンテナ、ネットワーク、イメージを全て削除することができる。
Dockerfileの作成
Dockerのイメージをどうやって作る?
Dockerfileを作成する。
これが作れれば、自分で開発環境が作れる…!
sinatora
今回は、sinatraという、ルビーの軽いFrameworkを用いる。
そして、Gemfileというものを作成していく。
これは、ライブラリのパッケージ管理ツールである。その中に、インストールするGem(今回はsinatraというライブラリ)を指定してやる。
Gemfileの中はこんな感じ
source "https://rubygems.org"
git_sources(:github) {|repo_name| "https://github.com/#{repo_name}"}
gem "sinatra"
- その後、Dockerfileを作る。
基本的にDockerファイルは、コンテナの立ち上がりに必要なコマンドを順に記載していくイメージ。
-
FROM ruby:2.7
で、ruby2.7のイメージを指定する。 -
WORKDIR /var/www
は、ワークディレクトリ。作業する場所を指定する。特に指定はない。 -
WORKDIR /app
も指定する。- ディレクトリがない時、ディレクトリを作ってくれる。
-
ソースコードを、コンテナ内にコピーする。
COPY ./src /var/www
で、srcを、wwwの中にコピーする。 -
CMD ["/bin\bash"]
は、シェル(bash)を起動させるコマンド。- これで一回Dockerのコンテナの中に入って、その後うまく行ったコマンドがあれば、それをDockerfileに記載していく。
- イメージを一度作成する。
sample/sinatra:latest というタグを設定する。
docker image build -t sample/sinatra:latest .
- コンテナを作成&起動
- シェルのようなインタラクティブなコンテナを起動する時は、
-itを使う。
これを使う事で、インタラクティブモードで立ち上がる。 - ポート番号の指定は、シナトラはデフォルトで4567になるので、ローカルも4567としておく。
- 参照しやすいように、--nameでコンテナの名前を付ける。
sinatra
とする。 - -vで、ソースコードの共有をする。
${PWD}/src:/var/www
- これで、自分の現在のディレクトリ下のsrcディレクトリを、コンテナ側の
/var/www
と同期するという意味。
これを行わないと、**何かソースコードの変更をした時に、いちいちイメージを作り直さないとソースコードがイメージに反映されない。**それは面倒臭いので、-vをつけると、ローカルの指定したディレクトリに合わせて中身が変わる。
- イメージ名を指定する。
sample/sinatra:latest
docker container run -it -p 4567:4567 -v ${PWD}/src:/var/www sample/sinatra:latest
- 実行すると、プロンプトが変わる。つまり、bashが起動したという事。さらに、
-it
で指定したので、既にコンテナの中に入っている。
itoudaiware@itoudaiwarenoMacBook-Pro sources % docker container run -it -p 4567:4567 -v ${PWD}/src:/var/www sample/sinatra:latest
root@75a4d2fd2236:/app#
そして、Gem fileが中にいる。catで見てみる事もできる。これは、ローカル側のGemfileになっている。
root@75a4d2fd2236:~# cd /var/www
root@75a4d2fd2236:/var/www# ls
Gemfile
root@75a4d2fd2236:/var/www# cat Gemfile
source "https://rubygems.org"
git_source(:github) {|repo_name| "https://github.com/#{repo_name}"}
この状態で、Gemfileを変更したりすると、中身も変わってくる。変更して保存すると、こんな感じで変更されているのがわかる。
gem "sinatra"root@75a4d2fd2236:/var/www# cat Gemfile
# frozen_string_literal:true
source "https://rubygems.org"
git_source(:github) {|repo_name| "https://github.com/#{repo_name}"}
コンテナにて、gemをインストールしていく。
以下コマンドで、vendor/bundleにインストール先を指定する
bundle config --local set path 'vendor/bundle'
これができたら、インストールコマンドを実行
bundle install
うまくいったらこんな感じ。
省略。
Bundle complete! 1 Gemfile dependency, 7 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.
そして、アプリのコードを作成していく。
srcの下に、app.rb
を作成する。
受け付けるIPアドレスは、0.0.0.0で全て。get '/'
で、トップページに来たらHello world
で、ハローワールドを表示する。
require 'sinatra'
configure do
set :bind, '0.0.0.0'
end
get '/' do
'Hello world!!'
end
この状態で、このアプリケーションを実行。bundleを使用した時は、前にbundle
を付ける。そして、ruby
のファイル中の、app.rb
を実行する。
bundle exec ruby app.rb
ここで、ブラウザにアクセスする。
すると、アクセスすることができた!
ここまでの処理を、Dockerfileで実現する。
先ほど実行した、bundle config --local set path 'vendor/bundle'
と、bind install
を、RUN の引数に指定して記載する。ちなみに、バックスラッシュ
や&&で、一つにまとめることも可能
そして、実行するファイルを書き直す。
先ほどはbash(/bin/bash
)のみだったが、
- bundle
- exec
- ruby
- app.rb(file名)
を記載する。
CMD ["bundle","exec","ruby","app.rb"]
これで、コンテナが起動した瞬間に、これらが実行されるようになる。
ちなみに、linuxのコマンドではbundle exec ruby app.rb
と、スペース区切りで行なっていたが、
CMDの中は、""と,を用いて区切っていく。
コンテナ作り直し
- Ctrl + C で一度やめる
-
exit
で、コンテナから抜ける - コンテナを削除する。
docker container rm sinatra
- 新しく、イメージを作る
docker image build -t sample/sinatra:latest .
- この時、こんな感じでエラーが出た。
gem "sinatra"root@75a4d2fd2236:/var/www# bundle config --local set path 'vendor/bundle'
root@75a4d2fd2236:/var/www# bundle install
[!] There was an error parsing `Gemfile`: Undefined local variable or method `git_sources' for Gemfile. Bundler cannot continue.
# from /var/www/Gemfile:4
# -------------------------------------------
#
> git_sources(:github) {|repo_name| "https://github.com/#{repo_name}"}
#
# -------------------------------------------
インストールしようとしているディレクトリにはGemfileがないらしい。
そのため、WORKDIR/app
を、WORKDIR /var/www
の上にすることで、問題なく実行できた。
WORKDIR /app
WORKDIR /var/www
- もう一度コンテナを起動する。-itは今回必要ないので、削除しておく。
docker container run -p 4567:4567 -v ${PWD}/src:/var/www sample/sinatra:latest
再度実行しても、こんな感じで問題なく出力されている。
docker container run -p 4567:4567 -v ${PWD}/src:/var/www sample/sinatra:latest
まとめ
Dokcerfileの作り方は基本的には、
- まずコンテナに入る。
- コンテナ内で、コマンドを実行
- そのコマンドがうまくいけば、Dockerfileに記載する。
Dockercomposeで、Rails開発環境を構築する。
Webサービスは、
DockerCompose
複数のアプリケーションをまとめて操作できる。連携も簡単にできる。
servicesというものの下に、dbやwebなど指定していく。
基本操作コマンドはあまり変わらない
- イメージのビルド
docker-composebuild
- コンテナの作成・起動(-dはバックグラウンドで起動)
docker-compose up -d
- コンテナを停止・削除
docker-compose down
- コンテナの一覧表示
docker-compose ps
- コンテナのログ表示
docker-compose logs
- コンテナを作成して、コマンドを実行。つまりこれを使うと、コンテナを一から作り直す。
docker-compose run <サービス名><コマンド>
- 起動中のコンテナにコマンドを実行
docker-compose exec <サービス> <コマンド>
実際に作成する。
Dockerfile作成
今回、ディレクトリに以下のファイルを作成する。
- src/Gemfile
- docker-compose.yml
- Dockerfile
今回のDocker fileの中身はこんな感じ。
FROM ruby:2.7
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && echo "deb https://dl.yarnpkg.com/debian/ stablemain" | tee /etc/apt/sources.list.d/yarn.list && apt-get update -qq && apt-get install -y nodejs yarn
WORKDIR /app
COPY ./src /app
RUN bundle config --local set path 'vendor/'
ここのRUNで、nodejsとyarnを外部からインストールしている。
Gemfileなどをまとめている。
Gemfileの中身はこんな感じ
source 'https://rubygems.org'
gem 'rails', '~> 6.1.0'
gemで、railsのみを指定している。
次に、docker-compose.yml
の中身をみる。
ここには、servicesというものがあり、その下に
-
db
-
web
の二つの要素(サービス)が定義されている。 -
dbには、mysqlのイメージを今回使用している。
- commandというのは、認証形式に関する設定
- volumesは、左側
./src/db/mysql_data
がローカルのディレクトリで、右側/var/lib/mysql
が、コンテナ側のファイルと同期するという設定になる。
mysqlのコンテナが消えると、データを入れ直したりする必要が出てくるので、
同期しておく。
-
environmentは環境変数。mysqlのpasswordを指定しておく。
-
webには、Railsを使用している。
-
build: .
は、カレントディレクトリのDockerfileを参照するという事 -
commandは、実行するコマンド。ここではRailsのサーバーを、ポート3000番で起動している。
-
volumesは、.src内を、/appと同期させるという意味。
-
portsはローカル、3000。
-
depends_onは、依存関係DBサービス。
- **これは、webサービスは、DBサービスに依存しているよという意味になる。**これをしないと、Rails -> Mysqlに接続する時に、dbとするだけで接続できる。(本来はIPアドレスが必要になる。)
初期設定
以下コマンドを実行する。これは、rails newコマンドで、railsの雛形が作成される。
docker-compose run web rails new . --force --database=mysql
なお、M1チップのMacでは、エラーが出た。
ERROR: no matching manifest for linux/arm64/v8 in the manifest list entries
そのため、docker-compose.ymlに、以下platform情報を追記した。
platform: linux/x86_64 (ここ)
image: mysql:8.0
command:
インストールが完了すると、srcの中に、Railsのデフォルトのファイル群達が追加された。
その中の、Gemfileが新しく更新される。
なので、一度、イメージを更新しておく。
docker-com pose build
これでRailsの雛形を作り、イメージを作り直す事ができた。
DBの内容を変える
src/config/database.yml
をみる。その中のpasswordの部分を、docker-compose-ymlの方のenvironmentで指定したものにする。
次に、localhostをDBにする。接続先情報を修正する。
host: localhost
をいかに変更
host: db
DBを作る
これで、webのサービス
に対して、railsのdb:createというコマンドを実行する
。という意味。
docker-compose run web rails db:create
こんな感じで二つ造られる。
itoudaiware@itoudaiwarenoMacBook-Pro rails_docker % docker-compose run web rails db:create
Creating rails_docker_web_run ... done
Created database 'app_development'
Created database 'app_test'
itoudaiware@itoudaiwarenoMacBook-Pro rails_docker %
起動させる。
以下コマンドで、サーバを起動させる。
docker-compose up
ブラウザで、Railsの3000ポートを見てみる。
起動した!!やったね!
追加の操作
サーバの止め方は、Ctrl + Cでもできるが、もう一つおこなってみよう。
- もう一つタブを出し、さっき
docker-compose
を実行したディレクトリに移動。 - そして、以下コマンドを実行すると、停止して削除する事ができる。
docker-compose down
- もう一度実行する時は、upとする。-dをつければ、バックグラウンドになる。
docker-compose up -d
- コンテナの一覧と状況を見るには、
docker-compose ps
を使う。 - ログを見るには、
docker-compose logs
- コンテナ内でコマンドを実行する時は以下を実行
docker-compose exec web /bin/bash
- 修正を反映させる時。
-
docker-compose build
で、イメージを再作成 -
docker-compose up
で、コンテナを再作成
本番環境でDockerコンテナを公開
今までのやつは、ローカルでつかう手順だった。
本番環境で使えるようにしよう!
本番環境で使わないと、思わぬ差異が発生したりする。
本番環境でも使えば、同じコンテナを起動させるだけでOK.いちいちライブラリを入れたりする必要がない。
なので、本番環境でdocker運用する所まで行おう!
今回は、Herokuというホスティングサービスを用いる。https://jp.heroku.com
流れはこんな感じ。
- Herokuにログイン
- Herokuアプリを作成
- DBを追加&設定
- Dockerfileを本番環境用に修正
- Dockerイメージをビルド&リリース
- 機能追加
事前準備
まず、Githubが必要なので、登録する。
https://github.com
githubの設定
そして、GitHubが、Herokuで使えるようにする。
- ターミナルを開きGithubのユーザ名を入力
git config --global user.name "itohdaigo"
- ギットハブで登録したemailを登録する。
itoudaiware@itoudaiwarenoMacBook-Pro rails_docker % git config --global user.email "XXXXXXX@gmail.com
- 登録した方が便利。マージの際に、ファストフォワードが起こらないようにする。
itoudaiware@itoudaiwarenoMacBook-Pro rails_docker % git config --global merge.ff
false
- プルした時に、リベースするというもの。
itoudaiware@itoudaiwarenoMacBook-Pro rails_docker % git config --global pull.reb
ase merge
- 以下コマンドで確認できる。
git config --list
Herokuの設定
ホームページにアクセスし、新規登録を行う。
https://jp.heroku.com
自分はなんかもう作ってあった。
これのログインには、Authenticatorから、認証コードを読み取る必要があった。
-
billingの所で、クレジットカードの登録が必要(今回は、無料の範囲内で行う。)
アドオンでmysqlを登録するときに、クレジットカードが必要 -
HerokuCLIという,コマンドでHerokuを操作できるものをインストールする。
https://devcenter.heroku.com/ja/articles/heroku-cli
自分はmacなので、このコマンドでインストールする。
brew tap heroku/brew && brew install heroku
HerokuにCLIでログインする。
以下コマンドでログイン
heroku login
そして、適当なキーを押したら、ブラウザが出てくるので、Loginを押す。
成功したら以下のようにでる。
Logging in... done
Logged in as bladrain.32@gmail.com
Herokuアプリを作る。
運用したいサービスを、アプリとして作成する。
以下コマンドを実行createの後は、アプリ名である。diegoは自分の名前。このアプリ名は、世界中の人と重複してはいけない。
heroku create rails-docker-diego
DBの追加・設定
Herokuでは、今作ったアプリに、DBをアドオンとして追加するという形になる。
mysqlは、Herokuでは一つだけcleardb
というのが無料なので、今回はそれを使用する。
ただし、無料枠のmysqlは,バージョンが5系しかない。dockerのイメージではもっと新しいのを使っているので、本当は揃えた方がいい。今回は特に問題がないので、そのまま使用する。
heroku addons:create cleardb:ignite -a rails-docker-diego
次に、接続先情報を変える。
今回、環境変数にして、接続先情報を渡すようにする。
DBに不正侵入されてしまう恐れがあるので、環境変数にいれる。
config/databese.yaml
を見てみる。一番下の、productionを変更する。
production:
<<: *default
database: app_production
username: app
password: <%= ENV['APP_DATABASE_PASSWORD'] %>
これを、こんな感じにする。
production:
<<: *default
database: <%= ENV['APP_DATABASE'] %>
username: <%= ENV['APP_DATABASE_USERNAME'] %>
password: <%= ENV['APP_DATABASE_PASSWORD'] %>
host: <%= ENV['APP_DATABASE_HOST'] %>
そして、接続先になるべきDBの情報は、以下コマンドで確認できる。
heroku config -a rails-docker-diego
出力はこんな感じ
itoudaiware@itoudaiwarenoMacBook-Pro rails_docker % heroku config -a rails-docker-diego
=== rails-docker-diego Config Vars
CLEARDB_DATABASE_URL: mysql://bd71f48521eb76:5dacd1c6@us-cdbr-east-04.cleardb.com/heroku_edab841a62d88d9?reconnect=true
- mysqlより後の
bd71f48521eb76
がユーザー名。 -
5dacd1c6
がパスワード -
us-cdbr-east-04.cleardb.com
がホスト名 -
heroku_edab841a62d88d9
がDB名である
そして、これを環境変数として設定するコマンドを使う。先ほどdatabese.yml
にて設定した環境変数名に応じて記載する。
heroku config:add APP_DATABASE='heroku_edab841a62d88d9' -a rails-docker-diego
heroku config:add APP_DATABASE_USERNAME='bd71f48521eb76' -a rails-docker-diego
heroku config:add APP_DATABASE_PASSWORD='5dacd1c6' -a rails-docker-diego
heroku config:add APP_DATABASE_HOST='us-cdbr-east-04.cleardb.com' -a rails-docker-diego
確認するには、以下コマンド
heroku config -a rails-docker-diego
Dockerfileを本番用に修正
dockerfileをいじる。
FROMの下に一行記載した後、
末尾に以下を追記する。
FROM ruby:2.7
ENV RAILS_ENV=production
以下略
COPY start.sh /start.sh
RUN chmod 744 /start.sh
CMD ["sh","/start.sh"]
- start.shをコンテナにコピーする
- 実行するために、実行権限を変える
- start.shを実行する
という処理をしている。
ソースコードで、start.sh
というシェルスクリプトファイルをdockerfileと同列に作る。
これに、本番環境用の処理を入れる。
#!/bin/sh
if [ "${RAILS_ENV}" = "production"]
then
bundle exec rails assets:precompile
fi
bundle exec rails s -p ${PORT:-3000} -b 0.0.0.0
- 一行目はシェルの約束
- if分の中は、本番環境の時のみ、
assets:precompile
というものを実行したいという意味の文になっている。Rails特有の処理。本番だと、これを実行する必要がある。- dockerファイルは条件分岐が難しいので、それを行うために、シェルのプログラムを入れている。
-
bundle exec rails s
で、Railsのサーバーを起動している。環境変数で何も設定されていなければ、3000番を使用する。IPアドレスは、どこからでも受け付けるという設定0.0.0.0
Dockerfileで、分岐をする時は、
- 今回のようにシェルを使うor
- Dockerfile.developみたいに、Docker fileを複数作るという手がある。
assets:precompileを実行するために、
以下の環境変数を設定しておく。
heroku config:add RAILS_SERVE_ATATIC_FILES='true' -a rails-docker-diego
のちに必要になる設定を入れる
タイムアウト時間について
https://tools.heroku.support/limits/boot_timeout
以下のリンクにアクセス。
無料だとマシンパワーが少なく、ポートバインド時間を過ぎるとタイムアウトされるという事がよくあるので、タイムアウトの時間を変更する。
ローカルのサーバーを削除する。
ローカルでサーバーが立ち上がっていると、本番用のものとコンフリクトして、起動しなくなる事がある。(Herokuの問題)
docker-compose down
また、念の為、src/tmp/pids/server.pid
というファイルも削除する。これは、downされたら消えるはずだが、これがあるとエラーが起こるので、削除しておく。
rm src/tmp/pids/server.pid
Dockerイメージをビルド&リリース
herokuにイメージをビルドしてリポジトリにアップするには、以下コマンドを使う。
heroku container:push web -a rails-docker-diego
ビルドになるので、結構時間かかると思われる。
ちなみに、こんな感じのエラーが出た。
no basic auth credentials
! Error: docker push exited with Error: 1
解決策として、ログインし直すと、正常にできた。
heroku container:login
レジストリにあるイメージをHeroku常にコンテナをリリースしていく。
heroku container:release web -a rails-docker-diego
また、通常だと、DBのマイグレーションの処理を行う。Railsの場合。
- マイグレーション。データベースの更新の仕組み。テーブルを更新する時に使うコマンド。
heroku run bundle exec rake db:migrate RAILS_ENV=production -a rails-docker-diego
ローカルで実行するには、こんなコマンド。compose up をした後に実行する。
docker-compose exec web bundle exec rake db:migrate
ソースコードを修正したら、イメージを再作成する必要がある。つまり、もう一度pushし直す必要がある。
アプリを開いていく。
heroku open -a rails-docker-diego
ブラウザが開く。今回エラー起きている。環境変数のエラーっぽいけど、やるきおきないので放置。
Yeah! your Rails !!というのは、ローカルの環境でないと動作しない。
エラーがおきたら、ググって調べる?
一つ、環境変数を設定しておきたい。
これを行うと、たくさんログが表示されるようになる。
heroku config:add RAILS_LOG_TO_STDOUT='true' -a rails-docker-diego
そして、これを設定した上で、以下コマンドを打つと、ログが表示される。
heroku logs -t -a rails-docker-diego
機能追加
トップページにアクセスしたら、何か表示されるというものを作っておきたい。
- railsのコントローラーを作成する。
docker-compose exec web bundle exec rails g controller users
- ソースコードで、ルーティングの設定をみる。
routes.rb
をみるそして、以下のように変更- ルーティング:どのURLに来たら、どこに飛んで、どうアクションするかを記載する。
Rails.application.routes.draw do
# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
get '/', to: 'users#index'
end
- コントローラーをみる。
app/controllers/users_controller.rb
にある。
class UsersController < ApplicationController
def index
end
end
- viewファイルの作成
/src/app/views/users/index.html.erb
を作成する。中身は適当でOK.
これができたら、プッシュとリリースをやってみよう。
その状態で、heroku open
とすると、また表示される。再度見てみると、変更されているのではないだろうか。
CI/CDについて
CI・CDをdockerで構築する。
本番環境を構築したのはいいが、直した時にいちいち手動でデプロイするのが面倒。
そこで、ソースコードが修正されたら、自動でデプロイされるようにしたい。
まずは、GitHubにソースコードを共有する。
そして、チームのみんなが同じコードを参照する。
用語
CIとは
継続的なインテグレーション。
ビルド・テストを自動で実行してくれる。
コードの品質を一定に保ってくれる。
CDとは
継続的なデリバリ。
マージされたら、自動でデプロイしてくれる仕組み。
CircleCI
CI/CDをクラウド上で行なってくれるサービス。
UnityであればGameCIのようなもの。
そして、これらを組み合わせた流れはこんな感じ
- 作ったコードは、CIでテストされ、GitHubに送られる
- GitHubから、CDによってHerokuにデプロイされる
コードをgithubに挙げる
- まずは、ブランチ(並行で作業していく時に作るもの。)を作る。
- ファイルの修正が終わったら、コミット(ファイルの履歴を保存)をする。
- GitHub常に上げるものを、プッシュという。
- そしてGitHub上で、チーム開発するために、プルリクエストを行う
- それが良ければ、マージ(修正内容を、メインブランチにつなげる)
- そして、ローカルのブランチを切り替え、新しいブランチをプルする。
主なコマンド
- gitリポジトリの作成。このディレクトリ以下を対象にするというコマンド。
git init
- GithubのURLを登録。リポジトリのURLを登録させる。
git remote add origin <URL>
- ブランチを作成して切り替える。新しいブランチに切り替える。
git switch -c <ブランチ名>
- 変更内容をステージングに追加
git add .
- 変更内容をコミット(addとセットで使う。addされたものをcommitさせるので。)
git commit -m "メッセージ"
- Githubにプッシュ
git push origin <ブランチ名>
- ブランチを作成して切り替える。(メインブランチ)
git switch <ブランチ名>
- GitHubの変更内容を取り込む
git pull origin <ブランチ名>
- 変更したファイルを確認
git status
- 変更したファイル内容の確認
git diff
githubでの流れ
リポジトリ作成
- 名前はアプリ名と揃えておく(わかりやすくするため)
rails-docker-diego
- publicでもprivateでもOK
- descriptionがいるなら記載
そして、Create repogitoryを押す
Gitでコードを管理する。
リポジトリができたら、コードを管理する。基本的には、ローカルで、真ん中あたりに出てるコードを打ち込むことになる。
git init
git add README.md
git commit -m "first commit"
git branch -M main
git remote add origin https://github.com/itohdaigo/rails-docker-diego.git
git push -u origin main
- 今回作ったファイル達が含まれているコードのルートになる所(ここではrails_docker)で、
git init
を実行する。(ちなみに、2回やるとエラーになる。)
itoudaiware@itoudaiwarenoMacBook-Pro rails_docker % ls
Dockerfile docker-compose.yml src start.sh
-
.gitignore
を追加する。機密情報とかを上げるのは危険。バージョン管理で、いちいちあげたりするものを無視する設定。
いちおう、元々のsrcの中にもあるが、これは直下でないと意味がない。
なので、これらを示す2つのファイルを移動させる
mv src/.gitignore .
mv src/.gitattributes .
そして、src直下の.gitignoreなどを削除しておく。(srcの中にいると、二重管理になり、エラーが起こるため。)
rm -rf src/.gitignore
itoudaiware@itoudaiwarenoMacBook-Pro src % rm -rf .git
- git.ignoreを修正する。
# Ignore bundler config.
/.bundle
# Ignore all logfiles and tempfiles.
/log/*
/tmp/*
!/log/.keep
!/tmp/.keep
# Ignore pidfiles, but keep the directory.
/tmp/pids/*
!/tmp/pids/
!/tmp/pids/.keep
こんな感じになっているのを、src直下であるというふうに、指定しなおしていく。全ての設定の所を、srcの下とする。
# Ignore bundler config.
src/.bundle
# Ignore all logfiles and tempfiles.
src/log/*
src/tmp/*
!src/log/.keep
!src/tmp/.keep
# Ignore pidfiles, but keep the directory.
src/tmp/pids/*
!src/tmp/pids/
!src/tmp/pids/.keep
また、追加でsrc/db/mysql_data
も、上のファイルに追記する。ちなみにこれは、バージョン管理する必要がないので、docker-compose.yaml
にて、指定している。
- ステージングに追加
git add .
この時、src % rm -rf .git
としないと、
error: 'src/' does not have a commit checked out
fatal: adding files failed
と表示される。
5. コミット&プッシュ
git commit -m "first commit"
- ブランチ作成
git branch -M main
- リモートリポジトリにアクセス(今回、SSH認証を既にしているので、これでいく。)
git remote add origin git@github.com:itohdaigo/rails-docker-diego.git
- プッシュする。
git push -u origin main
これでリロードすると、リポジトリがあるのがわかる。
CIを作る。
流れはこんな感じ。
- テストコードを記載
- CircleCIに登録
- プロジェクトを登録
- configを設定
- 環境変数を設定
- Githubにプッシュ
- テストを修正
テストコード記載
実は、既に/src/test/controllers/users_controller_test.rb
に、テストコードがある。
それを改造していく。
まずは、コメントアウトを外し、assert false
とする。
require "test_helper"
class UsersControllerTest < ActionDispatch::IntegrationTest
# test "the truth" do
# assert true
# end
end
そして、まずDocker-compose up をする。
docker-compose up -d
そして、テストを実行する。bundle exec rake test
がテストを実行するコマンド。
docker-compose exec web bundle exec rake test
エラーで落とされたらOK
Circle CIに登録する。
以下リンクにアクセス
https://circleci.com/ja/
初めてなら、登録から登録を行う。
そして、登録する時は、**GitHubでログインを選ぶ。**そうすると、GitHubと連携してくれる。
プロジェクトを登録する。
対象のリポジトリを選ぶ。そして、これのセットアッププロジェクトを押す。
なんか説明と表記が違うけど、まあ、とりあえずこのまま進む。
コンフィグの設定
.circleci の中で、config.ymlを参照することで、CIができるようになる。
- RAILS直下に
.circleci
のフォルダを作る。 - その下に、
config.yml
を作成する。
orbsは、ジョブを定義しておいて、共有できるもの。
ここでは、build
とtest
を行うようにしている。一番下のworkflow
に定義された順番に処理をおこなっていく。今回は、ビルドして、実行(テストしている。)
- working_directoryは、GitHubのリポジトリの名前にする。
- チェックアウトのパスも、リポジトリ名にする。
- orbsを使うと、install-devsが用いれる。
テストの中身は、
- rubyとmysqlのイメージを取得している。
- DATABASEのユーザー名などは、APPTestといった形にしている。
- APPDATABASEHOSTは、127.0.0.1(自分自身)を設定する。
- この書式で、db:migrateコマンドを実行するという
- run:
name: Database setup
command: bundle exec rails db:migrate
- stepの所でも、同じようにコマンドを実行している。
version: 2.1
orbs:
ruby: circleci/ruby@1.1.2
heroku: circleci/heroku@1.2.3
jobs:
build:
docker:
- image: circleci/ruby:2.7
working_directory: ~/rails-docker-dito/src
steps:
- checkout:
path: ~/rails-docker-dito
- ruby/install-deps
test:
docker:
- image: circleci/ruby:2.7
- image: circleci/mysql:5.5
environment:
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: app_test
MYSQL_USER: root
environment:
BUNDLE_JOBS: "3"
BUNDLE_RETRY: "3"
APP_DATABASE_HOST: "127.0.0.1"
RAILS_ENV: test
working_directory: ~/rails-docker-dito/src
steps:
- checkout:
path: ~/rails-docker-dito
- ruby/install-deps
- run:
name: Database setup
command: bundle exec rails db:migrate
- run:
name: test
command: bundle exec rake test
deploy:
docker:
- image: circleci/ruby:2.7
steps:
- checkout
- setup_remote_docker:
version: 19.03.13
- heroku/install
- run:
name: heroku login
command: heroku container:login
- run:
name: push docker image
command: heroku container:push web -a $HEROKU_APP_NAME
- run:
name: release docker image
command: heroku container:release web -a $HEROKU_APP_NAME
- run:
name: database setup
command: heroku run bundle exec rake db:migrate RAILS_ENV=production -a $HEROKU_APP_NAME
workflows:
version: 2
build_test_and_deploy:
jobs:
- build
- test:
requires:
- build
- deploy:
requires:
- test
filters:
branches:
only: main
また、これとは別に追記する。
test:
<<: *default
database: app_test
host: <%= ENV.fetch("APP_DATABASE_HOST") { 'db' } %>
ここのhostの部分は、環境変数が入っている時は、これを使うが、CircleCIで環境変数を用いている場合、APP_DATABASE_HOST
がない時のみ、dbを使うという処理である。
また、/src/config/master.keyというものは、ネットでばれるとよくないものであるので、ignoreに入っていた。しかし、これをHeroku
にいれたいので、環境変数にする。
heroku config:add RAILS_MASTER_KEY="xxx" -a rails-docker-diego
そして、この変更をGitに上げる。ciの変更分を、masterに変更する。
git switch -c ci
git branch
git add .
git commit -m "circle-ciが動くようにconfigを設定した"
git push origin ci
そして、Create pull request
を押す。
じつは、pushが始まった瞬間に、CircleCIが動作を行う。
成功すると緑、失敗すると赤になる。
基本的に、テストに落ちるとマージリクエストのボタンが押せなくなる。
users_controller_test.rb
のassertをtrue
にして、達ようにする。
require "test_helper"
class UsersControllerTest < ActionDispatch::IntegrationTest
test "the truth" do
assert true
end
end
テストが通るか確認。ちなみに、以下だと失敗という意味である。
itoudaiware@itoudaiwarenoMacBook-Pro rails_docker % docker-compose exec web bundle exec ra
ke test
service "web" is not running container #1
ちなみに、今回失敗した例を確認するために、こんなデバッグをした。
- コマンドを実行したら、webが動いていないと言われる。
itoudaiware@itoudaiwarenoMacBook-Pro rails_docker % docker-compose exec web bundle exec rake db:migrate
service "web" is not running container #1
- 動いていないコンテナをみる。
docker ps -a
今回はwebが動いておらず、DBが動いているのがわかる。
itoudaiware@itoudaiwarenoMacBook-Pro rails_docker % docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f0265e7affcc rails_docker_web "bundle exec rails s…" 48 minutes ago Exited (1) 5 minutes ago rails_docker-web-1
5b844e315934 mysql:8.0 "docker-entrypoint.s…" 52 minutes ago Up 5 minutes 3306/tcp, 33060/tcp rails_docker-db-1
129d3336c6fe 254a938785d2 "/bin/sh -c 'curl -s…" 3 days ago Exited (100) 3 days ago distracted_blackburn
- 動いてないコンテナのログをみる。
docker logs rails_docker-web-1
すると、上の方に、databese.ymlの三十行目に何かあるらしいと書いてある。
=> Booting Puma
=> Rails 6.1.4.1 application starting in production
=> Run `bin/rails server --help` for more startup options
/app/config/database.yml:30:in `block in <main>': Cannot load database configuration: (NameError)
undefined local variable or method `db' for main:Object
Exiting
docker-compose exec web bundle exec rake test
のコマンドを実行して問題なさそうで
通ったなら、gitに変更していく。
git add .
git commit -m "テスト通過した"
git push origin ci
うまくいったコードをローカルにもってくる。
git switch main
git pull origin main
これで、CIの仕組みが完成。
肝は、設定(circle.config)を入れることで、プッシュされる度にテストされる。
ということが実行されるということ。
CDについて
流れはこんな感じ
- configを修正
- 環境変数を設定
- viewファイルの修正
- githubにプッシュ
- マージ&自動デプロイ
とりあえず、開発用ブランチを作成
git switch -c cd
また、ブランチを削除するには、-dオプションを使う。
git branch -d ci
configの修正
circle.ci/config.yml
を修正する。
orbsに以下を追加する。
heroku: circleci/heroku@1.2.3
さらに、workflowに、jobsを追加する。
メインのbranchに、マージされた時だけ、deployのjobが追加されるという形式である。
jobs:
- build
- test:
requires:
- build
- deploy:
requires:
- test
filters:
branches:
only: main
setup_dockerをいれると、dockerを使う。
- setup_remote_docker:
version: 19.03.13
また、runの所にあつのは、実際に打って行った
コマンドである。
- run:
name: heroku login
command: heroku container:login
- run:
name: push docker image
command: heroku container:push web -a $HEROKU_APP_NAME
- run:
環境変数の設定
こんな感じに、環境変数を入れ込む処理を行なっているので、circlre.ciに、環境変数を入れる処理が必要。
- run:
name: push docker image
command: heroku container:push web -a $HEROKU_APP_NAME
-
circleciにアクセス
-
projectから、自分のアプリ(rails-docker-diego)を選択
もう一個、HEROKU_API_KEYというのを設定する。
これは、HEROKUにログインしてから、AccountSettingsの中の、下の方にあるAPIKeyをみる。これをコピーして、貼り付ける。
viewファイルの修正を行う。
src/app/views/users/index.html
のファイルをみる。
修正されたのが分かるように、一部を変える。
<h1> sample ß </h1>
を、いかに修正
<h1> sample ß !!</h1>
docker-compose upで、ローカルで試してみるのも良いだろう。
Githubにプッシュする。
git add .
git commit -m "cd用設定を追加"
git push origin cd
pushしたら、GitHubを確認。
先ほどと同じように、cdのプルリクエストが行えるようになっているので、押す。
baseがmainで、compareがcdになっているのを確認し、プルリクエストを押す。
ちなみに、:の後にスペースがない場合、そこでうまくいかなくなったりする。
そして、マージプルリクエストを押す。
そして、Confirm Merge
を押す。
ついでに、古いブランチも消しとくDELETE branch
デプロイされているか確認
circlrciのWebの画面をみてみると、現在デプロイ中である。
これがうまくいけば、緑のチェックがつくハズである。
今回、このようにエラーがでたので、deploy部分のymlを修正する。
deploy:
docker:
- image: circleci/ruby:2.7.4
ソースコードを変えずに、環境変数のみ追加等をする場合、循環するマークを押せば、もう一度ビルドとテスト、デプロイもシテくれる。
デプロイが問題なく実行されたら、
heroku open -a rails-docker-diego
とする。