このハンズオンは
超初心者向けのRuby on Rails on Dockerハンズオンです!
プログラミングなんてやったことない、別の言語でhello worldしたことならある、Dockerって名前は聞くけど...という感じの方に向けてお送りしたいと思います。
僕は誰か?
軽く自己紹介です。と思いましたが、自己紹介はリンク先で。
注目してほしいところは、僕は社会人になって以来、常にサービス開発・システム開発に携わってきました。
しかしながら、僕は仕事でプログラミングをしたことがありません。このハンズオンにきてくれた人たちも同じような境遇の人が多いんじゃないかと思います。
僕がプログラミングを始めたきっかけは、そうやってサービス開発・システム開発をしていく中で、「自分でちゃんと動くものを作れるようになったら自分がコードを書く書かないによらずもっといいプロダクトを創れるんじゃないか」と思ったからです。あ、普通に面白そうとかもありましたけどね。
僕がプログラミングを始めたのが2017年の夏くらいです。まず「Progate」を有料会員になって全部やって、そこからは自分の考えたプロダクトを作ってました。やっぱり作ってみるのが一番学びが早いです。
それから今まで趣味程度でプロダクトを作ったりしてきましたが、その成果は確実に業務にも活かされていると思います。Webサービスのプロダクトマネージャーをやるときはフロント・バック・インフラ問わず方針検討・デベロッパーとのディスカッションができていると思いますし、Dockerをプライベートで触っていたからこそ、CloudNativeのようなちょっとチャレンジングなプロジェクトにも参画させてもらっています。
そして、やっぱりプログラミングは楽しいです。笑
まぁ楽しいのがなによりだと思いますので、みなさんもぜひこのハンズオンを楽しんでください!
なんでハンズオンをやろうと思ったのか?
- プログラミングは私には難しそう...と躊躇っている人を後押ししたかった
- 技術楽しいじゃん!と盛り上がれる仲間を増やしたかった
- そのくらい自分たちで作っちゃうか!って文化を作りたかった
このハンズオンを通してどんなことが学べるのか(目標)
学べること
- Ruby on Rails
- Docker
- Docker Compose
- HTML
- CSS / SASS (SCSS)
- Bootstrap
- Javascript / jQuery
- AWS
- Heroku
学べないこと(今のところスコープ外)
- 学べることのふか〜いところ(僕も知らない)
- Ruby以外の言語(Java / C / Perl / Go / Python / ...)
- Rails以外のフレームワーク(Sinatra / Larabel / Django / ...)
- Git (これはやるかもしれない)
- CI/CD (これもやるかもしれない)
- API / SaaS / mBaaS / ...
- GCP / Azure / ...
- Kubernetes ...
ハンズオンを受ける上でのお願い
Input for Output.
このハンズオンでインプットをするからには何かにアウトプットしてください。何かを作るでもいい。誰かに話すでもいい。他者に見えること・ものにすることを意識すると学習が一気に捗るはずです!
前置きながくてすみません!こっから本題です!
最初に言っておきますが、今日はコード書きません。
プログラミングの3原則
実際にプログラミングを始める前に、プログラミングの3原則である『KISS』『YAGNI』『DRY』を心の中に刻み込んでください。
KISS - Keep In Simple, Stupid.
意訳すると『シンプルにしとけよ、バーカ』です。
これはサービスを企画したりする段階から言えることだと思っているのですが、シンプルであるほど『使う人』にとっても『創る人』にとってもいいプロダクトのはずです。しかし実際には、様々なパターンを複雑に絡み合わせてシステムにしてしまっているケースも多く、そのせいでメンテナンス性が悪く、すぐには発展させられないような状況になってしまっているプロダクトは多いのではないでしょうか。
シンプルに保つことはとても難しいことです。妥協せずにシンプルに保ちましょう。
YAGNI - You Aren't Gonna Need It
意訳すると『それいらねーべ』です。
上のKISSを実現するための考え方な気がしますが、サービスやコード、システムが複雑になってしまう原因第一位はおそらくこのマインドがないからでしょう。
パレートの法則に従えば、全体の80%のユーザーが利用する機能は全体の20%です。今はこれが90:10、99:1になってきていると言われている時代。『多分いる』『きっといる』を排除する勇気を持ちましょう。
DRY - Don't Repeat Yourself
意訳すると『何度も同じことをするんじゃない!』です。
似たようなコードを何回も書いたり、同じようなファイルをあっちゃこっちゃに作ったり。こう言う状況もKISSを阻害しますし、コードのメンテナンス性を大きく下げさらにはバグを引き起こします(あっちは直してたけどこっち直すの忘れた)。
ここまで3つの話をしてきましたが、総じて『シンプルさ』を求めていることがわかります。
直感的に考えてみると当然のことですが、シンプルであればあるほどバグは少なく、シンプルであればあるほど拡張性が高くなりそうですよね。
ここから先は、このハンズオンの中心となってくる『Ruby』『Rails』『Docker』『Docker Compose』を紹介していきます。
Rubyって何?
Rubyはまつもとゆきひろさんによって開発されたオブジェクト思考スクリプト言語です。1995年に公開されて以降今でも活発に開発が続けられてるプログラミング言語です。
Javaとかもちょっと触ったことがあるのですが、初めてRubyを触ったときは、シンプルに直感的にかけるなーという印象を持ちました。
gem
と呼ばれるライブラリを追加することで、そりゃあもういろいろなことができます。
Railsって何?
Railsは2004年に公開されたRuby用のWebアプリケーションフレームワークです。Rails自体もgem
の1つとして配布されています。WebアプリケーションフレームワークはWebアプリケーションの開発するためのあれやこれやを最初から準備してくれていて開発をサポートしてくれるものです。
元々Twitter社が利用していたこともあり世界的に有名なのかなと思います。現在でもAirbnb, GitHub, Hulu, Shopifyなどで利用されています。日本だとCookpadや食べログなどで利用がなされているはずです。
RailsではDRYとConvention over Configuration (CoC)を基本理念としています。CoCは開発者が色々と設定を弄るのではなくWebアプリケーションフレームワークが決めた規約の中で開発を進めていくことで、開発者の決定しなくてはいけないことを極力減らしWebアプリケーションをシンプルに素早く実装することができるようにします。
Dockerって何?
Dockerはコンテナ技術のデファクトスタンダードになっている技術です。コンテナ技術は仮想化技術の一種でVMと並ぶ技術と思ってください。VMに比べて軽量で共有しやすく、起動・停止も高速です。
詳しくは以下の記事がとても参考になります。
DockerはDockerfileにミドルウェア以上の情報をInfrastructure as Code (IaC)できるのもいいところだと思っています。Dockerfileを共有したり、DockerHubなどのRegistryサービスを経由してDocker imageを共有することでmacのローカルマシーンと遠隔のLinuxマシーンのような異なるプラットフォーム上でも全く同じ環境でアプリケーションを動かすことができます。
詳しくは上の記事を参考にしてほしいのですが、まず大まかにDocker imageとDocker containerの関係性を理解しましょう。
わかりやすい方で、Docker containerを起動させることで仮想的にアプリケーションを動作させることができます。Docker imageはこのDocker containerの型になるものです。
例えば、とあるRailsアプリケーションのDocker imageがあるとします。このDocker imageからDocker container AとDocker container Bを別々のポート番号で起動させることができます。このDocker container A/Bは起動させたり停止させたり、はたまた中のファイルが更新されたりしますが、これらは型となるDocker imageには何の影響も与えません。そのため毎回同じ初期状態でDocker containerを起動させることができるのです。
Docker image自体を更新したい場合はbuildという行為を行います。これは起動中のDocker containerをベースにDocker imageを作成することもできますが、たいていの場合Dockerfileをbuildして行います。この辺りの詳しい話は、この後のハンズオンで実際に手を動かして理解していってもらえればと思います。
Dockerを試してみる。
Dockerは様々なインストール方法があります。ここは各自のOSなどに合わせてインストールしてみてください。macを利用している場合はDocker Desktop for Macを使うのが一番楽かと思います。Install Docker Desktop on Mac | Docker Documentation
では、試しにWebサーバーの一つであるnginxをDocker上で起動してみます。
あ、ちなみに今後↓のように$
が書いてあったらターミナルでコマンドを入力するんだと思ってください。コマンドには$
は不要です。
$ docker image pull nginx
$ docker run -d -p 8080:80 nginx
たったこれだけでローカル上にnginxが立ち、http://localhost:8080
でアクセスできるようになっています。
少しコマンドを説明します。
docker pull
docker pull
はDocker imageをレジストリ(Docker imageを保存するためのサービス)からローカルに取得するコマンドです。引数には<image name>:<tag>
を指定します。今回はDockerHubからnginxを取得しています。<tag>
は省略可能で、省略されている場合はlatest
(最新バージョン)が選択されます。最新バージョンはどんどん更新されていくので、実際に開発を進めていく時にはタグを厳密に指定してあげないとバージョン差異の不具合を受けてしまう可能性があるので注意しましょう。
docker run
docker run
コマンドはDocker imageを元にDocker containerを起動させるコマンドです。オプションを除けばdocker run nginx
となりますが、先ほどローカルに取得したnginx
イメージを設計書としてコンテナを起動させています。オプションの説明は以下の通り。
-
-d
: コンテナをバックグラウンドで実行する。これをつけないとターミナル上にコンテナのログが表示され続けて操作できなくなる(その場合はCtrl+Cでコンテナを停止させる) -
-p <host port>:<container port>
:container port
をhost port
で公開する。Dockerコンテナはホスト(ローカル)上のDocker networkと呼ばれる閉塞ネットワークで起動しており、外部(http://localhost
など)からアクセスできない。このオプションをつけることで<container port>
と<host port>
を関連づけて<host port>
からコンテナにアクセスできるようにしている。
なかなか理解が追いつかないのはわかります。いっぱい触って感覚掴みましょう。
DockerHubにはいろいろなDocker imageが公開されており、詳細ページには使い方も細かく書かれています。色々気になったものを触ってみましょう。
もう少しコンテナの様子をみていきます。
docker ps
docker ps
コマンドはDocker containerの情報を確認するためのコマンドです。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8230d7a776e1 nginx "nginx -g 'daemon of…" 25 minutes ago Up 25 minutes 0.0.0.0:8080->80/tcp vigilant_johnson
-
CONTAINER ID
: コンテナのID。コンテナ初回起動時に振られる。 -
IMAGE
: コンテナの元になっているイメージ。 -
COMMAND
: コンテナ内で起動時に実行されているコマンド。アプリケーションの起動コマンドなどが元々Docker imageで定義されているのでそれが表示されている。 -
CREATED
: コンテナが作成された日時。 -
STATUS
: コンテナのステータス。起動しているときはいつから起動しているのかが表示される。 -
PORT
: コンテナのポートが表示されます。 -
NAMES
: コンテナのニックネームです。オプションで自分でつけることもできますが、デフォルトではランダムな名前が自動的につきます。
docker ps
コマンドを使って、コンテナが起動中であることが確認できました。
次にコンテナを停止してみます。
docker stop
docker stop
コマンドはコンテナを停止させるコマンドです。引数としてCONTAINER ID
かNAMES
を与えます。
$ docker stop vigilant_johnson
今回はvigilant_johnson
の名前がついていたのでそれを停止させました。
ではまずhttp://localhost:8080
に再度アクセスしてみましょう。リロードでも構いません。先ほどのnginxのwelcomeページが表示されなくなっているはずです。このことからコンテナが停止したことがわかると思います。
さらに先ほど使ったdocker ps
コマンドでコンテナが停止したことを確認してみましょう。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
おや、何も表示がされませんね。実はdocker ps
コマンドは起動中のコンテナのみが表示されるようになっています。停止中のコンテナの情報も確認したい場合は-a
オプションをつける必要があります。
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8230d7a776e1 nginx "nginx -g 'daemon of…" 58 minutes ago Exited (0) 2 minutes ago vigilant_johnson
先ほどのコンテナが表示されましたね。STATUS
がExited
になっていることがわかります。このことからコンテナが停止したことが読み取れます。またPORT
も公開されなくなっているので何も表示されていません。
docker start
このように停止状態になっているコンテナはすぐに再起動させることができます。
$ docker start vigilant_johnson
また、http://localhost:8080
にアクセスするとnginxのwelcomeページが表示されていると思います。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8230d7a776e1 nginx "nginx -g 'daemon of…" About an hour ago Up About a minute 0.0.0.0:8080->80/tcp vigilant_johnson
docker ps
コマンドでも起動を確認できました。
docker rm
さて、ここまででコンテナをdocker stop
で停止しても、停止しただけでホストにはコンテナが残り続けているのがわかったと思います。再度起動する可能性がある場合はすぐに再起動ができるので便利なのですが、本当にもういらないやつは残り続けているとホストのボリュームを圧迫する原因にもなってしまうので完全削除したくなります。この場合docker rm
コマンドを使うことでコンテナを完全に削除することができるので試してみましょう。
$ docker stop vigilant_johnson
$ docker rm vigilant_johnson
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
これでコンテナは完全に削除されました。
docker images
コンテナのLifecycleは以上の形になります。ではイメージはどうでしょうか?
先ほどdocker pull
コマンドでnginxのDocker imageをローカル(ホスト)にダウンロードしていました。コンテナを削除しても設計書となるイメージは残り続けているのでまずはそれを確認してみましょう。
ダウンロード済のイメージを確認するためのコマンドがdocker images
です。
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 5ad3bd0e67a9 10 days ago 127MB
いますね。再度このイメージを使ってコンテナを起動させる場合は残しておくとダウンロードが不要になるので便利なのですが、今回はもう使わないので削除します。
docker rmi
docker rmi
コマンドはホストに保存されているイメージを削除するコマンドです。docker images
で調べたREPOSITORY:TAG
の形式かIMAGE ID
を引数に与えてイメージを削除します。
$ docker rmi nginx:latest
もう一度docker images
などで確認していただくとイメージも削除されたことがわかります。
このような感じで、Dockerを使うことで本来であれば色々とミドルウェアやファイルを用意しないと動かないアプリケーションをDocker imageを元にDocker containerを起動させるだけで扱えるようになります。便利ですね。
Docker Composeって何?
さて、Dockerはとても便利なのですが、イメージ名とかオプションとか毎回覚えてられないですよね。
また、今後Webアプリケーションを開発するとなると、WebアプリのコンテナとDBのコンテナなど複数のコンテナを相互に関連付けながら起動・停止させないといけなくなるわけで、その手順を覚えておくのも面倒です。
こんなことを解決してくれるのがDocker Composeです。Docker Composeを使えば、複数のコンテナのコンテナ起動時のオプションなどをyamlファイルで定義することができます。百聞は一見に如かずですので、試しに先ほどのnginxコンテナをDocker Composeを使って起動させてみましょう。
Docker ComposeはDocker Desktop for Macなどをインストールしている場合は一緒に使えるようになっています。そのほかの方法でDockerをインストールしている場合は、別途Docker Composeもインストールしないといけないので頑張ってください。笑
version: '3'
services:
nginx:
image: nginx:latest
ports:
- 8080:80
少し説明します。
-
version
: Docker Composeのファイルフォーマットのバージョンです。現在の最新のメジャーバージョンの3
を指定しています。 -
services
: この下に管理したいコンテナの定義を書いていきます。 -
nginx
: これが一つコンテナの定義の塊です。名前は何でも自由につけられます。 -
image
: 起動するコンテナの元となるimageを指定します。docker run
でコンテナを起動させたときと同じようにregistry:tag
を指定します。 -
ports
: ホストとコンテナのポートの関連付けをしてます。docker run
でいう-p
オプションの役割。
これをつかってコンテナを起動させます。
$ docker-compose up -d
これでdocker-compose.yml
の定義に沿ってコンテナが起動します。-d
オプションはdocker run
の時と一緒でバックグラウンドでコンテナを起動させるオプションです。同じようにhttp://localhost:8080
でnginxのwelcomeページが表示されるようになっていると思います。
docker-compose
はデフォルトでコマンドが実行されたディレクトリのdocker-compose.yml
をターゲットに実行します。ファイルを指定する場合は-f [file path]
をつけます。イメージは↓。
$ docker-compose -f ./docker-compose.test.yml up -d
docker-compose ps
でdocker-compose.yml
で起動させたコンテナの情報だけをみるためにはdocker ps
ではなくdocker-compose ps
を使うと便利です。
$ docker-compose ps
Name Command State Ports
-------------------------------------------------------------------
xxxxx_nginx_1 nginx -g daemon off; Up 0.0.0.0:8080->80/tcp
コンテナを停止するときは以下のコマンドです。
$ docker-compose down
これで何回でも同じ条件で楽にコンテナを作ることができますね。
まとめ
前置きがかなり長くなってしまいましたが、今日は実際に開発を始めていくにあたって、
- プログラミングの3原則を学んだ
- これからキーとなる『Ruby』『Rails』『Docker』『Docker Compose』を学んだ
ができたと思います。次回はRuby on Rails on DockerでHello world(とりあえず立ち上げてみた)をやっていきたいと思います。乞うご期待!
Next: コーディング未経験のPO/PdMのためのRails on Dockerハンズオン vol.2 -Hello, Rails on Docker- - Qiita
Reference
- Ruby on Rails チュートリアル:実例を使って Rails を学ぼう
- Ruby - Wikipedia
- Ruby on Rails - Wikipedia
- docker | Docker Documentation
- Overview of Docker Compose | Docker Documentation