kmkのメモ帳

気が向いたときにLinuxだったり、プログラミングだったり、適当なメモを書いてます。

Blogは移転しました。

自動的にリダイレクトします。

dockerとdocker-composeのインストール&基本操作 (CentOS7)

dockerとdocker-composeについて

www.docker.com

dockerはコンテナ型の仮想環境を作ることができるOSSです。

仮想環境が構築できるOSSKVMXenなどが有名ですが、KVMなどはハードウェアをシミュレートして仮想環境(ゲストOS)を立てるため、その分負荷が高いです。

dockerはハードウェアはシミュレートせずに仮想環境を実現しています。カーネルをホストと共通のものを使用してプロセスレベルで隔離する形式で仮想環境を実現しています。 ハードウェアをシミュレートしないためKVMなどの形式よりは負荷が低く済んだり、KVMのゲストOS上でdockerとか少しきもいこともできます。

個人的にdockerを知った時は、自分がよく知っているKVMと比較して理解しようとして少し混乱しましたが、どちらかというとchrootに似ていると感じるようになってから理解が進みました。語弊があるかもしれませんが、dockerはchrootの強化版だと勝手に思ってます。

また、docker経由でアプリケーションを起動させた場合、連動する複数アプリケーションを起動したい時が多々あります。nginxとMySQLとか。1つ1つdockerで起動してもいいのですが、管理が煩雑になります。その時に便利なのがdocker composeです。docker-composeはdockerで複数のアプリケーションの起動を管理できるツールです。docker-composeではコンテナの起動順序も指定できます。今回はdockerとdocker-composeについて試していきます。

尚、最初はCentOS6で試してたのですが、docker-composeの実行の際にエラー吐いて、ググってるうちにCentOS6では推奨されてないことに後から気づいたのでCentOS7でやってます。(最初から要件見ろよっていうね)

Does Red Hat provide docker for RHEL 6? - Red Hat Customer Portal

docker インストール

まずはdockerをyumでお手軽にインストールして起動します。

# yum install docker-io
# systemctl start docker

気軽に試そうと思っただけなので今回特に何も考えずdocker-io入れましたが、dockerパッケージ複数パッケージがありdocker-ioはもう古いようです。docker-ce (free community edition)というパッケージが現状(2018年6月現在)推奨のようです。

stackoverflow.com

docs.docker.com

docker-ioはUbuntuがメンテしていて、docker-ceはdockerがメンテしているようです。そしてdocker公式の手順では「docker-ceインストールしてね」と書いてあります。私はdocker-ioインストールしちゃいましたが、今後はdocker-ceをインストールした方がよさそうです。

他にもあるっぽいので調べた限りをまとめておきます。

  • docker-ce : 現状の推奨パッケージ(free community版)
  • docker-ee : 現状の推奨パッケージ(enterprise版)
  • docker-engine : 現状(2018年6月現在)すでに古いパッケージ
  • docker-io : Ubuntuが管理してるパッケージ。こちらもすでに古いパッケージ。docker公式のUbuntuへのインストール手順でも現状はdocker-ceを推奨。

docker-composeインストール

次にdocker-composeをインストール&実行権限を付与します。

docs.docker.com

# curl -L https://github.com/docker/compose/releases/download/1.6.2/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
# chmod +x /usr/local/bin/docker-compose

バージョン確認

#  docker-compose --version
docker-compose version 1.6.2, build 4d72027
#

これでdockerとdocker-composeの準備完了です。

nignxのdockerコンテナをインストール

試しにdocker経由でnginxを起動してみます。nginxをdocker経由で起動するために、今回はDocker Hubからnginxのdocker imageを持ってきます。 Docker Hubは自分で作成したdockerのコンテナを共有できるdocker社が提供しているサービスです。

https://hub.docker.com/

Docker Hubに公式がnginxのdocker imageを公開しているのでそれを使用していきます。

https://hub.docker.com/_/nginx/

まずは現在インストールされているdocker image一覧を確認します。まだ、インストールしてないので、何も出てこないはずです。

# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
#

nginxのdocker imageをdocker pullコマンドで持ってきます。

# docker pull nginx

docker pullが終わったら再度image一覧を確認してみます。正常にdocker imageの取得が終わっていれば、nginxのdocker imageが表示されるはずです。

# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
nginx               latest              01133ef0d8b6        4 weeks ago         108.9 MB
#

nignx(dockerコンテナ)を起動/停止/削除

nginxのdockerコンテナの準備が終わったので、nginxをdockerで起動します。docker runコマンドで起動します。

https://docs.docker.com/engine/reference/run/

# docker run  -p 8080:80 nginx

-pオプションをつけなくても起動はするのですが、その場合、コンテナ内で起動したnignxの80番ポートに外部からアクセスするすべが無くnginxにアクセスできません。 そのため「ホストOSの8080番にアクセスした場合、dockerコンテナとして起動しているnginxの80番ポートにアクセスが行く」設定を-p 8080:80オプションで実施します。

上記docker runコマンドを実施すると待ち状態になります。他ターミナルからポートのLISTEN状況を確認してみます。

# netstat -nltp|grep 8080
tcp        0      0 :::8080                     :::*                        LISTEN      11585/docker-proxy  
#

docker-proxyが8080番ポートをLISTEN状態なことがわかりました。 また、この状態で# curl localhost:8080でホストOSにアクセスするとアクセスできるはずです。アクセスが正常にできた場合、docker runを実行しているターミナルにアクセスログが出力されます。

docker runコマンドを終了したい場合は、とりあえずCtrl+cで抜けてしまってOKです。 docker runコマンドをバックグランドで実行したい場合はdocker runコマンドに-d(--detach)オプションをつけることでバックグランドで実行が可能になります。

# docker run  -p 8080:80 nginx -d nginx

一度上記のようにdocker runを実行するとコンテナが登録されてdocker psコマンドで見えるようになります。Ctrl+cで一旦停止してしまったので、docker ps-aつけて停止中のコンテナも見てます。

docker ps | Docker Documentation

# docker ps -a
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS                     PORTS               NAMES
8fa26a7ebbac        nginx               "nginx -g 'daemon of   24 seconds ago      Exited (0) 3 seconds ago                       goofy_curie
#

尚、情報を省略したくないときは下記の通り、--no-truncオプションをつけます。

# docker ps -a --no-trunc
CONTAINER ID                                                       IMAGE               COMMAND                    CREATED             STATUS                     PORTS               NAMES
8fa26a7ebbaca3ba697df8e2de611ba4dcc18a0faba9c9ef0e4b05bee891f509   nginx               "nginx -g 'daemon off;'"   4 minutes ago       Exited (0) 4 minutes ago                       goofy_curie
#

上記の通りdocker runコマンドを実施したことによりgoofy_curieという名前のdockerコンテナが登録されたことがわかりました。 この登録されたコンテナを起動してみます。docker runコマンドでは無くdocker startコマンドで起動してみます。

# docker start goofy_curie
goofy_curie
#
# netstat -nltp|grep :8080
tcp        0      0 :::8080                     :::*                        LISTEN      24692/docker-proxy
#
# docker ps
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS              PORTS                  NAMES
8fa26a7ebbac        nginx               "nginx -g 'daemon of   9 minutes ago       Up About a minute   0.0.0.0:8080->80/tcp   goofy_curie
#

無事起動しました。デーモン化してるのでログアウト等しても起動し続けてくれます。停止はdocker stopで停止できます。

# docker stop goofy_curie
goofy_curie
#
# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
#
# docker ps -a
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS                     PORTS               NAMES
8fa26a7ebbac        nginx               "nginx -g 'daemon of   11 minutes ago      Exited (0) 5 seconds ago                       goofy_curie
#

また、このdocker コンテナが不要になったら、docker rmで削除可能です。

# docker rm goofy_curie
goofy_curie
#
# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
#

これでdocker コンテナ削除完了です。

rootディレクトリを指定してnginxを起動

先ほどは素の状態でnginxを起動しました。今回はホスト側の任意のディレクトリをコンテナのnginxのrootディレクトリにマウントして、ホスト側のディレクトリをrootディレクトリして使うように起動してみます。

# docker run -p 8080:80 -v /home/test/htdocs/:/usr/share/nginx/html:ro -d nginx

-v(--volume)オプションでホスト側の/home/test/htdocs/ディレクトリを、コンテナ内の/usr/share/nginx/htmlディレクトリにマウント(読み込み権限roのみ)してます。

コンテナ内からホスト側のファイルを読み込むときはこのようにマウントして使用します。

nginxが死んだら自動起動するように設定

先ほど起動したコマンドの場合、nginxが突然死んだ場合死んだままになります。

・起動させる。

# docker run -p 8080:80 -v /home/test/htdocs/:/usr/share/nginx/html:ro -d nginx
e975b1419ae221637782ebeaa998efb9ce887fdbd5dcf133fde25f303f87646f
#
# docker ps
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS              PORTS                  NAMES
e975b1419ae2        nginx               "nginx -g 'daemon of   6 seconds ago       Up 5 seconds        0.0.0.0:8080->80/tcp   ecstatic_euclid
#
# ps auxwwf
----
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root     10904  0.0  0.6  32552  3172 ?        Ss   09:15   0:00  \_ nginx: master process nginx -g daemon off;
101      10929  0.0  0.3  33004  1588 ?        S    09:15   0:00      \_ nginx: worker process
----
#

・殺してみる。

# kill 10904 
#

・死んだ。死にっぱなし。

# ps auxww|grep nginx  
root     11877  0.0  0.1   6444   676 pts/2    S+   09:17   0:00 grep nginx 
#
# docker ps 
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES 
#
# docker ps -a
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS                      PORTS               NAMES
e975b1419ae2        nginx               "nginx -g 'daemon of   2 minutes ago       Exited (0) 42 seconds ago                       ecstatic_euclid
#

上記の通り死んだら死にっぱなしになります。下記のように--restart=alwaysをつけることによりプロセスが死んだら自動的に起動するようにできます。

--restart=alwaysをつけて起動。

# docker run -p 8080:80 -v /home/test/htdocs/:/usr/share/nginx/html:ro -d --restart=always   nginx
e828d2119a481d1f80b4604e97022c39894183c5e4c5c421c2ee083d1246863a
#
# docker ps
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS              PORTS                  NAMES
e828d2119a48        nginx               "nginx -g 'daemon of   3 minutes ago       Up 3 minutes        0.0.0.0:8080->80/tcp   boring_thompson
#
# ps auxwwf
----
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root     14419  0.0  0.3  32552  1608 ?        Ss   09:23   0:00  \_ nginx: master process nginx -g daemon off;
101      14445  0.0  0.2  33004  1336 ?        S    09:23   0:00      \_ nginx: worker process
----
#

・殺してみる。

# kill 14419
#

・プロセスIDとプロセスの起動時間がが変わった。一回死んで生き返った。

# ps auxwwf
----
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root     16441  0.1  0.6  32552  3256 ?        Ss   09:28   0:00  \_ nginx: master process nginx -g daemon off;
101      16445  0.0  0.3  33004  1608 ?        S    09:28   0:00      \_ nginx: worker process
----
#
# docker ps
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS              PORTS                  NAMES
e828d2119a48        nginx               "nginx -g 'daemon of   8 minutes ago       Up 3 minutes        0.0.0.0:8080->80/tcp   boring_thompson
#

上記の通りdockerでは突然死したときに自動で起動してくるdaemon tools的な機能を備えてます。最高ですね。 次にdocker-composeを試していきます。

docker-composeでnginxを起動

まずは適当にdockerのディレクトリをほって、docker-composeで起動する時に必要なymlファイルを作成します。

#  mkdir -p ./docker/nginx/
#
# vi ./docker/nginx/docker-compose.yml
#

./docker/nginx/docker-compose.ymlの中身

version: '2'

services:
  nginx :
    image: nginx
    ports:
      - "8080:80"
    volumes:
      - /home/test/htdocs/:/usr/share/nginx/html:ro
    restart: always

docker-compose.ymlを作成したら、docker-compose up -dコマンドで起動させます。

# cd ./docker/nginx/;pwd
/root/docker/nginx
#
# ls
docker-compose.yml
#
# docker-compose up -d
Starting nginx_nginx_1
#

これで起動したはずです。docker-compose.ymlを利用すれば、docker runコマンドのようにいちいち長いコマンドを打たなくてもいいですし、ファイルにも設定が残ります。また、nginx以外にも同じファイルにサービスを書けば複数のdockerコンテナを起動することが可能です。 試しにMySQLとnginxを同じdocker-compose.ymlに記述して起動してみます。

まずは、MySQLのdockerの公式イメージをdocker pullコマンドで持ってきます。

# docker pull mysql

docker-compose.ymlにMySQLを起動する記述を追加します。

# cd ./docker/nginx/;pwd
/root/docker/nginx
#
# cat docker-compose.yml
version: '2'

services:
  nginx :
    image: nginx
    ports:
      - "8080:80"
    volumes:
      - /var/www/html:/usr/share/nginx/html:ro
    restart: always

  mysql :
    image: mysql
    ports:
      - "3306:3306"
    environment:
      - MYSQL_ROOT_PASSWORD=test

#

docker-composeコマンドで起動させます。

# docker-compose up -d
Creating nginx_nginx_1
Creating nginx_mysql_1
#
# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS              PORTS                    NAMES
130c49cf16da        mysql               "docker-entrypoint..."   About a minute ago   Up About a minute   0.0.0.0:3306->3306/tcp   nginx_mysql_1
87a880588a96        nginx               "nginx -g 'daemon ..."   About a minute ago   Up About a minute   0.0.0.0:8080->80/tcp     nginx_nginx_1
#

MySQLとnginxのコンテナ二つを起動することがきました。MySQLコンテナの後にnginxコンテナを起動したい場合は、depends_on:にどのservice起動後にnginxを起動したいのか書けばOKです。 ただし、MySQLのコンテナが起動しているかだけを見て、MySQLが正常に起動しているかは見てくれないので注意が必要です。あくまでもMySQLコンテナが起動しているかしか見てくれません。

version: '2'

services:
  nginx :
    image: nginx
    ports:
      - "8080:80"
    depends_on:
      - mysql         <---mysqlコンテナの後にnginxコンテナを起動
    volumes:
      - /var/www/html:/usr/share/nginx/html:ro
    restart: always

  mysql :
    image: mysql
    ports:
      - "3306:3306"
    environment:
      - MYSQL_ROOT_PASSWORD=test

尚、この方法だと、MySQLのデータはdockerコンテナが再起動するたびに消えます。データを永続的に使用したい場合は、volumesでホスト側の領域をマウントしてそこの領域をMySQLのデータ領域として使う必要がありますので注意してください。

おわりに

今更ながらdockerをはじめて触って見ましたが、これは確かにソフトウェアエンジニアに人気でるだろうなと感じました。便利ですからね。個人的な感想としては大雑把すぎるでしょうが、高機能なchroot+daemontoolsという印象を受けました。単純に便利なので、これからも積極的に使っていこうと思います。

# # #