contained_mr 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7dd43659d3e4a97eb0c431a28fd0e18ef0df524e
4
- data.tar.gz: c460e444b84ebd56df7295147150e1b49fa42649
3
+ metadata.gz: ddef939463b55a174ccb6f44f90ad8f28f9f8bdc
4
+ data.tar.gz: b80c4c9a95e03b2fc61bd378f1e405a26a633513
5
5
  SHA512:
6
- metadata.gz: a91d0f3867c8ceda6e96d134bacffaf22f50c6332077b177060cd5a6b03d77e22ce7e81af7770ed18e989e6358324cf54e8cb2bdb0124bd3ea6567994cac8144
7
- data.tar.gz: 07322eb0b6961b86c92ce5b3798764847695479473d043167160cb5c9ca07783f11a9dee2cc33eb96d872719abe042225edbb5cbe16cada66623c93837861a34
6
+ metadata.gz: 195e87944d7a7d3d447d7526ee58459c091381a5c7c25f78ac7c1768fc9857f1f3106f8b011554f3d232e6b7dd36f47a24cf402bc861912751d3abfc2317f79a
7
+ data.tar.gz: e19354cfca2219c5d2765e268a2d8a93ffd243168b50bd46b87e8b023cfc976d74f52631926daa917f33a4674b9be75d254be1f745f2f900084bd9a1a9570b95
data/README.md CHANGED
@@ -5,6 +5,35 @@
5
5
 
6
6
  Map-Reduce where both the mappers and the reducer run inside Docker containers.
7
7
 
8
+ ## Development Environment
9
+
10
+ `contained-mr` requires access to a Docker daemon. The easiest way to
11
+ bring up a development setup is to install
12
+ [Docker Machine](https://github.com/docker/machine) and
13
+ [VirtualBox](https://www.virtualbox.org/).
14
+
15
+ The commands below install the prerequisites on OSX using
16
+ [Homebrew](http://brew.sh/).
17
+
18
+ ```bash
19
+ brew install brew-cask docker docker-machine
20
+ brew cask install virtualbox
21
+ ```
22
+
23
+ Create a Docker VM. This is a one-time setup.
24
+
25
+ ```bash
26
+ docker-machine create --driver virtualbox dev
27
+ ```
28
+
29
+ Set up the local environment to point to the Docker daemon in the VM. This must
30
+ be executed in every shell where `contained-mr` is used.
31
+
32
+ ```bash
33
+ eval "$(docker-machine env dev)"
34
+ ```
35
+
36
+
8
37
  ## Contributing to contained_mr
9
38
 
10
39
  * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.0
1
+ 0.3.0
data/contained_mr.gemspec CHANGED
@@ -2,16 +2,16 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: contained_mr 0.2.0 ruby lib
5
+ # stub: contained_mr 0.3.0 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "contained_mr"
9
- s.version = "0.2.0"
9
+ s.version = "0.3.0"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib"]
13
13
  s.authors = ["Victor Costan"]
14
- s.date = "2015-09-17"
14
+ s.date = "2015-10-09"
15
15
  s.description = "Plumbing for running mappers and reducers inside Docker containers"
16
16
  s.email = "victor@costan.us"
17
17
  s.extra_rdoc_files = [
@@ -67,7 +67,7 @@ Gem::Specification.new do |s|
67
67
  ]
68
68
  s.homepage = "http://github.com/pwnall/contained_mr"
69
69
  s.licenses = ["MIT"]
70
- s.rubygems_version = "2.4.5"
70
+ s.rubygems_version = "2.4.5.1"
71
71
  s.summary = "Map-Reduce with Docker containers"
72
72
 
73
73
  if s.respond_to? :specification_version then
@@ -9,7 +9,7 @@ require 'docker'
9
9
  class ContainedMr::Job
10
10
  include ContainedMr::JobLogic
11
11
 
12
- # @see {ContainedMr::TemplateLogic#create_job}
12
+ # @see {ContainedMr::TemplateLogic#new_job}
13
13
  def initialize(template, id, json_options)
14
14
  @template = template
15
15
  @id = id
@@ -55,13 +55,17 @@ module ContainedMr::JobLogic
55
55
  { "Name" => k.to_s, "Soft" => v, "Hard" => v }
56
56
  end
57
57
 
58
+ env = @template.mapper_env i
59
+ env.push "affinity:image==#{mapper_image_tag}"
60
+
58
61
  {
59
62
  'name' => "#{@name_prefix}_mapper.#{@id}.#{i}",
60
- 'Image' => @mapper_image_id,
63
+ 'Image' => mapper_image_tag,
61
64
  'Hostname' => "#{i}.mapper", 'Domainname' => '',
62
65
  'Labels' => { 'contained_mr.ctl' => @name_prefix },
63
- 'Env' => @template.mapper_env(i), 'Ulimits' => ulimits,
66
+ 'Env' => env, 'Ulimits' => ulimits,
64
67
  'NetworkDisabled' => true, 'ExposedPorts' => {},
68
+ 'HostConfig' => container_host_config(@mapper_options),
65
69
  }
66
70
  end
67
71
 
@@ -71,15 +75,45 @@ module ContainedMr::JobLogic
71
75
  { "Name" => k.to_s, "Soft" => v, "Hard" => v }
72
76
  end
73
77
 
78
+ env = @template.reducer_env
79
+ env.push "affinity:image==#{reducer_image_tag}"
80
+
74
81
  {
75
82
  'name' => "#{@name_prefix}_reducer.#{@id}",
76
- 'Image' => @reducer_image_id,
83
+ 'Image' => reducer_image_tag,
77
84
  'Hostname' => 'reducer', 'Domainname' => '',
78
85
  'Labels' => { 'contained_mr.ctl' => @name_prefix },
79
- 'Env' => @template.reducer_env, 'Ulimits' => ulimits,
86
+ 'Env' => env, 'Ulimits' => ulimits,
80
87
  'NetworkDisabled' => true, 'ExposedPorts' => {},
88
+ 'HostConfig' => container_host_config(@reducer_options),
89
+ }
90
+ end
91
+
92
+ # Computes the value of the HostConfig key in container creation params.
93
+ #
94
+ # @param {Hash<Symbol, Object>} job_section the "mapper" or "reducer" section
95
+ # in the options
96
+ # @return {Hash<String, Object>} a container's HostConfig params
97
+ def container_host_config(job_section)
98
+ ram_bytes = (job_section[:ram] * 1048576).to_i
99
+ if job_section[:swap] == 0
100
+ swap_bytes = -1
101
+ else
102
+ swap_bytes = (job_section[:swap] * 1048576).to_i + ram_bytes
103
+ end
104
+
105
+ # NOTE: The value below is 1 second, in microsecodns. This is the maximum
106
+ # value, and it minimizes scheduling overheads, at the expense of
107
+ # precision.
108
+ cpu_period = 1_000_000
109
+
110
+ {
111
+ 'Memory' => ram_bytes, 'MemorySwap' => swap_bytes,
112
+ 'CpuShares' => (job_section[:vcpus] * cpu_period).to_i,
113
+ 'CpuPeriod' => cpu_period
81
114
  }
82
115
  end
116
+ private :container_host_config
83
117
 
84
118
  # Reads in JSON options and sets defaults.
85
119
  def parse_options(json_options)
@@ -87,9 +121,11 @@ module ContainedMr::JobLogic
87
121
  mapper_ulimits = mapper['ulimits'] || {}
88
122
  @mapper_options = {
89
123
  wait_time: mapper['wait_time'] || 60,
124
+ vcpus: mapper['vcpus'] || 1, # logical processors
125
+ ram: mapper['ram'] || 512, # megabytes
126
+ swap: mapper['swap'] || 0, # megabytes
90
127
  ulimits: {
91
128
  cpu: mapper_ulimits['cpu'] || 60, # seconds
92
- rss: mapper_ulimits['rss'] || 500_000, # pages
93
129
  }
94
130
  }
95
131
 
@@ -97,9 +133,11 @@ module ContainedMr::JobLogic
97
133
  reducer_ulimits = reducer['ulimits'] || {}
98
134
  @reducer_options = {
99
135
  wait_time: reducer['wait_time'] || 60,
136
+ vcpus: reducer['vcpus'] || 1, # logical processors
137
+ ram: reducer['ram'] || 512, # megabytes
138
+ swap: reducer['swap'] || 0, # megabytes
100
139
  ulimits: {
101
140
  cpu: reducer_ulimits['cpu'] || 60,
102
- rss: reducer_ulimits['rss'] || 500_000,
103
141
  }
104
142
  }
105
143
  end
@@ -69,7 +69,7 @@ module ContainedMr::TemplateLogic
69
69
  # @private common code from mapper_dockerfile and reducer_dockerfile
70
70
  def job_dockerfile(job_definition, input_source)
71
71
  <<DOCKER_END
72
- FROM #{@image_id}
72
+ FROM #{image_tag}
73
73
  COPY #{input_source} #{job_definition['input'] || '/input'}
74
74
  WORKDIR #{job_definition['chdir'] || '/'}
75
75
  ENTRYPOINT #{JSON.dump(job_definition['cmd'] || ['/bin/sh'])}
@@ -9,6 +9,14 @@ class TestJobLogic < MiniTest::Test
9
9
  JSON.load(File.read('testdata/job.hello'))
10
10
  end
11
11
 
12
+ def test_mapper_image_tag
13
+ assert_equal 'contained_mrtests/mapper.testjob', @job.mapper_image_tag
14
+ end
15
+
16
+ def test_reducer_image_tag
17
+ assert_equal 'contained_mrtests/reducer.testjob', @job.reducer_image_tag
18
+ end
19
+
12
20
  def test_mapper_container_options
13
21
  assert_equal @template, @job.template
14
22
  assert_equal 'contained_mrtests', @job.name_prefix
@@ -19,16 +27,22 @@ class TestJobLogic < MiniTest::Test
19
27
 
20
28
  golden = {
21
29
  'name' => 'contained_mrtests_mapper.testjob.2',
22
- 'Image' => @job.mapper_image_id,
30
+ 'Image' => 'contained_mrtests/mapper.testjob',
23
31
  'Hostname' => '2.mapper',
24
32
  'Domainname' => '',
25
33
  'Labels' => { 'contained_mr.ctl' => 'contained_mrtests' },
26
- 'Env' => [ 'ITEM=2', 'ITEMS=3' ],
34
+ 'Env' => [ 'ITEM=2', 'ITEMS=3',
35
+ 'affinity:image==contained_mrtests/mapper.testjob' ],
27
36
  'Ulimits' => [
28
37
  { 'Name' => 'cpu', 'Hard' => 3, 'Soft' => 3 },
29
- { 'Name' => 'rss', 'Hard' => 1000000, 'Soft' => 1000000 },
30
38
  ],
31
39
  'NetworkDisabled' => true, 'ExposedPorts' => {},
40
+ 'HostConfig' => {
41
+ 'Memory' => 256.5 * 1024 * 1024,
42
+ 'MemorySwap' => (256.5 + 64) * 1024 * 1024,
43
+ 'CpuShares' => 1500000,
44
+ 'CpuPeriod' => 1000000,
45
+ },
32
46
  }
33
47
  assert_equal golden, @job.mapper_container_options(2)
34
48
  end
@@ -36,16 +50,22 @@ class TestJobLogic < MiniTest::Test
36
50
  def test_reducer_container_options
37
51
  golden = {
38
52
  'name' => 'contained_mrtests_reducer.testjob',
39
- 'Image' => @job.mapper_image_id,
53
+ 'Image' => 'contained_mrtests/reducer.testjob',
40
54
  'Hostname' => 'reducer',
41
55
  'Domainname' => '',
42
56
  'Labels' => { 'contained_mr.ctl' => 'contained_mrtests' },
43
- 'Env' => [ 'ITEMS=3' ],
57
+ 'Env' => [ 'ITEMS=3',
58
+ 'affinity:image==contained_mrtests/reducer.testjob' ],
44
59
  'Ulimits' => [
45
60
  { 'Name' => 'cpu', 'Hard' => 2, 'Soft' => 2 },
46
- { 'Name' => 'rss', 'Hard' => 100000, 'Soft' => 100000 },
47
61
  ],
48
62
  'NetworkDisabled' => true, 'ExposedPorts' => {},
63
+ 'HostConfig' => {
64
+ 'Memory' => 768.5 * 1024 * 1024,
65
+ 'MemorySwap' => -1,
66
+ 'CpuShares' => 500000,
67
+ 'CpuPeriod' => 1000000,
68
+ },
49
69
  }
50
70
  assert_equal golden, @job.reducer_container_options
51
71
  end
@@ -14,6 +14,12 @@ class TestMockRunner < MiniTest::Test
14
14
  { 'Name' => 'rss', 'Hard' => 1000000, 'Soft' => 1000000 },
15
15
  ],
16
16
  'NetworkDisabled' => true, 'ExposedPorts' => {},
17
+ 'HostConfig' => {
18
+ 'Memory' => 256.5 * 1024 * 1024,
19
+ 'MemorySwap' => (256.5 + 64) * 1024 * 1024,
20
+ 'CpuShares' => 1500000,
21
+ 'CpuPeriod' => 1000000,
22
+ },
17
23
  }
18
24
  @runner = ContainedMr::Mock::Runner.new @container_options, 2.5,
19
25
  '/usr/mrd/map-output'
@@ -11,9 +11,14 @@ class TestRunnerLogic < MiniTest::Test
11
11
  'Env' => [ 'ITEM=2', 'ITEMS=3' ],
12
12
  'Ulimits' => [
13
13
  { 'Name' => 'cpu', 'Hard' => 3, 'Soft' => 3 },
14
- { 'Name' => 'rss', 'Hard' => 1000000, 'Soft' => 1000000 },
15
14
  ],
16
15
  'NetworkDisabled' => true, 'ExposedPorts' => {},
16
+ 'HostConfig' => {
17
+ 'Memory' => 256.5 * 1024 * 1024,
18
+ 'MemorySwap' => (256.5 + 64) * 1024 * 1024,
19
+ 'CpuShares' => 1500000,
20
+ 'CpuPeriod' => 1000000,
21
+ },
17
22
  }
18
23
  @runner = ContainedMr::Mock::Runner.new @container_options, 2.5,
19
24
  '/usr/mrd/map-output'
@@ -9,13 +9,11 @@ class TestTemplateLogic < MiniTest::Test
9
9
 
10
10
  def test_mapper_dockerfile
11
11
  golden = File.read 'testdata/Dockerfile.hello.mapper'
12
- golden.sub! 'contained_mrtests/base.hello', 'mock-template-image-id'
13
12
  assert_equal golden, @template.mapper_dockerfile, 'mapper Dockerfile'
14
13
  end
15
14
 
16
15
  def test_reducer_dockerfile
17
16
  golden = File.read 'testdata/Dockerfile.hello.reducer'
18
- golden.sub! 'contained_mrtests/base.hello', 'mock-template-image-id'
19
17
  assert_equal golden, @template.reducer_dockerfile, 'reducer Dockerfile'
20
18
  end
21
19
 
data/testdata/job.hello CHANGED
@@ -1,10 +1,16 @@
1
1
  {
2
2
  "mapper": {
3
3
  "wait_time": 2.5,
4
- "ulimits": { "cpu": 3, "rss": 1000000 }
4
+ "vcpus": 1.5,
5
+ "ram": 256.5,
6
+ "swap": 64,
7
+ "ulimits": { "cpu": 3 }
5
8
  },
6
9
  "reducer": {
7
10
  "wait_time": 2,
8
- "ulimits": { "cpu": 2, "rss": 100000 }
11
+ "vcpus": 0.5,
12
+ "ram": 768.5,
13
+ "swap": 0,
14
+ "ulimits": { "cpu": 2 }
9
15
  }
10
16
  }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: contained_mr
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Victor Costan
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-09-17 00:00:00.000000000 Z
11
+ date: 2015-10-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: docker-api
@@ -209,7 +209,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
209
209
  version: '0'
210
210
  requirements: []
211
211
  rubyforge_project:
212
- rubygems_version: 2.4.5
212
+ rubygems_version: 2.4.5.1
213
213
  signing_key:
214
214
  specification_version: 4
215
215
  summary: Map-Reduce with Docker containers