docker

Page content

Docker introduction

どっかーがんばるぞ~

docker vs. vagrant

同じ時期に Vagrant も見ていたので、やるならどっちかなぁと考えた時があったので。 ここ が優しい

docker installation

公式をごらんなさい。至って簡単です。 一応、mac用の簡単インストール: Qiita - Docker for Macをインストールしてみた

proxy の設定

これでだいたいカバーできそう: 防火壁の中の Docker でもプロキシ配下の環境ってのはいろいろ手間だし嫌だよね。

docker-compose

  • 複数のコンテナの設定、起動をまとめて行うもの。
  • installation: 公式をごらんなさい

TIPS

tips 書くよ。

イメージの操作

  • イメージ一覧(ダウンロード済のもの): docker images

    REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
    <none>              <none>              f99cd0762d12        3 days ago          248MB
    <none>              <none>              6ebf2fc54f77        4 days ago          225MB
    <none>              <none>              94b927c827e9        4 days ago          511MB
    <none>              <none>              5c6e9b479563        4 days ago          531MB
    <none>              <none>              03811835d1a3        4 days ago          531MB
    <none>              <none>              9d49d5dccac0        4 days ago          531MB
    <none>              <none>              d8b062142c51        4 days ago          488MB
    centos              7                   1e1148e4cc2c        2 months ago        202MB
    
  • イメージ削除: docker rmi <image_id>

  • イメージの取得: docker pull

    • 解説: dockerhub などにある既成のコンテナイメージを取得するにはこれ
  • イメージのビルド: docker build -t <name> <build_context>

    • 解説: 自前のコンテナイメージを生成するにはこれ
    • options:
      • -t <name>: ここで指定した image name になる。
      • <build_context>: docker daemon に送信するディレクトリ。だいたい Dockerfile を編集しながら実行するので、カレンドディレクトリ . を指定することが多い。大きいサイズの不要なファイルを底に置くのは避けよう(不必要にdocker daemonに送信されてビルドが長時間化する)
      • --no-cache をつけると作成済みレイヤーをキャッシュせず、1からビルドし直してくれる。
    • その他説明:
      • Dockerfile の各行がステップで、イメージのレイヤーになる。
  • コンテナ起動: docker run <image_name> [<cmd_inside_container>]

    • 解説: docker pull や docker build で取得or生成したイメージを元にコンテナを起動する。使い方によってはイメージ取得 (docker pull) も包含される
    • 実行例 (詳細のコマンド解説は「コンテナの操作」の章で)
      $ docker run docker/whalesay cowsay Hello!
      ________
      < Hello! >
      --------
          \
          \
          \
                          ##        .
                  ## ## ##       ==
              ## ## ## ##      ===
          /""""""""""""""""___/ ===
      ~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ /  ===- ~~~
          \______ o          __/
              \    \        __/
              \____\______/
      
  • イメージの詳細情報を見る: docker inspect <image_name>

    $ docker inspect my_whalesay
    [
        {
            "Id": "sha256:6b362a9f73eb8c33b48c95f4fcce1b6637fc25646728cf7fb0679b2da273c3f4",
            "RepoTags": [
                "docker/whalesay:latest",
                "my_whalesay:latest"
            ],
            "RepoDigests": [
                "docker/whalesay@sha256:178598e51a26abbc958b8a2e48825c90bc22e641de3d31e18aaf55f3258ba93b"
            ],
            "Parent": "",
            "Comment": "",
            ...
    
  • Docker hub へログイン: docker login [<url>]

  • イメージにタグ付け: docker tag <image_name> <Docker ID>/<image_name>:<tag>

  • イメージをDocker hubへプッシュする: docker push <Docker ID>/<image_name>:<tag>

    • 事前にログインが必要 ( docker login )
  • 起動中のコンテナからイメージとして保存する: docker commit <container_name or container_id> <image_name>:<tag>

    • 実行中のコンテナに入って色々編集したものを、イメージとして保存できる。
    • ただし、 docker history に残らないので、何をしてあるのかがわからず、不自由する面も。
    • ベーシックな使い方であれば、やはり Dockerfile を編集してイメージを作成するほうが良い。
  • 履歴とレイヤーを確認する: docker history <image_name or image_id>

    $ docker history commit-test:ver2
    IMAGE               CREATED              CREATED BY                                      SIZE                COMMENT
    44ce43b51809        About a minute ago   /bin/bash                                       10.5MB
    47b19964fb50        3 weeks ago          /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B
    <missing>           3 weeks ago          /bin/sh -c mkdir -p /run/systemd && echo 'do…   7B
    <missing>           3 weeks ago          /bin/sh -c rm -rf /var/lib/apt/lists/*          0B
    <missing>           3 weeks ago          /bin/sh -c set -xe   && echo '#!/bin/sh' > /…   745B
    <missing>           3 weeks ago          /bin/sh -c #(nop) ADD file:529264c6593975a61…   88.1MB
    
    • commit で行われた変更は /bin/bash としか表現されていないため、このように何が行われたかわからなくなってしまう。
    • 上の行ほど新しい更新=新しいレイヤー

コンテナの操作

  • コンテナを立ち上げるコマンド: docker run --name <container_name> -d -p <host_port>:<container_port> <image_name>

    • options:
      • -d: toggle detach mode
      • --rm: Automatically remove the container when it exits
      • バインドマウント: -v <host_dir>:<container_target_mount_point>:<readwrite_option>
        • <readwrite_option>: ro (readonly) だけ覚えておけば普通は良さそう
        • マウントされたファイルを編集すると、即時反映される(i.e. nginx の index.html を編集してブラウザをリロードすると更新後のファイルが見える)
  • 起動中のコンテナを一覧: docker ps

  • 停止中のものを含む全てのコンテナを一覧: docker ps -a

  • コンテナをストップ: docker stop <container_name>

  • コンテナを削除: docker rm test-nginx

  • コンテナを立ち上げ直す場合: ストップ、削除してから docker run ... し直すこと。

  • ホストマシンのファイル → コンテナ内へのコピー: docker cp <src_host_file_path> <container_name or container_id>:<target_path>

  • コンテナ内のファイル → ホストマシンへのコピー: docker cp <container_name or container_id>:<src_path> <target_host_file_path>

  • コンテナのシェルに接続する方法2つ

    1. docker attach <container_name or container_id>: 抜ける時に誤ってコンテナを停止する事もできてしまうので非推奨かな
    2. docker exec -it <container_name or container_id> /bin/bash

Automated Build

github への push をトリガーに、自動ビルドできる!

  • dockerhubにリポジトリを作る
  • githubにもリポジトリを作る
  • dockerhubで automated build の設定をし、 github とリンクさせる
  • 条件の設定は色々。ブランチへのコミットやタグ名を正規表現で引っ掛けてビルドのトリガーにできる。
    • 以下はイメージ: automated_build

network

  • ネットワーク一覧の出力: docker network ls

    • 例:
      NETWORK ID          NAME                      DRIVER              SCOPE
      250df2d30d1f        bridge                    bridge              local
      0fdcb5eceb66        gitbook-uml_default       bridge              local
      081080240b02        host                      host                local
      1122ef3cedc6        nginx-proxy_default       bridge              local
      c8eb35a84aea        none                      null                local
      ba5737f49d7d        revealjs-docker_default   bridge              local
      
    • 補足
      • 何も指定がないと、コンテナは デフォルトで用意される bridge というネットワークに接続される。
  • ネットワークの詳細を見る: docker network inspect <bridge_nw_name>

    [
        {
            "Name": "bridge",
            "Id": "250df2d30d1f1402be767281024f322cc261f4e8cb7d70e50d6803cb319135f3",
            "Created": "2019-02-25T12:34:44.2070634Z",
            "Scope": "local",
            "Driver": "bridge",
            "EnableIPv6": false,
            "IPAM": {
                "Driver": "default",
                "Options": null,
                "Config": [
                    {
                        "Subnet": "172.17.0.0/16",
                        "Gateway": "172.17.0.1"
                    }
                ]
            },
            "Internal": false,
            "Attachable": false,
            "Ingress": false,
            "ConfigFrom": {
                "Network": ""
            },
            "ConfigOnly": false,
            "Containers": {},
            "Options": {
                "com.docker.network.bridge.default_bridge": "true",
                "com.docker.network.bridge.enable_icc": "true",
                "com.docker.network.bridge.enable_ip_masquerade": "true",
                "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
                "com.docker.network.bridge.name": "docker0",
                "com.docker.network.driver.mtu": "1500"
            },
            "Labels": {}
        }
    ]
    
  • ネットワークにコンテナが所属していると、以下のようなプロパティが追加されている:

    "Containers": {
        "e331635c1597ed0b24b7547a4539d52cdb3c24bcc4504cbc3b01edd53489d98a": {
            "Name": "alpine1",
            "EndpointID": "260af34175578e7a81dc8c79e61a8733677d477493bf9bc563ad2b2b59f62b4e",
            "MacAddress": "02:42:ac:11:00:02",
            "IPv4Address": "172.17.0.2/16",
            "IPv6Address": ""
        }
    },
    
  • コンテナ間の通信

    • デフォルトの bridge では ip addr でしか通信できない
    • 個別に作ったブリッジネットワークでは名前解決が可能
  • ブリッジネットワークの作成: docker network create <nw_name>

  • 特定のブリッジネットワークに稼働中のコンテナを接続する: docker network connect <nw_name> <container_name>

  • コンテナ起動時に接続するブリッジネットワークを指定する: docker run -itd --name alpine3 --network my_nw alpine (alpine3 というコンテナを my_nw というネットワークに接続する)

  • 特定のブリッジネットワークにコンテナを切断する: docker network disconnect <nw_name> <container_name>

  • 作成したブリッジネットワークでは、名前解決が可能

    • 証拠:
      $ docker exec -it alpine2 /bin/sh
      / # ifconfig
      eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:02
                inet addr:172.17.0.2  Bcast:172.17.255.255  Mask:255.255.0.0
                UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
                RX packets:12 errors:0 dropped:0 overruns:0 frame:0
                TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
                collisions:0 txqueuelen:0
                RX bytes:968 (968.0 B)  TX bytes:0 (0.0 B)
      
      / # ping alpine1
      PING alpine1 (172.18.0.2): 56 data bytes
      64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.149 ms
      ^C
      --- alpine1 ping statistics ---
      1 packets transmitted, 1 packets received, 0% packet loss
      round-trip min/avg/max = 0.149/0.149/0.149 ms
      
      / # netstat -rn
      Kernel IP routing table
      Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
      0.0.0.0         172.17.0.1      0.0.0.0         UG        0 0          0 eth0
      172.17.0.0      0.0.0.0         255.255.0.0     U         0 0          0 eth0
      172.18.0.0      0.0.0.0         255.255.0.0     U         0 0          0 eth1
      
      / # nslookup alpine1
      Name:      alpine1
      Address 1: 172.18.0.2 alpine1.my_nw
      
  • その他のデフォルトのネットワーク: none と host があるが、気が向いたら書く

    • none network: どのネットワークにも接続しないようにすることができる
    • host network: ホストと同じネットワークに所属する。 ポートのバインドをすることなく、ローカルホストから接続できる

お試し

試行中のメモなので正しくないかもですよ

公式の nginx でリバースプロキシ

  • docker-compose+nginxでリバースプロキシを設定する
    • default.conf のコピーは ./nginx/Dockerfile に書かずに docker-compose.ymlservices.nginx.volumes に書いたら動いたよ

    • docker-compose.yml

      version: "3"
      services:
          nginx:
          image: nginx
          container_name: nginx
          ports:
              - "80:80"
          volumes:
              - ./nginx/default.conf:/etc/nginx/conf.d/default.conf
          depends_on:
              - portainer
              - gitbook
              - swagger-ui
          restart: always
      
          gitbook:
          image: fellah/gitbook
          container_name: gitbook
          ports:
              - "4000:4000"
          volumes:
              - ./gitbook/data:/srv/gitbook
          restart: always
      
          swagger-ui:
          image: swaggerapi/swagger-ui
          container_name: swagger-ui
          volumes:
              - ./swagger-ui/data/swagger.yaml:/usr/share/nginx/html/swagger.yaml
          environment:
              API_URL: swagger.yaml
          ports:
              - "8080:8080"
      
    • nginx/default.conf

      server {
          listen       80;
          server_name  localhost;
      
          location / {
              root   /usr/share/nginx/html;
              index  index.html index.htm;
          }
      
          location /portainer/ {
          proxy_http_version 1.1;
          proxy_set_header Connection "";
          proxy_pass    http://portainer:9001/;
          }
      
          location /portainer/api/websocket/ {
          proxy_set_header Upgrade $http_upgrade;
          proxy_set_header Connection "upgrade";
          proxy_http_version 1.1;
          proxy_pass http://portainer:9001/api/websocket/;
          }
      
          # location /gitbook/ {
          #   proxy_pass    http://gitbook:4000/;
          # }
      
          location /swagger-ui/ {
          proxy_pass    http://swagger-ui:8080/;
          }
      
          location /gitbookuml/ {
          proxy_pass    http://gitbookuml:4000/;
          }
      }
      

swaggerapi/swagger-ui

jwilder/nginx-proxy で自動のリバースプロキシ

公式 nginx に比べてコンテナ追加・削除に自動追随できるっぽいです。できてます。

うまく行っていないやつ

消すか動くように直します。

gitbook

  • fellah/gitbook

    • リンクの参照がどんどん崩れていく… 階層構造をやめるか、 network を分断するか, リンクの貼り方を相対じゃなく絶対にするか, gitbook のコードを monkey patchするか
  • newgyu/gitbookuml

    • リンクの参照がどんどん崩れていく… 状況は同じ
    • docker-compose.yml にはこれ足した
      services:
          gitbookuml:
              image: newgyu/gitbookuml
              container_name: gitbookuml
              command: serve
              ports:
                  - "4000:4000"
              volumes:
                  - ./gitbookuml/data:/tmp/src
              restart: always
      

複数のWebアプリを1サーバーのDockerを使ってSSL対応のサブドメインで簡単に運用する

  • docker-compose up -d したとき、 php のサービスに対して以下のエラーが出て進まない。
    debconf: delaying package configuration, since apt-utils is not installed
    ---(略)---
    error: /usr/src/php/ext/mcrypt does not exist
    
    usage: /usr/local/bin/docker-php-ext-install [-jN] ext-name [ext-name ...]
       ie: /usr/local/bin/docker-php-ext-install gd mysqli
           /usr/local/bin/docker-php-ext-install pdo pdo_mysql
           /usr/local/bin/docker-php-ext-install -j5 gd mbstring mysqli pdo pdo_mysql shmop
    
    if custom ./configure arguments are necessary, see docker-php-ext-configure
    
    Possible values for ext-name:
    bcmath bz2 calendar ctype curl dba dom enchant exif fileinfo filter ftp gd gettext gmp hash iconv imap interbase intl json ldap mbstring mysqli oci8 odbc opcache pcntl pdo pdo_dblib pdo_firebird pdo_mysql pdo_oci pdo_odbc pdo_pgsql pdo_sqlite pgsql phar posix pspell readline recode reflection session shmop simplexml snmp soap sockets sodium spl standard sysvmsg sysvsem sysvshm tidy tokenizer wddx xml xmlreader xmlrpc xmlwriter xsl zend_test zip
    
    Some of the above modules are already compiled into PHP; please check
    the output of "php -i" to see which modules are already loaded.
    ERROR: Service 'php' failed to build: The command '/bin/sh -c apt-get update     && apt-get install -y libicu-dev libmcrypt-dev libxml2-dev     && docker-php-ext-install -j$(nproc) intl mcrypt xml mbstring opcache     && mkdir -p /var/www' returned a non-zero code: 1
    

かいてる通りやってもダメそうなので、勉強しないとなぁ…