マスタリング DEA/NG 第2版岩嵜 雄大NTT Software Innovation Center2012-09-13                 NTT Software Innovation Center
はじめに              情報はすべて資料作成当時のものです              – 更新が頻繁なため情報がすぐに古くなります              – 必ず最新のソースコードを確認してください2012-09-13    ...
今日の内容              そもそもDEAとは              – 簡単な紹介              DEA_NG起動から、Warden上でのアプリ               ケーション実行までを追う       ...
そもそもDEAとは2012-09-13    NTT Software Innovation Center   4
DEAとは  ユーザのアプリケーションを実行するためのコン   ポーネント      – Dropletと呼ばれる形式のアプリケーションを実行する      – DEAを増やすことでCloud Foundryの実行能力はスケー        ...
DEAがやること              Dropletのダウンロード              ランタイム(Java, Ruby, etc)の管理              アプリケーション隔離用コンテナの管理            ...
DEAサーバの起動から             アプリケーションの起動まで2012-09-13      NTT Software Innovation Center   7
全体的な概念図(今日話す範囲)                       DEA                  Instance                     Instance                        In...
エントリーポイント              /bin/dea               bootstrap = Dea::Bootstrap.new(config)                EM.run do            ...
DEA serverの起動  /lib/dea/bootstrap.rb      – プロセスの初期セットアップ (setup_*)      – NATSクライアントの起動         • あとはNATSまかせ            ...
NATSに対するディスパッチャーの登録  /lib/dea/nats.rb      – アプリケーションインスタンスの起動イベント   def start   …     subscribe("dea.#{bootstrap.uuid}.s...
Bootstrap側のハンドラ  DEA::Instance オブジェクトを生成      – オブジェクトはレジストリに登録する def handle_dea_directed_start(message)   instance = cre...
インスタンスの起動  /lib/dea/instance.rb        – Promiseについては後述  def start(&callback)  …        if !droplet.droplet_exist?       ...
コンテナの生成設定  DEAホストのDropletとランタイムをコンテナ内   から見えるように追加のマウント情報を設定def promise_create_container…    connection = promise_warden_...
コンテナの生成設定  ライブラリ類もマウントとして追加 …前ページから    # Extra mounts (these typically include libs like pq, mysql, etc)    bootstrap.con...
アプリケーションインスタンスの実行  Warden Protocolによりコンテナを起動 …前ページから    create_request = ::Warden::Protocol::CreateRequest.new    create_...
【寄り道】      promise_warden_callで何が起きているのか  connectionは EM::Warden::Client::Connection  def promise_warden_call(connection,...
【寄り道】      Warden Clientの話  Warden本体については「すごく分かるWarden」      – http://www.slideshare.net/i_yudai/warden  3つのライブラリ      –...
【寄り道】      Warden Protocol  Wardenに対する各種命令        •    ping              •   run        •    create            •   info  ...
【寄り道】      EM::Warden::FiberAwareClient  /em-warden-client/lib/em/warden/client.rb      – create()メソッドは存在しない         • me...
【寄り道】      EM::Warden::FiberAwareClient  /em-warden-client/lib/em/warden/client.rb      – create()メソッドは存在しない         • me...
【寄り道】      EventMachine::Warden::Client::Connection  /em-warden-   client/lib/em/warden/client/connection.rb      – EM::C...
【寄り道】      コンテナ生成時におけるマウントの追加  /warden/warden/lib/warden/container/linux.rb      – フックにマウントの命令を追加する   def write_bind_moun...
Dropletの展開  コンテナ上でtarコマンドを実行   def promise_extract_droplet     Promise.new do |p|       connection = promise_warden_conne...
スタートアップスクリプトの調整  アプリケーション起動スクリプトのプレースホル   ダを置換する      – @がデリミタ   def promise_prepare_start_script     Promise.new do |p| ...
スタートアップスクリプトの呼び出し   def promise_start     Promise.new do |p|       script = []       script << "renice 0 $$"       script ...
Promise パターンについて2012-09-13       NTT Software Innovation Center   27
Promise(future)パターンとは DEA::InstanceがPromiseまみれになった             • 非同期プログラミング              – Wardenとの通信が発生する             • ...
イメージ 処理AのIO待ち中に処理Bを済ませておきたい             • 処理Aをスタートし、引換券(Promise)をもらう             • IO待ち中に処理Bを開始する             • どうしても処理Aの...
Upcoming SlideShare
Loading in...5
×

マスタリング DEA/NG 第2版

1,504

Published on

Cloud Foundryのコンポーネントの1つであるDEAの次期バージョンについて、ソースコードを追いながら簡単な解説を行います。

Published in: Technology, Business
0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
1,504
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
41
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide

マスタリング DEA/NG 第2版

  1. 1. マスタリング DEA/NG 第2版岩嵜 雄大NTT Software Innovation Center2012-09-13 NTT Software Innovation Center
  2. 2. はじめに  情報はすべて資料作成当時のものです – 更新が頻繁なため情報がすぐに古くなります – 必ず最新のソースコードを確認してください2012-09-13 NTT Software Innovation Center 2
  3. 3. 今日の内容  そもそもDEAとは – 簡単な紹介  DEA_NG起動から、Warden上でのアプリ ケーション実行までを追う – エントリーポイントからインスタンス起動まで  Promiseパターンについて – DEA_NGに頻出するPromiseとは何者か2012-09-13 NTT Software Innovation Center 3
  4. 4. そもそもDEAとは2012-09-13 NTT Software Innovation Center 4
  5. 5. DEAとは  ユーザのアプリケーションを実行するためのコン ポーネント – Dropletと呼ばれる形式のアプリケーションを実行する – DEAを増やすことでCloud Foundryの実行能力はスケー ルする App App App App App App App App App App App DEA App App DEA App App App DEA DEA2012-09-13 NTT Software Innovation Center 5
  6. 6. DEAがやること  Dropletのダウンロード  ランタイム(Java, Ruby, etc)の管理  アプリケーション隔離用コンテナの管理 – コンテナには独自の「Warden」を使用  アプリケーションの管理・死活監視2012-09-13 NTT Software Innovation Center 6
  7. 7. DEAサーバの起動から アプリケーションの起動まで2012-09-13 NTT Software Innovation Center 7
  8. 8. 全体的な概念図(今日話す範囲) DEA Instance Instance Instance Instance 1対1対応で生成や起動などを担当 通信はWarden Protocol 生成CCからの命令 NATS基本的にはイベントドリブン App App App App App DEAプロセスの セットアップ ContainerContainerContainer ContainerContainer bin/dea BootStrap Warden VM ※他にもDroplet RegistryやDirectory Serverなどがサブモジュールがある2012-09-13 NTT Software Innovation Center 8
  9. 9. エントリーポイント  /bin/dea bootstrap = Dea::Bootstrap.new(config) EM.run do bootstrap.setup bootstrap.start end – コマンドライン引数のパース – DEAプロセスをキック2012-09-13 NTT Software Innovation Center 9
  10. 10. DEA serverの起動  /lib/dea/bootstrap.rb – プロセスの初期セットアップ (setup_*) – NATSクライアントの起動 • あとはNATSまかせ def start start_component start_nats start_directory_server start_finish end … def setup_nats @nats = Dea::Nats.new(self, config) end2012-09-13 NTT Software Innovation Center 10
  11. 11. NATSに対するディスパッチャーの登録  /lib/dea/nats.rb – アプリケーションインスタンスの起動イベント def start … subscribe("dea.#{bootstrap.uuid}.start") do |message| bootstrap.handle_dea_directed_start(message) end … end def subscribe(subject) sid = client.subscribe(subject) do |raw_data, respond_to| message = Message.decode(self, subject, raw_data, respond_to) logger.debug "Received on #{subject.inspect}: #{message.data.inspect}" yield message end @sids[subject] = sid end2012-09-13 NTT Software Innovation Center 11
  12. 12. Bootstrap側のハンドラ  DEA::Instance オブジェクトを生成 – オブジェクトはレジストリに登録する def handle_dea_directed_start(message) instance = create_instance(message.data) … instance.start end … def create_instance(attributes) instance = Instance.new(self, Instance.translate_attributes(attributes)) instance.on(Instance::Transition.new(:born, :starting)) do instance_registry.register(instance) end … (他のインスタンス状態変化トリガ) instance end2012-09-13 NTT Software Innovation Center 12
  13. 13. インスタンスの起動  /lib/dea/instance.rb – Promiseについては後述 def start(&callback) … if !droplet.droplet_exist? logger.info("Starting droplet download") … promise_droplet_download.resolve ドロップレット end をダウンロード promise_container = Promise.new do |p| promise_create_container.resolve promise_setup_network.resolve promise_limit_disk.resolve promise_limit_memory.resolve コンテナの準備 p.deliver end … promise_extract_droplet.resolve promise_prepare_start_script.resolve インスタンスの … promise_start.resolve 起動 end2012-09-13 NTT Software Innovation Center 13
  14. 14. コンテナの生成設定  DEAホストのDropletとランタイムをコンテナ内 から見えるように追加のマウント情報を設定def promise_create_container… connection = promise_warden_connection(:app).resolve # Droplet and runtime bind_mounts = [droplet.droplet_dirname, runtime.dirname].map do |path| bind_mount = ::Warden::Protocol::CreateRequest::BindMount.new bind_mount.src_path = path bind_mount.dst_path = path bind_mount.mode = ::Warden::Protocol::CreateRequest::BindMount::Mode::RO bind_mount end…次ページに続く2012-09-13 NTT Software Innovation Center 14
  15. 15. コンテナの生成設定  ライブラリ類もマウントとして追加 …前ページから # Extra mounts (these typically include libs like pq, mysql, etc) bootstrap.config["bind_mounts"].each do |bm| bind_mount = ::Warden::Protocol::CreateRequest::BindMount.new bind_mount.src_path = bm["src_path"] bind_mount.dst_path = bm["dst_path"] || bm["src_path"] mode = bm["mode"] || "ro" bind_mount.mode = BIND_MOUNT_MODE_MAP[mode] bind_mounts << bind_mount end …次ページへ2012-09-13 NTT Software Innovation Center 15
  16. 16. アプリケーションインスタンスの実行  Warden Protocolによりコンテナを起動 …前ページから create_request = ::Warden::Protocol::CreateRequest.new create_request.bind_mounts = bind_mounts response =promise_warden_call (connection, create_request).resolve … end end  コンテナ起動後にメモリとディスクの制限を行う – promise_setup_network – promise_limit_disk – promise_limit_memory2012-09-13 NTT Software Innovation Center 16
  17. 17. 【寄り道】 promise_warden_callで何が起きているのか  connectionは EM::Warden::Client::Connection def promise_warden_call(connection, request) Promise.new do |p| logger.debug2(request.inspect) connection.call(request) do |result| logger.debug2(result.inspect) … if error logger.warn "Request failed: #{request.inspect}" logger.log_exception(error) p.fail(error) else p.deliver(response) end end … end2012-09-13 NTT Software Innovation Center 17
  18. 18. 【寄り道】 Warden Clientの話  Warden本体については「すごく分かるWarden」 – http://www.slideshare.net/i_yudai/warden  3つのライブラリ – warden-client • Unix Socketによる(簡易な)実装 • ライブラリ的なものも含む – em-warden-client • EventMachineを使用した実装 • warden-clientに依存 – warden-protocol • サーバクライアント間の通信に使うクラスのセット2012-09-13 NTT Software Innovation Center 18
  19. 19. 【寄り道】 Warden Protocol  Wardenに対する各種命令 • ping • run • create • info • stop • LimitDisk • spawn • LimitMemory • link • net_in • stream • net_out  コマンドラインコマンドとほぼ同等ping - ping wardencreate [OPTION OPTION ...] - create container, optionally pass options.destroy <handle> - shutdown container <handle>stop <handle> - stop all processes in <handle>spawn <handle> cmd - spawns cmd inside container <handle>, returns #jobidlink <handle> #jobid - do blocking read on results from #jobidstream <handle> #jobid - do blocking stream on results from #jobidrun <handle> cmd - short hand for stream(spawn(cmd)) i.e. spawns cmd, streams the resultlist - list containersinfo <handle> - show metadata for container <handle>limit <handle> mem [<value>] - set or get the memory limit for the container (in bytes)net <handle> #in - forward port #in on external interface to container <handle>net <handle> #out <address[/mask][:port]> - allow traffic from the container <handle> to address<address>2012-09-13 NTT Software Innovation Center 19
  20. 20. 【寄り道】 EM::Warden::FiberAwareClient  /em-warden-client/lib/em/warden/client.rb – create()メソッドは存在しない • method_missing()からcall()が呼ばれる def call(*args, &blk) … f = Fiber.current @connection.call(*args) {|res| f.resume(res) } result = Fiber.yield result.get EventMachine::Warden::Client::Connection end def method_missing(method, *args, &blk) call(method, *args, &blk) end2012-09-13 NTT Software Innovation Center 20
  21. 21. 【寄り道】 EM::Warden::FiberAwareClient  /em-warden-client/lib/em/warden/client.rb – create()メソッドは存在しない • method_missing()からcall()が呼ばれる def call(*args, &blk) … 使わなくなりました f = Fiber.current @connection.call(*args) {|res| f.resume(res) } result = Fiber.yield result.get EventMachine::Warden::Client::Connection end def method_missing(method, *args, &blk) call(method, *args, &blk) end2012-09-13 NTT Software Innovation Center 21
  22. 22. 【寄り道】 EventMachine::Warden::Client::Connection  /em-warden- client/lib/em/warden/client/connection.rb – EM::Connectionを継承def call(*args, &blk) if args.first.kind_of?(::Warden::Protocol::BaseRequest) request = args.first Protocolオブジェクトが else 渡されている場合 … request = ::Warden::Client::V1.request_from_v1(args.dup) @v1mode = true argsに”create”が渡されていれば end Warden::Protocol::CreateRequest @request_queue << { :request => request, :callback => blk } process_queueend2012-09-13 NTT Software Innovation Center 22
  23. 23. 【寄り道】 コンテナ生成時におけるマウントの追加  /warden/warden/lib/warden/container/linux.rb – フックにマウントの命令を追加する def write_bind_mount_commands(request) return if request.bind_mounts.nil? || request.bind_mounts.empty? File.open(File.join(container_path, "hook-parent-before-clone.sh"), "a") do |file| … request.bind_mounts.each do |bind_mount| src_path = bind_mount.src_path dst_path = bind_mount.dst_path # Fix up destination path to be an absolute path inside the union dst_path = File.join(container_path, "union", dst_path[1..-1]) mode = case bind_mount.mode when Protocol::CreateRequest::BindMount::Mode::RO "ro" when Protocol::CreateRequest::BindMount::Mode::RW "rw" else raise "Unknown mode" end file.puts "mkdir -p #{dst_path}" % [dst_path] file.puts "mount -n --bind #{src_path} #{dst_path}" file.puts "mount -n --bind -o remount,#{mode} #{src_path} #{dst_path}" end end end2012-09-13 NTT Software Innovation Center 23
  24. 24. Dropletの展開  コンテナ上でtarコマンドを実行 def promise_extract_droplet Promise.new do |p| connection = promise_warden_connection(:app).resolve script = "tar zxf #{droplet.droplet_path}" promise_warden_run(connection, script).resolve p.deliver end end2012-09-13 NTT Software Innovation Center 24
  25. 25. スタートアップスクリプトの調整  アプリケーション起動スクリプトのプレースホル ダを置換する – @がデリミタ def promise_prepare_start_script Promise.new do |p| connection = promise_warden_connection(:app).resolve script = "sed -i s@%VCAP_LOCAL_RUNTIME%@#{runtime.executable}@g startup" promise_warden_run(connection, script).resolve p.deliver end end2012-09-13 NTT Software Innovation Center 25
  26. 26. スタートアップスクリプトの呼び出し def promise_start Promise.new do |p| script = [] script << "renice 0 $$" script << "ulimit -n %d" % self.file_descriptor_limit script << "ulimit -u %d" % 512 script << "umask 077" env = Env.new(self) env.env.each do |(key, value)| script << "export %s=%s" % [key, value] end startup = "./startup" # Pass port to `startup` if we have one if self.instance_host_port startup << " -p %d" % self.instance_host_port end script << startup script << "exit" connection = promise_warden_connection(:app).resolve request = ::Warden::Protocol::SpawnRequest.new request.handle = attributes["warden_handle"] request.script = script.join("¥n") response = promise_warden_call(connection, request).resolve attributes["warden_job_id"] = response.job_id p.deliver end end2012-09-13 NTT Software Innovation Center 26
  27. 27. Promise パターンについて2012-09-13 NTT Software Innovation Center 27
  28. 28. Promise(future)パターンとは DEA::InstanceがPromiseまみれになった • 非同期プログラミング – Wardenとの通信が発生する • ブロックを避けたい – Wardenの処理待ち中ブロックされたくない • deferredに似てる – JavaScriptプログラマーにはおなじみ2012-09-13 NTT Software Innovation Center 28
  29. 29. イメージ 処理AのIO待ち中に処理Bを済ませておきたい • 処理Aをスタートし、引換券(Promise)をもらう • IO待ち中に処理Bを開始する • どうしても処理Aの結果がほしくなったら引換券を 実際の値に交換してもらう(resolve) • 処理Aは結果が出たら値を記録しておく (deliver)2012-09-13 NTT Software Innovation Center 29
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×