Dockerのこと色々

:::note info
当記事は随時更新していきます。
:::

# Dockerのインストール、起動
* こちらに記載
  [Docker Desktopを使用せずにWSL2でdocker環境を構築](https://qiita.com/bonny_d/items/e2d53fd9e46ab69946bd)

# コマンド色々
## runコマンド
### 実行時イメージ
![docker_runコマンド実行時イメージ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281492/e19c2075-f018-9008-2f2f-d90e46fa6b7a.png)
* runコマンドは、下記3つのコマンドを同時に行う
  * pull　　・・・イメージの取得、ダウンロード
  * create　・・・指定したイメージ上に書き込み可能なコンテナ・レイヤを作成　
  * start　 ・・・dockerコンテナを起動
### オプション
#### -d：デタッチ
* 標準入出力をコンソールからデタッチする→
コンテナ起動後、そのままコンソールからコマンドが入力できる
※ログが見たい場合　```docker logs [CONTAINER ID]```
#### -it：-i（interactive）と-t（tty）
* ざっくりと、docker runを実行したコンソールで、そのまま入出力ができる　といった感じ

#### -p：ポートのマッピング
* -p [ホストのポート]:[コンテナのポート]
``` -p 1234:5678```
ホストのポート1234とコンテナのポート5678を紐づける

#### --net：ネットワークの指定
* --net [ネットワーク名]
* ネットワークは下記コマンドで作成する
```docker network create [ネットワーク名]```

## 起動中のコンテナ内に入る
```docker exec -it [コンテナ名またはコンテナID] bash```

## コンテナの停止
```docker stop xxxxxx```

## イメージの作成 commit
* CONTAINER IDの確認
```
user01@DESKTOP-5FA6FSN:~$ docker ps -a
CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS                      PORTS                                       NAMES
cf6d7ae93d7d   ubuntu:20.04   "bash"                   24 minutes ago   Exited (0) 18 minutes ago                                               ruby_bash
```
* イメージ作成
```
user01@DESKTOP-5FA6FSN:~$ docker commit cf ruby:tag1
sha256:45994187050fe27b914c4fc3fe89a613514efc073b3cddfb933b41e486aae013
```
docker commit [コンテナID] [コンテナ名]:[タグ名]
コンテナIDはフル桁じゃなくても、一意になる桁までの指定でOK

* 確認
```
user01@DESKTOP-5FA6FSN:~$ docker images
REPOSITORY    TAG       IMAGE ID       CREATED          SIZE
ruby          tag1      45994187050f   2 minutes ago    156MB
```

## ログ参照
```docker logs [コンテナID、コンテナ名]```
* 使用例
```
$ docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED             STATUS             PORTS                 NAMES
8119a5ec7968   mysql:8.0.29   "docker-entrypoint.s…"   35 minutes ago      Up 35 minutes      3306/tcp, 33060/tcp   mydb
b2bb822da447   rubyimg:tag1   "bash"                   About an hour ago   Up About an hour                         dreamy_payne
$ docker logs mydb
2023-06-05 01:42:08+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.29-1.el8 started.
　：
$ docker logs 8119a5ec7968
2023-06-05 01:42:08+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.29-1.el8 started.
　：
```
## 小技的なコマンド
### 全てのコンテナIDの取得
```docker ps -aq```
#### 使用例
```
$ docker ps -a
CONTAINER ID   IMAGE          COMMAND                  CREATED         STATUS                     PORTS                                       NAMES
1f7f7e124bb9   hello-world    "/hello"                 7 seconds ago   Exited (0) 6 seconds ago                                               hungry_bohr
a1db76564eac   rubyimg:tag1   "ruby myapp.rb -o 0.…"   2 weeks ago     Exited (255) 2 weeks ago   0.0.0.0:4567->4567/tcp, :::4567->4567/tcp   cool_zhukovsky
$ docker ps -aq
1f7f7e124bb9
a1db76564eac
```

#### 応用例
* 全てのコンテナを削除する
```
$ echo $(docker ps -aq)
1f7f7e124bb9 a1db76564eac
$ docker rm  $(docker ps -aq)
1f7f7e124bb9
a1db76564eac
$ docker ps -a
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
```


# Dockerfileについて
* Dockerfileとは：イメージの構築手順をコード化したもの
* Dockerfielを利用する際のざっくりとした流れ
  * Dockerfile作成
  * イメージ作成（build実行）
  * 作成したイメージを実行してコンテナ起動
  
## Dockerfile内容説明
```
# ベースイメージを指定
FROM ubuntu:20.04

# イメージの構築をする際、実行するコマンド
RUN apt update
RUN apt install -y ruby ruby-bundler
```

## イメージ作成　build
* コマンド
```docker build -t img-ruby:tag1 .```
* コマンド解説
  * docer build:dockerのビルドコマンド
  * -t : TAGを指定するオプション
  * img-ruby ：任意のREPOSITORY名
  * tag1　：任意のTAG名
  * .　：（とりあえず）おまじない的なもの
* 作成したイメージの確認
```
$ docker images
REPOSITORY    TAG          IMAGE ID       CREATED          SIZE
img-ruby      tag1         b1e3e239a668   37 seconds ago   156MB
```
　
## イメージの起動
* イメージを起動（bashも）して、rubyのバージョン確認
```
$ docker run -it img-ruby:tag1 bash
root@91966cec694c:/# ruby -v
ruby 2.7.0p0 (2019-12-25 revision 647ee6f091) [x86_64-linux-gnu]
```


# ホストOSの環境とコンテナでのファイル共有（ボリューム、マウント）
* コンテナ内で作成したファイルは、コンテナを削除するとファイルも削除される
* ボリューム（マウント）機能を利用することで、ホストOS側とファイルの共有ができる

## ボリュームオプション -v
* イメージ起動時のコマンド
```docker run -it -v $PWD:/work/myapp -w /work/myapp my-ruby:dockerfile bash```

* コマンド解説
  * -v ：ボリュームオプション
  * ```$PWD:/work/myapp```：
    ホストの\$PWD（カレントディレクトリ）をコンテナの/work/myappに紐づける
  * -w ：コンテナ内のワークディレクトリ指定オプション
  * /work/myapp ：コンテナ内のワークディレクトリのパス

## 【補足】WSLとwindowsのファイル共有
* wslからは、```/mnt/[ドライブ名]``` でアクセスできる
* windows上でDockerfileを編集して。。。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281492/3354f015-f627-1f90-e788-899aaef4a272.png)
* wslからアクセス　ということができる
```
$ cd /mnt/c/tmp
$ ls
Dockerfile
```

# Dockerの構成イメージ
![tmp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281492/8e36b96f-0a8b-2d7a-53cf-8124534198d2.png)

# ネットワーク関連　ホストとコンテナ間
## portについて
* ホストとコンテナはネットワークが分離している
* portも別々なので、ホストとコンテナのportをマッピングする必要がある
* portのマッピングは docker run実行時に-pオプションで設定する
* -pオプションについては、上記の「基本的なコマンド－runコマンド」参照

## コンテナ内で立ち上げたWebServerにアクセスするまで
### 起動中のコンテナ内のbashに入る
* ```docker exec -it [コンテナID] bash```
### ネットワーク状況を確認
* ※ssコマンドについては、インストール済み→```apt install iproute2``` 
```
$ ss -antup
Netid                      State                        Recv-Q                       Send-Q                                             Local Address:Port                                             Peer Address:Port                      Process
tcp                        LISTEN                       0                            4096                                                   127.0.0.1:4567                                                  0.0.0.0:*                          users:(("ruby",pid=1,fd=5))
```
* "127.0.0.1:4567"について
ローカルホストのポート4567が動いている　という状態

### ホストからdockerプロセスの確認
```
$ docker ps
CONTAINER ID   IMAGE          COMMAND           CREATED         STATUS         PORTS     NAMES
857476638f03   rubyimg:tag1   "ruby myapp.rb"   6 seconds ago   Up 5 seconds             stupefied_perlman
```
* PORTS が空欄→ポートのマッピングがされていない
### コンテナとホストのportをマッピング
* 実行中のコンテナを止める　→```docker stop [コンテナID]```
* -p オプションでポートをマッピング
```
$ docker run  -v $PWD:/work/myapp -w /work/myapp -d -p 4567:4567 rubyimg:tag1 ruby myapp.rb
5383f6e79de0f368d057f6ac8131d70915b9bb47ae0b07cffc9f55eee69413a7
```
* 確認すると、"0.0.0.0:4567->4567/tcp"となっており、ホストの4567とコンテナの4567がマッピングされた状態となっている
```
$ docker ps
CONTAINER ID   IMAGE          COMMAND           CREATED          STATUS          PORTS                                       NAMES
5383f6e79de0   rubyimg:tag1   "ruby myapp.rb"   13 seconds ago   Up 12 seconds   0.0.0.0:4567->4567/tcp, :::4567->4567/tcp   zealous_wright
```

### コンテナに入りネットワーク情報を確認
* ```docker exec -it [コンテナID] bash```
* ネットワーク情報確認
```
# ss -antup
Netid                      State                        Recv-Q                       Send-Q                                             Local Address:Port                                             Peer Address:Port                      Process
tcp                        LISTEN                       0                            4096                                                   127.0.0.1:4567                                                  0.0.0.0:*                          users:(("ruby",pid=1,fd=5))
```
* " 127.0.0.1:4567"について
127.0.0.1はローカルホストのことだが、自分自身（コンテナ）内からの通信だけ受け付けるという意味らしい
* コンテナ内からのcurlは正常終了する（curlはインストール済み）
```
# curl http://localhost:4567
Hello world!
```

### 自分自身（コンテナ）以外からの通信も受け付けるようにする
* 起動中のコンテナを止める
* 下記コマンドでコンテナ起動
※ここで使用しているのはsinatraで、sinatraの場合は-o 0.0.0.0
```
$ docker run  -v $PWD:/work/myapp -w /work/myapp -d -p 4567:4567 rubyimg:tag1 ruby myapp.rb -o 0.0.0.0
```

### コンテナに入って、ネットワーク情報を確認
```
$ docker exec -it b bash
# ss -antup
Netid                      State                        Recv-Q                       Send-Q                                             Local Address:Port                                             Peer Address:Port                      Process
tcp                        LISTEN                       0                            4096                                                     0.0.0.0:4567                                                  0.0.0.0:*                          users:(("ruby",pid=1,fd=5))
```
* Local Address:Portが「0.0.0.0:4567」となり、外からの通信も受け付けるようになった

# ネットワーク関連 コンテナ間通信
* 以下の2つの方法がある
  * Dockerネットワークを作成
  * ```--link```オプション
* --linkオプションはレガシーらしく、Dockerネットワークが推奨されているらしい
* ここではDockerネットワークの説明をする
### ネットワークの作成
```docker network create [ネットワーク名] ```
### コンテナA,Bでの通信
* 以下の様に、実行時に--netオプションでネットワークを指定する。
→コンテナA,Bが、同じネットワークに属した状態となる
※ ネットワーク名：mynetで作成済みとする
  * コンテナA 
  ```
  docker run --name [コンテナ名A] <各オプション> --net mynet イメージA:タグA
  ```
  * コンテナB 
  ```
  docker run -- name [コンテナ名B] <各オプション> --net mynet イメージB:タグB
  ```
* コンテナAからコンテナBに対しての通信の設定を行う場合、ホスト名に[コンテナ名B]を設定する。

# コンテナ内から見た、ホストマシンのIPアドレスを確認する
### 事象（困ったこと）
* コンテナAで立ち上げたDBに、コンテナBで立ち上げたアプリケーションからlocalhostで接続できなかった。
* ローカルPCからは、コンテナAのDBにlocalhostでDB接続できていたので、コンテナBからもlocalhostで接続できると思っていた。

### 参考にした記事
* [Dockerコンテナの中からホストマシンのlocalhostに接続する方法](https://peblo.gs/get-host-machine-ip-address-in-docker-container/)

### 対応方法
* コンテナ内から見た、ホストマシンのIPアドレスを確認する
* コンテナBからはホストマシンのIPアドレスで接続する
* きっと他にも良い方法があると思う
### コンテナ内から見たホストマシンIPアドレスの確認方法
* コンテナ名の確認
```
docker ps -a
```

* コンテナ内に入る
```
docker container exec -it コンテナ名 bash
```

* ホストマシンIPアドレス確認
```
cat /etc/hosts | awk 'END{print $1}' | sed -e 's/[0-9]\+$/1/g'
```

# その他
* [DockerでPostgresql環境を作成し、Windowsから接続](https://qiita.com/bonny_d/items/8d59a043b93c5dff3e57)