Dockerfileのinstruction 続き

Docker初心者がDockerについて勉強した時のメモ。

前回の記事

https://qiita.com/aaaasahi_17/items/4710f313a8e9d20f6f0a


## COPY
COPYはbuild context内のファイルをHostからDocker imageに組み込むことができる。

```
COPY <src> <コピー先>
```

例

```terminal
mkdir docker
cd docker
touch Dockerfile something
```
dockerというフォルダを作成し、その中にDockerfileとsomethingというファイルを作成します。

```docker:Dockerfile
FROM ubuntu:latest
RUN mkdir　/new_dir
COPY something　/new_dir/
```
```docker
$ docker build .
```
できたimageを確認してrunします。

```
$ docker images
REPOSITORY               TAG       IMAGE ID       CREATED          SIZE
<none>                   <none>    59376b2bdd75   16 seconds ago   72.8MB

$ docker run -it --rm  59376b2bdd75 bash
root@5c13457b9805:/
```

`COPY`で記述したnew_dirの中にsomethigがあるか確認します。

```
root@5c13457b9805:/ls
bin  boot  dev  etc  home  lib  lib32  lib64  libx32  media  mnt  new_dir  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

root@5c13457b9805:/# ls /new_dir
something
```
これでbuild　context内のsomethingをコンテナ内に渡せていることが分かります。

## COPYとADDの違い
`ADD`は`COPY`と同様にbuild context内のファイルをHostからDocker imageに組み込むことができる。
**どう使い分けるか？**

- 単純にファイルやフォルダをコピーする場合はCOPYを使う
- tarの圧縮ファイル(階層、要領の多いものをまとめて圧縮)をコピーして解凍したいときはADDを使う。
    - 圧縮することでbuild時に時間短縮。build後解凍されている。
- `ADD`は中上級者向け 

## Dockerfileがbuild contextにない場合
**どういう時にそういう状況になるのか？**
Dockerfileを複数用意する時。
例えば、開発環境とテスト環境で分けたい時など。その際ファイル名には、Dockerfile.dev、Dockerfile.testのように名前をつけるのが一般的。

```docker
$ docker build -f <dockerfilename> <build context>
```

例
dockerフォルダの中にsample_folderフォルダを作りそのsample_folderの中にDockerfileがある場合。

```
mkdir docker
cd docker
mkdir sample_folder
cd sample_folder
touch Dokerfile.dev
```
sample_folderの位置で以下を実行。

```docker
$ docker build -f ../Dockerfile.dev .
```
`../Dockerfile.dev`はDockerfileの位置、`.`はbuild contextの位置。

## CMDとENTRYPOINT
### CMD復習
CMDはDockerfileの最後に記述するコンテナのデフォルトのコマンド。

```docker:Dockerfile
CMD ["実行可能なコマンド", "コマンドの引数1", "コマンドの引数2"]
```

```docker:Dockerfile
CMD ["/bin/bash"]
```

```docker
$ docker run -it ubuntu bash
```
`bash`の部分。
`run`の時に他のコマンドで上書き可能。
### ENTRYPOINT
ENTRYPOINTもCMDと同様にデフォルトのコマンドを指定することができる。
ENTRYPOINTはCMDと違いrun時に上書きできない。つまりrun時に上書きできるのはCMDのみ。
ENTRYPOINTがある場合CMDは以下のようなコマンドの引数のみの形をとる。
コンテナを1つのコマンドのようにして使いたい時に使うらしい。あんまり使うことはない感じかも。

```docker:Dockerfile
ENTRYPOINT ["実行可能なコマンド"]
CMD ["コマンドの引数1", "コマンドの引数2"]
```

例

```docker:Dockerfile
ENTRYPOINT ["ls"]
CMD ["--help"]
```
この場合runで上書きできるのはCMD`--help`の部分だけ。

## ENV
ENVは環境変数を設定する。

```docker:Dockerfile
ENV key value1
ENV key=value2 
```
書き方はどっちでも同じ。複数あるときは下の書き方の方が分かりやすい。

## WORKDIR
WORKDIRはDocker instructionの実行ディレクトリを変更する。

```docker:Dockerfile
FROM ubuntu:latest
RUN mkdir sample_folder
RUN cd sample_folder
RUN touch sample_file
```
このDockerfileでやりたいのは、sample_folderを作りそのsample_folderに移動しsample_folder内でsample_fileを作りたい。
実際に実行してsample_folder内でsample_fileがあるか確認する。

```
$ docker build .

$ docker run -it 111b027b6948 bash
root@c52e6db17dba:/# ls
bin   dev  home  lib32  libx32  mnt  proc  run          sample_folder  srv  tmp  var
boot  etc  lib   lib64  media   opt  root  sample_file  sbin           sys  usr
```
sample_fileはsample_folder内ではなくroot直下に作られている。
そもそも、`RUN`などのDockerのinstructionは全てroot直下で実行される。

**どうするか？**

RUNを&&で繋げて書けばsample_fileはsample_folderを作ることができる。
ただ毎回sample_folderに移動するのは手間。

```docker:Dockerfile
FROM ubuntu:latest
RUN mkdir sample_folder &&\
    cd sample_folder &&\
    touch sample_file
```
WORKDIRを使う。

```docker:Dockerfile
FROM ubuntu:latest
RUN mkdir sample_folder
WORKDIR /sample_folder         
RUN touch sample_file
```
WORKDIRを使うことで実行するディレクトリを変更してくれる。
WORKDIRのパスは絶対パスで指定する。

ちなみに、WORKDIRではフォルダがない場合そのフォルダを作ってくれるので以下のような書き方も可能。

```docker:Dockerfile
FROM ubuntu:latest
WORKDIR /sample_folder         
RUN touch sample_file
```
# 参考
https://www.udemy.com/course/aidocker/