docker in docker

昼食後は昼寝と言うかうたた寝と言うかシエスタと言うか多層睡眠をする事にしてる。本格的に布団を敷いて寝てしまうと、起きられなくなって しまうので、ソファーにごろり。肘置きを枕にしてね。

で、その昼寝で悲劇が起こった。大惨事。さて、どんな惨事でしょうか? 報告はCMの後で、 とかやっちゃうと、最近とみに酷いTV並みになっちゃうんで、取り合えず想像して楽しんで ください。

寝ぼけてソファーから落っこち、肋骨を折った。長年使ってヘタってきた ソファが壊れて、尻が挟まった?

寝違えて、全治1週間のむち打ち症状。幸いな事に交通事故を喰らって、むち打ち症って経験は 無いんだけど、多分、これがむち打ち症なんだろな。

首が(痛くて)回せません。本を読むのでちょっと頭を下向きに出来ません。女房に呼ばれても首を回せません、体ごと反転させます。首へのコルセットが欲しいとマジで思った次第。でも、じっと我慢。

散歩ぐらいは出来るんだけど、前から来た人に軽く会釈するってのが出来ない。こちらの人は 律儀で、よく頭を下げて挨拶してくれるんだけど、返礼が出来ない。申し訳ない。 いちいち、ただいま、寝違えて首を垂れませんと言うもの馬鹿みたいだしね。

そんなこんなで、難儀な一週間でした。

nc

前回見つけておいたpyftpdlibを使って、マストドン内のファイルをClearLinux側に転送してみる。

clearLinux側で、サーバーを立てて

[clr tmp]$ python3 -m pyftpdlib
[I 2017-06-24 16:03:56] >>> starting FTP server on 0.0.0.0:2121, pid=1299 <<<
[I 2017-06-24 16:03:56] concurrency model: async
[I 2017-06-24 16:03:56] masquerade (NAT) address: None
[I 2017-06-24 16:03:56] passive ports: None                                     [I 2017-06-24 16:04:31] 172.18.0.2:47196-[] FTP session opened (connect)
[I 2017-06-24 16:04:31] 172.18.0.2:47196-[anonymous] USER 'anonymous' logged in.[I 2017-06-24 16:04:31] 172.18.0.2:47196-[anonymous] FTP session closed (disconnect).

マストドン側からput

/tmp # ftpput -P 2121 -u anonymous -p anonymous 172.18.0.1 secret.log
ftpput: unexpected server response to STOR: 550 Not enough privileges.

特権が足りないと言われててもねぇ。送り出し側がrootってのが気に障るのかしらん。 マストドンユーザーにしても、やはり同様エラー。一応 -vを付けてみた。

Connecting to 172.18.0.1 (172.18.0.1:2121)
ftpput: cmd (null) (null)
ftpput: cmd USER anonymous
ftpput: cmd PASS anonymous
ftpput: cmd TYPE I (null)
ftpput: cmd PASV (null)
ftpput: cmd STOR secret.log
ftpput: unexpected server response to STOR: 550 Not enough privileges.

PASVがnullって、そりゃないでしょ。

まあ、こういう事もあらーな。強い兵士は、サバイバルできなければいけません。 で、/usr/binの中をじっと観察します。オイラーの琴線に触れるコマンドが見つかりましたよ。 幸い、ClearLinux側にも同様なコマンドが用意されてました。(後で調べたら、BSDにも有る、 標準コマンドでした)

サーバー側(Clear Linux)で待ち受けする。

[clr tmp]$ nc -l -p 1234 > T.txt

そしてクライアント側(mastodon in docker)から送信する。

/tmp # nc -n  172.18.0.1 1234 < T.txt

サーバー側は、データを受信すると、コマンドが自動終了する。これ、面倒なくて便利。

result

前回の続きで、シークレットはどうしてるか? 調べたら、下記の動的ファイルに有った。

vendor/bundle/ruby/2.4.0/gems/railties-5.0.3/lib/rails/tasks/misc.rake

desc 'Generate a cryptographically secure secret key (this is typically used to
generate a secret for cookie sessions).'
task :secret do
  require 'securerandom'
  puts SecureRandom.hex(64)
end

もう、追うの止めよう、どんどんと迷宮に入って行く感じがするから。

pyftpdlibの正しい使い方

先に試した、pyftpdlibでftpサーバーを作り、そこにftpputを使ってファイルをアップロード する作戦。パッシブモード問題と瞬間判断したけど、早とちりだな。転送コマンドが出された後に、特権が無いと言ってるから。(年寄りですから、判断が鈍るのね。歳は取りたくないな) 端的に言うと、サーバー側の問題だ。

場所を変えて、Debianで検証してみる。で、困った事が有る。ftpputなんてのが無い。ftpなら 有るんだけど...で、ftpでもいいじゃんと思ってmanするも、ポートは昔から21番と決まってて、任意に設定出来ない。

諦めて、pyftpdlibの__main__.py あたりを見ると、オプションで任意に設定出来るように なってた。21番さんは特権ポートなので、特権を付けて起動。

[debian tmp]$ sudo /home/sakae/conda3/bin/python -m pyftpdlib  -p 21

普通のftpを普通に使ってみた。

[debian ob61]$ ftp localhost
ftp: connect to address ::1: Connection refused
Trying 127.0.0.1...
Connected to localhost.
220 pyftpdlib 1.5.2 ready.
Name (localhost:sakae): anonymous
331 Username ok, send password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls
200 Active data connection established.
125 Data connection already open. Transfer starting.
  :
drwxrwxrwt   2 root     root           40 Jun 24 20:19 .font-unix
drwx------   2 sakae    sakae          60 Jun 24 20:26 tmux-1000
226 Transfer complete.
ftp> put serial
local: serial remote: serial
200 Active data connection established.
550 Not enough privileges.
ftp> quit
421 Data connection timed out.

サーバー側のデフォルトのdirは、サーバーを起動した(/tmp)場所になってた。で、putして みると、特権足りないぞ、ボケ が、出てきた。

改めて、__main__.py を見直すと

    parser.add_option('-p', '--port', type="int", default=2121, metavar="PORT",
                      help="specify port number to run on (default 2121)")
    parser.add_option('-w', '--write', action="store_true", default=False,
                      help="grants write access for the anonymous user "
                           "(default read-only)")

grantsってSQLのコマンド名に採用されてたな。と言う落ちが待ってましたよ。英語が 分からない君にもヒントって事で、デフォルトでは読み出しだけよって、注意書きも されたたぞ。親切な作者さんだ。これがpython流のおもてなしだな。

実際に-wを付けて起動すると、誰でも書き込めちゃ危ないよと警告が出てきた。putすると、 受け取ったファイル名とそのサイズを報告しつつ、格納してくれたよ。

raspberry pi

数独を解くのに現代風なWolframを使うとかで、雲の向こう側にあるサーバーをアクセス するんだけど、手元にも置いておきたい。何処かにあったなと過去の記憶を辿ると、 去年の夏ぐらいに、ラズパイの真似をした時に出てきてた。あの時は、32Bit版のWindows7 だったので、今回のWindows10でどれだけ速くなったか検証してみる。

QEMUでRaspbianのsandbox環境を構築する

Raspberry pi(Raspbian Jessie)を OS X の QEMU で動かす

Raspberry Pi 不要パッケージの削除

こんな所を参考に入れてみた。使ったカーネルは下記。

pi@raspberrypi:~$ uname -a
Linux raspberrypi 4.4.34+ #3 Thu Dec 1 14:44:23 IST 2016 armv6l GNU/Linux

いざ実行すると、大分待たされたあげぐ、ユーザー登録しろと 言われた。待たされるのは、ブラウザーから登録させようとしてるからかな?

/optの中にあるmathを起動するも、やはりユーザー登録を要求してるっぽい。さして速いとも 思われないので、使うのを断念したよ。

その代わり、qemu-arm-staticを入れて、armの雰囲気だけを味わう事にした。 unameを問うと、amd64と言ってきた。なのに、けなげにarmv61のふりをしてくれてる。 おかげで、ドッカー並みに直ぐに使えるけどね。

[debian RASP]$ ./boot
root@debian:/# uname -a
Linux debian 3.16.0-4-amd64 #1 SMP Debian 3.16.43-2 (2017-04-30) armv6l GNU/Linux
root@debian:/# cat /etc/os-release
PRETTY_NAME="Raspbian GNU/Linux 8 (jessie)"
NAME="Raspbian GNU/Linux"
VERSION_ID="8"
VERSION="8 (jessie)"
ID=raspbian
ID_LIKE=debian
HOME_URL="http://www.raspbian.org/"
SUPPORT_URL="http://www.raspbian.org/RaspbianForums"
BUG_REPORT_URL="http://www.raspbian.org/RaspbianBugs"

bootっていう、いかにもな名前を付けてるけど、実態は、 イメージをループマウントしてから、chrootしてるだけ。

[debian RASP]$ cat boot
sudo mount -o offset=47185920 170410.img rootfs
sudo QEMU_CPU=arm1176 chroot rootfs
sudo umount /home/sakae/RASP/rootfs

qemu-aarch64-static なんてのが有って、どうもこれがarm64だと思うんだけど、、、 OSのタスク切り替え処理とaarch64(ARM64)の関数呼び出し規約やっぱり、そうなのね。知らなかったぞ。

docker in docker

ドッカーって、chrootっぽい事をやってないかい? ただ使うだけだと、実態が闇に包まれて しまっているんで、紐解いてみたい。

去年のアドベンドカレンダーに投稿されてたのを参考に、後追いしてみる。

Docker Engineをソースコードからビルドする

[clr docker]$ make BIND_DIR=. shell
  :
Step 51/51 : COPY . /go/src/github.com/docker/docker
 ---> 539486b8857a
Removing intermediate container 7b121ea28e92
Successfully built 539486b8857a
Successfully tagged docker-dev:master
docker run --rm -i --privileged   -e BUILD_APT_MIRROR -e BUILDFLAGS -e KEEPBUNDLE -e DOCKER_BUILD_ARGS -e DOCKER_BUILD_GOGC -e DOCKER_BUILD_PKGS -e DOCKER_CLI_PATH -e DOCKER_DEBUG -e DOCKER_EXPERIMENTAL -e DOCKER_GITCOMMIT -e DOCKER_GRAPHDRIVER -e DOCKER_INCREMENTAL_BINARY -e DOCKER_PORT -e DOCKER_REMAP_ROOT -e DOCKER_STORAGE_OPTS -e DOCKER_USERLANDPROXY -e TESTDIRS -e TESTFLAGS -e TIMEOUT -e HTTP_PROXY -e HTTPS_PROXY -e NO_PROXY -e http_proxy -e https_proxy -e no_proxy -v "/home/sakae/docker/.:/go/src/github.com/docker/docker/." -v /home/sakae/docker/.git:/go/src/github.com/docker/docker/.git -v "dockerdev-go-pkg-cache-gopath:/go/pkg" -v "dockerdev-go-pkg-cache-goroot-linux_amd64:/usr/local/go/pkg/linux_amd64" -v "dockerdev-go-pkg-cache-goroot-linux_amd64_netgo:/usr/local/go/pkg/linux_amd64_netgo"   -t "docker-dev:master" bash
root@12579827e63d:/go/src/github.com/docker/docker#

途中、debianの開発環境をごっそり取って来るので、結構時間がかかる。なんたって、51の ステップに分かれて、ごちゃごちゃやりますからねえ。

で、出来上がった物。これでやっとこさdockerを作るための環境が整った。

[clr tmp]$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
docker-dev          master              539486b8857a        58 seconds ago      2.34GB
debian              jessie              a25c1eed1c6f        9 days ago          123MB
[clr tmp]$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
12579827e63d        docker-dev:master   "hack/dind bash"    2 minutes ago       Up 2 minutes                            nostalgic_noether

次は、いよいよバイナリーを作るとな。

root@12579827e63d:/go/src/github.com/docker/docker# hack/make.sh binary

---> Making bundle: binary (in bundles/17.06.0-dev/binary)
Building: bundles/17.06.0-dev/binary-daemon/dockerd-17.06.0-dev
Created binary: bundles/17.06.0-dev/binary-daemon/dockerd-17.06.0-dev
Copying nested executables into bundles/17.06.0-dev/binary-daemon

後は、成果物を確認。

root@12579827e63d:/go/src/github.com/docker/docker/bundles/17.06.0-dev/binary-daemon# ls -l dockerd
lrwxrwxrwx 1 root root 19 Jun 25 07:30 dockerd -> dockerd-17.06.0-dev

実体の方を /usr/bin/dockerd として、コピーしておいた。 そして、いよいよ起動。

root@12579827e63d:/go/src/github.com/docker/docker# dockerd -D &
[1] 4087
root@12579827e63d:/go/src/github.com/docker/docker# DEBU[0000] Listener created
for HTTP on unix (/var/run/docker.sock)
INFO[0000] libcontainerd: new containerd process, pid: 4092
DEBU[0000] containerd: grpc api on /var/run/docker/libcontainerd/docker-containe
rd.sock
  :
DEBU[0001] Registering POST, /networks/prune
DEBU[0001] Registering DELETE, /networks/{id:.*}
INFO[0001] API listen on /var/run/docker.sock

そして、動作確認の一歩目。

root@12579827e63d:/go/src/github.com/docker/docker# docker version
DEBU[0302] Calling GET /_ping
DEBU[0302] Calling GET /v1.30/version
Client:
 Version:      unknown-version
 API version:  1.30
 Go version:   go1.8.3
 Git commit:   unknown-commit
 Built:        unknown-buildtime
 OS/Arch:      linux/amd64

Server:
 Version:      17.06.0-dev
 API version:  1.31 (minimum version 1.12)
 Go version:   go1.8.3
 Git commit:   4f259698b
 Built:        Sat Jun 25 07:08:22 2017
 OS/Arch:      linux/amd64
 Experimental: false

心配だった docker は、/usr/local/bin の下に用意されてたぞ。バージョン不明って言ってるで、 今回作られたものじゃなく、debianと共にやって来たものかな?

第2歩目は、お約束のハロワとalpineです。

root@12579827e63d:~# docker ps -a
DEBU[1935] Calling GET /_ping
DEBU[1935] Calling GET /v1.30/containers/json?all=1
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                     PORTS               NAMES
415f0300b1b0        alpine              "/bin/ash"          3 minutes ago       Exited (0) 2 minutes ago                       nervous_boyd
98d68bfb4b99        hello-world         "/hello"            7 minutes ago       Exited (0) 7 minutes ago                       eloquent_hermann

ちゃんと動きました。

docker service

ClearLinux側のdockerdって、どんな風に起動してるか、調べてみる。手がかりは、登録時に 出て来るあれ。

[clr ~]# systemctl enable docker
Created symlink /etc/systemd/system/multi-user.target.wants/docker.service → /usr/lib/systemd/system/docker.service.

そして、docker.serviceの仕様書になるかな。

[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target docker.socket firewalld.service
Wants=network-online.target
Requires=docker.socket

[Service]
Type=notify
ExecStart=/usr/bin/dockerd -H fd:// --storage-driver=overlay
ExecReload=/bin/kill -s HUP $MAINPID
LimitNPROC=infinity
LimitCORE=infinity
TimeoutStartSec=0
Delegate=yes
KillMode=process
Restart=on-failure
StartLimitBurst=3
StartLimitInterval=60s

[Install]
WantedBy=multi-user.target

こちらは、同じ所にあった、docket.socket

[Unit]
Description=Docker Socket for the API
PartOf=docker.service

[Socket]
ListenStream=/var/run/docker.sock
SocketMode=0660
SocketUser=root
SocketGroup=docker

[Install]
WantedBy=sockets.target

コピペの作法

よくWebに掲載されてるコードをコピペして試す事が有る。コピペ用の台紙は、viなりemacsの 白紙のページって事が多い。

コードがpython語とかhaskell語みたいに、レイアウト命って場合は、都合が悪い事が発生 する場合が有る。前行のレイアウトを見て、editorが勝手にレイアウトを変更してしまう事が 有るんだ。そんな場合はどうするか?

答えは、editor画面に張り付けるな。奴らはインテリジェント過ぎるから。

[clr tmp]$ cat -- > hoge.py
   :     ;; ペーストする
Ctl+d    ;; 終了

常識だったら、スマソ。

これも常識っぽいけど、 以前出て来た あらゆる数独パズルを解く を、ipython上で試そうとすると

In [1]: import sudoku

In [2]: grid1 = '003020600900305001001806400008102900700000008006708200002609500
   ...: 800203009005010300'

In [3]: display(parse_grid(grid1))
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-4-5b55b305dbdd> in <module>()
----> 1 display(parse_grid(grid1))

NameError: name 'parse_grid' is not defined

と、何も考えないコピペ野郎は、怒られるのであります。で、少しは頭を使って

In [1]: from sudoku import *

In [2]: grid1 = '003020600900305001001806400008102900700000008006708200002609500
   ...: 800203009005010300'

In [3]: display(parse_grid(grid1))
4 8 3 |9 2 1 |6 5 7
9 6 7 |3 4 5 |8 2 1
2 5 1 |8 7 6 |4 9 3
------+------+------
5 4 8 |1 3 2 |9 7 6
7 2 9 |5 6 4 |1 3 8
1 3 6 |7 9 8 |2 4 5
------+------+------
3 7 2 |6 8 9 |5 1 4
8 1 4 |2 5 3 |7 6 9
6 9 5 |4 1 7 |3 8 2

何とか、切り抜けられました。

clear Linux + miniconda3

VBOXに入れたclear Linuxでもグラフを書きたい。常用してるのはgnuplotなんだけど、 そんなのバンドルに入っていない。そこで、バッテリーであるminiconda3を入れました。

下記のように、設定。

sakae@clr:~$ cat /etc/ssh/sshd_config
X11Forwarding=yes
sakae@clr:~$ echo $DISPLAY
localhost:10.0

テストスクリプト。最後にshowが無いと、描画されないので注意。

sakae@clr:~$ cat t.py
import numpy as np
import matplotlib.pyplot as plt

plt.hist(np.random.randn(1000))
plt.show()

ipythonにrunコマンドが有った事を思い出した。

sakae@clr:~$ ipython
Python 3.6.1 |Continuum Analytics, Inc.| (default, May 11 2017, 13:09:58)
Type 'copyright', 'credits' or 'license' for more information
IPython 6.1.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: run t.py
QXcbConnection: XCB error: 145 (Unknown), sequence: 165, resource id: 0, major code: 139 (Unknown), minor code: 20

どきっとするようなメッセージを表示しつつも、ヒストグラム図が表示されたぞ。