Docker基礎 Dockerを使ってみる

Dockerについて勉強した時のメモ。

# Docker概要
### Dockerとは?
コンピュータ上にコンテナと呼ばれる箱を作ってそこにOSや他のソフトを入れてあたかも違うコンピュータのように扱えるもの。
### Dockerを使うと何がいいの？
コンテナ内で環境構築を行うので、他の人のPCでの環境、開発環境、テスト環境、本番環境全て同じ環境を簡単かつ便利に構築できる。
つまりDockerを使えばめんどくてしんどい環境構築のエラーに悩まされなくて済むということ！

### Dockerの基本の流れ
![スクリーンショット 2021-10-15 11.06.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/974719/587a1d51-e1ec-aff3-f14d-a0d93065d446.png)

DockerfileからDocker imageを作成し、Docker imageから各コンテナを作成するのが基本の流れ。


# Dockerを使ってみる
今回はDocker Hubからdocker imageをpull(自分のPCに持ってくる)し、持ってきたdocker imageに変更を加えて、再度Docker Hubにリポジトリとして保存するということをやってみます。

## Docker Hubからdocker imageをpullする
以下のURLからDocker Hubに登録しログインする。
https://hub.docker.com/

```docker
$ docker login
```
ログインできたらHost(自分のPC)にdocker imageをpullしていく

```docker
$ docker pull hello-world

Using default tag: latest
latest: Pulling from library/hello-world
2db29710123e: Pull complete
Digest: sha256:37a0b92b08d4919615c3ee023f7ddb068d12b8387475d64c622ac30f45c29c51
Status: Downloaded newer image for hello-world:latest
docker.io/library/hello-world:latest
```
`Pull complete`とあればpull成功。

```
$ docker images

REPOSITORY    TAG       IMAGE ID       CREATED       SIZE
hello-world   latest    feb5d9fea6a5   3 weeks ago   13.3kB
```
`docker images`コマンドでHostにあるimageのリストを確認できる。

## docker imageからコンテナを作る

pullしてきたdocker imageからコンテナを起動する。

```docker
$ docker run hello-world

ello 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/
```
`run`コマンドを使うことでdocker imageからコンテナを作成できる。
ちなみに出力されているのはdocker imageであるhello-worldのデフォルトコマンド。

```docker
$ docker ps
$ docker ps -a

CONTAINER ID   IMAGE         COMMAND    CREATED         STATUS                     PORTS     NAMES
6d4f7a8029be   hello-world   "/hello"   4 minutes ago   Exited (0) 4 minutes ago             dazzling_gagarin
```
`docker ps`コマンドでコンテナを見ることができる。
`ps`はactiveなコンテナ`ps -a`は全てのコンテナを見ることができる。
ちなみに`ps`はProcess Statusの略。
今回の場合hello-worldはexit状態にあるので`docker ps -a`で確認できる。

ここまでの流れを図でまとめるとこんな感じ。
![スクリーンショット 2021-10-16 8.03.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/974719/1b23cb0b-e55e-863c-f98a-892619db999d.png)
docker　imageを`run`するとコンテナが`create`されコンテナ内設定されているプログラムを`excute`(実行)し`exit`するというのがコンテナが作られる流れ。

## ubuntuのdocker imageをrunする
hello-worldをrunした時に出力されていたコマンドを実行してみる。

```docker
$ docker run -it ubuntu bash
```
`-it`はオプション`ubuntu`はLinux派生のOSで`bash`の部分はコンテナ起動時に実行するプログラムを指定している。

実際に実行してみる。

```docker
$ docker run -it ubuntu bash

Unable to find image 'ubuntu:latest' locally
latest: Pulling from library/ubuntu
f3ef4ff62e0d: Pull complete
Digest: sha256:a0d9e826ab87bd665cfc640598a871b748b4b70a01a4f3d174d4fb02adad07a9
Status: Downloaded newer image for ubuntu:latest
root@8650a53129ac:/#
```
今の状態は、`ubuntu`をdocker hubから`pull`してきてubuntu内のプログラムである`bash`を起動してコンテナの中にいる状態。

ここにtestというファイルを作成してコンテナを更新し更新できたら`exit`します。

```docker
root@8650a53129ac:/# touch test
root@8650a53129ac:/# ls
bin  boot  dev  etc  home  lib  lib32  lib64  libx32  media  mnt  opt  proc  root  run  sbin  srv  sys  test  tmp  usr  var

root@8650a53129ac:/# exit
exit
```
## exitとdetach
コンテナをexitして抜けるとコンテナのstatusはexitになります。

```docker
$ docker ps -a
CONTAINER ID   IMAGE         COMMAND    CREATED       STATUS                     PORTS     NAMES
8650a53129ac   ubuntu        "bash"     2 hours ago   Exited (0) 3 minutes ago             kind_shannon
```
detachを使うことでexit状態にしないで抜けることができます。
そもそもexitというのはいままで動いていたプロセスを切ってコンテナから抜けます。
逆にdetachはプロセスを残したまま抜けることができます。

実際に見てみましょう。
先ほどexitして抜けたコンテナに再度入ります。
そのためにまずコンテナを`restart`させます。コンテナの指定はIDを使って指定しています。

```docker
$ docker restart 8650a53129ac
```
Upになっていることを確認します。

```docker
$ docker ps -a
CONTAINER ID   IMAGE         COMMAND    CREATED       STATUS                   PORTS     NAMES
8650a53129ac   ubuntu        "bash"     2 hours ago   Up 13 seconds                      kind_shannon
```
コンテナに再度入るためのコマンドは`exec`を使います。

```
$ docker exec -it <container> bash
```
コンテナ名を指定して実際に実行してみます。

```docker
$ docker exec -it 8650a53129ac bash
root@8650a53129ac:/# ls
bin  boot  dev  etc  home  lib  lib32  lib64  libx32  media  mnt  opt  proc  root  run  sbin  srv  sys  test  tmp  usr  var
```
コンテナに入ることができ、先ほど作ったtestファイルもちゃんとあります。
ここで前回はexitで抜けましたが今回はdetachで抜けます。
detachで抜ける方法は`ctrl+p+q`で抜けることができます。
実際に抜けてコンテナのstatusを確認します。

```
root@8650a53129ac:/# read escape sequence
$ docker ps -a
CONTAINER ID   IMAGE         COMMAND    CREATED       STATUS                   PORTS     NAMES
8650a53129ac   ubuntu        "bash"     2 hours ago   Up 9 minutes                       kind_shannon
```
Up状態のまま抜けることができました。
基本はexitで抜けることが多いらしいです。
こういうやり方もあるのだと今の段階では覚えておけばいいと思います。

## docker commit 
testというファイルを追加したdocker imageを元のdocker imageに`commit`して更新していきます。

`commit`のコマンド

```docker
$ docker commit <container> <new image>
```
実際に動かしてみます。
`:`でimageにタグをつけることができます。

```docker
$ docker commit 8650a53129ac ubuntu:updated

sha256:6f8a0c2aee370356b0ef80aee365575901c90684a8ca303619eeb1b8069481ff
$ docker images
REPOSITORY    TAG       IMAGE ID       CREATED         SIZE
ubuntu        updated   6f8a0c2aee37   2 minutes ago   72.8MB
ubuntu        latest    597ce1600cf4   2 weeks ago     72.8MB
```
ubuntuのimageが2つあるのが分かります。
![スクリーンショット 2021-10-16 9.02.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/974719/85f28188-58f4-8e94-8182-5b116832b5eb.png)

docker imageはlayer構造になっていて、既存のimageに新しく何かを追加すると、新しいlayerとして追加されます。
今回の場合だとtestファイルを作成したというlayerが追加され、新しいdocker imageがcommitによって反映されたということです。

## Docker Hubにリポジトリ作成
作成したdocker imageをDocker Hubに上げていきます。
まずはDocker Hubにリポジトリを追加します。
右上にある青いボタンのCreate Repositoryを押してリポジトリを作成します。
今回リポジトリ名は`my-first-repo`としています。
![スクリーンショット 2021-10-16 11.53.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/974719/98bdc271-c62e-254b-e5fe-82635fcc0f8a.png)


## Docker Hubにpushする
Docker Hubにpushする前に現在のimage名をDocker Hubのリポジトリ名に合わせます。
tagコマンドを使うことで変更できます。

```
$ docker tag <今の名前> <更新する名前> 
```
今回の場合は以下のように書き`docker images`で名前が変わっているか確認します。

```docker
$ docker tag ubuntu:updated <username>/my-first-repo
$ docker images
REPOSITORY               TAG       IMAGE ID       CREATED          SIZE
aaaasahi/my-first-repo   latest    6f8a0c2aee37   39 minutes ago   72.8MB
```
新しく設定したimageができてることが確認できます。

最後にDocker Hubにpushしていきます。

```
$ docker push aaaasahi/my-first-repo
```
pushの際に実際にpushされるのは追加したlayerだけです(図で見るとlayer5の部分)
残りのlayer1〜4はもともとDocker Hubに存在するのでわざわざpushする必要がなく容量の節約になるわけです。
![スクリーンショット 2021-10-16 9.02.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/974719/85f28188-58f4-8e94-8182-5b116832b5eb.png)

最後に必要ないdocker imageは`rmi`コマンドで削除できます。

```docker
$ docker rmi <image>
```

# 参考
https://www.udemy.com/course/aidocker/