【Docker】コンテナでアプリを開発するときにやっていること

今までコンテナを使ってアプリを開発してきたなかで気付いた、スムーズに開発ができるようになるコツをまとめてみたいと思います。

## 頻繫に変更するファイルがあるディレクトリをマウントする

### 方法

`docker run`コマンドだと`-v`でディレクトリをマウントします。

```bash
docker run -v <ホストディレクトリ>:<コンテナディレクトリ> <イメージ名>
```

`docker-compose.yml`だと`volumes`でマウントします。

```yml:docker-compose.yml
version: '3'
services:
  example:
    build: .
    volumes:
      - <ホストディレクトリ>:<コンテナディレクトリ>

```

### 理由

開発中でソースコードや設定ファイルを変えてから素早く動作確認したいとき、いちいちビルドして最新のファイルを反映しなくてよくなるからです。
Pythonとかのビルドが必要ない言語だと特に便利です。

## 頻繫に確認したいファイルがあるディレクトリをマウントする

### 方法

[頻繫に変更するファイルがあるディレクトリをマウントする](#頻繫に変更するファイルがあるディレクトリをマウントする)と同じです。
私が良くマウントするのは、アプリの実行結果として作成されるアウトプットファイルがあるフォルダやログファイルがあるフォルダです。

### 理由

わざわざコンテナの中に入って`cat`コマンドなどで見るのはめんどくさいです。ホスト側から直接見られる方が便利です。
もしログファイルのように見たいだけで、ホスト側から間違って変更したくない場合はボリュームのマウントのときに`ro`をつければ**read-only**になります。

```bash
docker run -v <ホストディレクトリ>:<コンテナディレクトリ>:ro <イメージ名>
```

```yml:docker-compose.yml
version: '3'
services:
  example:
    build: .
    volumes:
      - <ホストディレクトリ>:<コンテナディレクトリ>:ro

```

## 開発環境用のDockerfileをつくる

### 方法

`Dockerfile.dev`のように、開発用とわかるようなファイル名にします。
使用するときは、コマンドで明示的にファイルを指定します。

```bash
docker build . -f ./Dockerfile.dev -t docker-dev
docker run docker-dev
```

### 理由

開発環境だけコンテナにインストールしたいライブラリやコマンドがあったりすると、開発のときだけ書き足して、本番環境で使うときはまた消してを繰り返すのは面倒だからです。

## 開発環境用のdocker-compose.ymlをつくる

### 方法

Dcokerfileのときと同じく、`docker-compose.dev.yml`などでつくります。
`build`で任意のDockerfileを指定することもできます。

```bash
version: '3'
services:
  example-dev:
    build:
      context: .
      dockerfile: Dockerfile.dev
```

使用するときも同じく、コマンドで明示的にファイルを指定します。

```bash
docker-compose -f docker-compose.dev.yml build
docker-compose -f docker-compose.dev.yml up -d
```

### 理由

開発環境では`docker-compose.yml`で指定する環境変数の値が違う(DBの接続情報、デバッグフラグ)ことがよくあります。
Dockerfileと同じく、毎回書き換えるのは面倒なので分けると便利です。

## README.mdを作成して普段使うコマンドをまとめる

### 方法

こんな感じで、普段使うコマンドをメモ程度でいいので`README.md`にまとめておきます。

```text:README.md

# example

## ローカル開発環境

ビルド

$ docker-compose -f docker-compose.dev.yml build --no-cache

起動

$ docker-compose -f docker-compose.dev.yml up -d

コンテナに入る

$ docker exec -it <コンテナ名 or コンテナID> bash

スクリプト実行

# /src/start.sh

## 本番環境用イメージ作成

$ docker build -t example-prod .

```

### 理由

後から自分が見返したときに楽です。
バグに気づいて直すときに、コンテナの使い方を忘れててもスムーズに思い出せますし、もし他の人が使うってなった時も最低限の使い方が書いてあれば、0から説明する手間も省けます。

## ずっと起動させて使うコンテナは、自動で起動するようにする

### 方法

プロセスが永続的に実行されているDBやapacheサーバーが入っているコンテナや`tty`を`true`を設定しているコンテナに対して、`restart`を`always`に設定することで、ホストの起動と同時に自動でコンテナも立ち上がるように設定できます。

```bash
docker run --restart=always <イメージ名>
```

```yml:docker-compose.yml
version: '3'
services:
  example:
    build: .
    restart: always

```

### 理由

いちいちDocker Desktopを開いたり`docker ps`コマンドを使ったりして、「あのコンテナって起動してたっけ？」と確認する手間が省けます。クラウドサービスみたいにお金がかかるわけでもなく、ただただ便利。
プロセスが増えるのでホストが重くならないようにだけ注意しましょう。

## Dockerfileで必要なコマンド、シンボリックリンク、エイリアスを設定する

### 方法

開発でコンテナに入って使用するものは、Dockerfileの`RUN`で予め用意された状態のイメージにします。
必要なライブラリをインストールしたり、`bin`にシンボリックリンクを作成します。

```Dockerfile:Dockerfile
FROM python:latest

# コマンドインストール
RUN apt-get update 
RUN apt-get install -y vim

# 自分で追加したライブラリのシンボリックリンク作成
ADD ./lib /opt/lib
RUN ln -s /opt/lib/example/example.py /bin/example

# エイリアス設定
RUN echo "alias ll='ls -al'" >> ~/.bashrc
```

### 理由

ローカルで開発するときは、`docker exec`でコンテナに入ってあれこれすることがたまにあります。
そんなとき、Dockerイメージがミニマム構成なゆえにコマンドが少なすぎると感じたので、予めDockerfileでインストールしてしまったら楽だなと思ったからです。

# さいごに

最後までありがとうございます。
コンテナ使ったアプリ開発の参考にして頂ければ嬉しいです。