Dockerを基礎理解した-7つの基礎操作編-

# はじめに
Dockerの概要・特徴について下記でまとめたので、このページではインストール手順について。


https://qiita.com/uehiro22/items/788560c3721f36ad232f


※個人ブログから技術的アウトプットはQiitaへ引っ越ししたので、こちらは過去に書いたブログとなります。

# 1/ インストール

### Docker Hubに登録することで、インストールできる

- [Docker Hub](https://hub.docker.com/)とは：Githubがソースコードを管理する場所であるように，Docker HubはDocker Imageを管理（保存）する場所。ソースコードが日々更新されるのと同じく、使うパッケージのバージョンを更新したり新しいパッケージをインストールしたり、Docker Imageも日々更新される。
- **`‘Sign up for Docker Hub’`** をクリックし、Docker ID、 Email、 Passwordを入力

### Docker Imageとは

- **Docker Imageは、コンテナをつくるもととなるもの**
- Docker HubからDocker ImageをHost（自分のPC）にpullしてローカルで使う

# 2/ Dockerにログイン

```java
$docker login
```

すると、こんな感じになる

```java
$docker login

Login with your Docker ID to push and pull images from Docker Hub.
If you don't have a Docker ID, head over to https://hub.docker.com to create one.

Username: XXXXXX
Password: XXXXXX
Login Succeeded
```

# 3/ Docker HubからDocker Imageをpull

library/hello-worldレポジトリからHostにpull。以下内部処理のイメージ

![https://cdn-ak.f.st-hatena.com/images/fotolife/h/hiroism0329/20210215/20210215224729.png](https://cdn-ak.f.st-hatena.com/images/fotolife/h/hiroism0329/20210215/20210215224729.png)

- 上図の通り、**コンテナはDocker Imageから作られる**
- **Docker Imageは、コンテナを作るためのもととなるもの**。配布など可
- そのDocker ImageはDocker Hubに保存されている
- 使いたいコンテナがある場合は、まずDocker Imageを手に入れて（HostにPull）それを実行することでコンテナを作ることができる

```java
$docker pull {IMAGE名:TAG名}
```

例えば、hell-worldというIMAGE名のlatestというTAGをもったDocker ImageをPULLするとする。この**タグ**というのはDocker Imageのバージョンのようなもの

```java
$docker pull hello-world

Using default tag: latest
latest: Pulling from library/hello-world
0e03bdcc26d7: Pull complete
Digest: sha256:95ddb6c31407e84e91a986b004aee40975cb0bda14b5949f6faac5d2deadb4b9

Status: Downloaded newer image for hello-world:latest
docker.io/library/hello-world:latest
```

- 上図では、`library/hello-world`からImageをpullしている。
- この`library//`というのはDocker Hub libraryをさし，その中のhello-worldというレポジトリからpullしている

```
$docker images
```

- **今手元にあるDocker imageのリストを確認可**

```java
$docker images

REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest bf756fb1ae65 13 months ago 13.3kB
// ↑レポジトリ名
```

# 4/ Docker Imageからコンテナを作成

コンテナをImageから作る

```java
$docker run {Image名}
```

- ホストにイメージがある場合：そのイメージを使ってコンテナをつくる
- ホストにイメージがない場合：Docker Hubから自動的にプルしてくれる

例）hello-worldというコンテナを実行

```java
$docker run hello-world

Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:

1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(amd64)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an Ubuntu container with:

$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/get-started/
```

# 5/ コンテナの一覧表示

2つの一覧表示方法がある。

- $docker ps：ローカルにある全コンテナ（停止中も含む）の一覧表示
- $docker ps -a：activeのコンテナだけ表示

1つずつ見ていく。

まず、ローカルにある全コンテナ（停止中も含む）の一覧表示の場合。

```java
// 停止中のコンテナも表示
$docker ps
                                    //Exited（消されて）されている
CONTAINER ID     IMAGE    COMMAND CREATED     STATUS      PORTS           NAMES
e7d8a8bb03e7 hello-world "/hello" 3 minutes ago Exited (0)  3 minutes ago clever_yonath
```

次にactiveのコンテナだけ表示

```java
$docker ps  -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
```

# 6/ コンテナに入る

```java
$docker exec[コンテナ名] [コマンド名]
```

- docker exec はコンテナ内で新たなプロセスを実行
- 指定したコマンドやスクリプトなどを指定したコンテナ内部で起動
- 例）**`$docker exec -it <CONTAINER ID> bash`** ：コンテナを指定して、コンテナにプログラムを実行

### （例）UbuntuのDocker imageをrunしてコンテナに入る

- Dockerは、指定されたimageをrunする時にローカルのimageを見にいく
- ローカルのimageがない場合，指定されたレジストリ(今回のケースだとDocker Hub)にそのimageを取りに行き，runする（コンテナを作成）
- 実は、わざわざpullしなくても，runを実行すれば勝手にpullしてくれる

```
$docker run -it ubuntu bash
```

- ubuntuとはOSの1つ
- ホストにubuntuイメージが有る場合：そのイメージを使ってコンテナをつくる
- ホストにubuntuイメージがない場合：Docker Hubから自動的にプルしてくれる

```java
$docker run -it ubuntu bash

// 1. ホストにない
Unable to find image 'ubuntu:latest' locally

// 2. 1の結果を受けてプルしている
latest: Pulling from library/ubuntu
83ee3a23efb7: Pull complete
db98fc6f11f0: Pull complete
f611acd52c6c: Pull complete
Digest: sha256:703218c0465075f4425e58fac086e09e1de5c340b12976ab9eb8ad26615c3715

Status: Downloaded newer image for ubuntu:latest
// コンテナ内の現在のルートを確認
root@0031c4bf85b1:# pwd
// コンテナ内のフォルダを確認
root@0031c4bf85b1:# ls
bin boot dev etc home lib lib32 lib64 libx32 media mnt
opt proc root run sbin srv sys tmp usr var
```

- 3つpullされているのは，ubuntuのDocker imageを構成する**Docker Image Layer**
- 2746a4a261c9’などの乱数時は**Layer ID。つまりこのDocker imageは3つのImage Layerから構成されているということ。**
- Docker イメージは、親子関係を持つ、複数のイメージ、レイヤ（Image layer）によって構成されている。

例）4つのImage Layerから構成されている場合（IDは仮）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563702/87c180d4-90a1-0f14-58bd-808608321994.png)


### なんでレイヤーごとに別れているか？

- このimageに機能を追加した新しいDocker imageを作ったとき，共通の部分は新しく作る必要がなくなるから。(正式にはマウントされている)
- 結果、同じ部分は複製せず，共有することでストレージが節約可能
- 例えば、Docker imageをpullする時も，すでに同じLayerがローカルにあった場合、pullしなくて済む！結果、時間が短縮される

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563702/345197e6-4bf1-ee27-96ee-0bb8e99001c9.png)


### レイヤーの追加について

- コンテナに入ってなにか更新することで，その都度新しいlayerが追加される
- ちなみに、**コンテナとイメージの大きな違い**は、最上部に書き込みレイヤ（下記で言う新しく追加されたレイヤ）があるかどうか。既存のイメージ・レイヤは読み取り専用
- 正確には、Gitのように更新後commitというコマンドでセーブする必要がある

### コンテナに入ると

```java
root@0031c4bf85b1:/# root@0031c4bf85b1:/#
```

となり、コンテナを実行しbashを起動したので，コンテナの中に入ることができた状態がこれ。rootというのはコンテナ内のuserで，デフォルトだとroot権限での実行。

### コンテナ内にファイルを作成

```java
$touch <ファイル名>
```

```java
root@0031c4bf85b1:# touch test
bin boot dev etc home lib lib64 media mnt opt
proc root run sbin srv sys *test tmp usr var
```

### コンテナを抜ける

2通りあり

- **exit**
- **detach（デタッチ）**

### **Exit**

- **コンテナを完全に止める**

```
$exit
```

```
$exit
root@0031c4bf85b1:/#exit
exit

$docker ps -a  //Exitされている
CONTAINER ID       IMAGE     COMMAND CREATED STATUS       PORTS         NAMES
e7d8a8bb03e7 hello-world "/hello" 5 hours ago Exited (0) 5 hours ago clever_yonath
```

# 7/ 再度コンテナを起動

```
$docker restart {ID}
```

これにより一度抜けたコンテナのステータスをExit→UPに更新する

```
$docker restart  e7d8a8bb03e7
funny_hopper

$docker ps -a
CONTAINER ID IMAGE COMMAND    CREATED     STATUS          PORTS NAMES
e7d8a8bb03e7 ubuntu     "bash"  2 hours ago   Up 45 seconds  funny_hopper
b3fd07c7d4a4 ubuntu     "zsh" 2 hours ago   Created    clever_kowalevski
e7d8a8bb03e7 hello-world "/hello" 3 hours ago   Exited 3 hours ago clever_yonath
```

### detach

```
ctrl +p+q
```

- 「コンテナを動かしたまま」「止めたくない」という場合はdetachする
- **`$exit`**は、processを切ってコンテナを出る。結果、完全にプロセスを切るので、STATUSはExitedに。
- 一方、**デタッチ**はprocessを切らずにコンテナを出る。結果、プロセスは切らないので、STATUSはUpのまま

# 7/ 再びコンテナに入る（アタッチ）

```
$docker attach コンテナ名/ID
```

- detachしたときのプロセスに入りたい場合はattachを使う。
- ただし、実務ではあまり使わない

# まとめ

- *docker hub*：docker imageを保管しているレジストリサービス。複数のレポジトリがあって、イメージ単位でレポジトリが保管されている
    - また、1つのイメージに対して複数のタグが切られている
- *docker image*：コンテナを作るもととなるもの
- *docker login*：docker hubにアクセス
- *docker pull* ：docker hubからImageをhostにpull
- *docker image run -it bash*：docker imageからコンテナを起動させる。
    - コンテナ内でubuntuというOSと会話するためにbashを起動させる
- *exit*：コンテナで作業をし終えたらdockerからHostに戻る
- *docker ps -a* ：コンテナのステータスを確認
    - psとは：process statusなのでプロセスのステータスがわかると覚えよう
- *docker images*：HostにあるImagesを確認
- *docker restart*：exit状態のコンテナに再度入るために、exitをUpというステータスに変更して起こしてあげる
- *docker exec -it <コンテナ>bash*：指定したコンテナに対して指定したプログラム（例 .bash）を実行する。結果、OS（例. ubuntu）とコミュニケーションできる
- *docker commit <コンテナ><イメージ>*：更新（変更）をかけた（例. Pythonのversionを変えたり）コンテナからイメージをつくる。
    - イメージにすることで、Dockerを通してやりたい、他の人に配布などができる
    - コンテナからイメージをつくる。例）ubuntu → ubuntu:updated
- *docker tag<今のイメージ><新しいイメージ>*：他の人に配るなどするためにリモート環境。docker hubにプッシュする。
    - しかし、それをするためにはdocker imageの名前はプッシュするレポジトリ名と同じ必要があるため、イメージ名を変更し、新しいタグ付をする必要がある
- *docker push <イメージ>*：リモートのレポジトリにPushして、作成・更新したコンテナを共有可能にする
- *docker rmi <イメージ>*：不要なイメージを削除