【Docker】初めてのdockerでimageまで作成

https://docker-curriculum.com/
ここを読んで覚えていったことを書いていってます！

他参考サイト
http://docs.docker.jp/engine/userguide/dockerizing.html

バックエンド寄りなことも知っとかないとな〜と日々思うので、
まずはdockerについて学習してみます。

##dockerのすごいところ！
Virtual Boxなんかより軽い。
そもそもの構成が違うみたい。ここでは深くは触れない。
https://qiita.com/supaiku2452/items/8b06b774c0e2fce7df92
この辺が参考になりました。

##Hello world!（ダウンロード〜動作確認）

まずはdockerをダウンロード
Mac https://docs.docker.com/docker-for-mac/install/
Windows https://docs.docker.com/docker-for-windows/install/
Linux https://docs.docker.com/install/linux/docker-ce/ubuntu/

ダウンロードが終わったらMacだとターミナルを開いて

```
docker run hello-world
```
を入力すると、

```
Hello from Docker.
This message shows that your installation appears to be working correctly.
...
```
と表示されたらうまくいってます。

##dockerの用語と簡単な仕組み
ざっくりと。

**container** ・・・dockerがアプリケーション起動を動かしてくれる仮想環境の一つの枠組み
**image**　・・・そのコンテナを起動する際に使う、コンテナの設計が書かれている
**docker daemon**　・・・containerを管理・制御してる
**docker client**　・・・そのdocker daemonとのやりとりを可能にしてくれるコマンドラインツール
**docker hub**　・・・imageが登録されている、imageのディレクトリのようなもの

流れとしては、docker hubからimageをpullする（持ってくる）
そのimageをもとにcontainerを作る
という感じ。

##早速コンテナを扱ってみる

まず、コンテナの元となるimageをdocker hubからpullします。
今回は`busybox`を引っ張ってみます。

```
docker pull busybox
```

コンテナを生成して起動する

```
docker run busybox
```

一見何も動いてないようですが、コマンド等を渡してないから起動しただけで何も実行されなかったということみたいです。

```
docker run busybox echo "hello from busybox"
```

これを入力するときちんと`echo` が実行されているのがわかります。


`docker ps`コマンドで現在起動されているコンテナ一覧が表示されています。
今動いていないコンテナも表示する場合は`-a`オプションをつけます。

```
docker ps -a
```

コンテナの中に入って色々実行したい場合は

```
docker run -it busybox sh
```

です。`-i`と`-t`オプションをつけることで、コンテナ内部のコマンドラインを操作できるようになります。
オプションやらコマンドやらで困ったら`--help`を使います。

```
docker run -- help
// 以下オプション等の説明がずらっと出力される
```

##コンテナを削除する
このまま`run`でコンテナを生成しまくっていたらメモリに限界がきます。
`docker ps -a`で削除したいコンテナIDを確認して、以下のコマンドでコンテナを削除します。

```
docker rm 305297d7a235(削除したいコンテナのdocker id)
```

複数削除もできますが、毎度docker idをコピーしてくるのも面倒です。そんな時は以下のコマンド

```
docker rm $(docker ps -a -q -f status=exited)
```

`-q`でidの数字だけを表示、`-f`で特定のステータスだけのコンテナをフィルターできます。
この場合はステータスがexitedのコンテナIDを全て表示し、一括削除しています。
新しいバージョンのdockerだったら、以下のコマンドで同じ挙動になります。楽チン！

```
docker container prune
```

ちなみに、いちいち削除するのが面倒な場合は、実行後自動でコンテナを削除してくれる便利な`--rm`というオプションもあります。

```
docker run --rm (任意のimage) 
```


##imageの一覧確認と削除

一覧表示

```
docker image
```

必要なくなったimageを削除したい場合は

```
docker rmi 305297d7a235(削除したいimageのimage id)
```

imageの一括削除もできます！（コメントで教えていただきました）
タグ付けされておらず、コンテナから参照されていないimageが削除対象です。

```
docker image prune
```

##静的サイトを実行する

>Let's begin. The image that we are going to use is a single-page website that I've already created for the purpose of this demo and hosted on the registry - prakhar1989/static-site. 

https://docker-curriculum.com/
の方で元となるimageを準備してくれてます。

こちらのコマンドで起動しましょう。

```
docker run --rm prakhar1989/static-site
```

ちなみに今回のように、ローカルにimageがない状態でrunすると、自動でimageを引っ張ってくれるみたいです。
`Nginx is running...`が表示されたら成功です。
....それで、どうやってサイトをみるんでしょうか。
これでは実はポートが発行されていません。`Ctrl + c`で一旦コンテナを停止させます。

まず、サイトを起動するにあたって便利な**デタッチモード**というものがあります。これはコンテナに入らずバックグラウンドでコンテナを起動させることができるモードです。何が嬉しいかというと、ターミナルを閉じててもコンテナを起動し続けることができる点です。オプション`-d`でデタッチモードになります。

そして`-P`オプションでランダムなポートに公開します。
仕上げに`--name　名前`オプションでコンテナに名前をつけます。

```
docker run -d -P --name static-site prakhar1989/static-site
```

これでポートを見に行けるようになってるはずです。

```
docker port static-site
```

そうすると以下のレスポンスが返ってくるので、ブラウザで見にいって表示できたら成功です。
この場合は, http://localhost:32769/ になります。

```
80/tcp -> 0.0.0.0:32769
443/tcp -> 0.0.0.0:32768
```

↓ブラウザに表示された状態
![スクリーンショット 2019-10-25 16.33.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/441432/488eeffd-4026-0bd8-aebe-1bc93571f136.png)


特定のポートを指定することももちろんできて、それには小文字の `-p 指定するポート`
でいけます。

```
docker run -p 8888:80 prakhar1989/static-site
```

デタッチモードで開いたコンテナを停止させる場合は`docker stop`で停止させます。

```
docker stop static-site
```

ここまでで人通り用意されたimageからの操作はバッチリです！
次は自分でimageを作れるようになってみたいですね。

##Docker images
dockerのイメージには二種類ある。
**Base image**　・・・・　コンテナのベースになる。大体 ubuntuやbusyboxなどのようにOSっぽいもの
**Child image** ・・・・  base image上でbuildされて、色々機能を追加してくれるもの

あとは以下の分類法もある。
**official image** ・・・・dockerが提供してるっぽい。基本的に１単語。`python` `ubuntu` `hello-world`など
**user image**  ・・・・一般の人が作ったもの。 基本的に`user/image-name`という感じの名前


とimageの種類を作ったところで、自分のimage作りにチャレンジしてみます。
簡単なFlaskのアプリケーションを作ります。猫がランダムに表示されるアプリらしいです🐈
（Pythonのフレームワークです。私はPythonをやったことないけどこのドキュメントにしたがってみます）

以下のコマンドを打ち込みます。（注意：コンテナの中で実行じゃないよ）

```
git clone https://github.com/prakhar1989/docker-curriculum.git
cd docker-curriculum/flask-app
```

これは言語がpythonなので、base imageは`python:3-onbuild`を使用します。
onbuild　について何ですが、dockerfileを使うことで色々便利になるバージョン指定、ということが書かれています。

>onbuild version of the image includes helpers that automate the boring parts of getting an app running. Rather than doing these tasks manually (or scripting these tasks), these images do that work for you. We now have all the ingredients to create our own image - a functioning web app and a base image. How are we going to do that? The answer is - using a Dockerfile.


###Dockerfileって何よ
イメージを作るときに使う命令なんかをやってくれる便利テキスト。
Linux commandと書き方がほぼ同じらしい。
先ほどクローンしてきた**flask-app**ディレクトリの中に、`Dockerfile`という名前でファイルを作ります。
（このディレクトリではすでにDockerfileの記述がしてありますが、一から作る練習もかねて削除します。）
ファイル作成(flask-app内で）

```
touch Dockerfile
```

それではDockerfileの中をいじっていきます。
エディター等で開いて、次の一行を追加して`Base image`を指定します。

```dockerfile:Dockerfile
FROM python:3-onbuild
```

`FROM`で`Base image`を指定できるんですね。
次は使うポート番号を指定します。今回は5000を使います。

```dockerfile:Dockerfile
EXPOSE 5000
```

次は`CMD`を書きます。
`CMD`は`docker run`する時のコンテナ作成時に実行されるんだとか。

```dockerfile:Dockerfile
CMD ["python", "./app.py"]
```

上記によって`$ python app.py`が走ります。

まとめるとDockerfileは以下の内容になります。

```dockerfile:Dockerfile
FROM python:3-onbuild
EXPOSE 5000
CMD ["python", "./app.py"]
```

これでDockerfileは完成です！
あとはビルドすればimageが作れます。
以下のコマンドをflask-app内で実行します。

```dockerfile:Dockerfile
docker build -t （自分のdocker hubID）/catnip .
```
`-t　タグ名`で任意のタグの名前をつけることができます。

これでイメージができました！
あとは以下でimgageを実行します。

```
docker run -p 8888:5000 （自分のdocker hubID）/catnip
```

http://localhost:8888/ をみに行くと、ランダムな可愛い猫ちゃんのgifが流れてきます！


##終わりに
一通りのコンテナの扱いや、imageの作り方を覚えることができました！
でもまだまだ環境に合わせてカスタマイズする方法などはわからないので、次回もチュートリアルをみつつdockerを学んでいければと思います！