【個人的に】Dockerがはかどる小技

初めて知ったときは感動したけど 自分の中で知ってて当然になってしまった小技をまとめました
まだこの小技を知らない人に届いてくれるとうれしい

## Dockerfile

### RUNを1つにまとめる

```dockerfile:Dockerfile
RUN echo '1つ目のコマンド'
RUN echo '2つ目のコマンド'
```

`&&` を使って1つにまとめる

```dockerfile:Dockerfile
RUN echo '1つ目のコマンド' && echo '2つ目のコマンド'
```

`&&` はDockerの小技というよりシェルの機能です
不用意にイメージレイヤーを増やすと イメージサイズが大きくなってしまうので RUNはなるべく1つにまとめた方が良い

### RUNで条件分岐

```dockerfile:Dockerfile
ARG HOGE="hoge"

RUN if [ "$HOGE" = "hoge" ]; then \
      echo 'hoge'; \
    fi
```

これもDockerの小技というよりシェルの機能です
特定のビルド引数が入ってきたときにのみ実行したい処理があるときに便利です

> :warning: 使いどころに注意
> そのイメージの本質が変化してしまうような使い方はあんまり良くないです。
> ちょっとしたツールを入れたりオプショナルな使い方がおすすめです

### ディレクトリを移動して作業する

```dockerfile:Dockerfile
RUN pwd \
    && (
      cd /another/path \
      && pwd \
      && echo '()の中は/another/path' \
    ) \
    && pwd \
    && echo '()の外は1つ目のpwdと同じ(元のディレクトリ)'
```

これまたシェルの機能ですが `()` の内側に閉じ込めると、どこのディレクトリで作業しているのか分かりやすくなります

> `cd -` で元のディレクトリに戻る方法もありますが
> `()` を使ったやり方だと、(するかどうかは置いておいて)ネストもできるのでおすすめです


### 別のイメージからファイルをCOPYする

```dockerfile:Dockerfile
COPY --from=composer:2.0 /usr/bin/composer /usr/bin/composer
```

特定のコマンドを持ってくるときに便利
自前でインストールするコマンドを書かなくても 公式のイメージから持ってこれる安心感

### 環境によってCOPYするファイルを変える

```dockerfile:Dockerfile
ARG TARGET_ENV

COPY ./docker/nginx/$TARGET_ENV/nginx.conf /etc/nginx/nginx.conf
```

```
docker/
  nginx/
    dev/
      nginx.conf
    ci/
      nginx.conf
    pro/
      nginx.conf
```

ただビルド引数を使っているだけですが ディレクトリを分けて環境ごとの設定を書いておくことで 開発環境、テスト環境、本番環境などの切り替えが楽になります

### マルチステージビルド

```dockerfile:Dockerfile
FROM nginx AS MOUNT

# some code

FROM MOUNT AS BUNDLE

# カレントディレクトリを丸ごと /usr/share/nginx/html にコピーする
COPY . /usr/share/nginx/html
```

イメージをビルドするときに `--target string` を指定してどこまでビルドするのか選べます

`docker build --target MOUNT .` にすると `/usr/share/nginx/html` にはなにも入ってない状態
コンテナ起動するときにマウントして開発できる

`docker build --target BUNDLE .` にするとイメージにコードが含まれているのでそのままコンテナを実行できる

みたいな使い方できます

## DockerCompose

### .env

```ini:.env
NGINX_PORT=80
```

docker-compose.yml は 環境変数を使用することができ、 .env ファイルにも対応しています

```yaml:docker-compose.yml
version: '3.8'

services:
  nginx:
    image: nginx
    ports:
      - ${NGINX_PORT}:80
```

人によって設定を変えたいような項目は .env に書き出しておくと便利

「80番ポート他でもう使ってるよ」ってことがあるのでホスト側のポートは 変数 にしがち

### docker-compose.override.yml

docker-compose.ymlの設定を上書きできるファイル

docker-compose.yml

```yaml:docker-compose.yml
version: '3.8'

services:
  php:
    image: php
    ports:
      - 80:80
```

docker-compose.override.yml

```yaml:docker-compose.override.yml
version: '3.8'

services:
  php:
    volumes:
      - ${APP_DIR}:/app
      - php_vendor:/app/vendor
    depends_on:
      - mysql
  
  mysql:
    image: mysql
    volumes:
      - mysql_data:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=${DB_PASS}

volumes:
  mysql_data:
  php_vendor:
```

ローカルだけ `docker-compose.override.yml` を作ってデータベースのコンテナを用意する
みたいな使い方ができます

## その他

### .dockerignore

`COPY` するときに除外したいファイルやフォルダを指定するファイル

```:.dockerignore
.vscode
.env
.git
.gitignore
.gitattributes
**/.gitkeep
**/Dockerfile
docker-compose.yml
docker-compose.override.yml
```

### host.docker.internal

コンテナからホストマシンのIPアドレスを指定したいときに使う

XDebug のようなデバッグツールの設定でつかったり

```ini:php.ini
[xdebug]
xdebug.client_host=host.docker.internal
```