contained_mr 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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