Dockerfile 基礎的なこと

UdemyでDockerを勉強し、いちチャプターで学んだことをまとめてみました。
自分用の備忘録として書いたので分かりにくいと思います。

##Dockerfile
DockerfileとはDocker imageの設計図。
テキストでどのようなDocker imageを作るか記述して、それを基にDocker imageを作成する。
どのようなコンテナが作られるのかが分かりやすい。

#####Dockerfileを基にimageを作成

```
$docker build <ディレクトリ>
例えばカレントディレクトリだと
$docker build .
```

名前を付けるならば

```
docker build -t <name><ディレクトリ>
```

##書き方

###FROM

・ベースとなるimageを決定している
・DockerfileはFORMから書き始める
・FROMで指定したimageの上に、layerとしてどんどん命令を書いていく

　ほとんどのケースがubuntuを指定するらしい。

```docker
FROM ubuntu:latest
RUN touch test
```
この場合touchはLinuxのコマンドなので、LinuxのOSが必要。
ubuntuをベースとしているのでtouchをしようすることができる。
ubuntuの上にtouch testを実行しているイメージ。

###RUN

・Linuxコマンドを実行する
・RUNを使うことでどんどんカスタマイズしていく
・RUNをしようする度にlayerが追加されていくので使いすぎるとDockerfileのサイズが大きくなってしまう

```dockerfile
FROM ubuntu:latest
RUN touch test
RUN echo 'hello world' > test
```
この場合はtestファイルが作られ、testファイルにhello worldを追記する。

####<font color="Red">サイズを最小限に抑えるために</font>
RUNを使いすぎるとlayerが多くなり、サイズが重くなってしまう。
サイズを最小限に抑えるためには、コマンドを&&で繋げていく。

```docker
FROM ubuntu:latest
RUN touch test &&  echo 'hello world' > test
```
RUNを2つ使っていたものを&&で繋げて1つのRUNにする

パッケージをインストールする時も

```docker
FROM ubuntu:latest
RUN apt-get update #新しいパッケージリストを取得
RUN apt-get install xxx #パッケージをインストール
RUN apt-get install yyy
RUN apt-get install zzz
```
RUNを4つ使っているけど以下のように1つにまとめる

```docker
FROM ubuntu:latest
RUN apt-get update && RUN apt-get install\ 
xxx\
yyy\
zzz
```

### cache機能
Dockerにはcache機能がある

例えば以下のファイルで新しくnginxをインストールしたい時に

```docker
FROM ubuntu:latest
RUN apt-get update && RUN apt-get install\ 
curl\
cvs
```

以下のように普通にnginxを追記すると、buildした時に全てのlayerを作り直すことになり時間がかかってしまう

```docker
FROM ubuntu:latest
RUN apt-get update && RUN apt-get install\ 
curl\
cvs\
nginx
```

以下のようにRUNを分ければ、今まで作られたlayerはcacheとして保持され追記されたRUNだけを実行するので、最初からlayerを作る必要がなくなる。

```docker
FROM ubuntu:latest
RUN apt-get update #ここのlayerは既にあるので実行されない
RUN apt-get install\ #ここのlayerは既にあるので実行されない
curl\
cvs
RUN apt-get install nginx #追記したここだけ実行される
```

前述の通りRUNが沢山あるとサイズが大きくなるので、上記の処理が正常に動作することを確認したら、RUNを&&で繋げる。
Dockerfileをメンテナンスするときはcacheを使用し、最終的にはRUNを&&で繋げという流れです。

```docker
FROM ubuntu:latest
RUN apt-get update && RUN apt-get install\ 
curl\
cvs\
nginx
```

##CMD
・コンテナのデフォルトコマンドを指定
・docker run された時に実行される
・RUNとの違いはlayerを作成するか(CMDはlayerを作成しない)

```docker
FROM ubuntu:latest
RUN apt-get update && RUN apt-get install\ 
curl\
cvs\
nginx
CMD ["/bin/bash"]
```

## COPY
・ファイルをDocker imageに組み込む時に使用する

new_dirというディレクトリを作成してsampleというファイルをnew_dir直下に置く例

```docker
FROM ubuntu:latest
RUN mkdir/new_dir
COPY sample/new_dir/
```

## WORKDIR
・それ以降の実行ディレクトリを変更する
RUNなどのインストラクションは全てルート直下で行われる
例えば...

```docker
FROM ubuntu:latest
RUN mkdir new_folder
RUN cd new_folder
RUN touch test
```
この場合3行目でnew_folderに移動しているから4行目のtouch testはnew_folder直下で行われていると思うが、実際はルート直下で行われている。testというファイルはnew_folder直下ではなくルート直下にできる。なのでWORKDIRを使用してディレクトリを変更する。
WORKDIRで指定したディレクトリが無い場合は自動で作ってくれるので、mkdirを使わなくても大丈夫。

```docker
FROM ubuntu:latest
RUN mkdir new_folder #無くても大丈夫
WORKDIR /new_folder  #絶対パスが良い
RUN touch test
```
こうすればnew_folder直下にtestファイルが作成され、これ以降のRUNなどは全てnew_folder直下で行われる。
&&で繋げていればcdで移動した先で実行されるが、cdを使うために毎回&&を使うよりWORKDIRを使った方が簡単。

```docker
FROM ubuntu:latest
RUN mkdir new_folder && \
    cd new_folder && \
    touch test #new_folder直下に作られる
```

## Dockerfileという名のファイルがない時

開発用とテスト用でDockerfileを分けていて、Dockerfile.devとDockerfile.testの2つが存在するとする。
Dockerfile.devをビルドしたい時は

```
$ docker build -f Dockerfile.dev .
```

## 環境変数
ENV ＜key＞ ＜value＞ 
キーとバリューの組み合わせでできる
書き方は複数ある

```docker
ENV key1 aaa
ENV key2=bbb
ENV key3="ccc"
```