ハンズオン！dockerとAWS（EC2+ALB+RDS）を触ってみて学んだこと

この記事は[エイチーム引越し侍 / エイチームコネクト Advent Calendar 2019](https://qiita.com/advent-calendar/2019/hikkoshi) 14日目の記事です。本日はエイチーム引越し侍に入社してWEBエンジニア歴４ヶ月目に突入した@halktが担当します！
## なぜこれをやろうと思ったのか？
一言で言うと、<font color=red>**自分の力でWEBサービスをデプロイする経験をしてみたかったから**</font>です。

WEBエンジニアになる前は、社内サービスの維持運用を主として行なっていたため、物理的なサーバを建てたり、仮想マシンを作成したりということはしておりましたが、インフラなどはすでに構成された社内ネットワークの中でしか触ったことはありませんでした。

そのため、Webサービスを外部に公開する上での考慮事項や外からサービスに接続するための知識は特に足りていないと感じていたので、このテーマにまずは挑戦しようと思いました！！

兎にも角にもまずは触ってみなきゃ始まらん！と思い、下記の構成を目指し、タイトル通りハンズオン形式で学んだ内容をまとめてみたいと思います！

## ゴールのイメージ
<img width="758" alt="01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278426/287572fb-0c9f-ae69-b635-ddc82e787833.png">

Railsなのは特にこだわりがあるわけでなく、たまたまあるアプリを使っただけです。最近だとECSやFargateを使った構成が多いと知りましたので別途挑戦したいと思います・・・！

## 🐳docker/docker-compose編
最初にローカルで作成していた既存のRailsアプリをdockerにのせました。dockerの勉強したいから、という理由がきっかけですが、コンテナをデプロイできるようになれば、他のアプリでデプロイをしたいときに応用が効くことを期待してdocker化から初めました。

### 実施内容
細かな作業内容などは割愛しますが、ざっくり下記のようなことをやりました。

+ Dockerfile（Railsやnginx）の作成
+ pumaとnginxのソケット通信の設定
+ nginxの設定ファイルの修正
+ **docker-compose.ymlの作成**
+ **buildしてアプリケーションを実行しアクセスする**
+ githubにpushしておく

### docker-compose.ymlの作成
docker-composeは、複数コンテナ群の構成や動きを管理することができます。所謂**インフラ構成のコード化**が実現できます。

```dockerfile=
version: '3'
services:
  app:
    build:
      context: .
    environment:
      MYSQL_ROOT_PASSWORD: XXX
      MYSQL_DATABASE: XXX
    command: bundle exec puma -C config/puma.rb
    volumes:
      - .:/app
      - public-data:/app/public
      - tmp-data:/app/tmp
      - log-data:/app/log
    depends_on:
      - db
  db:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: XXX
      MYSQL_DATABASE: XXX
    ports:
      - "3306:3306"
  web:
    build:
      context: containers/nginx
    volumes:
      - public-data:/app/public
      - tmp-data:/app/tmp
    ports:
      - 80:80
    depends_on:
      - app
volumes:
  public-data:
  tmp-data:
  log-data:
  db-data:
```
### docker-composeコマンドを使ってbuildしてアクセス！
ここまで準備が整えば、あとはbuildするだけで環境の作成ができます。便利なのは、このファイル群を使えば同じインフラが一発で再現ができるようになった点ですね〜本当にいい時代だ。。。（しみじみ）

```
# コンテナを起動する
$ docker-compose build # コンテナをビルド
$ docker-compose up -d # コンテナの一斉起動

# railsの設定
$ docker-compose run --rm app rails db:create
$ docker-compose run --rm app rails db:migrate
```
ここまでするとnginx経由でアクセスができるようなりました！

### ここで学んだこと
頭では理解していたつもりでしたが、もともと普通に構築したアプリをdocker化することでその良さをより知ることができたと思います！

それまでミドルウェアのインストールから設定からまでやっていた環境構築が数回のコマンドで再現できるのは感動的😂😂😂

今後はガシガシコンテナを使って色々と構築していき、理解を深めていきたいと思います！！


## 🌥AWS編
コンテナ化までできたので、デプロイそのもののハードルはほぼなくなりました。ここからは、本丸に挑戦・・・！

### 実施した内容
+ VPCの作成
+ **RDSインスタンスの構築と接続設定**
+ **EC2インスタンスの作成**
+ ALBの作成
+ ドメインの取得
+ ACMによる証明書の作成
+ **HTTPS化**

### RDSインスタンスの構築と接続設定
RDSは、DBエンジンを提供するサービスでDBサーバーとして利用することができます。こちらの生成は正直そこまで難しいことはありませんが、RailsアプリからこちらのDBに接続する設定を直接書き出してしまうのは危険なため、credentialを使って隠蔽する設定を行いました。

```
# credentialsの設定
$ docker-compose run -e EDITOR="vim" app rails credentials:edit
```
```
# credentialsの中身
# ここに書いた内容は外から見ることはできません
rds:
  host: RDSのエンドポイント
  database: RDSの「データベースの名前」
  username: RDSの「マスターユーザの名前」
  password: RDSの「マスターパスワード」
```
+ config/database.yml

```yaml
production:
  <<: *default
  host: <%= Rails.application.credentials.rds[:host] %>
  database: <%= Rails.application.credentials.rds[:database] %>
  username: <%= Rails.application.credentials.rds[:username] %>
  password: <%= Rails.application.credentials.rds[:password] %>
```
こうすることで、本番環境の接続DBをRDSに設定することができました。

### EC2インスタンスの作成
EC2インスタンスはssh接続できるように設定し、コンテナを動かすためにdockerやdocker-composeのインストールを行いました。

その後、🐳**docker編**で作成したアプリのgithubからリポジトリごとcloneしてきます。また、githubには存在しない`master.key`を個別にconfigファイルにコピーしていきます。これをしないと、先ほどcredentialsに設定した内容を参照できないのでご注意を。

```
$ scp -i ~/.ssh/myapp.pem ~/myapp/config/master.key 
```

ここまできたらdockerを起動してアプリを起動・・・！

```
$ docker-compose build
$ docker-compose run app rails db:create
$ docker-compose run app rails db:migrate
$ docker-compose run app rails assets:precompile

# nginxとpumaのソケット通信
$ mkdir tmp/sockets
$ touch tmp/sockets/puma.sock

# コンテナ起動
$ docker-compose up
```
IPアドレス経由ですが、Webアプリケーションにアクセスができるようになりました！！！

### HTTPS化
最後に、EC2＋RDSで構成されたアプリにALB経由で接続するようにします。また、ACMで証明書を作成してALBに設定することで、**外部→ALBの通信をHTTPS化（暗号化）**します。※ALBとnginx間は同一ネットワーク内なのでHTTP通信になります。

これにより、特定のドメインでHTTPS化した状態でWebアプリにアクセスできるようになりましたーーー！！！

### ここで学んだこと
今回、ほぼ無料枠のみで**WebアプリケーションをSSL化してインターネット上に公開すること**ができました!!

インスタンスの生成やロードバランサーがこんなにサクッとできるのはやはりすごいですね。今回は１台構成ですが、冗長構成なども容易にできそうな実感を得られました。

また、デプロイは単純にEC2上にリポジトリをコピーしただけだったので、今後はCIできるようにしたり、Githubと連携させたり、なかなかコストはかかりそうですが色々やりたいことも見えてきたので、他のサービスの利点を知るためにも継続的に触っていきたいと思います。

## まとめ
目的だった**自分の力でWEBサービスをデプロイする経験する**ことができ、知らなかったサービスやインフラの基礎的な部分を効率よく学ぶことができたのはGOODでした！

ハンズオン形式で触りながら学ぶことで、技術の恩恵をより実感することができました。一度触ることで、学びたいサービスや領域が広がったのもいい収穫だったと思います。まだまだいろんなサービスがあるので、どんどん触れてみてITで解決できることの幅を増やしていきたいと思います！

まだまだ勉強不足で毎日学ぶことの連続ですが、着実に力をつけていきたいと思います！！

## 参考にさせていただいた記事
これを実施するために下記の記事を参考にさせていただきました。
[docker-compose（公式）](https://docs.docker.com/compose/install/)
[知識0から、AWSのEC2でウェブサーバーを構築するまで](https://qiita.com/shunsuke227ono/items/23dbf4f3bc663a2875f0)
[丁寧すぎるDocker-composeによるrails5 + MySQL on Dockerの環境構築(Docker for Mac)](https://qiita.com/azul915/items/5b7063cbc80192343fc0)
[Docker導入のための、コンテナの利点を解説した説得資料](https://qiita.com/niisan-tokyo/items/88a53a1b4aa7ad60723e)
[Nginx + Rails (Puma) on Docker のいくつかの実用パターン](https://qiita.com/na-o-ys/items/1a863419e1f6c3063ace)
[無料！かつ最短？で Ruby on Rails on Docker on AWS のアプリを公開するぞ。](https://qiita.com/at-946/items/1e8acea19cc0b9f31b98)
## お知らせ
エイチームグループでは一緒に活躍してくれる優秀な人材を募集中です。
興味のある方はぜひとも[エイチームグループ採用ページ](https://www.a-tm.co.jp/recruit/)よりご応募ください。
[WEBエンジニア詳細ページ](https://www.a-tm.co.jp/recruit/requirements/career/lifestylesupport-webengineer/)よりお問い合わせ下さい。

## 明日
明日は@2boさんの記事です！
どんな内容か楽しみです、それではお楽しみに〜〜