Docker基礎 とりあえず触って覚えてみる

#1.Dockerのインストール#

##1-1.公式ページのとおりにインストールする##
[Get Docker CE for CentOS](https://docs.docker.com/install/linux/docker-ce/centos/)

###プロキシ###
なお、プロキシ環境下で docker run を実行したら、↓のようなエラーが表示されてしまうので、
![image.png](https://qiita-image-store.s3.amazonaws.com/0/280929/72e7231d-b59b-75c3-8b52-44c826fb498f.png)

プロキシ環境下で実行する際は、以下のページの対処が必要です。
[Control Docker with systemd](https://docs.docker.com/config/daemon/systemd/)

手順で必ず確認していきたいのは↓で設定反映されたことを必ず確認すること。

```console
6.Verify that the configuration has been loaded:

$ systemctl show --property=Environment docker
Environment=HTTP_PROXY=http://proxy.example.com:80/
```

##1-2.sudoなしにdockerを実行できるようにしておく##

```console
# dockerグループがなければ作成する。（おそらくある。）
$ sudo groupadd docker

# 現行ユーザをdockerグループに所属させる
$ sudo gpasswd -a $USER docker

# dockerを再起動する
$ sudo systemctl restart docker

# exitして再ログイン。
$ exit
```

これで、sudo なしで docker が実行できるようになった。

<br>

#2.docker runを実行してみる#


##2-1.Hello world の実行##

**docker run** でコンテナを実行する。
ここでは、ubuntu、centos のイメージを実行している。

```console
$ docker run ubuntu /bin/echo 'Hello world'
Hello world

$ docker run centos /bin/echo 'Hello world'
Hello world
```

Docker はまずホスト上にイメージがあるかどうか確認します。
イメージがローカルに存在していなければ、Docker Hub からイメージを pull します。

<br>

**docker images** で確認すると、イメージが出来上がっています。

```console
$ docker images
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/280929/1985ff0d-a851-83b4-b0e1-f604b0af335a.png)

2回目以降はホスト上にあるこのイメージから、docker run することとなる。

<br>

Docker コンテナが実行されていたのは、指定したコマンドを処理していた間のみです。
この例では、コマンドを実行したのち、直ちにコンテナが停止しました。
**docker ps -a** を実行すると、STATUS が Exited です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/280929/73aeff9f-f4b7-7e8c-1dd9-fc012ddfe56f.png)

<br>

##2-2.インタラクティブなコンテナを実行##

**docker run** でコンテナを実行し、
**-t** で tty (端末デバイス)を使い、
**-i** で コンテナの標準入力を聞く。
ここでは、ubuntu のイメージを実行している。

```console
$ docker run -t -i ubuntu /bin/bash
```

適当に、**pwd** や **ls** などで中身を確認し、**exit** で終了しておきます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/280929/e13af11d-0f49-db25-1979-ae0ee8b299cc.png)

先ほど作成したコンテナと同様に、Bash シェルのプロセスが終了すると、コンテナは停止します。
**docker ps -a** で確認すると、STATUS が Exited です。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/280929/3d7feaf4-da6c-97d7-a01c-7b2f1529dabc.png)

<br>

##2-3.Docker 化した Hello world の起動と停止##

**docker run** でコンテナを実行し、
**-d** でバックグラウンドで実行する。

```console
$ docker run -d ubuntu:14.04 /bin/sh -c "while true; do echo hello world; sleep 1; done"
```

**docker -ps** で確認すると、STATUS は Up で実行されている。
NAMES は fervent_banzai というもので作成されています。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/280929/b83ea00f-a7c1-ac5c-f309-db1d8e499dfb.png)

実際に実行されているか確認するには、**docker logs** で確認していきます。

```console
$ docker logs fervent_banzai
hello world
```

次ぎに、**docker stop** で停止してみましょう。

```console
$ docker stop fervent_banzai
fervent_banzai
```

**docker ps -a** で停止されたか確認してみます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/280929/51956110-1aae-b372-e4e8-03b362cd0a58.png)

<br>

#3.アプリケーションの実行#

##3-1.Docker で python app.py を実行する##

**docker run** でコンテナを実行し、
**-d** でバックグラウンドで実行、
**-P** でコンテナ内部のネットワークで必要なポートを、ホスト側にマップさせる。
training/webapp イメージを指定し、コンテナに対して python app.py を実行する。

```console
$ docker run -d -P training/webapp python app.py
```

**docker ps -l** で実行されていることを確認しておきます。
今回の場合、Docker はコンテナのポート 5000 をホスト上のポート 32768 上に公開しています。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/280929/849def89-8cd6-0395-ad1d-56d5073bec5a.png)


##3-2.割り当てポートを確認する##

以下の方法でも割り当てポートを確認することができます。

```console
$ docker port コンテナ名
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/280929/7960e50b-2f18-f9ec-89de-7cc894292e45.png)


ローカルホスト上のポート 80 を、コンテナ内のポート 5000 に割り当てる場合は以下の通りです。

```console
$ docker run -d -p 80:5000 training/webapp python app.py
```

なお、ローカルホスト上の各ポートに 1:1 で割り当て可能なポートは１つだけです。
例えば、２つの Python アプリケーションを実行したいとします。
いずれもコンテナの中でポート 5000 を使うものです。この場合 Docker のホスト上で、ポート 5000 にアクセスできるコンテナは常に１つだけです。

ちなみに、ポートが既に使われていた時は↓のようなエラーが表示されます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/280929/3179e86d-4c2e-3087-7f54-989af4924212.png)


##3.3 プロセスを確認する##

**docker top** で動作しているプロセスを確認できます。

```console
$ docker top コンテナ名
```

python app.py コマンドが実行されているのがわかります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/280929/e4bddffc-1342-8001-64e5-f2f76def71d5.png)

##3.4 情報を確認する##

**docker inspect** で構成情報やステータス情報を、JSON 形式で取得します。

```console
$ docker inspect コンテナ名
```

##3.5 コンテナを削除する##

**docker stop** で停止してから、**docker rm** で削除する必要があります。

```console
$ docker stop  コンテナ名
$ docker rm コンテナ名
```



#4.docekerイメージを構築する#

##4.1 docekerイメージのダウンロード##

docekerイメージを予めダウンロードしておく場合は、**docker pull** を使います。
以下は、centos:6 のイメージです。

```console
$ docker pull centos:6
```

##4.2 docekerイメージの検索##

イメージは、[Docker Hub](https://hub.docker.com/search/?q=&type=image) にアップロードされています。

**docker search** で検索することもできます。

```console
$ docker search 検索文字列
```

STARS はイメージがソーシャル上で有名かどうか測るものです。

##4.3 ユーザーdocekerイメージのダウンロードと実行##

**docker pull** で training/sinatra をダウンロードし、**docker run** でコンテナを実行してみましょう。
ubuntu や centos はDocker 社によって提供、構築、認証、サポートされています。
下記は、training ユーザーによって作成された sinatra です。

```console
$ docker pull training/sinatra
$ docker run -t -i training/sinatra /bin/bash
```

##4.4 docker commitでイメージを変更する##

gemを追加し、**exit**で終了。

```console
$ root@f6c7a45449bd:/# gem install json
$ exit
```

こんなエラーになった場合は、
![image.png](https://qiita-image-store.s3.amazonaws.com/0/280929/60b734c8-aa28-2854-4f18-868305b8d811.png)
プロキシを通せば行けた！

```console
$ gem install パッケージ名 -r -p http://your.proxy.hostname:port番号
```

これで変更したコンテナができましたが、次に、
**docker commit** でイメージに対してこのコンテナのコピーを収容し、
**-m** で、コミット・メッセージを指定し、
**-a** で、更新した担当者を書きます。

```console
$ docker commit -m "Added json gem" -a "naoki-s" \
f6c7a45449bd naoki-s/sinatra:v2
```

**docker images** を見ると naoki-s/sinatra:v2 のイメージが出来上がっています。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/280929/69df415b-8122-1c7d-ce50-ddd7b294a8df.png)

作成されたイメージで **docker run** でコンテナを作成するには、次のとおりです。

```console
$ docker run -t -i ouruser/sinatra:v2 /bin/bash
```

##4.5 docker buildでイメージを構築する##

元となる Dockerfile を作成します。

```console
$ mkdir sinatra
$ cd sinatra
$ touch Dockerfile
$ vim Dockerfile
FROM ubuntu:14.04　#Docker に対して基となるイメージを伝える。
MAINTAINER aaa <abc@example.com>　#誰がこの新しいイメージを管理するか。
RUN apt-get update && apt-get install -y ruby ruby-dev #APT キャッシュを更新しRuby と RubyGem をインストール
RUN gem install sinatra #Sinatra gemをインストール
```

**docker build** を使い、Dockerfile から独自のイメージをビルドします。

```console
$ docker build -t naoki-s/sinatra:v2 .
```

あとは、新しいイメージからコンテナを作成できます。

```console
$ docker run -t -i naoki-s/sinatra:v2 /bin/bash
```

##4.6 docker tag でタグを設定する##

**docker tag**を使います。↓はv100に変更しています。

```console
$ docker tag 5cafcb57cba1 naoki-s/sinatra:v100
```

**docker images** で変更されていることを確認してみてください。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/280929/07fa3676-00c8-6876-79b7-a0e3c8e9fca8.png)

##4.7作成したイメージを Docker Hub に送信##

イメージを構築・作成したあとは、**docker push** で Docker Hub に送信できます。

```console
$ docker push naoki-s/sinatra
```

##4.8作成したイメージを Docker Hub に送信##

イメージの削除には、**docker rmi** を使います。 

```console
$ docker rmi naoki-s/sinatra
```

なお、**docker rm** で先にコンテナを削除しないと、↓のようなエラーが表示されてしまう。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/280929/89aa576f-f06e-5b5d-b033-fba206666e07.png)



#5.コンテナのネットワーク#

##5.1 コンテナに名前を付ける##

**--name** オプションを使います。下記はwebというコンテナ名をつけています。

```console
$ docker run -d -P --name web training/webapp python app.py
```

**docker ps** や **docker inspect** で確認してみましょう。

```console
$ docker ps
$ docker inspect web
```

なお、同じコンテナ名はもちろん使えません。


##5.2 デフォルトのネットワーク##

Docker Engine は、自動的に３つのデフォルト・ネットワークをインストールします。
**docker network ls** で確認してみましょう。

```console
$ docker network ls
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/280929/cdf052e5-84c5-f4b5-118c-c3c75c6e0dd7.png)

特に指定しなければ、Docker は bridge で常にこのネットワーク上にコンテナを起動します。

**docker run** で、networktest というコンテナを作成しておき、**docker network inspect** で中身を見てみましょう。

```console
$ docker run -itd --name=networktest ubuntu
$ docker network inspect bridge
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/280929/b8779de7-fdb5-26b2-7936-6e547ab97679.png)

コンテナをネットワークから切断しようとしても、 bridge という名前で組み込まれている ブリッジ ネットワークを削除できません。


##5.3 ブリッジ・ネットワークを作成する##

次の例は、ブリッジ・ネットワークの作成です。

**docker network create** で作成します。 
**-d** で新しいネットワークで使用する bridge ドライバを指定します。
bridge2 という名前で作成されています。

```console
$ docker network create -d bridge bridge2
```

**docker network ls** で確認してみます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/280929/43fdbdcc-b95e-1080-cb9d-812c33a769aa.png)

この状態では、コンテナはまだ存在していないので次で作成していきます。


##5.4 ネットワークにコンテナを追加する##

先程作成したネットワークにコンテナを追加してみたいと思います。

**docker run** で、
bridge2 のネットワークを指定し、
db というコンテナを作成します。

```console
$ docker run -d --net=bridge2 --name db training/postgres
```

**docker inspect** で確認すると、bridge2 に所属していることがわかります。

```console
$ docker inspect db
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/280929/522203e8-5e49-9eea-d90e-81e0a7428e30.png)


##5.5 docker exec でプロセスを実行する##

**docker run** で、
web というコンテナを作成しておいてください。
ネットワークは指定しないので、デフォルトの bridge に作成されます。

```console
$ docker run -d --name web training/webapp python app.py
```

**docker inspect** でwebコンテナのIPアドレスを確認しておきます。

```console
$ docker inspect web
```

下準備はできたので、ここからが本題です。
**docker exec** でシェルを開き、webコンテナの 172.17.0.3 へ ping を実行してみます。

```console
$ docker exec -it db bash
root@a205f0dd33b2:/# ping 172.17.0.3
```

もちろん、応答しません。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/280929/f1ee8267-d051-c64c-7f49-37f1a4a62f31.png)

必要に応じてコンテナに対して多くのネットワークをアタッチできます。

webコンテナには、bridge というネットワークしか今は存在しませんが、**docker network connect** で追加していきます。

```console
$ docker network connect bridge2 web
```

同様に ping を実行しますが、今回はIPアドレスではなく、Dockerコンテナ名を指定します。

```console
$ docker exec -it db bash
root@a205f0dd33b2:/# ping web
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/280929/6e24287e-ef5b-e47a-c9b3-951df85d1981.png)

このとおり実行できたのがわかります。


#6.コンテナでデータ管理をする#

データ・ボリュームとは、ディレクトリのことです。データ・ボリュームは、データを保持するために設計されています。
したがって、コンテナの削除時、Docker は決して自動的にボリュームを消しません。コンテナから参照されなくなっても後片付けをせず、ボリュームはそのままとなります。


##6.1 データ・ボリュームを追加する##

**docker create** か **docker run** で、
**-v** でコンテナにデータ・ボリュームを追加します。
webコンテナを作成し、/webapp という新しいボリュームを作成しています。

```console
$ docker run -d -P --name web -v /webapp training/webapp python app.py
```

**docker inspect** でボリュームの場所を確認できます。

```console
$ docker inspect web
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/280929/135cd1f3-f56a-cd7b-9545-fa7a6f5f08fc.png)
Source がホスト、Destination がコンテナ内のボリューム指定、RW はボリュームの読み書き可能を意味します。


##6.2 データ・ボリュームとしてホスト上のディレクトリをマウントする##

**-v** はホスト上にあるディレクトリも、コンテナにマウント可能です。

ホスト側のディレクトリ /svc/webapp をコンテナ内の /opt/webapp にマウントする例です。

```console
$ docker run -d -P --name web -v /svc/webapp:/opt/webapp training/webapp python app.py
```


##6.3 共有ストレージをデータ・ボリュームとしてマウントする##

いくつかの Docker ボリューム・プラグイン は iSCSI、NFS、FC のような共有ストレージにプロビジョニングやマウントが可能です。

共有ボリュームを使う利点は、ホストに依存しない点です。
共有ストレージ・バックエンドにアクセス可能なホストと、プラグインさえインストールしておけば、コンテナがどこで動いてもボリュームを利用可能です。

**--volume-driver** には flocker をを使い、
**-v** で naoki-s-volume というボリュームを作成しています。

```console
$ docker run -d -P \
  --volume-driver=flocker \
  -v naoki-s-volume:/opt/webapp \
  --name web training/webapp python app.py
```

もしくは、
**docker volume create** でボリュームを作成し、
**-d** で flocker のドライバーを指定。

```console
$ docker volume create -d flocker --name naoki-s-volume -o size=20GB
$ docker run -d -P \
  -v naoki-s-volume:/opt/webapp \
  --name web training/webapp python app.py
```


##6.4 ホスト上のファイルをデータ・ボリュームとしてマウントする##

**-v** はホストマシン上のディレクトリだけではなく、単一のファイルに対してもマウント可能です。

新しいコンテナ内の bash シェルを流し込む。
**--rm** でコンテナ終了時は、ホスト上の bash 履歴に対し、コンテナ内で実行したコマンドを履歴として記録する。

```console
$ docker run --rm -it -v ~/.bash_history:/.bash_history ubuntu /bin/bash
```


##6.5 データ・ボリューム・コンテナの作成とマウントする##

データに永続性を持たせたい場合、名前を付けたデータ・ボリューム・コンテナを作成し、そこにデータをマウントするのが良い手段です。

**docker create -v** で /dbdata ボリュームを持ち、
**--name** で共有するための新しい名前付きコンテナ dbdata を作成します。
イメージは training/postgres を利用し、
全てのコンテナから利用可能なレイヤを作成します。

```console
$ docker create -v /dbdata --name dbdata training/postgres /bin/true
```

**--volumes-from** で 他のコンテナから /dbdata ボリュームをマウント可能にします。

```console
$ docker run -d --volumes-from dbdata --name db1 training/postgres
$ docker run -d --volumes-from dbdata --name db2 training/postgres
```

ボリュームのマウントは連鎖できます。
先に作成した、db1 から db3 を作成している例です。

```console
$ docker run -d --name db3 --volumes-from db1 training/postgres
```


##6.6 データ・ボリュームのバックアップ・修復・移行する##


新しいコンテナを起動し、dbdata コンテナからボリュームをマウントします。
ローカルのホスト上のディレクトリを /backup としてマウントします。
最終的に、tar コマンドで dbdata ボリュームに含まれる内容をバックアップします。

```console
$ docker run --volumes-from dbdata -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata
```

新しいコンテナを作成します。
新しいコンテナのデータ・ボリュームにバックアップしたファイルを展開します。

```console
$ docker run -v /dbdata --name dbdata2 ubuntu /bin/bash
$ docker run --volumes-from dbstore2 -v $(pwd):/backup ubuntu bash -c "cd /dbdata && tar xvf /backup/
```


##6.7 ボリュームを削除する##

Docker データ・ボリュームはコンテナを削除しても残り続けます。**rm** で削除します。

**-v** で/foo ボリュームを作成し、
**--rm** でコンテナを削除時、Engine は /foo ボリュームを削除しますが、 awesome ボリュームは削除しない。

```console
$ docker run --rm -v /foo -v awesome:/bar busybox top
```


#7 Docker Hubを利用する#

##7.1 アカウントを作成する##

[Docker Hub](https://hub.docker.com/account/signup/)

##7.2 ログインする##

```console
$ docker login
Username
Password
```

##7.2 イメージを検索する##

**docker search** でここでは、centos を検索。

```console
$ docker search centos
```

##7.3 イメージをダウンロードする（pull）##

先程の **docker pull** で　centos をダウンロード。

```console
$ docker pull centos
```

バージョンの指定がない場合は、latest（最新）でダウンロードされる。

バージョンを指定して、ダウンロードをしたい場合は以下のとおり。

```console
$ docker pull centos:centos5
```

##7.4 イメージをダウンロードする（push）##

```console
$ docker push username/centos:latest
```

これで、同僚やコミュニティにおいても利用可能になります。


##7.5 プライベート・リポジトリ##

**プライベート・リポジトリ**
イメージを一般公開せずに、プライベートにする。

**組織とチーム**
プライベート・リポジトリは、組織で特定メンバーのみとの共有することができます。


---
はじめて触る方には[入門 Docker](https://y-ohgi.com/introduction-docker/3_production/design/)もおすすめです。ベストプラクティスについてもよく書かれており、よい練習となります。