Docker SwarmとDocker Composeについての軽い所感

Docker社が前々から作ってたよって言ってたアレコレが先日公開されました。

Dockerが、分散環境構築ツール群「Docker Machine」「Docker Swarm」「Docker Compose」を公開 - Publickey

コンテナクラスタの構築やらスケジューリングやらサービスディスカバリやらルーティングやらが公式謹製ツールでいい感じになるのかなぁと思って触ってみた感想です。*1

Docker Swarm

複数のDocker Engineをひとつに見せる、と言ってもよく分かりませんが、要するに複数ホストで稼働しているdockerデーモンをひとまとめにしたAPIエンドポイントを作るやつのようです。
Docker Swarmが提供するAPIエンドポイント経由でDockerクライアントを使うと、Inter-Hostで動いてるコンテナが見れたりします。*2
じゃあこれ使ってrunするとどのホストで起動するの?と言うと、現在2種類の戦略があるらしく、ひとつは"リソースが空いてそうなホストを選ぶ"、もうひとつは"ランダム"。
Docker Swarmを使うことによって、クライアントからは複数のコンテナホストがまるでひとつのホストであるかのように扱えるようになるということっぽいです。*3
ただ、サービスディスカバリとしてはイマイチで、コンテナクラスタに参加しているDockerホストの一覧は取得できるんですが、その上で動いているコンテナの情報(どのコンテナがどのホストどのポートで動いているか)は取れないっぽくて惜しいなあと言う感じがしました。
コンテナクラスタを大資源ぽく抽象化してデプロイ出来るのは良いです。

Docker Compose

figと呼ばれていた奴と同じです。公式に飲み込まれて名前が変わりました。
runする時の設定をyamlに書いておいてdocker-composeコマンドに指定すると、そのyamlの定義に従ってコンテナを立ち上げたりします。
figの時はシングルホスト用であんまり使い道ないなあって思ってたんですがSwarmと合わせて利用することでcompose側から見た時にswarmによってマルチホスト的なところが隠蔽されるので、マルチホストで使えるcomposeみたいになって非常によいです。scaleもちゃんと動きました。
composeでグワッと撒いてscaleでズバッと簡単スケールアウトみたいなのむっちゃ近未来っぽいんですがdockerエコシステムの中にサービスディスカバリとルーティングの機構がないのでグワッとしてズバッとしてもサービスが動いてる場所を特定できないのつらみがあります。惜しい。

まとめ

インストールも楽だし公式でこういうツール出てくるの手っ取り早くて嬉しいんですが個人的にはまだ機能不足という感じ。
だったらregistrator動かしてるdockerホストにmesos-marathonで撒いてetcd経由でconfdでnginxの設定書き換えた方がマシなんじゃと言う気持ちになりました。

終わり。

*1:使い方やセットアップとかはQiitaやらにいっぱい記事あるので書きません。

*2:Swarm APIはDocker APIと互換性があるので既存のクライアントからもちゃんと呼べる

*3:簡易mesos-marathonみたいな感じ?

VisualStudioもF# も何も知らないズブの素人がLinux上でF# でHelloWorldしたメモ

※追記

F# Advent Calendar 2014 - connpassの26日目の記事になりました。今年は一切アドベントカレンダー参加してなかったのに25日越えてほとんど縁遠かった分野のアドカレに参加することになるとは…。


今までも数多くの物事を完全にマスターしてきた僕ですが、よりオープンになった新生Visual Studio~無償版Visual Studio Community 2013ほか,注目機能が多数実装,.NET Framework/.NET Core RutimeはOSS化:レポート|gihyo.jp … 技術評論社によるとVisualStudio Pro相当の機能が無料で使えるようになったとの事なので、前からガブさんに微妙にプレッシャーをかけられていた気がするし、F# 触ってみました。

最初は「Linuxで動く.NET実行環境出たっぽいし試してみよう」と言う感じだったのですが、何かざっくりぐぐってみるとまだリリースされてないっぽいのでmonoと言う前から存在していたそれっぽいやつでやってみます。

VisualStudio CommunityEditionのインストール

Downloads | IDE, Code, & Team Foundation Server | Visual StudioからDLしてインストールします。ウィザードなので特にすることはありませんがむっちゃ時間かかりました。
日本語リソースのインストール中に

とか言われましたが無視してもインスコできたっぽいです。

コンソールアプリケーションの作成

最初からF#のプロジェクト作成が選べたので、よくわからないまま[新規作成] -> [プロジェクト]からF#のコンソールアプリケーションを選んでプロジェクト作成しました。

プロジェクト作成時点で既にHelloWorldより高度なプログラムが作成されている気がしないでもないですが気にしないことにして勘でこのようにコードを修正します。

[<EntryPoint>]
let main argv = 
    printfn "F#完全にマスターした"
    0

実行

上の方にある[▶ 再生]というやつを押すとプログラムを実行できるっぽいです。
実行するとコマンドプロンプトが立ち上がってプログラムが実行されるんですが、上記のプログラムを実行すると人間が視認するより早くプログラムの実行が終了し、コマンドプロンプトも閉じてしまうため実行されている感じが分かりません。
上部のビルドメニューからソリューションのビルドというのを実行するとbinフォルダ配下にexeが生成されるらしいので、それを実行すると普通に実行結果が見れます。

…だるすぎませんかね?と思っていたら

と言うお告げを頂きました。
Ctrl + Alt + Fを押すとFSharp Interactiveと言うペインがニョキッと現れ、そこに

printfn "にゃん";;

と入力すると入力したコードが実行されます。楽ですね。
ちなみに「;;」は「入力したコード評価してください」という意味とのことです。

mono環境の構築

docker pull mono

以上

mono上でさっきのexeを実行する

さっき作ったexeを適当なディレクトリにおいて

$ docker run -i -t -v /path/to/dir:/tmp mono /bin/bash

みたいな感じでコンテナを起動し

$ mono FSharpHelloWorld.exe

とすれば

ウッ。

上記のdockerイメージだと日本語環境になってないので

$ apt-get update && apt-get install -y locales && echo "ja_JP.UTF-8 UTF-8" >> /etc/locale.gen && locale-gen && export LANG=ja_JP.UTF-8

を実行します。

で、改めて実行すると

やりましたね!

まとめ

F#完全にマスターした*1

*1:この程度のこと達成するのに4時間ぐらいかかりました

Hちょびよみ勉強ノート(10回目)

引き続き圏論で足し算

圏論縛りプレイルール

使っていい言葉とかが制限されてる

名詞
  1. 対象
  2. 図式
述語
  1. 射の合成 <- 関数合成
  2. 射が恒等 <- def id(a: A): A = a
  3. 射が存在する <- 関数が定義できる
  4. 射が一意 <- 具体例一つだけ確かめればよい。射と射が等しいと言える
  5. 図式が可換 <- ある射とある射が等しい*1

圏論では具体的な値に言及できないので、気軽に「何かと何かが等しい」とは言えない縛りプレイ。何かと何かが等しいことを言いたければ、可換図式を書いて射と射が可換であるということを言う戦略をとることが多いらしい。

「0は 0 + a = a と言う性質がある」を言いたければ「"0 + a"を表す射と"0"を表す射が等しい」と言う必要があって、前述のとおり「等しい」を言うためには「射が一意」か「図式が可換」であることを使うので、"0 + a"の射と"0"の射の可換図式が書ければ上記のことが言えた、となるらしい。

0 + a の射

足し算の話なのでまず

add: Z × Z → Z

を用意する。
圏論ではドメイン*2とコドメイン*3は一回書いたら変えられない。
ここで書きたいのは 0 + a = a なので、上記のaddの定義では範囲が広すぎてダメ。ドメインをもうちょっと制限してやる必要がある。
ので

       add
 Z × Z → Z
   ↑ zero × id
0Z × Z

を書いて制限する。

  • 整数と整数からある整数が求まる計算addがある
  • 特殊な整数集合0ZからZへの射が存在する*4

間をすっ飛ばすと(射を合成すると)、0Z × Z → Z という風になって、0 + a が何らかの整数になることを表す射が存在することを書けた

a の射

      0 + a これは書けた
        →
0Z × Z    Z
        →
        a 別の経路でZへ行くこの射を可換図で書ければ 0 + a と a が可換(等しい)と言える

0Z × Z → Z は左をガン無視して右だけとればZになるのでright*5関数を設定すれば

               add
         Z × Z → Z
zero × id ↑  / right
        0Z × Z

となって、0 + a(zero × idとaddの合成)とa(right)は可換(等しい)となる。

*1:射は合成された結果の射かもしれない

*2:矢印の左側、関数の引数の方の定義

*3:矢印の右側、関数の戻り値に当たる方

*4:zero: 0Z → Z

*5:実際はright関数の性質についても言わなければならないらしいけど既に使って良い道具として用意されてると思って使ってる。rightはPairの性質を言うと使えるようになるらしい。

Hちょびよみ勉強ノート(9回目)

前回の続き。
前回はぐるぐるの図(可換図式)を書いて整数Zの足し算の性質のうち

  • 関数 add: Z × Z → Z が存在する
  • ある特殊な集合 0Z が存在して zero: 0Z → Z が一つだけ存在する
  • 0Z × Z → Z となる(0 + a = a, a ∈ Z 的な意味) add・(zero, id): 0Z×Z → Z×Z → Z と right: 0Z×Z → Z が可換

をやった。

けど、足し算を言うには

  • a + 0 = a*1
  • a + (-a) = 0
  • (-a) + a = 0

も言わないとダメっぽい。

a + 0 = a

前回 0Z × Z を逆にしただけ

a + (-a) = 0

ある整数にその整数の負の数を足すと0になる。

neg: Z     → Z
    (∋ a)   (∋ -a)

と言う関数をまず置く。
negってnegativeの事なんでしょ?とか負の数とはみたいなことは全て忘れて「えぬいーじーと言う関数は整数から整数への関数なんだって〜」というぐらい頭真っ白にする。

で、このnegとかいう関数を使って「a + (-a) = 0」と言う性質を図式で表すと

こう。

上からたどると「aがaと-aになってa+(-a)が0になる」となって、下からたどると「aを問答無用で0にして、0を0にする」となって、上から辿っても下から辿っても結果が同じなので良いという感じ…でいいのかな。

0Zを終対象 集合の圏の終対象*2 *3 と言うとか何とか言ってた気がするけど分かりません…。

※ 上の図で「右はそのまま、左はnegの結果」とか書いてありますが思っきり逆であることに図を作ってから気づいたものの直すの面倒なので読み替えてください。

(-a) + a = 0

上の図の id × neg を逆にするだけ。

*1:前回の逆

*2:https://twitter.com/cocoatomo/status/534284227261370370

*3:元が1つだけの集合の事で『1』とも書くけど今はややこしいので『0Z』って書いてるんですよと @cocoatomo さんから指摘があったので更に追記

Hちょびよみ勉強ノート(8回目)

代数的データ型と圏論の導入の導入。

代数的データ型

代数的データ型Xとは

X <- A + B

A + Bっていうのは集合Aと集合の重複の無い和との事。

┌── X───┐
│┌─┐┌─┐│
││ A││B ││
│└─┘└─┘│
└──────┘

javaで言うところのenumみたいなもの。
ただしJavaでは

enum X { // 型
  A, // 値
  B; // 値
}

だけど、代数的データ型では

 X  <- A   +  B
(型)  (型)   (型)

との事。

   -> (match, unapply Eitherをパターンマッチで分解する的な?)
 X   A  +  B
   <- (コンストラクタ eitherA = Left(a) みたいな事?)

圏論の導入の導入

今までの数学

  1. 集合(型)
  2. 集合と集合の対応(関数)
  3. 集合の元(値)

でいろんなことを考えるけど、圏論

  1. 対象(object, なんかしらのモノ)
  2. 射(対象と対象との間の関数)

でいろんなことを考えるらしい。
ざっくり言うと集合は対象、対応は射に対応していて、従来の数学と違うのは「元」と言う言葉を利用する事(言及すること)を禁止しているところとの事。
要するに集合の構成要素に触れないのでより抽象的(強い)ということっぽい。

圏論で「整数には足し算がある」という事を言う

Zを整数としたとき

「a, b ∈ Z に対して a + b ∈ Z が計算できる」(これが足し算だ)

↓が

「関数 add : Z × Z -> Z が存在する」(addが足し算だ。元a, bに対する言及が消えた)

こうなる。
しかし、足し算を言いたいときには「0を足しても変わらない」ということも言わないとダメ。

0 + a = a + 0 = a (a ∈ Z)

でもこれだと元(aとか0とか)が見えてるのでダメ

「0という特別な値がある」

「zeroと言う関数があるということにすればいいのでは??」*1

zero : 0Z -> Z が一つだけ必ず存在する*2
( 0Z = {0}, Z = {0, ±1, ±2 ...} と言うイメージ )


ぐるぐるのやつで足し算と言う計算を言う?

Z × Z  -> Z (最初に出てきた式)

Z × Z  -> Z

0Z × Z -> Z(0と計算しても変わらない的なことを言いたいやつ)

 Z × Z  -> Z
    / (行き先同じなのでまとめた)
0Z × Z 

    (ここがadd関数)
 Z × Z  -> Z
    /
0Z × Z

          add
   Z × Z  -> Z
※↑   /
  0Z × Z

※ここの関数は?
左側: 0Z -> Z -> zero関数だこれ
右側: Z  -> Z -> id関数(素通りさせるだけのやつ)だこれ
-> zero × id

                 add
          Z × Z  -> Z
zero × id↑   / right(左無視して右側を常に選ぶ)
         0Z × Z

可換図式っていうのは矢印の方向に歩くならどのルート通っても結果は同じになるらしいので

right = add ○ (zero × id) // 関数合成

が成り立つらしい。

具体的な元を当てはめて確かめてみると

                0 + a
                  ->
     (0,a)       add  a
          Z × Z  -> Z a
zero × id↑   / right
         0Z × Z
     (0,a)

矛盾ないっぽいので、Zには足し算という演算があるよ、と言えるらしい。

まとめ

この先Functorとか出てくるので道具立ての意味で圏論のさわりのさわりみたいな話聞いたけどまだ完全にフワッフワしています

*1:詐欺っぽいよねって言ってました

*2:一意に、とか存在する、とか可換、とかいう言葉は使っていいらしい

Hちょびよみ勉強ノート(4 〜 7回目)

ブログ書くのむっちゃサボってる…。

多相の種類

polymorphism ┬ universal(静的) ┬ parametric(ジェネリクス)
             │                 └ inclusion(サブタイプ) ┬ nominal(継承)
             │                                          └ structural(ダックタイピング)
             └ ad-hoc(実行時)  ┬ overloading(オーバーロード)
                                └ coercion(暗黙の型変換)

OCamlにはoverloading多相は無いらしいので完全な型推論が出来るらしい。

型推論の完全性
def f(x, y) = x + y 
↑
↓
def f(x: Int, y: Int): Int = x + y

が相互に完全に求まること

カリー化

他引数関数を1引数関数のチェーンにすること

(a, b, c) -> d
  ↓
a -> (b -> (c -> d))

カリー化すると何が嬉しい?

  • 関数が取り回しやすくなる
  • ラムダ計算界隈の話に載せられるようになる
ラムダ計算
  • 変数
  • 1引数関数
  • 適用

で全ての計算を行う体系。チューリング完全

カタモーフィズム

「Listはfoldrだ」

  • List(データ構造)
    • cons*1(a1, cons(a2, cons(a3, ..., cons(an, nil()) ... )
  • foldr(処理構造)
    • f(a1, f(a2, f(a3, ..., f(an, zero) ... )

なんか構造が似ている気がする。

似ている?

Listの定義(Aは型変数)

List<A> : Nil | cons(A, List<A>)  # Nilか任意の値とリストの組
nil     : () -> Nil
cons    : A × List<A> -> List<A> # 任意の値とリストの組でリストにする
head    : A × List<A> -> A       # 任意の値とリストの組から先頭の要素を取り出す
tail    : A × List<A> -> List<A> # 任意の値とリストの組から先頭以外のリストを取り出す
isnil   : List<A> -> Boolean      # リストがnilかどうか

tailやheadが組になってるのは要素が最低1はあるってことを言いたいのかな?

folrの定義(AとBは型変数)

f              : A × B -> B
zero           : Nil -> B
foldr(f, zero) : List<A> -> B

似ている。

List cons : A × List -> List nil : () -> Nil
foldr f : A × B -> B zero : Nil -> B

List

  cons
  /\
a1  cons
     /\
   a2  cons
        /\
       a3   nil

foldr

   f
  /\
a1    f
     /\
   a2    f
        /\
      a3   zero

似ている*2

ListはF始代数*3

foldrの最も汎用的な形がList*4

foldrの始対象がList*5

ListはF代数の圏におけるF始代数*6

List                              foldr
  cons                                f
  /\                               /\
a1  cons                            a1   f
     /\     <------ 抽象的 ------     /\
   a2  cons   - 関数(射)が作れそう->  a2    f
        /\                               /\
      a3   nil                            a3  zero
可換図式*7

何を書いているのか分からねーと思うが僕も何を書いているのかわからない。

     List<A>   =   Nil | A × List<A>
foldr↓                 ↓ id | id × foldr(f, zero)
      B       ←   Nil | A × B
          (ex, sum)

良くどころか完全に分からないんだけど、結局のところ何故foldrがListの様に見えるのかというと上の図の下向き矢印に当たる関数が存在するから、とのこと…。

とにかく、代数的データ型(F代数の構造を持つもの→右側が再帰している構造のもの)のうち最も汎用的なもの(始代数)がListであり、代数的データ型であればfoldrが出来る、という事?
Optionは要素数が0か1のList、Eitherは要素数が2固定のListという風にみなせるらしい。

要するに

ルノアールで2時間聞いただけで理解できるはずがなかった

*1:コンスセルって言って組を作るやつとの事

*2:右側が再帰している構造

*3:この辺りでもう脳は限界を迎えていた

*4:foldrは右が関数だけどListは何でもいい

*5:「始」は最もシンプル、汎用的なという意味らしい。対象とは「何かしらのモノ」の事

*6:脳みそが限界を越えた。F代数という話題の中で最もシンプルな代数。代数って何や…。代数 extends 対象との事らしいけれども

*7:アバッ…アッ…アバッーッ

Dockerで複数プロセス管理する場合でrun時に環境変数で設定指定する話

備忘録


仕事でDockerを使っていて

  • CMD ["app"]みたいな単一プロセスでコンテナを立ち上げるのではなくCMD ["/sbin/init"]みたいにしてsshdとか複数プロセスを立ちあげたい
  • DBの接続設定みたいな、本番環境とか開発環境とかの設定を切り替えたい
  • 環境ごとにイメージをビルドするのはナンセンス
  • ならdocker run時に-eオプションで環境変数で設定を指定しよう

というような状況があってウンウンやってたんですが、うまくアプリに環境変数が渡ってくれない。

具体的には/sbin/initがsupervisordを起動していて、supervisordがアプリのプロセスを管理しているという状況なんですが、Google先生に聞いてみても単一プロセスで使ってみた環境変数でいい感じに出来るよ*1と言う記事が多くて、複数プロセス立ち上げる場合run時に環境変数で設定注入するんどうしたらええんやーってなってたんですが、どうやらDocker云々と言うより/sbin/initの挙動っぽい。
Linux力ないので分からないですが、多分/sbin/initはなんかそう言う事前状況みたいなの無効化する力を持っているんだと思う。

結果的に、普通にCMD ["supervisord", "--nodaemon"]で動きました、という話でした。

*1:rails動かしてみたみたいな