ソフトウェア/docker/覚書 のバックアップの現在との差分(No.5)

更新


  • 追加された行はこの色です。
  • 削除された行はこの色です。
[[公開メモ]]

* docker について自分用のメモを [#kfba0e63]

いろいろ検証しないとあやふやなところがあるので間違っているところも多いかもしれません。
すみません。

#contents

** Dockerfile [#h7473aae]

各命令は個別に実行され、都度、新しいイメージが生成されるため、たとえば RUN cd /tmp という命令は続く命令に影響を与えない。

|#コメント ||
|FROM someone/imagename:tag AS tag_name|"アカウント名/イメージ名:バージョン番号" が基本。公式イメージではアカウント名の部分を省略。|
|RUN command1 && command2|デフォルトでは Linux では /bin/sh -c で、 Windows では cmd /S /C で処理される。|
|SHELL |RUN で使われるシェルを変更する|
|RUN ["/path/cmd", "arg1", "arg2"]|シェルを使わず exec で直接実行される。引数は JSON なので必ず " で囲み、必要に応じて \ をエスケープして \\ にする。環境変数は展開されないし、PATH も効かないためコマンドはフルパスで指定する|
|ENV variable_name=default_value|後に $variable_name あるいは ${variable_name} で参照|
|${variable:-default_value} |variable が定義されていないときは default_value になる|
|${variable:+switch_value} |variable が定義されているとき switch_value になる。定義されていなければ空。|
|\$variable|$ は \ でエスケープ可能|
|環境変数の置き換えが有効なコマンド|ADD, COPY, ENV, EXPOSE, FROM, LABEL, STOPSIGNAL, USER, VOLUME, WORKDIR, ONBUILD (RUN が入っていないことに注意! build には環境変数は渡せない)|
|ENV で指定した環境変数はコンテナにも引き継がれる|確認するには docker inspect <image>, 置き換えるには docker run --env <キー>=<値>|
|ARG で指定した変数はコンテナに引き継がれない|build 中のみ意味を持つ|
|FROM の前にある ARG variable|FROM でのみ利用可能で構築ステージからは参照できない。参照したければ構築ステージにデフォルト値なしの ARG variable を書けば、外の値を引き継げる|
|キャッシュ|ADD 命令や COPY 命令より後ろの RUN 命令の内容はキャッシュされない。|
|CMD|RUN と同様にシェル形式と exec 形式の2つの書き方ができる。ENTRYPOINT が設定されていれば、JSON 配列形式で引数を記述する。docker run で上書きされない限り、デフォルトで実行されるコマンドになる|
|LABEL multi.label1="value1" multi.label2="value2" other="value3"|docker image inspect で参照可能なイメージのラベル情報を設定する|
|LABEL maintainer="SvenDowideit@home.org.au"|最近は MAINTAINER ではなく LABEL で著者情報を書き込むのが推奨|
|EXPOSE <ポート> [<ポート>/<プロトコル>...]|docker run -P とした際に公開されるポートを指定する?docker run --expose で公開ポートを追加できるし、この指定とは無関係に や docker run -p で任意のポートを公開できる。|
|ADD [--chown=<ユーザ>:<グループ>] <追加元>... <追加先>|追加元にはワイルドカードが使えるし、リモートや圧縮ファイルも指定できる。|
|COPY [--chown=<ユーザ>:<グループ>] [--from=<イメージ>] <コピー元>... <コピー先>|別のイメージからコピーすることもできる|
|ENTRYPOINT ["実行ファイル", "パラメータ1", "パラメータ2"]|シェル形式だと CMD や run コマンドラインの引数を使えず、シグナルも受け取れないので通常はこの exec 形式にする。|

** build [#r2e028ed]

 LANG:console
 $ DOCKER_BUILDKIT=1 docker build -f someDockerfile --build-arg ARG=VALUE --pull --rm=true -t tag-name (path|URL|-)

|-f someDockerfile | 指定されなければ path/Dockerfile が使われる|
| --build-arg ARG=VALUE | Dockerfile 中で ARG で定義された引数に値を設定する|
|環境変数|build には環境変数を渡せないので ARG を使う|
|DOCKER_BUILDKIT=1|BuildKit バックエンドを使う|
| --pull | 常に最新のイメージを pull する|
| --no-cache |キャッシュを使わず最新の情報でイメージを作成する|
| --rm=true | ビルドに成功したら中間コンテナを削除する|
| -t tag-name | イメージにタグをつける。複数指定してもいい。|
| -v でボリュームを指定することはできない| 代わりに COPY や ADD を使う|
| path の代わりに URL を与える| URL を git clone して、それをコンテキストとして使う|
| path の代わりに - とした場合|$ docker build - < Dockerfile などとできる。 標準入力へ hoge.tar.gz などを突っ込むとちゃんと展開して使われる|
| path にあるすべてのファイルが docker に渡される|ファイルが多いとパフォーマンスに影響する。 不必要なファイルを path/.dockerignore に入れておく。|
|返り値| 成功したら 0、失敗したらエラーコード|
 
*** 注意点 [#ha9ba21b]

docker build が docker run と大きく違うところが2つ
- 環境変数を引き継げないこと
- -v によるボリュームの指定が効かないこと

これらは docker の解説の中でもっともっと強調されるべきだと思う。

そして、この不整合のせいで Dockerfile やイメージ、コンテナの取り回しが非常に悪くなっているので、
何とか統合する方向で解消してほしい。

例えば build に COPY で Gemfile を与えて bundle install しても、
更新された Gemfile.lock はイメージの中にあって、app フォルダを -v 
でマウントしてしまうと隠れちゃう。それを回避するためにはむちゃくちゃ
アクロバティックなことをしなきゃならなくなるんだと思う。

build の環境と run の環境が異なった方が良いことなんてほとんどないはずなので、
ほんとこれ何とかしてほしい。

** run [#mcc4ded5]

 LANG:console
 $ docker run -it image

|-p 13000:3000|コンテナ内のポート 3000 をホストのポート 13000 経由で「外部へ」公開する。公開しなくてもホストや明示的に同じネットワークに置かれた他のコンテナからは任意のポートにアクセス可能。icc=true であれば任意の他のコンテナからアクセス可能。|
|-p 127.0.0.1:8080:8080|ポートを公開する範囲を制限する|
|--net some-network|docker network create some-network のようにして作成されたネットワークへ接続する。bridge には接続されなくなる。--net を付けなければデフォルトの bridge ネットワークに接続される。icc=true であれば bridge 内で自由に通信できる。icc=false であれば bridge 内では通信ができない。たぶん icc=false として docker-compose で個別ネットワークを作るのが楽なので直接触らなくてもいいのかも?|
|--net none|IP アドレスが振られなくなる。(none ネットワークへ接続する)|
|--restart=unless-stopped|stopされていれば再起動しない。ほとんどのケースで always より便利な気がする?|
|--add-host=host.docker.internal:host-gateway|コンテナの /etc/hosts にホストへの参照を host.docker.internal として追加する。コンテナからホストへ host.docker.internal という名前でアクセスできるようになる。|

* network [#i2ef2d87]

connect, create, disconnect, inspect, ls, prune, rm ができる。

たぶん docker-compose から使った方が楽なので直接触らなくてもいいのかも?

* /etc/docker/daemon.conf [#y70d72fb]

|icc=false|コンテナ間の通信をデフォルトで遮断する。通信するには個別にネットワークを張る必要がある。docker-compose でやれば簡単なはず。|

* Go テンプレート [#b0644795]

inspect に -f で与えるテンプレートの書式でよく使うもの。

https://astaxie.gitbooks.io/build-web-application-with-golang/content/ja/07.4.html

https://golang.hateblo.jp/entry/golang-text-html-template

https://pkg.go.dev/text/template

|{{.Name1.Name2}}||
|{{index .Name1.Name2 "Name.3"}}|名前をエスケープすなければならないときは index を使う|
|{{with .Item}}name: {{.Name}}, email: {{.Email}}{{end}}|スコープを設定する|
|{{range .Items}}{{.Name}}{{end}}|ループする|

* docker-compose [#af5bf4b0]

- docker-compose.yml 内ではホストの環境変数を自由に使える
-- sudo 経由で起動するときに環境変数を渡したければ sudo -E docker-compose のようにする
-- 環境変数が指定されなかった場合の規定値を .env ファイルに書いておける

- environment で指定した環境変数のみがコンテナに渡される
-- environment で値を指定しなかった環境変数はホストの変数の値がコンテナに渡される
-- environment で値を指定した場合にはホストの変数の値にはよらず指定された値がコンテナに渡される
-- environment で、ホストに変数が設定されていなかった場合の規定値を設定したい場合には~
VARIABLE=${VARIABLE:-(default-value)} のように ${  :-  } を使う

* docker 実験 [#mdd985f2]

** docker build で環境変数が効かないことを確認 [#nbd7068c]

 LANG:console
 $ cat Dockerfile
 FROM busybox
 ENV var1=default
 RUN echo var1=$var1
 $ var1=hello docker build --no-cache .
 $ var1=hello sudo -E docker build --no-cache .
 Sending build context to Docker daemon  3.072kB
 Step 1/3 : FROM busybox
  ---> 16ea53ea7c65
 Step 2/3 : ENV var1=default
  ---> Running in a6d8c3e7f731
 Removing intermediate container a6d8c3e7f731
  ---> 73d02c41b6f8
 Step 3/3 : RUN echo var1=$var1
  ---> Running in db039a001e2a
 var1=default
 Removing intermediate container db039a001e2a
  ---> 672ad5660024
 Successfully built 672ad5660024

やっぱり環境変数は渡せない。

inspect してもこうだし。

 LANG:console
 $ docker inspect 672ad5660024
 $ sudo docker inspect 672ad5660024
 [
     {
         "Id": "sha256:672ad5660024782ced68878e68c26dba5d54877d6bbcb6b2051b6e7168d67c4b",
         "RepoTags": [],
         "RepoDigests": [],
         "Parent": "sha256:73d02c41b6f8c9c9ce2c0fe672d1adfa445de303dfa419513746a808ab8d01c2",
         "Comment": "",
         "Created": "2021-09-22T13:31:35.877130065Z",
         "Container": "db039a001e2a0702dae61880f118155732e0ad4dec891e6defc0104efbaaba08",
         "ContainerConfig": {
             "Hostname": "",
             "Domainname": "",
             "User": "",
             "AttachStdin": false,
             "AttachStdout": false,
             "AttachStderr": false,
             "Tty": false,
             "OpenStdin": false,
             "StdinOnce": false,
             "Env": [
                 "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                 "var1=default"
             ],
             "Cmd": [
                 "/bin/sh",
                 "-c",
                 "echo var1=$var1"
             ],
             "Image": "sha256:73d02c41b6f8c9c9ce2c0fe672d1adfa445de303dfa419513746a808ab8d01c2",
             "Volumes": null,
             "WorkingDir": "",
             "Entrypoint": null,
             "OnBuild": null,
             "Labels": null
         },
         "DockerVersion": "20.10.8",
         "Author": "",
         "Config": {
             "Hostname": "",
             "Domainname": "",
             "User": "",
             "AttachStdin": false,
             "AttachStdout": false,
             "AttachStderr": false,
             "Tty": false,
             "OpenStdin": false,
             "StdinOnce": false,
             "Env": [
                 "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                 "var1=default"
             ],
             "Cmd": [
                 "sh"
             ],
             "Image": "sha256:73d02c41b6f8c9c9ce2c0fe672d1adfa445de303dfa419513746a808ab8d01c2",
             "Volumes": null,
             "WorkingDir": "",
             "Entrypoint": null,
             "OnBuild": null,
             "Labels": null
         },
         "Architecture": "amd64",
         "Os": "linux",
         "Size": 1235724,
         "VirtualSize": 1235724,
         "GraphDriver": {
             "Data": {
                 "MergedDir": "/var/lib/docker/overlay2/b4f2f0e969d6cbb29e2b74c6d622ed7b526ff6088949cd48e7d6a98749272892/merged",
                 "UpperDir": "/var/lib/docker/overlay2/b4f2f0e969d6cbb29e2b74c6d622ed7b526ff6088949cd48e7d6a98749272892/diff",
                 "WorkDir": "/var/lib/docker/overlay2/b4f2f0e969d6cbb29e2b74c6d622ed7b526ff6088949cd48e7d6a98749272892/work"
             },
             "Name": "overlay2"
         },
         "RootFS": {
             "Type": "layers",
             "Layers": [
                 "sha256:cfd97936a58000adc09a9f87adeeb7628a2c71d11c4998e6e7f26935fa0cd713"
             ]
         },
         "Metadata": {
             "LastTagTime": "0001-01-01T00:00:00Z"
         }
     }
 ]

やはり、

 LANG:console
             "Env": [
                 "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                 "var1=default"
             ],

なんてなっていて、環境変数を正しく渡せていない。

* DOCKER_OPTS="--iptables=true --icc=false" でちゃんと止まるか? [#x0dfe228]
** DOCKER_OPTS="--iptables=true --icc=false" でちゃんと止まるか? [#x0dfe228]

まずはデフォルトの状態で icc=true になっていることを確認。

 LANG:console
 $ docker --version
 $ sudo docker --version
 Docker version 20.10.8, build 3967b7d
 $ docker network inspect bridge 
 $ sudo docker network inspect bridge 
 [
     {
         "Name": "bridge",
         "Id": "f6990d3a60f07c2bcd8508e3b31ab06592e788e664c3f2b265b32ad6c18b0c61",
         "Created": "2021-09-23T23:07:43.180478077+09:00",
         "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": {}
     }
 ]
 $ docker network inspect bridge -f '{{index .Options "com.docker.network.bridge.enable_icc"}}'
 $ sudo docker network inspect bridge -f '{{index .Options "com.docker.network.bridge.enable_icc"}}'
 true

このときの iptables は、

 LANG:console
 $ sudo iptables -L -n
 ...
 
 Chain FORWARD (policy DROP)
 target     prot opt source               destination         
 DOCKER-USER  all  --  0.0.0.0/0            0.0.0.0/0           
 DOCKER-ISOLATION-STAGE-1  all  --  0.0.0.0/0            0.0.0.0/0           
 ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
 DOCKER     all  --  0.0.0.0/0            0.0.0.0/0           
 ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           
 ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           
 ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
 DOCKER     all  --  0.0.0.0/0            0.0.0.0/0           
 ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           
 ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           
 ufw-before-logging-forward  all  --  0.0.0.0/0            0.0.0.0/0           
 ufw-before-forward  all  --  0.0.0.0/0            0.0.0.0/0           
 ufw-after-forward  all  --  0.0.0.0/0            0.0.0.0/0           
 ufw-after-logging-forward  all  --  0.0.0.0/0            0.0.0.0/0           
 ufw-reject-forward  all  --  0.0.0.0/0            0.0.0.0/0           
 ufw-track-forward  all  --  0.0.0.0/0            0.0.0.0/0           
 ...
 
 Chain DOCKER (2 references)
 target     prot opt source               destination         
 ACCEPT     tcp  --  0.0.0.0/0            172.17.0.2           tcp dpt:5000
 ACCEPT     tcp  --  0.0.0.0/0            172.17.0.3           tcp dpt:25565
 ACCEPT     tcp  --  0.0.0.0/0            172.20.0.2           tcp dpt:3000
 
 Chain DOCKER-ISOLATION-STAGE-1 (1 references)
 target     prot opt source               destination         
 DOCKER-ISOLATION-STAGE-2  all  --  0.0.0.0/0            0.0.0.0/0           
 DOCKER-ISOLATION-STAGE-2  all  --  0.0.0.0/0            0.0.0.0/0           
 RETURN     all  --  0.0.0.0/0            0.0.0.0/0           
 
 Chain DOCKER-ISOLATION-STAGE-2 (2 references)
 target     prot opt source               destination         
 DROP       all  --  0.0.0.0/0            0.0.0.0/0           
 DROP       all  --  0.0.0.0/0            0.0.0.0/0           
 RETURN     all  --  0.0.0.0/0            0.0.0.0/0           
 
 Chain DOCKER-USER (1 references)
 target     prot opt source               destination         
 RETURN     all  --  0.0.0.0/0            0.0.0.0/0           
 ...

実のところよくわからん。

オライリーの Docker 本にあったように、
netcat を 4000 で動かしてそこにメッセージを送るテストをしてみる。

 LANG:console
 $ cat<<EOT |docker build -t debian-netcat -
 $ cat<<EOT | sudo docker build -t debian-netcat -
 FROM debian:bullseye-slim
 RUN sed -i "s/debian bullseye main/debian bullseye main contrib non-free/" /etc/apt/sources.list && \ 
     apt update && \
     apt upgrade -y && \
     apt install -y netcat
 EOT
 $ docker run --name nc-server -d debian-netcat nc -l 4000
 $ sudo docker run --name nc-server -d debian-netcat nc -l 4000
 d429f376731d0415071f9ad8f930f3152b5b62b4b2ef9b7c2068f195ad6b7505
 $ docker inspect -f {{.NetworkSettings.IPAddress}} nc-server
 $ sudo docker inspect -f {{.NetworkSettings.IPAddress}} nc-server
 172.17.0.5
 $ docker run --rm debian-netcat /bin/sh -c "echo 'hello' | nc -w 2 -v 172.17.0.5 4000"
 $ sudo docker run --rm debian-netcat /bin/sh -c "echo 'hello' | nc -w 2 -v 172.17.0.5 4000"
 Connection to 172.17.0.5 4000 port [tcp/*] succeeded!
 $ docker logs nc-server
 $ sudo docker logs nc-server
 hello
 $ docker ps -a
 $ sudo docker ps -a
 CONTAINER ID   IMAGE           COMMAND        CREATED              STATUS                      PORTS        NAMES
 72c9cf65c30b   debian-netcat   "nc -l 4000"   About a minute ago   Exited (0) 55 seconds ago                nc-server
 $ docker rm nc-server
 $ sudo docker rm nc-server

確かに送れる。

icc=false に設定を変えてみる。

 LANG:console
 $ cat /etc/default/docker  # これは効かないので編集しない
 # Docker Upstart and SysVinit configuration file
 
 #
 # THIS FILE DOES NOT APPLY TO SYSTEMD
 #
 #   Please see the documentation for "systemd drop-ins":
 #   https://docs.docker.com/engine/admin/systemd/
 $ sudo jed /etc/docker/daemon.json # こちらで設定する
 {
   "icc":false,
   "iptables":true
 }
 $ sudo systemctl restart docker
 $ docker network inspect bridge -f '{{index .Options "com.docker.network.bridge.enable_icc"}}'
 $ sudo docker network inspect bridge -f '{{index .Options "com.docker.network.bridge.enable_icc"}}'
 true

変更された。

 LANG:console 
 $ sudo iptables -L -n
 ...
 
 Chain FORWARD (policy DROP)
 target     prot opt source               destination         
 DOCKER-USER  all  --  0.0.0.0/0            0.0.0.0/0           
 DOCKER-ISOLATION-STAGE-1  all  --  0.0.0.0/0            0.0.0.0/0           
 ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
 DOCKER     all  --  0.0.0.0/0            0.0.0.0/0           
 ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           
 ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
 DOCKER     all  --  0.0.0.0/0            0.0.0.0/0           
 ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           
 ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           
 ufw-before-logging-forward  all  --  0.0.0.0/0            0.0.0.0/0           
 ufw-before-forward  all  --  0.0.0.0/0            0.0.0.0/0           
 ufw-after-forward  all  --  0.0.0.0/0            0.0.0.0/0           
 ufw-after-logging-forward  all  --  0.0.0.0/0            0.0.0.0/0           
 ufw-reject-forward  all  --  0.0.0.0/0            0.0.0.0/0           
 ufw-track-forward  all  --  0.0.0.0/0            0.0.0.0/0           
 DROP       all  --  0.0.0.0/0            0.0.0.0/0           
 ...
 
 Chain DOCKER (2 references)
 target     prot opt source               destination         
 ACCEPT     tcp  --  0.0.0.0/0            172.20.0.2           tcp dpt:3000
 ACCEPT     tcp  --  0.0.0.0/0            172.17.0.2           tcp dpt:5000
 ACCEPT     tcp  --  0.0.0.0/0            172.17.0.3           tcp dpt:25565
 ACCEPT     tcp  --  0.0.0.0/0            172.17.0.4           tcp dpt:8080
 ACCEPT     tcp  --  172.17.0.4           172.17.0.2           tcp dpt:5000
 ACCEPT     tcp  --  172.17.0.2           172.17.0.4           tcp spt:5000
 
 Chain DOCKER-ISOLATION-STAGE-1 (1 references)
 target     prot opt source               destination         
 DOCKER-ISOLATION-STAGE-2  all  --  0.0.0.0/0            0.0.0.0/0           
 DOCKER-ISOLATION-STAGE-2  all  --  0.0.0.0/0            0.0.0.0/0           
 RETURN     all  --  0.0.0.0/0            0.0.0.0/0           
 
 Chain DOCKER-ISOLATION-STAGE-2 (2 references)
 target     prot opt source               destination         
 DROP       all  --  0.0.0.0/0            0.0.0.0/0           
 DROP       all  --  0.0.0.0/0            0.0.0.0/0           
 RETURN     all  --  0.0.0.0/0            0.0.0.0/0           
 
 Chain DOCKER-USER (1 references)
 target     prot opt source               destination         
 RETURN     all  --  0.0.0.0/0            0.0.0.0/0           
 ...

確かに FORWARD の最後に DROP が追加されてるけど、
そもそも POLICY が drop だし、
その前に ACCEPT されてるので2重の意味で意味ないような???

実際に確認してみる。

 LANG:console
 $ docker run --rm --name nc-server -d debian-netcat nc -l 4000
 $ sudo docker run --rm --name nc-server -d debian-netcat nc -l 4000
 6d19b684d35586a2d5f2ae6a0eb543915751822335b0c13fca0afef12ad9a6a5
 $ docker run --rm debian-netcat /bin/sh -c "echo 'hello' | nc -w 2 -v 172.17.0.5 4000"
 $ sudo docker run --rm debian-netcat /bin/sh -c "echo 'hello' | nc -w 2 -v 172.17.0.5 4000"
 nc: connect to 172.17.0.5 port 4000 (tcp) timed out: Operation now in progress
 $ docker stop nc-server 
 $ sudo docker stop nc-server 
 nc-server

ふむ、ちゃんと止まってるね。

 LANG:console
 $ docker run --name nc-server -d debian-netcat nc -l 4000
 $ sudo docker run --name nc-server -d debian-netcat nc -l 4000
 d1c669103b25d8a7f7a3954d9bfa8d9a67c9473bbf550659fbfd66de7d4e64f6
 osamu@center:~$ echo "hello" | nc -w 2 -v `docker inspect -f {{.NetworkSettings.IPAddress}} nc-server` 4000
 172.17.0.3: inverse host lookup failed: Host name lookup failure
 (UNKNOWN) [172.17.0.3] 4000 (?) open
 $ docker logs nc-server 
 $ sudo docker logs nc-server 
 hello
 $ docker rm nc-server 
 $ sudo docker rm nc-server 

ホストからは通信できるのか。あれ?そうだっけ???

expose した場合も、

 LANG:console
 $ docker run --name nc-server --expose 4000 -d debian-netcat nc -l 4000
 $ sudo docker run --name nc-server --expose 4000 -d debian-netcat nc -l 4000
 a8d8a91971b39edb087ae2cf7de8a336caef898db45b5e70930e4891896a8784
 $ docker ps
 $ sudo docker ps
 CONTAINER ID   IMAGE           COMMAND        CREATED              STATUS             PORTS      NAMES
 a8d8a91971b3   debian-netcat   "nc -l 4000"   About a minute ago   Up About a minute  4000/tcp   nc-server
 $ docker run --rm debian-netcat /bin/sh -c "echo 'hello' | nc -w 2 -v 172.17.0.5 4000"
 $ sudo docker run --rm debian-netcat /bin/sh -c "echo 'hello' | nc -w 2 -v 172.17.0.5 4000"
 nc: connect to 172.17.0.5 port 4000 (tcp) timed out: Operation now in progress

そのままでは通信できず、明示的に繋いでやると繋がる。

 LANG:console
 $ docker network create nc-net
 $ docker network connect nc-net nc-server
 $ docker run --net nc-net --rm debian-netcat /bin/sh -c "echo 'hello' | nc -w 2 -v nc-server 4000"
 $ sudo docker network create nc-net
 $ sudo docker network connect nc-net nc-server
 $ sudo docker run --net nc-net --rm debian-netcat /bin/sh -c "echo 'hello' | nc -w 2 -v nc-server 4000"
 Connection to nc-server (172.18.0.2) 4000 port [tcp/*] succeeded!
 $ docker logs nc-server 
 $ sudo docker logs nc-server 
 hello
 $ docker rm nc-server 
 $ sudo docker rm nc-server 
 nc-server

ん?明示的に繋いだ場合には expose してなくても繋がるのか。

 LANG:console
 $ docker run --name nc-server -d debian-netcat nc -l 4000
 $ docker network connect nc-net nc-server
 $ docker run --net nc-net --rm debian-netcat /bin/sh -c "echo 'hello' | nc -w 2 -v nc-server 4000"
 $ sudo docker run --name nc-server -d debian-netcat nc -l 4000
 $ sudo docker network connect nc-net nc-server
 $ sudo docker run --net nc-net --rm debian-netcat /bin/sh -c "echo 'hello' | nc -w 2 -v nc-server 4000"
 Connection to nc-server (172.18.0.2) 4000 port [tcp/*] succeeded!
 $ docker logs nc-server 
 $ sudo docker logs nc-server 
 hello
 $ docker rm nc-server 
 $ sudo docker rm nc-server 
 nc-server

特定のポートだけ接続を許可することはできないんだっけ???

 LANG:console
 $ docker run --name nc-server -d debian-netcat nc -l 4000
 $ docker inspect -f {{.NetworkSettings.IPAddress}} nc-server
 $ sudo docker run --name nc-server -d debian-netcat nc -l 4000
 $ sudo docker inspect -f {{.NetworkSettings.IPAddress}} nc-server
 172.17.0.3
 $ docker inspect -f '{{.NetworkSettings.Networks}}' nc-server
 $ sudo docker inspect -f '{{.NetworkSettings.Networks}}' nc-server
 map[bridge:0xc0003f6000]
 $ docker network disconnect bridge nc-server
 $ docker inspect -f {{.NetworkSettings.IPAddress}} nc-server
 $ sudo docker network disconnect bridge nc-server
 $ sudo docker inspect -f {{.NetworkSettings.IPAddress}} nc-server
 
 $ docker network create nc-net
 $ docker network connect nc-net nc-server 
 $ docker inspect -f {{.NetworkSettings.IPAddress}} nc-server
 $ sudo docker network create nc-net
 $ sudo docker network connect nc-net nc-server 
 $ sudo docker inspect -f {{.NetworkSettings.IPAddress}} nc-server
 
 $ docker inspect -f '{{.NetworkSettings.Networks}}' nc-server
 $ sudo docker inspect -f '{{.NetworkSettings.Networks}}' nc-server
 map[nc-net:0xc000128000]
 $ docker inspect -f '{{index .NetworkSettings.Networks "nc-net" "IPAddress"}}' nc-server
 $ sudo docker inspect -f '{{index .NetworkSettings.Networks "nc-net" "IPAddress"}}' nc-server
 172.19.0.2 
 $ echo "hello" | nc -w 2 -v 172.19.0.2 4000
 172.19.0.2: inverse host lookup failed: Host name lookup failure
 (UNKNOWN) [172.19.0.2] 4000 (?) open
 $ sudo ip addr
 ...
 
 767: br-d0923cd048ab: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
     link/ether 02:42:4c:26:5f:cb brd ff:ff:ff:ff:ff:ff
     inet 172.19.0.1/16 brd 172.19.255.255 scope global br-d0923cd048ab
        valid_lft forever preferred_lft forever
     inet6 fe80::42:4cff:fe26:5fcb/64 scope link 
        valid_lft forever preferred_lft forever
 $ docker rm nc-server
 $ sudo docker rm nc-server
 nc-server
 $ docker network rm nc-net
 $ sudo docker network rm nc-net
 nc-net

ふむ。

bridge ネットワークから除いたとしても、ホストからはやはりアクセスできてしまうみたいだね。

オフトピだけど --net none で run すると、IP Address は割り振られないらしい。

 LANG:console
 $ docker run --net none --name nc-server -d debian-netcat nc -l 4000
 $ docker inspect nc-server 
 $ sudo docker run --net none --name nc-server -d debian-netcat nc -l 4000
 $ sudo docker inspect nc-server 
 ...
            "Networks": {
                "none": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "NetworkID": "34f9883d1ad191a0d5514423814aa52e2d0902070456f42d3ef1e658801d7e49",
                    "EndpointID": "193fedb535244c29f24cb31177978bdb0027dc5a1f59fe1203d630b851111233",
                    "Gateway": "",
                    "IPAddress": "",
                    "IPPrefixLen": 0,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "",
                    "DriverOpts": null
                }
            }
 $ docker rm -f nc-server
 $ sudo docker rm -f nc-server

いきなり --net で接続した場合も bridge へ接続されなくなる。

 LANG:console
 $ docker rm -f nc-server 
 $ sudo docker rm -f nc-server 
 nc-server
 $ docker run --net nc-net --name nc-server -d debian-netcat nc -l 4000
 $ docker inspect -f '{{.NetworkSettings.Networks}}' nc-server
 $ sudo docker run --net nc-net --name nc-server -d debian-netcat nc -l 4000
 $ sudo docker inspect -f '{{.NetworkSettings.Networks}}' nc-server
 map[nc-net:0xc0005e2000]
 $ docker rm -f nc-server
 $ sudo docker rm -f nc-server
 nc-server
 $ docker network rm nc-net
 $ sudo docker network rm nc-net
 nc-net

** --add-host=host.docker.internal でホストの smtp へアクセスする [#x3dda809]

ホスト側の設定も必要:
- ufw でコンテナからのアクセスを許可する
- exim4 でコンテナからのリレーを許可する

 LANG:console
 $ sudo docker run --rm --add-host=host.docker.internal:host-gateway busybox cat /etc/hosts
 ...
 172.17.0.1      host.docker.internal
 172.17.0.4      36dff2944ba8
 $ sudo ufw allow from 172.16.0.0/12 proto tcp to any port 25
 Rule added
 $ sudo docker run -it --rm --add-host=dockerhost:host-gateway busybox sh
 / # telnet dockerhost 25
 Connected to dockerhost
 220 dora.bk.tsukuba.ac.jp ESMTP Exim 4.94.2 Mon, 04 Oct 2021 13:12:29 +0900
 HELP
 214-Commands supported:
 214 AUTH STARTTLS HELO EHLO MAIL RCPT DATA BDAT NOOP QUIT RSET HELP
 QUIT
 221 dora.bk.tsukuba.ac.jp closing connection
 Connection closed by foreign host
 $ sudo jed /etc/exim4/exim4.conf.template
 + MAIN_RELAY_NETS = 172.16.0.0/12
 $ sudo update-exim4.conf
 $ sudo systemctl restart exim4
 $ sudo docker run --rm --add-host=host.docker.internal:host-gateway -it busybox \
   sh -c "echo testbody | /bin/sendmail -S host.docker.internal takeuchi.osamu.ft@u.tsukuba.ac.jp"

これでコンテナからメールを送れた。

** sudo -E で環境変数を受け渡す [#xafaa69d]

sudo に -E を付けることで、docker へ環境変数を引き継げる。

 LANG:console
 $ TEST=test sudo docker run --rm -e TEST busybox sh -c 'echo $TEST'
 
 $ TEST=test sudo -E docker run --rm -e TEST busybox sh -c 'echo $TEST'
 test

なので、.bashrc に

 alias docker='sudo -E docker'
 alias docker-compose='sudo -E docker-compose'

なんてしておくと便利。

自分を docker グループに入れちゃうと、万一、自分のアカウント権限を乗っ取られたときに自動的に root 権限まで取られてしまうのに対して、この alias 設定ならパスワードを聞かれるので少しは安全なはず。


Counter: 2976 (from 2010/06/03), today: 1, yesterday: 0