Docker

1.Dockerについて

(1)すごいの?

サーバ構築などが非常に簡単。たとえば、1行でWebサーバが構築できてしまう。

docker run --name ct1 -d -p 8080:80 nginx

もちろん、その前にDockerをインストールしてサービスを起動する必要がある。それにしても楽だ。

(2)Dockerについて

実際に運用するサーバOSと開発をするクライアントOSではもちろんOSやミドルウェアのバージョンが異なる。
→Dockerなら、開発環境をそろえることができる。
しかも、「簡単に」という点が特徴。
Build once, run anywhereと言われる。つまり、どこでも使える。

・コンテナと呼ばれる仮想化技術。※ちなみに、コンテナ技術はDocker以外にも「Hyper-Vコンテナ」「Linuxコンテナ」などもある。
・説明は、いろいろな本やサイトを読んでもらえばいい。特徴は、ファイルで管理できる。→軽量
・複数人で同じ環境でシステムを構築できる。違うバージョンのアプリ(たとえばnginxバージョンが違う)の環境を、平行して動作させることもできる。便利だ。
・イメージファイルそのものは、Docker HUBなどに置かれている。なので、テキストファイルで指定するだけで、イメージファイルを共有する必要が無い。
・Docker Composeが便利だと思う。
複数のアプリケーションをDockerfileで定義
docker-compose.ymlファイルで定義し、
docker-compose upで一斉に環境を起動できる。
http://docs.docker.jp/compose/overview.html

・欠点として、DockerはLinuxでしか動かないので、WindowsServerのサーバであれば、移行する必要があるね。

(3)実環境でも使えるの?

使える。大規模に実環境で使っているところも多いようだ。
ただ、実環境で動作するには、Kubernetesを使うことが一般的であろう。Kubernetesはクラウドが前提で動作し、AWSでも使えるはず。
https://kubernetes.io/ja/docs/concepts/overview/what-is-kubernetes/

2.Dockerに関する用語

(1)いくつかある

・Docker pull イメージを取得する
・docker commit イメージを送る
・docker run Dockerイメージを起動させる(コンテナを作ると思ってもいいだろう)

(2)dockerのイメージと、コンテナ

❶dockerイメージ
Apacheのイメージ、MySQLのイメージなど、使いたいアプリケーションを動かすためのイメージ(OSやミドルウェア、アプリケーションを含む)。OSにApacheを入れて、適切なUpdateをしてファイル置いて、みたいなことをしてイメージを作ることも可能。
・イメージの入手方法1):DockerHubなどで入手する。このあとに解説するが、docker pull centos などのコマンドで取得できる。
・イメージの入手方法2):Dockerfileを使って自分で作る。

※イメージにはTag付けをするのがいいかも。

❷コンテナ
・イメージの上にコンテナがあると考えよう。
・コンテナ=プロセスと考えてもいいと思っている。コンテナとは、貨物電車のコンテナのように、そのユーザ専用の箱である。アプリケーション1用のApacheのコンテナを80で立ち上げ、アプリケーション2用のコンテナを4000番ポートで立ち上げるなど。
https://blog.codecamp.jp/programming-docker-image-container
・イメージからコンテナを作成することを、ビルドという。
・注意点は、Apache、MySQLなどの複数のプロセスをまとめて1つのコンテナには(できるけど)しない。Dockerのメリットが薄くなる。

(3)ネットワーク環境
Dockerでは、内部に仮想ブリッジがあり、ポートフォワーディングをしてくれるので、コンテナのIPアドレスはあまり意識しなくてもいい(勝手に変換してくれる)

3.Dockerのインストール

Dockerは、ホストOSとして、Linux以外にMacやWindowsにもインストールできる。ここではLinuxサーバにインストールする。

(1)準備
#Dockerをインストール
yum -y install docker

#versionを確認しておこう(うまくインストールできたかの確認も込めて)
docker --version

#dockerの起動
systemctl start docker

#dockerの自動起動
systemctl enable docker
(2)イメージを取得する

❶イメージの取得
docker index (https://index.docker.io)にイメージがあり、それを自分の環境に取得する(docker pull)

#イメージを探す
docker search centos 
#==> たくさん表示される。

#centosのイメージを取得する(pull)
docker pull centos

#取得したイメージを確認する
docker images

#==>出力結果はこんな感じ
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
centos              latest              0d120b6ccaa8        2 months ago        215MB

❷イメージの削除
IMAGE IDでイメージを操作する。たとえば、このイメージを消すには以下。または、コンテナ名をつけておくと、コンテナ名でも削除できる。rmiは、おそらくremove image。比較として、コンテナを消す場合はdocker rmコマンド

docker rmi 0d120b6  # <=イメージIDを指定(途中まででいい)  
#もう一度以下で確認すると、消えていることがわかる。
docker images
(3)コンテナを作る

・作り方は簡単 docker run コマンド
❶イメージからコンテナを作る run

docker run -it -d --name ct1 centos

実行コマンドのオプション

オプション 解説
-d バックグラウンドでコンテナを実行
-i インタラクティブモード
-t terminalが使えるようにする
--name コンテナに名前を付ける
-p ポートフォワード設定。-p <host port>:<cont port>
ホストのポート(=外部から通信してくるポート)とコンテナのポートを対応づける。

❷コンテナを確認

#実行中のコンテナのみを表示
docker ps  

#結果はこんな感じ 
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
76bf698b022a        centos              "/bin/bash"         11 seconds ago      Up 11 seconds                           ct2

#以下は全てを表示
docker ps -a 

#結果はこんな感じ。STATUSがUpでないものも表示される。
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                      PORTS               NAMES
76bf698b022a        centos              "/bin/bash"              23 seconds ago      Up 22 seconds                                   ct2
3fe5643002d4        nginx               "/docker-entrypoint.…"   17 minutes ago      Exited (0) 12 minutes ago                       ct1

コンテナID、Dockerのイメージ、コンテナ起動時に実行するコマンド、STATUSなどが表示される。STATUSはupしているかも表示。

❸コンテナを削除 rm
CONTAINER IDを指定する。先頭の一部を指定すればいい。または、コンテナ名をつけておくと、コンテナ名でも削除できる

docker rm 5befc # <=コンテナIDを指定(途中まででいい) 

❹コンテナの停止 stop

docker stop [CONTAINER NAME]
#状態を確認
docker ps -a 

❺停止したコンテナの起動 start
毎回コンテナをビルド(イメージからコンテナを作成)する必要がなく、作成したコンテナを再度スタートする。

docker start  [CONTAINER NAME]
(4)コンテナイメージの保存

・ミドルウェアをインストールしたりしたイメージを新しく保存したい場合がある。
・これは、コンテナを保存するのではなく、コンテナに設定を加えたもの(たとえば、ソフトをインストールしたり、ファイルを追加)したものを、イメージとして保存する。

まず、コンテナを停止した上で、以下で保存
docker comiit コンテナID イメージ名
・イメージはユーザ名/名前 と付けるようにする。
・イメージが作成されたかどうかは、コマンドで確認
docker images

https://knowledge.sakura.ad.jp/14427/

4.各種の操作

・execとattachがある
https://qiita.com/leomaro7/items/649732faf2f632419f11

(1)コンテナにログインして各種の処理

・docker exec では、すでに実行しているコンテナでコマンドを実行する。
・基本構文は以下。
docker exec [オプション] コンテナ名 コマンド
・オプションはdocker runで書いた内容と同じだと思う。
・今回はintructive の-iとTerminal操作をする-tのオプションを付けている。
❶コマンド入力ができるようにbashを指定

#ct1というcentosのコンテナでbashを実行
[root@XX]# docker exec -it ct1 /bin/bash
[root@76bf698b022a /]#

#普通のcentosなので、自由に操作ができる。たとえばyumの実行
[root@76bf698b022a /]#yum update

#抜けるには
[root@76bf698b022a /]#exit
exit
[root@XX]# 

抜けたあとも、docker exec -it ct1 /bin/bash を実行すれば、またターミナル(コンソール)に入ることができる。

(2)ホストとコンテナ間でのファイルのやりとり

ホストにあるfile1.txtをコンテナのある/home/user1/フォルダにコピー
docker cp file1.txt ct1:/home/user1/

5.実際に動かしてみる

(1)nginx

・作り方は簡単で、CentOSのイメージではなく、Dockerのイメージを使う。※OSは自分のを使っているのか、このあたりは要調査
❶nginxの起動

#以下はすでに実行されているかもしれないが
yum -y install git
yum -y install docker
systemctl start docker

#nginxのイメージを取得
docker pull nginx

#8080ポートでnginxを起動
docker run -d --name ct1 -p 8080:80 nginx

❷実際にアクセス
IPアドレス:8080でアクセスすると、nginxのページが見えると思う。
❸その他

#確認コマンド
docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
3fe5643002d4        nginx               "/docker-entrypoint.…"   4 minutes ago       Up 4 minutes        0.0.0.0:8080->80/tcp   ct1

#コンテナの停止 今回はコンテナ名をct1としているので、それを指定
docker stop ct1
(2)Apache

AWSのCentOS上にhttpdをインストールする
❶dockerのインストール

yum -y update
yum -y install docker
systemctl start docker

❷コンテナの起動

#コンテナの作成と起動。-dでバックグラウンド。名前はct3。
[root]# docker run -d --name ct3 --privileged -p 80:80 centos /sbin/init
a4a78fbddd124fd4cd27d3330ccd909a0d638466aa7ed8d41f3b4a006ffa7f35
#シェルを実行
[root]# docker exec -it ct3 /bin/bash
#コンテナ上にログインできた
[root@a4a78fbddd12 /]# 

今回、 --privileged と /sbin/initを付与しているが、これを付与しないと権限が無いというので怒られる(以下)。コンテナにも強い権限を与えるようなものだと思う。 ※ただ、あとでhttpdのイメージを使ってコンテナを作ったときは、不要だった。

[root]# systemctl start httpd
System has not been booted with systemd as init system (PID 1). Can't operate.
Failed to connect to bus: Host is down

❸コンテナ上でApacheの設定
・この内容はDockerに限った話ではなく、通常のhttpdの起動と同じ
・dnf install httpdという入れ方もある

yum -y install httpd
systemctl start httpd
cd /var/www/html
echo hello>index.html

このとき、以下のエラーがでるときがある。

Failed to set locale, defaulting to C.UTF-8

以下をやってみよう。おまじないですね。

sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-Linux-*; 

無事にインストールできたら、curlで軽く起動のテストをしておこう。httpdが起動していれば、レスポンスのヘッダが表示されるはず。
curl -i http://localhost/

❹外部から通信
AWSのグローバルIPを入れて、通信してみよう。
→実ははまった。他に80で動いているサービスが無いか、AWSのセキュリティグループは正しいは、httpsでアクセスしていないかなどを確認。
また、今回は-p 80:80 でポートを変えていないが、変える場合はどちらをどちらに割り当てるのか、間違えないように。詳しくは次に
❺別のポート8080から通信させる
http://IPアドレス:8080 で通信させるようにする。ポートの対応が-p 80:8080ではないので注意。

docker run -d --name ct4 --privileged -p 8080:80 centos /sbin/init
docker exec -it ct4 /bin/bash

❻Dockerの腕の見せ所として、複数のApacheを建ててみよう。
以下のように複数のコンテナを作れば、1つのコンテナイメージで複数のWebサーバを瞬時に構築できる。

  • p 8001:80  ←WebServ1
  • p 8002:80  ←WebServ2
  • p 8003:80  ←WebServ3
#### 1. Dockerのインストール
#Dockerをインストール
yum -y install docker

#dockerの起動
systemctl start docker

#### 2. Dockerのイメージの取得
#centosのイメージを取得する(pull) ⇒サイズは231MBと非常に小さい
docker pull centos

#### 3. コンテナを作る
#イメージからコンテナを作る
docker run -p 8001:80 -d --privileged --name WebServ1 centos:latest /sbin/init
docker run -p 8002:80 -d --privileged --name WebServ2 centos:latest /sbin/init
docker run -p 8003:80 -d --privileged --name WebServ3 centos:latest /sbin/init

#### 4. コンテナにログイン
docker exec -it WebServ1 /bin/bash

#普通のcentosなので、自由に操作ができる。たとえばyumの実行
[root@76xxxx022a /]#yum update

Failed to set locale, defaulting to C.UTF-8
上記のエラーが出たら、以下をやってみよう。おまじないですね。
sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-Linux-*; 

yum -y install httpd
systemctl start httpd
#初期ファイルの作成(中身はhelloのみ)
echo hello>/var/www/html/index.html

これで、http://IPaddress:8001, http://IPaddress:8002, http://IPaddress:8003 の3つのWebサーバが起動する。
また、ip a でIF情報を見てみよう。
すると、内部的にはそれぞれのコンテナで、仮想のプライベートIPアドレスが割り振られている。
また、ファイル構造も別々であり、それぞれに/var/www/htmlのフォルダを作成できる。

❼【その2】複数のApacheを建ててみよう。
上記だと、コンテナイメージとしてCentOSにしています。
今度は、コンテナイメージをApacheにします。

#### 1. Dockerのインストール
#Dockerをインストール
yum -y install docker

#dockerの起動
systemctl start docker

#### 2. Dockerのイメージの取得
#httpdのイメージを取得する(pull) ⇒サイズは145MBと非常に小さい
docker pull httpd

#### 3. コンテナを作る
#イメージからコンテナを作る
docker run -d -p 8001:80 --name WebServ1 httpd
docker run -d -p 8002:80 --name WebServ2 httpd
docker run -d -p 8003:80 --name WebServ3 httpd

#### 4. コンテナにログイン
docker exec -it WebServ1 /bin/bash

#vimも入っていないので、入れる
apt-get update
apt-get install vim

#以下がデフォルトのフォルダなので、そのファイルを書き変える。
/usr/local/apache2/htdocs

これで、http://IPaddress:8001, http://IPaddress:8002, http://IPaddress:8003 の3つのWebサーバが起動する。
先ほどと違ってコンテナはCentOSのイメージではないので、ip a などがコンテナの中では使えなかった。なにか方法がある気もするが。
コンテナをexitで抜けて、コマンドにて確認

IPアドレスは、それぞれ分かれていることが確認できる。

# docker inspect WebServ1 | grep IPAddress
            "IPAddress": "172.17.0.3",
# docker inspect WebServ2 | grep IPAddress
            "IPAddress": "172.17.0.2",

# ip route
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1  #172.17.0.1が仮想ルータのコンテナ側のIPアドレス
172.31.80.0/20 dev eth0 proto kernel scope link src 172.31.81.38 #172.31.81.38が仮想ルータの外側(サーバのNICのIPアドレス)
その他

ネットワーク情報を見るには以下

docker network ls

6.Docker file

(1)概要

・DockerHUBからイメージを入手するのではなく、自分でイメージを作ることができる。自分でイメージを作るためには、Dockerfile(テキストファイル)を作成する。
・docker fileに記載できる。
https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/docker-basics.html
・そして、Dockerファイルからイメージを作成できる。
ということは、複数人で開発する場合でも、Docker Flieというテキストデータさえ共有すれば開発環境を共有できる。これが利点だと思う。

(2)基本の構文

構文は以下

・FROM:OSを指定 (例)FROM centos
・LABEL:コメント
・MAINTAINER: 作成者
・RUN:実行するコマンドを記載。yum update , yum install httpdなどのコマンドや、ファイルを作成するなど、普通にインストールする際と同じようなコマンドを実行する。
・ADD :ファイルやディレクトリを追加
・COPY :ファイルをコピー
・CMD: docker runを実行したときに実行されるコマンド。

RUNやADDもコマンドを実行するが、イメージを作成したときに実行される。CMDは、docker runを実行したときのコマンド。(docker runを実行するときに渡せば、書かなくてもいいような気がする)

Q.RUNとCMDの違いは?
A.RUNは1回だけ実行するもの(たとえばインストール)。CMDは起動時に実施するコマンドを書くと考えればいいだろう。

(3)Dockerファイルを使って、Webサーバを立ち上げる

❶作成したDockerfileは以下

#Filename ./Dockerfile
#イメージと管理者を設定。
FROM centos
MAINTAINER "no name"

#httpdのインストールなど
RUN yum -y install httpd
RUN echo hello>/var/www/html/index.html

#以下は省略可能だと思う
EXPOSE 80

#runで実行
CMD ["/usr/sbin/httpd", "-D", "FOREGROUND"] #デフォルトだとBACKGROUDで起動してしまう。コンテナだと都合が悪いみたい。

RUNのところで、systemctl start httpdを入れるとうまくいかなかった。あくまでもイメージを作るので、プロセスを起動させたりはダメなようだ。→インストールするのではなく起動時のコマンドなので、CMDかもしれない。→CMD /bin/systemctl -D FOREGROUND こんな感じかな。FOREGROUNDがいるかは不明。

❷docker buildでイメージを作る
構文は以下

docker build -t 作成するイメージ名 Dockerfileがあるディレクトリ

※Dockerfileのありかは、 . として末尾にドットを付けることで、同じフォルダのDockerfileを読み込む。
・実際に作成

#new1という名前で作成
docker build -t new1 .
#==>エラーが多少出る可能性がある。

#作成したイメージの確認。成功していれば、new1という名で作られているはず
docker images
# 結果はこんな感じ
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
new1                latest              69b00ffdf90c        44 seconds ago      254MB
centos              latest              0d120b6ccaa8        2 months ago        215MB

❸起動(コンテナの作成)

docker run -it -p 80:80 -d new1

これで、Webサーバが立ち上がる。Dockerファイルさえ作っておけば、起動は簡単である。※runはあくまでもコンテナ作成。
なので、docker run new1 を2回実行すると、コンテナを上書きではなく、複数作られる(Container ID)が違う複数のコンテナが作られる。以下で見るみよう。
# docker ps -a
接続するには docker attach コンテナID で(動いているコンテナには)接続できる。ただ、Dockerファイルがcatなどのコマンドのみであれば、プロセスが動いていないので、接続はできない。

7.Docker Compose

(1)Docker Composeについて

・多くの場合、PHP、Apache、MySQLなどの複数のアプリケーションを動かすことが多い。そこで、各バージョン複数のコンテナを一元的に管理するのがDocker Compose。
・Docker Composeを利用するには、docker-compose.ymlというファイルが必要

Q.Dockerファイルとdocker-compose.ymlの2つがあるのはなぜ?
A.どちらも設定を記載するという点では似ている。ただ、やっていることはそもそもレイヤが少し違う。
・Dockerファイルだと1つのコンテナしか作ったり、管理ができない。
・docker-compose.ymlでは、複数のコンテナの管理ができる。また、docker-compose.ymlでは、Dockerファイルで作ったコンテナを指定することも可能。
・コンテナ1つであれば、docker-composeは不要であろう。

CTFdの場合
Docker Composeをインストール
以下サイトの「Linux」のタブを開く
https://docs.docker.com/compose/install/

curl -L "https://github.com/docker/compose/releases/download/1.24.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
(2)docker-compose関連のコマンド

よくわかっていないが、とりあえず列挙
❶インストール
ちょっと違うかもしれんけど、イメージは以下

curl -L "https://github.com/docker/compose/releases/download/1.24.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose  #install。インストールをしないと使えない。
chmod +x /usr/local/bin/docker-compose #実行権限を付与する
ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
docker-compose -v #versionの確認

❶プロセスの確認
docker-compose ps

❷再起動
docker-compose restart

❸停止
docker-compose stop

❹起動  
docker-compose up
※-d をつけるとバックグラウンド処理なので、ログが表示されない。コンソール画面を占有しないので、別処理ができる。

❺削除 
docker-compose down

(3)docker-compose.ymlファイル

yml(ヤムル)ファイルを作成する。
Docker Compose 概要 — Docker-docs-ja 19.03 ドキュメント
上記に掲載されているサンプルファイルが以下である。

version: '3'
services:
  web:
    build: .
    ports:
    - "5000:5000"
    volumes:
    - .:/code
    - logvolume01:/var/log
    links:
    - redis
  redis:
    image: redis
volumes:
  logvolume01: {}

yamlファイルは、構造化されたフォーマットでデータを書いたもの。docker-composeは.ymlだが、awsでは.yamlを使う。どちらを使ってもいいだろう。

(3)Apacheのコンテナをdokcer-componseを使って作ってみる。

(1)Dockefileを使わない場合
(2)Dockefileを使う場合
大事な話として、コンテナ内に永続的なファイルは置かない。消えてしまうから。
なので、コンテナを作ったとしても、Apacheのコンテンツなどは、コンテナの外のLinuxサーバ上において、リンクを作る。

(1)Dockefileを使わない場合

フォルダは、以下の配下に置くとする。
/root/docker/ct1
+ html/index.html
+ Dockerfile
+ dokcer-componse.yml

mkdir docker
cd docker/
mkdir ct1
cd /root/docker/ct1

以下がdocker-compose.yml ファイル

version: '3'    #おそらく、シングルクォートでもOK
services:
  web:          #わかりやすいように、サービスの名前をwebと名前をつけた
    image: httpd
    container_name: "httpd"
    volumes:   
      - ./html:/usr/local/apache2/htdocs  #ローカルのLinuxのhtmlフォルダにコンテンツを配置し、コンテナの中のファイルとリンク
    ports:
      - "8080:80"

直接コンテナに操作するには、以下
# docker exec -it httpd bash

/htmlにindex.htmlを配置しておく。

## 起動  
docker-compose up -d

## テスト
http://x.x.x.x:8080 で接続してみる。 
ロカールのindex.htmlファイルを書き替えたら、以下で再起動しておこう。
docker-compose up
ちなみに、このコンテナを消すには、docker-compose down

(2)Dockefileを使う場合
・Dockerfileは以下で十分

FROM httpd

・docker-compose.ymlは、シンプルに書くと以下

version: '3' 
services:
  web: 
    build: .   # Dockefileを指定するが、直下なのでこの指定。./Dockerfileと指定しても同じ。
    container_name: "httpd"
    ports:
        - 8080:80
    volumes:   
      - ./html:/usr/local/apache2/htdocs 

8.DockerHUB

・DockerHubでイメージを管理
・Docker Hubは昔は「docker index」だった
・アカウントを作成する必要がある →DockerHUBに登録しないと、ダウンロードの回数制限があるようだ(1日100回とか)

#ログイン
docker login
#イメージのアップロード
docker push イメージ
#イメージのダウンロード
docker pull イメージ
#イメージの検索
docker search