Dockerの -it について調べてみた

普段なんとなく、あまり理解せず使っているdockerに関して少し調べてみた的な内容になっています。
調べながらまとめた内容になるので、間違っているところなどあればコメントなどでご指摘いただけるとありがたいです！

<br>
普段dockerでコンテナに入りshellを操作したい時に、

```sh
docker exec -it コンテナ名 bash
```

のようなコマンドをよく使います。
今回はこのコマンドに関して調べた内容をまとめました。

## docker exec
`docker exec` は [docker exec のリファレンス](https://docs.docker.jp/engine/reference/commandline/exec.html) によると、
>使い方: docker exec [オプション] コンテナ コマンド [引数...]
実行中のコンテナでコマンドを実行

<br>
とあるので、下記コマンドの場合は

```shell
docker exec -it コンテナ名 bash
```

`-it` がオプション、 `bash` がコマンドとなります。
なので上記コマンドは、**指定したコンテナで bash を実行するコマンド** ということになります。


## 本題
指定したコンテナでbashを実行するだけでは、普段のコンテナに入りshellを操作することはできないので、その部分を理解する為に`-it`オプションが何をしているか知る必要がある。
<br>

それぞれ [docker exec の リファレンス](https://docs.docker.jp/engine/reference/commandline/exec.html) によると

>-i, --interactive=false    アタッチしていなくても STDIN をオープンにし続ける
  -t, --tty=false            疑似ターミナル (pseudo-TTY) の割り当て

よ、よくわからない、、、
1つずつ確認していきます。

<br>
まずはコンテナを立ち上げたいので、下記コマンドを入力します。

```shell
docker run --name php-test php:apache
```

[docker run コマンド](http://docs.docker.jp/engine/reference/run.html)はイメージをもとにコンテナを立ち上げます。

上記コマンドでは、`php:apache` というイメージをもとに、`php-test` という名前コンテナを立ち上げます。

<br>
まずはこのコンテナの中に入ってshellを操作してみたいと思います。

```shell
docker exec -it php-test bash
```
上記コマンドを打つと、コンテナのshellを操作できるようになります

```shell
root@コンテナID:/var/www/html# ps a
   PID TTY     STAT   TIME COMMAND
   23  pts/0   Ss     0:00 bash
   31  pts/0   R+     0:00 ps a
```
`ps a` コマンドを打ち込み、現在のプロセスを表示すると、PID23で`bash`、それとPID31で先程打ち込んだ`ps a`コマンドのプロセスが表示されています。

この状態を維持したまま、新たに別のターミナルを起動し同じように下記コマンドでコンテナに入り、プロセスを表示します。

```shell
docker exec -it php-test bash

root@コンテナID:/var/www/html# ps a
  PID TTY      STAT   TIME COMMAND
   23 pts/0    Ss+    0:00 bash
   32 pts/1    Ss     0:00 bash
   38 pts/1    R+     0:00 ps a
```

確認すると `bash`コマンドのプロセスが１つ増えています。
ここで注目する部分は、TTYの項目になります。
前述した`docker exec` のオプション `-t`には下記のような記述がありました。

>  -t, --tty=false            疑似ターミナル (pseudo-TTY) の割り当て

pseudo は擬似という意味。
tty は [wikipedia](https://ja.wikipedia.org/wiki/Tty)より

>ttyとは、標準入出力となっている端末デバイス(制御端末、controlling terminal)の名前を表示するUnix系のコマンドである。元来ttyとはteletypewriter（テレタイプライター）のことを指す。
例えば、SSH などを経由し、Unix98 PTY の擬似端末に接続している状況で tty を実行すると、以下のような表示が返される。
% tty
/dev/pts/1


わかりそうでわからない(知識不足)。
わからないなりに、`docker exec -it php-test bash`をするたびに、TTYの項目、`pts/0`の数値部分が増えていくので、新たにttyが割り当てられていることがわかる。

おそらく`-t`コマンドをつけないとttyが割り当てられないのだろうと思い、
3つ目のターミナルで`-i`のみでコマンドを実行すると、

```shell
docker exec -i php-test bash 
```
、、、何も起きない、、、
おそらくttyが割り当てられていない状態だが、`-i`オプションが効いているのでこの画面で入力したコマンドは、コンテナがSTDIN(標準入力)を開き続けているので、そこと繋がっていると思われます。(後述)

なんの反応もない画面で3回くらい`bash`打ち込んだ後、２つ目のターミナルで`ps a`するとPIDが進んでいるので、bashのプロセス自体は作られているようでした。

次は`-t`のみをつけてコマンドを実行してみます。
3つ目のターミナルで、`control + c`で画面をもとに戻した後下記コマンドを実行。

```shell
docker exec -t php-test bash 
```

すると、見覚えのある画面になりますが、`ps a`はもちろんどのコマンドを打っても何も反応しません。
リファレンスにあったオプションの内容を再確認してみます。
>-i, --interactive=false    アタッチしていなくても STDIN をオープンにし続ける

**アタッチしていなくても** という部分から、おそらく`docker attach`コマンドなどでコンテナにアタッチする時は、STDINがオープンの状態になっているが、普段はコンテナのSTDINがオープンになっていない状態だろうということがわかります。

**STDINをオープンにし続ける**という部分から、`-i`を指定することで、コンテナにアタッチしていない状態でもSTDINをオープンにし続ける、標準入力を受け付ける状態にする、ということがわかります。

確認の為、２つ目のターミナルで`ps a`を実行すると、

```shell
root@5ee2e1cf4cb5:/var/www/html# ps a
  PID TTY      STAT   TIME COMMAND
   23 pts/0    Ss+    0:00 bash
   32 pts/1    Ss     0:00 bash
   56 pts/2    Ss+    0:00 bash
   64 pts/1    R+     0:00 ps a
```

`pts/2`が追加されているので、　`-t`をつけると、擬似ターミナルが割り当てられるが、`-i`がないとコマンドの実行などができないということがわかった。


## まとめ

`docker exec -it コンテナ名 bash`などで、コンテナ内でshellの操作をしたい時は、`-i -t`の2つのオプションの指定が必要。

`-t`だけだと、擬似ターミナルが割り当てられて、shell画面が表示されるが、標準入力と接続されていないので、コマンドの実行はできない。

`-i`だけだと、標準入力とつながるが、擬似ターミナルが割り当てられないので、コマンドを実行しても何が起こっているかわからない状態になってしまう。