Docker in Docker のメモ書き
「Dockerの中でDcckerを動かしたい」ということはよくあると思う. 主に2つのアプローチが存在する.
- dind(DockerinDocker)イメージを利用
- sockをホスト-コンテナで共有する
今回は後者を取り上げる. なお, どちらの方法もセキュリティ的にやや難ありなので注意して使う必要がある. 以降, すべてのホストをA
, 通常のコンテナをB
, コンテナ内から呼び出されるコンテナをC
とする.
利用方法は非常にシンプル. A
-B
間で「sock」と「dockerコマンドそのもの」をrun時にvolume経由で共有する. 以下, 簡単なサンプル.
# on A docker run -it -v /var/run/docker.sock:/var/run/docker.sock -v `which docker`:/bin/docker alpine sh # on B which docker # => /bin/docker docker info # => Aのデーモンのinfoが出力される docker ps # => B自身が含まれたリストが出力される
A
上でB
とC
が並列に実行されるイメージだ.
注意点
A
とB
のディストロが異なるとき
バイナリ互換?libc/glibc辺りのライブラリ不足?の関係か, 共有したはずのdockerコマンドが動かないことがある(ホストA
: ubuntu, コンテナB
: alpine で確認). どうしようもないので, B
に対してコマンドを個別でインストールまたはB
のイメージビルド時に埋め込む必要がある. (ちなみに公式docには, 「クライアントとしてのdockerコマンドならOS Xでビルドしてもlinux上でもだいたい動くはずだぜ!」とか書いてありますが動かないものは動かない, 悲しい)
Docker in Dockerのrun時にvolumeを使うとき
B
内でdockerコマンドを叩くときに -v
を使ってvolume共有したいことがあると思う. このとき, :
の前に記述したパスはsockの所有者, つまりA
のパスとして解釈される. B
のコンテンツをC
と共有したい場合は一旦A
を経由させる必要がある.
以下, 上記の注意点を考慮したサンプル
# on A docker run -it -v /var/run/docker.sock:/var/run/docker.sock -v /piyoA:/piyoB alpine sh # on B apk add --no-cache docker docker run -it -v /piyoA:/nyanC alpine sh
B
上の/piyoB
がA
上の/piyoA
を経由してC
上の/nyan
と共有される.
ISUCON6ダメでした #ISUCON
去年の に引き続き2回目のイスを投げるコンテストに @uadachiさん, @hayasshi_さんと チーム お腹すいたCity で出てきました. 自分は学生ですが一般枠です. 結論から言うと ダメでした
以下文章力がないのでメモみたいな箇条書き
前日まで
チームリハーサルとしてISUCON5のお題をakka-http+scalikejdbcでフルスクラッチ(!)
- akka-httpは初めてだったが同期/非同期制御周りが非常に扱いやすい印象. また使ってみたい
- が, やはりフルスクラッチに5hほどかかってしまった(しかもチェックしきれてない)ので断念, おとなしくチューニングで行く方針に
- (恐らく3人とも慣れていれば十分にできると思われ)
その他, githubのprivate repoとslackとかを使いながらいい感じのconf集めやらsnippetsの用意
当日
- インタァンの関係で自分はリモート参加
- 去年のエントリで「ハングアウトで通話しながらやってたんですが, 実際に集まるべきでした. 多分効率が全然違う.」とか書いたのに…
- 予定通りScala実装で, 去年と違いちゃんと動く実装だとのことで一安心
- ソースを読むと結構こなれたコードが散見された(出題がはてなさんだからかな?)
- よさisここにあり
- ソースを読むと結構こなれたコードが散見された(出題がはてなさんだからかな?)
- とりあえずベンチ回すと他のチームが3k~4kの中, 堂々の 0点
- 主に以下の分担で進めた
- DBやらクエリ周りをいい感じに
- Nginxとか静的ファイルとかをいい感じにしたり全体の管理とか(@uadachi)
- redis導入や非同期処理やデプロイ周りやら(@hayasshi_)
- apiごとの細かな部分はその場で分担
- 個人的にslow queryやコードから明らかだった
htmlify
の改善. (終わってから超重要なポイントだったと知る) - 「keywordはメモリで管理行けるやろwついでになんかすごい正規表現あるし適当に直そw」という軽いノリで直そうとする
- 当然のようにハマる
- concurrentなcollectionに慣れておらず微妙に手間取る
- escape処理をミスりまくってバグの嵐(contentが全部リンクになったりして楽しかった(棒))
- (模範解答らしい?)aho-corasick?trie?とか考える余裕なく
- 個人的にslow queryやコードから明らかだった
- 普段intellijで完結させてるせいで, 「あれ?UbuntuOnWindows環境でsbt動かないっけ?」とか言ってローカル環境で動かすのは諦めた(←後々致命的すぎた)
- その他, メンバー全員で非同期沼にハマったり(servletサン…)
- 最後の最後でそれなりの速さで動いた(っぽい)もののベンチマーク間に合わず😇
去年からの成長点
- リハーサルをしたおかげか, DB周りの(簡単な部分の)扱いがちょっと早くなった
- 設定を流し込んだり
- 一部計算をcolumn化したり
- indexやらメタ的な部分の確認・調整
- 開発スタイルの確立
- PRは作るがガンガンmerge
- あれ…?それだけ???
- まるでせいちょうしていない
去年からまるで成長してないことを思いしらされた。
— YutaAdachi (@uadachi) 2016年9月18日
もっとやるべきだったこととか
- キャッシュ箇所の洗い出し
- もっと早く, 明確に
- 大体メモリに載せれば早くなる(てきとう)
- ロジック変更を伴うチューニングといかにうまく並行して作業分担ができるか
- 若しくはキャシュ箇所は思考停止で先に全部やったほうが後々楽か(?)
- 正規表現の扱い
- aho-corasickとかtrieに切り替えていくための知識と勇気
- 統合の検討
- APIレベルであったり
- 今回のようなmicro serviceであればそれらの統合も視野(?)
- skinny frameworkに詳しくなる
- ベンチでfailした箇所を早期にデバッグ・解決する手段
- ローカル環境はなにがなんでも用意する
- やっぱり最初は デバッガ使ってアプリを実際に動かして 追いつつ
- 終盤色々弄ってバグらせないためにも必須
- リモートはダメ, ちゃんと集まる
- 打ち上げが許されない
お疲れ様でした. 結果はダメでしたが色々と知識が増えました. 最後に非常にいい感じのコミットログで〆
#scala_kb で「scala.collection 再入門」をしゃべってきた
spark+dl4j+scalaで遊んだ話と悩んだが, 自分の確認の意味も含めて scala.collection について調べ直した. 内容としては scala.collection のよく使われる各データ構造がどのように表現されているかの概要, どのような場面で使うべきかに焦点を当て, 詳しいアルゴリズム(e.g. red-black tree の挙動)は省いた. 詳しい内容はスライドで見て頂ければと思う. また, scala.collection の適切な選択のためのフローチャートを用意した.
指摘や提案を歓迎します (特にフローチャート)
2016/7/10 23:00, @xuwei_k さんよりimmutable.Stackがdeprecatedであると教えて頂いたため, 発表時から修正を入れました. ありがとうございます.
scala.collection 再入門(https://t.co/oHvkvRrBJp)
— amaya (@0x17E) 2016年7月10日
scala.collection選択フローチャート(https://t.co/GtpsnlE4Cq)
あっぷろーどしました! フローチャートのPRお待ちしてます! #scala_kb
sbtを使ってDeeplearning4jをSpark上で動かす(ver: 0.4-rc3.9)
Deeplearning4j(DL4J)をSpark上で動かしたかったがいろいろ問題点があったのでメモ. 最終的には動かすことに成功した.
sparkアプリケーションを動かすには
- 一旦jarを作ってから
spark-submit
コマンドで利用する方法- sparkの環境が必要
- アプリケーションに埋め込んでスタンドアロンに利用する方法
- 事前にsparkの環境は必要ないがクラスタは利用できない
があるが, 今回は「とりあえず試したい」程度だったので後者を目標とした(ちなみにsetMaster
を調整してsbt package
すれば簡単に前者のアプローチへ移行可能).
既存の問題点
- 本記事のタイトル通り「sbtを使ってDL4JをSpark上で動かす時に使うプラグイン」として提供されている GitHub - deeplearning4j/dl4j-spark-ml が古い
- そのサンプル実装とされている https://github.com/deeplearning4j/dl4j-spark-ml-examples が謎の404
- とにかくドキュメントが少ない. 英語ですらほとんど見当たらない(sparkでdeeplearningとかやってる人多そうなのになんで…)
- 適当にやってみるとライブラリのバージョン地獄に嵌まる
動かす
あまりに動かなかったのでDL4Jのgitterで聞きつつ実装したところなんとか動かすことが出来た.
特に注意が必要だったところだけ列挙する
0.4-rc3.9
からnd4j-x86
は不要になり,nd4j-native
のみで良くなったnd4j-native
を利用するにはclasspathTypes
の指定と実行環境に合わせたclassifier
の設定が必須nd4j-native
とnd4j-cuda-7.5
は併用できないjackson-databind
のバージョン依存がどうしようもないのでdependencyOverrides
で固定する必要があるdl4j-spark
が依存しているspark-core
が古いのでexcludeする
(dl4j-spark-cdh5-examplesを参考にしたが互換大丈夫なのか確信が持てない…がこれをしないと依存解決できない)- 性質上
OutOfMemoryError
が出やすいのでヒープサイズを増やす必要がある- スタンドアロン(sbt)を利用 =>
sbt run
時に-mem
で大きめの値を指定する spark-submit
を利用 =>spark-submit
の--driver-memory
と--executor-memory
で大きめの値を指定する
- スタンドアロン(sbt)を利用 =>
どれか一つでも欠けているとコケるという…なかなかシビアである. 以下が作ったサンプルである. テストの内容は GitHub - deeplearning4j/dl4j-spark-cdh5-examples: Examples to run on CDH5 with Spark を参考にした. なお, CNNを利用するMNISTのサンプルはかなりのマシンパワーを利用するので注意が必要である.
分からなくなったら
ライブラリの特性上DL4JはND4Jと密に関係しているのでこちらも参照されたし. ダメそうならgitterで聞いてみると良い.
LDAPにSSHの認証をやらせてみた(nscd版)
「LDAPとRadiusで無線LANとLinuxユーザとSSHの認証まとめたろw」と思ったのが発端. とりあえずLDAPでSSHの公開鍵認証は動くようになった. まとまった情報があまり見つからなかったのでメモ.
概要
実験環境
どこまでやるの
docker上に公開鍵の情報を含むLDAPサーバを作成し, SSHの認証でそれを参照させる. 既存LinuxユーザとLDAP上のユーザを共存させ, 初ログインのLDAPユーザには自動的にホームディレクトリを作成する.
LDAPサーバ
LDAPサーバのdockerコンテナを建てる
docker run --name ldap-server -p 389:389 --env LDAP_ORGANISATION="Example" --env LDAP_DOMAIN="example.com" --env LDAP_ADMIN_PASSWORD="password" -d osixia/openldap:1.1.2
公開鍵に対応したスキーマの設定
dockerコンテナ内. 本来ビルド時でいいが, とりあえずdocker exec
で.
echo "dn: cn=openssh-lpk-openldap,cn=schema,cn=config objectClass: olcSchemaConfig cn: openssh-lpk-openldap olcAttributeTypes: ( 1.3.6.1.4.1.24552.500.1.1.1.13 NAME 'sshPublicKey' DES C 'MANDATORY: OpenSSH Public key' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4. 1.1466.115.121.1.40 ) olcObjectClasses: ( 1.3.6.1.4.1.24552.500.1.1.2.0 NAME 'ldapPublicKey' DESC 'MANDATORY: OpenSSH LPK objectclass' SUP top AUXILIARY MUST ( sshPublicKey $ uid ) )" > /etc/ldap/schema/openssh-lpk-openldap.ldif ldapadd -H ldapi:/// -f /etc/ldap/schema/openssh-lpk-openldap.ldif ldapadd -H ldapi:/// -f /etc/ldap/schema/cosine.ldif ldapadd -H ldapi:/// -f /etc/ldap/schema/inetorgperson.ldif ldapadd -H ldapi:/// -f /etc/ldap/schema/nis.ldif
ldifファイルを作って公開鍵の情報を持ったユーザ追加(or ldapmodで既存ユーザに追加する)
dn: uid=karen,dc=example,dc=com objectClass: inetOrgPerson objectClass: posixAccount objectClass: ldapPublicKey uid: karen cn: karen sn: kujo gn: karen uidNumber: 11111 gidNumber: 11111 loginShell: /bin/bash homeDirectory: /home/karen mail: karen@example.com userPassword: password sshPublicKey: ssh-rsa AAAA略 #コメントは消しておいたほうがいいかも
ldapadd -H ldapi:/// -f karen.ldif
LDAPクライアント(SSH)
yum
を使うディストロであればopenssh-ldap
というパッケージがあるため, この項目と手法が異るので注意
LDAPクライアントに必要な物をインストールし有効にする
sudo apt install -y nscd ldap-auth-client #インストール時にLDAPサーバの情報を入力 sudo pam-auth-update #LDAPとCreate home directoryを有効にする
再設定は sudo dpkg-reconfigure ldap-auth-config
で可能.
pam-auth-update
時にCreate home directoryが出てこなかった場合
バージョンによってはデフォルトで用意されていないようなので自作する必要がある(e.g. ubuntu14.04)
新規作成 /usr/share/pam-configs/my_mkhomedir
Name: Create home directory on login Default: yes Priority: 0 Session-Type: Additional Session-Interactive-Only: yes Session: optional pam_mkhomedir.so
sudo pam-auth-update --force
nsswitchの設定
/etc/nsswitch.conf
に以下のようにldap
追記する.
passwd: files ldap shadow: files ldap group: files ldap
sudo serivce nscd restart
SSHの認証にLDAP上の公開鍵を利用する設定
LDAP上の公開鍵を取得するスクリプトを作成(/opt/ssh-ldap/getPublicKey
)
LDAPサーバの情報を設定する.
#!/bin/bash uri=ldap://piyo #server uri binddn=piyo #bind user bindpw=piyo #pwd base=piyo #base uid=$1 ldapsearch -LLL -H ${uri} -w "${bindpw}" -D "${binddn}" -b "${base}" "(& (objectClass=posixAccount) (uid=${uid}))" "sshPublicKey" | sed -ne '2,$p' | sed -e 's/sshPublicKey: //g' | sed -e 's/^ //g' | tr -d '\n'
ユーザから不可視にする.
sudo chmod 700 -R /opt/ssh-ldap sudo chown root:root -R /opt/ssh-ldap
SSHの設定(/etc/ssh/sshd_config
)
以下を追記する.
AuthorizedKeysCommand /opt/ssh-ldap/getPublicKey AuthorizedKeysCommandUser root
sudo service ssh reload
注意点
- SSSDを利用する方法もありそちらのほうがよりスマートらしいがnscdと排他的で試していない. 近々実験予定.
/etc/ldap/slapd.conf
を編集して~という情報は古いから今すぐ投げ捨てろ- OpenSSH6.9未満(?)の場合はAuthorizedKeysCommandが利用できないためパッチを当てる必要があるらしい(要確認). 少なくとも, Ubuntu16.04で入る7.2では問題なかった.
ところでなんでSSH-CA認証の証明書はX.501じゃないの…
ニューラルネットを実装してみた話
Docker native(Windows)を2週間程使ってみた所感
最近メイン環境をMacからWinへ移行したがやはりテスト・開発・実行環境として*nix系が使いたい. ちょうどDocker nativeのβ版が来ていたため試用することにした. closed-βのため, invitation codeが必要だったが申請して数時間で発行された.
降ってきたインストーラを実行し言われるがままにインストール. 結果, Hyper-V上にMobyLinuxVMというAlpineのVMが立ち上がりその上でコンテナが走る環境が作成された. その後, 例えばPowerShell上で適当にdocker run -it -p 8080:80 --rm nginx
とすることで問題なくコンテナの立ち上げに成功した. docker-compose
も問題なく利用できた. また, Settings -> Manage shared drives
からチェックを入れることでhost(win) <-> MobyLinuxVM(alpine)
間でボリュームが共有され, host(win) <-> container
でのボリューム共有が可能になった.
ただし, 問題が全く無いわけではない. 問題の一つとして, スリープ時の挙動が挙げられる. 明確な再現性はないが, 2, 3回に1回程度と比較的高い確率でdocker daemonがスリープからの復帰に失敗し, dockerが正常に利用できなくなる. dockerを再起動することで復活するが数分かかるため非常に手間である. もう一つの問題としてサードパーティ製品が未対応であることが多いことが挙げられる. β版なので当然といえば当然だがやはり面倒. 例えばIntellijのプラグインが部分的に利用できない. 具体的にはwindowsのパス文字列に含まれる:
が使えず, ボリュームの接続ができない(一応docker-compose経由にすることで回避できるが, デバッグ接続を別途する必要があったりそもそもコマンドからでいいのではという). 正式リリースされて対応するのが待ち遠しい.
FYI
ちなみにMac版は少し設定を弄ることでIntellijのプラグインが使えるようだ. 以下のサイト参照.
まとめ
タスクトレイに常駐するクジラがかわいい