Dockerとコンテナの概要

## この記事に関して
社内の若手勉強会用に作成しました
できるだけ簡単に、概要の理解、環境構築、実際に動作させるところまで説明しています

## 環境
* Windows 10
* Docker for Windows 2.3.0.4 stable edition
* 認証proxyが存在（項目をわけているので、proxyが無い方はとばせばOK）

## Dockerとコンテナの概要
### コンテナとは
仮想化技術の1つ

### Dockerとは
下記に示すコンテナエンジンの1つ

### 従来の仮想化（ハイパーバイザ型）とコンテナの違い
* コンテナはホストのOSのカーネルを共有するため、リソースの使用率が低く、起動が早い
* 依存関係をコンテナ内にパッケージ化することができる<br>
→コンテナ化されたアプリケーションは別環境でも実行することができる（可搬性）<br>
　従来のハイパーバイザ型では、別環境で動かす際、素材の入手と手動での環境構築が必要だった
![image2021-1-6_18-26-54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298390/c1ba97ea-1654-53f3-e9e3-cb1e7372c84c.png)

### OSとOSカーネルの話
* OSカーネル
    * ソフトウェアとハードウェアの仲介を行うOSの中でもメインの役割を担うもの。
    * 有名なカーネルとしてはLinux、Windowsカーネル(?)がある
* OS
    * カーネルの上に、ソフトウェア(UI,ドライバ、開発者ツール等)を乗せたもの
    * Linuxカーネルも、ソフトウェアによってUbuntu、CentOS、RHELといったOSに分かれる
    
    ![image2021-1-6_19-10-26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298390/cfc96244-fde2-0ab9-be09-d2564474a55b.png)


## Docker for Windowsの環境構築
### Hyper-Vの有効化
DockerをWindowsで動かすには、Hyper-Vの有効化が必要となるため、
下記コマンドを管理者権限で開いたpowershellで実行し、
Hyper-Vの有効化を行う（PCの再起動が必要となる）

```
>Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All
```

再起動後、BCDEdit※にてHyper-Vが有効になっているか確認する
powershellで下記コマンドを実行し、
`hypervisorlaunchtype  Auto`で出力されていたら有効化に成功している

※ブート構成データ (BCD) を管理するためのコマンドラインツール

```console
bcdedit /enum | find '"hypervisorlaunchtype"'
```

offだった場合、下記コマンドを実行し、もう一度再起動を行う。

```console
bcdedit /set hypervisorlaunchtype auto
```

### docker for windowsのインストール&セットアップ
Docker for Windows（2.3.0.4 stable edition）を下記リンクから入手する
https://docs.docker.com/get-docker/

インストール後に再起動を行う
再起動後、Dockerを起動するとDockerのスタートアップ手順が表示される
インストール完了後、画面右下のインジケーターにdocker for windowsが追加される

イメージやコンテナの起動に、メモリをかなり必要とするため
[Setting]→[Resources]からメモリ割り当てを2GBから4GBに変更する


<details><summary>下記はproxy認証が必要な方のみ</summary><div>

[Setting]→[Resources]→[PROXIES]に下記設定を入力する。
・http://<ユーザー名>:<パスワード>@プロキシホスト名:プロキシポート番号/　を設定する

</div></details>

### なぜコンテナなのにHyper-V(ハイパーバイザ)が必要なのか

Hyper-Vはハイパーバイザで、コンテナでは必要ないのでは？と思うかもしれない
これはDockerコンテナはLinuxがベースとなっており、Linuxカーネルが必要になるためである
Docker for WindowsはWindowsOS上にHyper-VでLinuxOSをたて、
そのHyper-V上のLinuxカーネルをコンテナで共有している

![image2021-1-6_19-33-42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298390/3b9959fe-56a5-dcc0-26f8-2a871cbf792c.png)

Dockerの動作環境さえ整えてしまえば、あとは好きなコンテナを動作させることができる
コンテナはDocker Hub(※後述)というネット上の管理場所から取得することができる
このとき、コンテナはコンテナイメージというスナップショットのような形式で配布されている
イメージ取得後、実行することでコンテナとして動作させることが可能となる

## Dockerの操作
### DockerHub
コンテナイメージは主にDocker Hubというネット上の管理場所から取得することができる
イメージの検索のみならユーザ登録無しで可能
ここでイメージ名、提供元、最新のバージョン等を確認することができる。
https://hub.docker.com/

### Dockerイメージの取得～コンテナの実行

docker for Windowsを入手すると、コマンドプロンプトからdockerコマンドが実行できるようになる
実際にalpineという軽量なlinuxのイメージをdocker hubから取得し、実行する

```console

>docker pull alpine:latest
latest: Pulling from library/alpine
801bfaa63ef2: Pull complete                                                                                                                                                                                                                  Digest: sha256:3c7497bf0c7af93428242d6176e8f7905f2201d8fc5861f45be7a346b5f23436
Status: Downloaded newer image for alpine:latest
docker.io/library/alpine:latest
 
>docker images
REPOSITORY                           TAG                    IMAGE ID            CREATED             SIZE
alpine                               latest                 389fef711851        2 weeks ago         5.58MB
 
>docker run -it  -d  alpine:latest  /bin/sh
 
>docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
c3a9d3cc09f4        alpine:latest       "/bin/sh"                6 seconds ago       Up 3 seconds                                 loving_mendeleev
 
docker exec -it c3a9d3cc09f4 /bin/sh
/ # ls
bin    dev    etc    home   lib    media  mnt    opt    proc   root   run    sbin   srv    sys    tmp    usr    var
/ # exit
```

各コマンドの説明は下記の通り

* docker pull <イメージ名：タグ名>
    * docker hubからイメージを取得している
    * イメージのバージョンをタグで指定する、指定しない場合は自動的にlatest(最新版)になる
* docker images
    * ローカルに保存しているイメージの一覧が確認できる
* docker run [オプション] <イメージ名> コマンド
    * dockerイメージをコンテナとして起動している
    * -itオプションを付与することで、コンテナで標準入出力を行えるようになる
    * またコマンドでログイン時に動かすコマンドの指定ができる
    * /bin/shではシェルを起動して、dockerにアクセス後コマンド入力できるようになっている
    * -dはバックグラウンドで起動することを指定している
* docker ps
    * 稼働しているコンテナの一覧を取得する
* docker exec [オプション] <コンテナ名> コマンド
    * 起動しているコンテナの中に入る
    * exitでコンテナから出ることができる

![image2021-1-7_10-47-17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298390/3a882dad-3d2d-aaa4-4475-1cd075fd2203.png)

### Dockerfile

実際にコンテナを作成する際、ベースイメージに加え
必要なミドルウェアやアプリを乗せてコンテナを作成することが多い
起動したコンテナの中に入って操作することも可能だが、
Dockerfileとして構成を作成すると、
セットアップや資源のコピーを自動で実施できるようになる

### Dockerfileを使用したWebサーバコンテナの起動
簡単なWebサーバーコンテナを作成する例を示す


```Dockerfile:Dockerfile
#Webサーバnginxのイメージを使用する
#ここで指定したイメージをdockerhubからpullする
FROM nginx:alpine
#ADDでローカル端末からコンテナ環境へ素材のコピーができる
#/usr/share/nginx/htmlはnginxで表示するhtmlを格納する場所
ADD ./index.html /usr/share/nginx/html
#コンテナ内の80ポートを解放
EXPOSE 80
#コンテナのエントリーポイントを設定する
ENTRYPOINT /usr/sbin/nginx -g "daemon off;" -c /etc/nginx/nginx.conf
```



```html:index.html
hello world,Docker
```

上記ファイルを作成後、保存したディレクトリで下記コマンドを実行していく

作業フォルダ/   ◀ここでコマンドプロンプト起動
├ Dockerfile
└index.html

```console
>docker build -t myimage .
Sending build context to Docker daemon  4.096kB
Step 1/5 : FROM nginx:alpine
 ---> 629df02b47c8
Step 2/5 : CMD echo "now running..."
 ---> Using cache
 ---> 2b4f225ff66e
Step 3/5 : ADD ./index.html /usr/share/nginx/html
 ---> Using cache
 ---> 8de80809c52c
Step 4/5 : EXPOSE 80
 ---> Using cache
 ---> 90168e587d3b
Step 5/5 : ENTRYPOINT /usr/sbin/nginx -g "daemon off;" -c /etc/nginx/nginx.conf
 ---> Running in eb60ad7be198
Removing intermediate container eb60ad7be198
 ---> d4d131ab1d24
Successfully built d4d131ab1d24
Successfully tagged myimage:latest
 
>docker run --name mycontainer -d -p 30080:80 myimage
```

* docker build -t <イメージ名> パス
    * Dockerfileの内容を元にイメージを生成する
    * -tは作成するイメージに名称を付けるためのオプション
    * イメージ名は自由に設定可能
    * パスではbuildに使用するDockerfileのパスを指定する
    * 今回はカレントに保存しているので【.】を指定
* docker run --name <コンテナ名> -d -p 30080:80 <イメージ名>
    * イメージ名を元にコンテナを作成する
    * --nameはコンテナに名前を付けるオプション
    * -pはコンテナのポートをホストに公開する設定
    * Dockerfileにてコンテナの80ポートを解放し、
    * ホストの30080ポートに接続するとコンテナの80ポートにつながるようになっている
コンテナ起動後、アクセスしてみるとwebサーバが起動しており先ほど作成したhtmlが表示された

![image2021-1-7_14-34-30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298390/ece50739-1f60-5b65-5e8a-4f8d00b1d2ca.png)
![image2021-1-7_14-42-59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298390/738465ba-e1b3-35f0-be45-96b8840c4f39.png)

#### 実際にコンテナを使ってみた感想
現在所属するプロジェクトでは、様々な技術を使用しているため
逐一環境構築するのが大変だったが、Dockerを使用すると、
Dockerfileを生成し、ソースリポジトリに入れておけば
メンバが各々コンテナ環境を作成して手を動かせるので非常に有用だと感じる
実際にはdocker-composeという複数コンテナを立てられる技術を使用しているのだが
力尽きたので別記事を参照ください
また、実際に運用するとなるとk8s等のオーケストレーションツールの活用が必須だが
フィジビリティ確認等軽く動かす程度ならこの程度の知識で十分だと思った