Dockerコンテナで開発するイメージ

# はじめに
普段Dockerを使用して環境構築をしているのですが、学習を始めた当初、これで本当に開発ができるのか？？と半信半疑でした。当時なぜそう思ったのか、そしてその疑問をどう払拭したのかを記事にまとめたいと思います。同じ境遇に陥っている人の助けに少しでもなりましたら嬉しいです。
# Dockerとは
Dockerとはコンテナ型の仮想環境を作成、配布、実行するためのプラットフォームです。Linuxのコンテナ技術を使ったものであり、軽量で高速に起動、停止などが可能です。
クライアント（ターミナル操作）・Dockerホスト・レジストリ（DockerHub）の関係性は以下公式ドキュメントの画像がシンプルでわかりやすかったので引用させていただきました。適宜、ご参照いただければと思います。

[![Image from Gyazo](https://i.gyazo.com/3795bacd9b4ffe882d6536a84681536d.png)](https://gyazo.com/3795bacd9b4ffe882d6536a84681536d)
引用元：https://docs.docker.jp/get-started/overview.html

# DockerfileからDockerコンテナ起動まで
Dockerでの開発にはコンテナを作り、起動させる必要があります。今回はDockerfileを活用したコンテナの起動方法について以下のとおり簡単な図で説明させていただきます。

[![Image from Gyazo](https://i.gyazo.com/2d2df098fc1be0f942f3f0e3ae6a28e1.png)](https://gyazo.com/2d2df098fc1be0f942f3f0e3ae6a28e1)
上図のDockerfileとはコンテナの設計書です。このDockerfileをもとにbuild(`docker build`コマンド)すればImageができます。その後、Imageを指定してrun（`docker run`コマンド）すればコンテナが起動するという順です。

# 簡単なコンテナ作ってみた
実際に上で説明したようにDockerfileからImageを作成し、コンテナを起動するまでをやってみたいと思います。
今回使用するDockerfileは以下の内容のものを使用し、出力結果を確認しながら少しずつ肉付けしていこうかと思います。Dockerfileの記述によって自分の作りたいコンテナが作れるというイメージを簡単に掴めたらと思います。
```Dockerfile:Dockerfile
FROM ubuntu:latest
```
内容としてはubuntuをベースとしたイメージを作成したいと思います。
以下のとおりディレクトリにDockerfileのみ配置します。簡単な構造ですが、ディレクトリ構造書きました。
```plaintext:ディレクトリ構造
docker-practice
└ Dockerfile
```
`docker-practice`ディレクトリ内で以下のコマンドを実行します。
1. `docker build .`
このコマンドによりDockerfileをもとにImageが作成されます。
一連のビルドがエラーなく完了すれば、ローカルにはubuntuのイメージが作成されているはずです。作成されたか確認するためには`docker images`で確認できます。
以下、私の環境下で確認した結果です。（個人的なImageは削除させていただいています。）
※tagなど指定していないため、noneとなっている部分が多くなっていますが、そこはご容赦ください。
    ```terminal:terminal
    docker-practice % docker images
    REPOSITORY              TAG               IMAGE ID       CREATED         SIZE
    中略　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　中略　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　中略　　　　　　　　　　　　　　　　　　　　　　　　中略　　　　　　　　　　　　　　　　　　　　　　　　　中略
    <none>                  <none>            7825af3e6bb4   3 weeks ago     69.2MB
    ```
2. `docker run -it <<イメージID>>　bash`
`docker images`コマンドなどで確認したイメージIDをもとに上記コマンドを実行するとコンテナが起動し、同時にコンテナの中に入ることができます。コンテナ内で試しに`ls`コマンドを実行してみるとルートディレクトリでは以下の結果が出力されます。
    ```
    ooseyuuki@ooseyuukinoMacBook-Pro docker-practice % docker run -it 7825af3e6bb4 b
    ash
    root@8bf7b05a3f41:/# ls
    bin   dev  home  media  opt   root  sbin  sys  usr
    boot  etc  lib   mnt    proc  run   srv   tmp  var
    ```

例えば、以下のようにDockerfileを修正してみるとします。
```Dockerfile:Dockerfile
FROM ubuntu:latest
RUN touch test.txt
```
RUNとはDockerコマンドの一つで、ビルド時にRUNの行にあるコマンドを実行するという意味合いを持ちます。（この場合で言うと`touch text.txt`をビルド時に実行します。）
このDockerfileも先ほどの1と2のコマンドを同様に実行して再度コンテナに入ると、コンテナ内に`text.txt`というファイルが新たに生成されていることがわかります。
```terminal:terminal
ooseyuuki@ooseyuukinoMacBook-Pro docker-practice % docker run -it 243c26ce632e b
ash
root@176e5117eca8:/# ls
bin   dev  home  media  opt   root  sbin  sys       tmp  var
boot  etc  lib   mnt    proc  run   srv   test.txt  usr
```
ここで終わるのも中途半端なので`docker run`したと同時にテキストの内容を出力してくれるコンテナを作成したいと思います。
Dockerfileの中身は以下のとおり変更させていただきました。
```Dockerfile:Dockerfile
FROM ubuntu:latest
RUN touch test.txt　&& echo 'Hello Docker!!' >> test.txt
CMD ["cat", "test.txt"]
```
こちらも同様にビルドしてイメージIDをもとにコンテナを起動（run）します。通常起動するだけではターミナルには何も表示されないのですが、今回CMDコマンドでコンテナ起動時に`cat test.txt`を実行しているため、テキスト内の「Hello Docker!!」が出力されるはずです。
```terminal:terminal
ooseyuuki@ooseyuukinoMacBook-Pro docker-practice % docker run 70a6c3d62a67
Hello Docker!!
```
ここまでやってきた通り、コンテナはDockerfileの記載を工夫することによりカスタマイズすることが可能です。

# 学習当時に抱いていた疑問
Dockerfileを使ってコンテナを作り、その中で作業することはわかったんですが、ただどうしても当時はDockerで開発するイメージが沸かなかったです。「Docker環境で開発とはローカルで作業するのか？」「それともコンテナ内に入って作業するのか？」なんて疑問を抱えてはもやもやしていました。
# Dockerを使って少しだけ開発してみる
果たしてそんな疑問を抱えている人がどれくらいいらっしゃるかわかりませんが、今回はRails6のコンテナ環境を構築して、少しいじることでイメージをお伝えできたらと思っております。
## 使用するリポジトリ
以下URLにRails6の環境構築用に作成したリポジトリを用意いたしました。今回の記事ではDockerで開発するイメージをつかむことを主目的としているため、ファイルの詳細な説明はしません。ご了承いただけると幸いです:cry:

https://github.com/ooooose/rails6_docker_sample

## Railsを起動
こちら、リポジトリのREADMEどおりにコマンドを実行すればおそらく以下の画面になるかと思います。(port番号は`3000`です)
[![Image from Gyazo](https://i.gyazo.com/faffd99621f9f8443d7c8872c74d6eb4.png)](https://gyazo.com/faffd99621f9f8443d7c8872c74d6eb4)
## volumesという技術
自分の抱いていた疑問（ローカルで作業するのか、コンテナで作業するのかと言う疑問）については、**ローカルで作業する**が結論になります。このことについて以下図にまとめてみました。
[![Image from Gyazo](https://i.gyazo.com/155c8a653936abc9403065faa800a446.png)](https://gyazo.com/155c8a653936abc9403065faa800a446)
上図のうち、ローカルとコンテナのボックスを繋ぐvolumesという技術によりローカルのファイルとコンテナのファイルが常に最新状態で共有（同期）されるようになっています。
## volumesとは
これ自体はdocker-compose.ymlで以下のように指定しています。右側がコンテナの、左側がローカルの作業ディレクトリを指定しています。
```yaml:docker-compose.yml
version: '3'

services:
  app:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/myapp　 # ここ！
    ports: 
      - 3000:3000
    depends_on:
      - db
    tty: true
    stdin_open: true

  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: password
    ports:
      - 3306:3306
    volumes:
      - ./tmp/db:/var/lib/mysql:delegated
      - ./my.cnf:/etc/mysql/conf.d/my.cnf
    cap_add:
      - SYS_NICE
```
volumesを設定することで、dockerコンテナと自分のローカルが同じファイルを一緒に共有しているようなイメージで、ローカルのファイルを編集するとコンテナのファイルも編集が反映されるといった関係性が実現されます。
これにより、ローカルでは開発作業をし、コンテナはローカルの変更内容を反映し、Railsの実行環境として機能することが実現されます。
## 実際にvolumes（バインドマウント）を検証してみる。
ローカルでファイルを編集した場合、コンテナのファイルも同じく変更が反映されている確認しようと思います。今回は`config/routes.rb`に以下のようなコメントを追加しようと思います。（ローカルで）
```ruby:routes.rb
Rails.application.routes.draw do
  # 今日はDockerの技術記事を書いています。
end
```
次に実際にコンテナの中に入って、変更が反映されているか確認してみます。
```terminal:terminal
ooseyuuki@ooseyuukinoMacBook-Pro rails6_docker_sample % docker-compose exec app bash
root@f29f1556f46a:/myapp# cat config/routes.rb
Rails.application.routes.draw do
  # 今日はDockerの技術記事を書いています。
end
```
コンテナ内のconfig/routes.rbにも同様のコメントが反映されていました。
docker-compose.ymlのvolumesでマウントするディレクトリを指定することでお互いが共有関係となり、コンテナ環境での開発を容易にしています。

# 最後に
Dockerを初めて学ぶ人にとってピンときづらいコンテナ環境での開発のイメージが少しでも湧けば嬉しいです。行ったり来たりな記事だったと思いますが、最後まで読んでいただき、本当にありがとうございます:bow:
定期的に記事を投稿しますので、引き続きよろしくお願いいたします:blush: