docker-rails-app 0.3.6
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 +7 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/lib/docker_rails_app/import_gem_rake_tasks.rb +9 -0
- data/lib/docker_rails_app/version.rb +3 -0
- data/lib/docker_rails_app.rb +5 -0
- data/lib/support/docker_api.rb +81 -0
- data/lib/support/docker_image_creator.rb +244 -0
- data/lib/support/docker_rails_app_creator.rb +60 -0
- data/lib/support/docker_rails_config_reader.rb +26 -0
- data/lib/support/docker_registry.rb +58 -0
- data/lib/support/docker_runner.rb +263 -0
- data/lib/support/image_files/DockerfileRepo +49 -0
- data/lib/support/image_files/DockerfileSelf +46 -0
- data/lib/support/image_files/entrypoint.sh +16 -0
- data/lib/support/image_files/wait_for_file.sh +9 -0
- data/lib/support/image_files/wait_for_port.sh +11 -0
- data/lib/support/initialize_project.rb +131 -0
- data/lib/support/launch_support.rb +62 -0
- data/lib/tasks/deploy.rake +45 -0
- data/lib/tasks/initialize.rake +13 -0
- data/lib/tasks/run.rake +38 -0
- metadata +108 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 89604320070bdd27a69e302b9ab8293462a8bbd7
|
4
|
+
data.tar.gz: 4e633b7d7f29fc3f07233be921023285f967178b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b0df7c6014209c36622f3845abdd89a8cff2c1f7f2b3f98773626795dafd9dc6713f0183eb336c5248aaee242591d7aaba1735bf4e1305841742f4542995dea1
|
7
|
+
data.tar.gz: 2a0ea6f57497d5702589e3fa8b7bde7a8d8094bc58c0ecfa2c58a6390f2e994c6586a5fb084039634c5a0090ce641275768163f361066a87eb464b459affa77e
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "docker_rails_app"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
# DOCKER_URL=tcp://qa2:4243 ruby lib/docker-api/docker_api_tests.rb
|
2
|
+
# DOCKER_URL=tcp://192.168.99.100:2376 ruby lib/docker-api/docker_api_tests.rb
|
3
|
+
require 'docker'
|
4
|
+
|
5
|
+
raise "Remove this monkey patch when API library provides this stats method" if (Docker::Container.respond_to? "stats")
|
6
|
+
class Docker::Container
|
7
|
+
# Non streaming stats
|
8
|
+
def stats(options = {})
|
9
|
+
path = path_for(:stats)
|
10
|
+
puts "Getting stats from: #{path}"
|
11
|
+
options[:stream] = false
|
12
|
+
container_stats = nil
|
13
|
+
begin
|
14
|
+
status = Timeout::timeout(5) {
|
15
|
+
container_stats = connection.get(path, options)
|
16
|
+
}
|
17
|
+
rescue Exception => e
|
18
|
+
return {error: e.message}
|
19
|
+
end
|
20
|
+
JSON.parse(container_stats)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class DockerApi
|
25
|
+
attr_accessor :connection
|
26
|
+
|
27
|
+
# Build a connection to docker on a remote host. Need a connection to be able to make multiple docker calls within the app to different hosts.
|
28
|
+
# host: {address: "olex-qa2.openlogic.com", docker_port: 4245 }
|
29
|
+
def self.connection(host)
|
30
|
+
cert_path = ENV['DOCKER_CERT_PATH']
|
31
|
+
scheme = "http"
|
32
|
+
scheme = "https" if (ENV['DOCKER_TLS_VERIFY'] == "1")
|
33
|
+
|
34
|
+
docker_connection_opts = {:client_cert=>"#{cert_path}/cert.pem", :client_key=>"#{cert_path}/key.pem",
|
35
|
+
:ssl_ca_file=>"#{cert_path}/ca.pem", :scheme => scheme}
|
36
|
+
|
37
|
+
# docker_connection_opts = {:client_cert=>"/Users/mikemoore/.docker/machine/machines/dev/cert.pem", :client_key=>"/Users/mikemoore/.docker/machine/machines/dev/key.pem",
|
38
|
+
# :ssl_ca_file=>"/Users/mikemoore/.docker/machine/machines/dev/ca.pem", :scheme=>"https"}
|
39
|
+
docker_connection_opts[:scheme] = "http" if (host[:ssl] == false)
|
40
|
+
docker_connection = Docker::Connection.new("tcp://#{host[:address]}:#{host[:docker_port]}", docker_connection_opts)
|
41
|
+
return docker_connection
|
42
|
+
end
|
43
|
+
|
44
|
+
def initialize(url, secure = true)
|
45
|
+
# Docker.logger = Logger.new(STDOUT)
|
46
|
+
# Docker.logger.level = Logger::DEBUG
|
47
|
+
address = url.split("//").last.split(":").first
|
48
|
+
port = url.split(":").last
|
49
|
+
host = {address: address, docker_port: port, ssl: secure}
|
50
|
+
@connection = DockerApi.connection(host)
|
51
|
+
end
|
52
|
+
|
53
|
+
def find_container_with_name(wanted_name)
|
54
|
+
options = {
|
55
|
+
all: true
|
56
|
+
}
|
57
|
+
all_containers = Docker::Container.all(options, @connection)
|
58
|
+
all_containers.each do |container|
|
59
|
+
json = container.json
|
60
|
+
name = json['Name']
|
61
|
+
return container if (name == "/#{wanted_name}")
|
62
|
+
end
|
63
|
+
return nil
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
#
|
69
|
+
# puts ""
|
70
|
+
# puts "Here are Containers on #{docker_url}"
|
71
|
+
# all_containers = Docker::Container.all
|
72
|
+
# all_containers.each do |container|
|
73
|
+
# puts "#{container.json['Name']}"
|
74
|
+
# puts " Running: #{container.json['State']['Running']}"
|
75
|
+
# puts " Running: #{container.json['State']['ExitCode']}"
|
76
|
+
#
|
77
|
+
# env_vars = container.json['Config']['Env']
|
78
|
+
# env_vars.each do |env|
|
79
|
+
# puts " Env: #{env}"
|
80
|
+
# end
|
81
|
+
# end
|
@@ -0,0 +1,244 @@
|
|
1
|
+
require_relative "./docker_runner"
|
2
|
+
require_relative "./docker_registry"
|
3
|
+
|
4
|
+
class DockerImageCreator
|
5
|
+
attr_accessor :use_date_as_version
|
6
|
+
|
7
|
+
REMOVE_INTERMEDIATE_FLAG = "--rm=true"
|
8
|
+
DAEMON_OPTIONS = " -d -t -P"
|
9
|
+
INTERACT_OPTIONS = " -a stdin -a stdout -i -t -P"
|
10
|
+
DOCKER_DIR = Dir.pwd + "/lib"
|
11
|
+
|
12
|
+
attr_accessor :version_forced, :image_name_forced, :docker_host, :docker_host_secure
|
13
|
+
attr_reader :definition
|
14
|
+
|
15
|
+
def initialize(definition)
|
16
|
+
raise "Definition is nil" if definition == nil
|
17
|
+
@definition = definition
|
18
|
+
@home = FileUtils.pwd
|
19
|
+
@version = nil
|
20
|
+
@docker_host = nil
|
21
|
+
@docker_host_secure = nil
|
22
|
+
end
|
23
|
+
|
24
|
+
def use_date_as_version?
|
25
|
+
false
|
26
|
+
end
|
27
|
+
|
28
|
+
def image_name
|
29
|
+
return (@image_name_forced) if (@image_name_forced)
|
30
|
+
build_def = @definition[:build]
|
31
|
+
name = @definition[:run][:image_name] if (@definition[:run])
|
32
|
+
name = build_def[:name] if (build_def)
|
33
|
+
return name
|
34
|
+
end
|
35
|
+
|
36
|
+
def docker_api
|
37
|
+
@docker_host = @docker_host || ENV['DOCKER_HOST']
|
38
|
+
@docker_host_secure = @docker_host_secure || (ENV['DOCKER_TLS_VERIFY'].to_s == '1')
|
39
|
+
raise "Need to define DOCKER_HOST env variable" if (!@docker_host)
|
40
|
+
raise "Need to define DOCKER_TLS_VERIFY env variable" if (@docker_host_secure == nil)
|
41
|
+
docker_api = DockerApi.new(@docker_host, @docker_host_secure)
|
42
|
+
end
|
43
|
+
|
44
|
+
def build_it()
|
45
|
+
docker_connection = docker_api.connection
|
46
|
+
build_def = @definition[:build]
|
47
|
+
if (build_def == nil)
|
48
|
+
puts "Warning: build not defined for #{definition[:code]} - ignoring request"
|
49
|
+
else
|
50
|
+
begin
|
51
|
+
before_build(@definition)
|
52
|
+
remove_intermediate = REMOVE_INTERMEDIATE_FLAG
|
53
|
+
|
54
|
+
volume_path = build_def[:volume_path]
|
55
|
+
build_command = nil
|
56
|
+
|
57
|
+
image_and_version = image_name()
|
58
|
+
image_and_version += ":#{version()}" if (version() != nil)
|
59
|
+
|
60
|
+
opts = build_def[:api_options] || {}
|
61
|
+
opts[:t] = "#{image_and_version}"
|
62
|
+
opts[:rm] = true
|
63
|
+
|
64
|
+
Excon.defaults[:write_timeout] = 1000
|
65
|
+
Excon.defaults[:read_timeout] = 1000
|
66
|
+
puts "Building image. Docker dir: #{docker_dir} ..."
|
67
|
+
|
68
|
+
image = Docker::Image.build_from_dir(docker_dir, opts, docker_connection) do |v|
|
69
|
+
begin
|
70
|
+
if (log = JSON.parse(v)) && log.has_key?("stream")
|
71
|
+
$stdout.puts log["stream"]
|
72
|
+
end
|
73
|
+
rescue Exception => ex
|
74
|
+
puts "#{v}"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
rescue Exception => ex
|
78
|
+
puts"Exception: #{ex.message}"
|
79
|
+
puts ex.backtrace
|
80
|
+
debugger
|
81
|
+
raise "Exception building image. #{ex.message}\nCheck connection to: #{docker_connection}"
|
82
|
+
ensure
|
83
|
+
after_build(@definition)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def version
|
89
|
+
return (@version_forced) if (@version_forced)
|
90
|
+
build_def = @definition[:build]
|
91
|
+
raise "No build definition for: #{@definition[:code]}" if (!build_def)
|
92
|
+
version = 'latest'
|
93
|
+
version = build_def[:version] if (build_def[:version] != nil)
|
94
|
+
return version
|
95
|
+
end
|
96
|
+
|
97
|
+
def tag_it(registry)
|
98
|
+
raise "DOCKER_REGISTRY environment variable not defined for push operation" if registry == nil
|
99
|
+
do_tag(registry)
|
100
|
+
end
|
101
|
+
|
102
|
+
#def do_tag(image_name, version, registry)
|
103
|
+
def do_tag(registry)
|
104
|
+
docker_connection = docker_api.connection
|
105
|
+
image = Docker::Image.get("#{image_name}:#{version}", {}, docker_connection)
|
106
|
+
puts "Tagging image: #{image_name}"
|
107
|
+
image.tag('repo' => "#{registry}/#{image_name()}", 'image' => 'unicorn', 'tag' => version(), force: true)
|
108
|
+
end
|
109
|
+
|
110
|
+
def push_it(registry)
|
111
|
+
raise "DOCKER_REGISTRY environment variable not defined for push operation" if registry == nil
|
112
|
+
build_def = @definition[:build]
|
113
|
+
do_push(registry)
|
114
|
+
end
|
115
|
+
|
116
|
+
def api_image(registry, docker_connection)
|
117
|
+
full_name = "#{registry}/#{image_name}"
|
118
|
+
full_name += ":#{version()}" if (version() != nil)
|
119
|
+
image = Docker::Image.get(full_name, {}, docker_connection)
|
120
|
+
puts "Pushing Image: #{full_name} ..."
|
121
|
+
return image
|
122
|
+
end
|
123
|
+
|
124
|
+
def do_push(registry)
|
125
|
+
if (registry)
|
126
|
+
Excon.defaults[:write_timeout] = 1000
|
127
|
+
Excon.defaults[:read_timeout] = 1000
|
128
|
+
|
129
|
+
docker_connection = docker_api.connection
|
130
|
+
|
131
|
+
image = api_image(registry, docker_connection)
|
132
|
+
|
133
|
+
credentials = nil
|
134
|
+
result = image.push(credentials, {tag: version, repo: registry})
|
135
|
+
puts "Done pushing Image: #{registry}/#{image_name}"
|
136
|
+
the_registry = DockerRegistry.new(registry)
|
137
|
+
|
138
|
+
if (the_registry.has_image_with_version?("#{image_name}", version) == false)
|
139
|
+
raise "After push, image doesn't appear in registry. Image: #{image_name}:#{version}. Push result: #{result}"
|
140
|
+
end
|
141
|
+
else
|
142
|
+
puts "No registry specified for pushing"
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def run_it(host, host_ssl, interact, run_instance_count, registry = nil)
|
147
|
+
@docker_host = host
|
148
|
+
@docker_host_secure = host_ssl
|
149
|
+
puts "Warning: registry not defined, assuming run is local" if registry == nil
|
150
|
+
run_def = @definition[:run]
|
151
|
+
build_def = @definition[:build]
|
152
|
+
if (run_def == nil)
|
153
|
+
puts "No run definition for: #{@definition[:code]}"
|
154
|
+
else
|
155
|
+
(1..run_instance_count).each do |instance_index|
|
156
|
+
use_extension = (run_instance_count > 1)
|
157
|
+
run_with_extension(:next, registry, interact, use_extension)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def run_with_extension(instance_index, registry, interact, use_extension)
|
163
|
+
@docker_api = DockerApi.new(@docker_host)
|
164
|
+
docker_runner = DockerRunner.new(self, nil)
|
165
|
+
docker_runner.registry = registry
|
166
|
+
docker_runner.instance_index = instance_index
|
167
|
+
docker_runner.use_extension = use_extension
|
168
|
+
docker_runner.interact = interact
|
169
|
+
docker_runner.image_name = image_name
|
170
|
+
docker_runner.code = @definition[:code]
|
171
|
+
docker_runner.remote_address = @docker_host
|
172
|
+
docker_runner.secure_docker_api = @docker_host_secure
|
173
|
+
docker_runner.run_with_extension
|
174
|
+
end
|
175
|
+
|
176
|
+
def add_it(host, host_ssl, run_instance_count, registry)
|
177
|
+
@docker_host = host
|
178
|
+
@docker_host_secure = host_ssl
|
179
|
+
number_added = 0
|
180
|
+
while (number_added < run_instance_count)
|
181
|
+
run_def = @definition[:run]
|
182
|
+
run_name = run_def[:name]
|
183
|
+
extension = 1
|
184
|
+
run_with_extension(:next, registry, false, true)
|
185
|
+
number_added += 1
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
def kill_all(host, host_ssl)
|
190
|
+
docker_runner = DockerRunner.new(self, nil)
|
191
|
+
docker_runner.registry = nil
|
192
|
+
docker_runner.use_extension = true
|
193
|
+
docker_runner.interact = false
|
194
|
+
docker_runner.remote_address = host
|
195
|
+
docker_runner.secure_docker_api = host_ssl
|
196
|
+
|
197
|
+
run_def = @definition[:run]
|
198
|
+
run_name = run_def[:name]
|
199
|
+
docker_runner.kill_all(run_name)
|
200
|
+
end
|
201
|
+
|
202
|
+
def subtract(host, host_ssl, count)
|
203
|
+
docker_runner = DockerRunner.new(self, nil)
|
204
|
+
docker_runner.registry = nil
|
205
|
+
docker_runner.use_extension = true
|
206
|
+
docker_runner.interact = false
|
207
|
+
docker_runner.remote_address = host
|
208
|
+
docker_runner.secure_docker_api = host_ssl
|
209
|
+
|
210
|
+
run_def = @definition[:run]
|
211
|
+
run_name = run_def[:name]
|
212
|
+
docker_runner.kill(run_name, count)
|
213
|
+
end
|
214
|
+
|
215
|
+
def openlogic_home()
|
216
|
+
@openlogic_home = @openlogic_home[0..(@openlogic_home.length - 2)] if (@openlogic_home.end_with? "/")
|
217
|
+
return @openlogic_home
|
218
|
+
end
|
219
|
+
|
220
|
+
def before_build(definition)
|
221
|
+
delete_image_support_from_stage()
|
222
|
+
copy_image_support_to_stage()
|
223
|
+
end
|
224
|
+
|
225
|
+
def after_build(definition)
|
226
|
+
delete_image_support_from_stage()
|
227
|
+
end
|
228
|
+
|
229
|
+
def delete_image_support_from_stage()
|
230
|
+
FileUtils.remove_dir("#{docker_dir}image_support", true)
|
231
|
+
end
|
232
|
+
|
233
|
+
def docker_dir
|
234
|
+
return @definition[:build][:docker_directory] + "/"
|
235
|
+
end
|
236
|
+
|
237
|
+
def copy_image_support_to_stage
|
238
|
+
raise "Definition nil" if @definition == nil
|
239
|
+
raise "Build Definition nil" if @definition[:build] == nil
|
240
|
+
image_support_dir = "#{FileUtils.pwd}/lib/support/image_support/"
|
241
|
+
FileUtils.cp_r(image_support_dir, docker_dir())
|
242
|
+
end
|
243
|
+
|
244
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require_relative "./docker_image_creator"
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
class DockerRailsAppCreator < DockerImageCreator
|
5
|
+
ARCHIVE_TMP_FILE = "/tmp/rails_application.tar.gz"
|
6
|
+
|
7
|
+
def docker_dir
|
8
|
+
dir = definition['build']['docker_dir'] || "#{FileUtils.pwd}/docker"
|
9
|
+
end
|
10
|
+
|
11
|
+
def before_build(definition)
|
12
|
+
build_from_current_dir = true
|
13
|
+
stage_files_dir = docker_dir() + "/files"
|
14
|
+
FileUtils.rm_rf stage_files_dir
|
15
|
+
FileUtils.mkdir_p stage_files_dir
|
16
|
+
|
17
|
+
archive_file = ARCHIVE_TMP_FILE
|
18
|
+
`rm -rf #{archive_file}`
|
19
|
+
`tar -czf #{archive_file} --exclude=tmp/* --exclude .git --exclude "*.log" *`
|
20
|
+
FileUtils.mv(archive_file, stage_files_dir)
|
21
|
+
|
22
|
+
create_database_config_file(definition, stage_files_dir)
|
23
|
+
end
|
24
|
+
|
25
|
+
def create_database_config_file(definition, directory)
|
26
|
+
db_host_name = definition['run']['name'] + "-db"
|
27
|
+
File.open("#{directory}/database.yml", "w") do |file|
|
28
|
+
content = "
|
29
|
+
#This file generated by Docker Rails when building docker image
|
30
|
+
production:
|
31
|
+
adapter: mysql2
|
32
|
+
database: application_db
|
33
|
+
pool: 5
|
34
|
+
timeout: 5000
|
35
|
+
host: #{db_host_name}
|
36
|
+
port: 3306
|
37
|
+
user: root
|
38
|
+
password: password
|
39
|
+
persistence: :db
|
40
|
+
"
|
41
|
+
file.write(content)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def prepare_for_git_pull
|
46
|
+
ssh_staging_dir = stage_files_dir + "/ssh/"
|
47
|
+
FileUtils.mkdir_p ssh_staging_dir
|
48
|
+
FileUtils.cp "#{ENV['HOME']}/.ssh/id_rsa", ssh_staging_dir
|
49
|
+
FileUtils.cp "#{ENV['HOME']}/.ssh/id_rsa.pub", ssh_staging_dir
|
50
|
+
end
|
51
|
+
|
52
|
+
def after_build(definiton)
|
53
|
+
if (build_source == :current)
|
54
|
+
stage_files_dir = docker_dir() + "/files"
|
55
|
+
FileUtils.rm_f stage_files_dir
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
|
2
|
+
class DockerRailsConfigReader
|
3
|
+
attr_accessor :definitions
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@definitions = nil
|
7
|
+
config_file = "#{FileUtils.pwd}/docker/docker-rails.json"
|
8
|
+
raise "Could not find your project config at: #{config_file} . Did you run: 'rake docker:install' ?" if (!File.exist?(config_file))
|
9
|
+
File.open(config_file, "r") do |file|
|
10
|
+
str = file.read
|
11
|
+
@definitions = JSON.parse(str)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def rails_app_configuration
|
16
|
+
@definitions.each do |definition|
|
17
|
+
name = definition.keys.first
|
18
|
+
if (name == "rails_app")
|
19
|
+
return definition
|
20
|
+
end
|
21
|
+
end
|
22
|
+
return nil
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
class DockerRegistry
|
4
|
+
|
5
|
+
def initialize(registry_url)
|
6
|
+
@server = registry_url
|
7
|
+
if (!registry_url.include? "://")
|
8
|
+
registry_url = "https://#{registry_url}"
|
9
|
+
end
|
10
|
+
@connection = connection(registry_url)
|
11
|
+
end
|
12
|
+
|
13
|
+
def find_images()
|
14
|
+
response = @connection.get "/v2/_catalog"
|
15
|
+
raise "catalog retrieval return error: #{response.status} #{response.body}" if (response.status != 200)
|
16
|
+
json = JSON.parse(response.body)
|
17
|
+
return json['repositories']
|
18
|
+
end
|
19
|
+
|
20
|
+
def find_tags(image_name)
|
21
|
+
response = @connection.get "/v2/#{image_name}/tags/list"
|
22
|
+
raise "Querying tags returned error code: #{response.status}" if (response.status != 200)
|
23
|
+
json = JSON.parse(response.body)
|
24
|
+
return json['tags']
|
25
|
+
end
|
26
|
+
|
27
|
+
def has_image_with_version?(image, commit_id)
|
28
|
+
tags = self.find_tags(image)
|
29
|
+
if (tags != nil)
|
30
|
+
tags.each do |tag|
|
31
|
+
return true if (tag == commit_id)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
return false
|
35
|
+
end
|
36
|
+
|
37
|
+
def images_and_versions
|
38
|
+
hash = {}
|
39
|
+
images = find_images()
|
40
|
+
images.each do |image|
|
41
|
+
tags = find_tags(image)
|
42
|
+
hash[image] = tags
|
43
|
+
end
|
44
|
+
return hash
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def connection(address)
|
50
|
+
if (!@service_connection)
|
51
|
+
@service_connection = Faraday.new address, :ssl => {:verify => false}
|
52
|
+
end
|
53
|
+
return @service_connection
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
|
58
|
+
end
|
@@ -0,0 +1,263 @@
|
|
1
|
+
require_relative "launch_support"
|
2
|
+
require_relative "./docker_api"
|
3
|
+
require 'pp'
|
4
|
+
|
5
|
+
class DockerRunner
|
6
|
+
include LaunchSupport
|
7
|
+
attr_accessor :instance_index, :registry, :use_extension, :interact, :image_name, :code
|
8
|
+
attr_accessor :host, :user, :deployment_id, :version, :secure_docker_api, :remote_address
|
9
|
+
attr_accessor :docker_host, :docker_host_secure, :run_untagged
|
10
|
+
|
11
|
+
|
12
|
+
def initialize(config)
|
13
|
+
@config = config
|
14
|
+
@run_config = config['run']
|
15
|
+
@build_config = config['build']
|
16
|
+
@run_untagged = false
|
17
|
+
|
18
|
+
@image_name = @run_config['image_name']
|
19
|
+
if (!@image_name)
|
20
|
+
if (@build_config)
|
21
|
+
@image_name = @build_config['name']
|
22
|
+
raise "Build config does not have 'name'" if (@image_name == nil)
|
23
|
+
else
|
24
|
+
raise "Can't find an image name. Either specify 'name' in build config or 'image_name' in run config."
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
@registry = @config['registry']
|
29
|
+
|
30
|
+
@instance_index = 0
|
31
|
+
@use_extension = false
|
32
|
+
@interact = false
|
33
|
+
@remote_address = nil
|
34
|
+
@api_container = nil
|
35
|
+
@version = nil
|
36
|
+
@secure_docker_api = true
|
37
|
+
@build_args = nil
|
38
|
+
end
|
39
|
+
|
40
|
+
def find_machine_apis
|
41
|
+
@run_on_apis = []
|
42
|
+
@all_docker_apis_in_cluster = []
|
43
|
+
if (@deploy_config != nil) && (@deploy_config[:hosts] != nil)
|
44
|
+
@deploy_config[:hosts].each do |host_key|
|
45
|
+
host = Hosts::HOSTS[host_key]
|
46
|
+
address = "tcp://#{host[:address]}:#{host[:docker_port]}"
|
47
|
+
docker_api = DockerApi.new(address, host[:ssl])
|
48
|
+
@all_docker_apis_in_cluster << docker_api
|
49
|
+
@run_on_apis << docker_api if (address == @remote_address) || ( @deploy_config[:targets][run_name] == :all)
|
50
|
+
end
|
51
|
+
else
|
52
|
+
# Config not given, we need to create api from remote address and ssl setting. This is the only api for this class.
|
53
|
+
@docker_host = @docker_host || ENV['DOCKER_HOST']
|
54
|
+
@docker_host_secure = @docker_host_secure || (ENV['DOCKER_TLS_VERIFY'].to_s == '1')
|
55
|
+
docker_api = DockerApi.new(@docker_host, @docker_host_secure)
|
56
|
+
|
57
|
+
@all_docker_apis_in_cluster << docker_api
|
58
|
+
@run_on_apis << docker_api
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def run_name
|
63
|
+
return @run_config['name']
|
64
|
+
end
|
65
|
+
|
66
|
+
def image_version
|
67
|
+
return @version if (@version != nil)
|
68
|
+
the_version = 'latest'
|
69
|
+
the_version = @build_config['version'] if (@build_config) && (@build_config['version'] != nil)
|
70
|
+
return the_version
|
71
|
+
end
|
72
|
+
|
73
|
+
def kill_all(name_prefix)
|
74
|
+
find_machine_apis
|
75
|
+
@all_docker_apis_in_cluster.each do |api|
|
76
|
+
#options = {filters: {status: [:running, :exited, :paused, :restarting]}}
|
77
|
+
options = {}
|
78
|
+
containers = Docker::Container.all(options.to_json, api.connection)
|
79
|
+
containers.each do |container|
|
80
|
+
if (container.json["Name"].start_with?("/#{name_prefix}"))
|
81
|
+
pp "Killing and removing: #{container.json["Name"]}"
|
82
|
+
container.kill() if (container.json["State"]["Running"])
|
83
|
+
container.remove() if (container != nil)
|
84
|
+
else
|
85
|
+
pp " * Container didn't match: #{container.json["Name"]}"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
def run
|
93
|
+
find_machine_apis
|
94
|
+
raise "No run on apis" if (@run_on_apis.count == 0)
|
95
|
+
|
96
|
+
code = @code
|
97
|
+
instance_index = 1
|
98
|
+
if (@instance_index == :next)
|
99
|
+
options = {filters: {status: [:running]}}
|
100
|
+
@active_container_names = []
|
101
|
+
containers = Docker::Container.all(options.to_json, @run_on_apis.first.connection)
|
102
|
+
containers.each do |container|
|
103
|
+
container_json = container.json
|
104
|
+
container_name = container_json["Name"]
|
105
|
+
@active_container_names << container_name
|
106
|
+
end
|
107
|
+
|
108
|
+
instance_index = 1
|
109
|
+
container_name_taken = true
|
110
|
+
while (true)
|
111
|
+
instance_ext = "_#{instance_index}"
|
112
|
+
instance_name = "/#{run_name}#{instance_ext}"
|
113
|
+
if (!@active_container_names.include? instance_name)
|
114
|
+
@instance_index = instance_index
|
115
|
+
break
|
116
|
+
else
|
117
|
+
instance_index += 1
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
instance_ext = ""
|
123
|
+
instance_ext = "_#{@instance_index}" if (@use_extension)
|
124
|
+
instance_name = "#{run_name}#{instance_ext}"
|
125
|
+
|
126
|
+
@all_docker_apis_in_cluster.each do |docker_api|
|
127
|
+
kill_previous_containers_in_cluster(docker_api, instance_name)
|
128
|
+
end
|
129
|
+
image_name = image_name_with_registry()
|
130
|
+
|
131
|
+
@run_on_apis.each do |docker_api|
|
132
|
+
if (!@run_untagged)
|
133
|
+
pull_image_to_host(docker_api, registry)
|
134
|
+
end
|
135
|
+
run_container(docker_api, instance_name)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
|
140
|
+
private
|
141
|
+
|
142
|
+
def pull_image_to_host(docker_api, registry)
|
143
|
+
return if (registry == nil) || (@run_untagged)
|
144
|
+
Excon.defaults[:write_timeout] = 500
|
145
|
+
Excon.defaults[:read_timeout] = 500
|
146
|
+
options = {}
|
147
|
+
options[:repo] = registry
|
148
|
+
options[:fromImage] = "#{image_name_with_registry}:#{image_version}"
|
149
|
+
pp "See if Host needs to pull image (#{options[:fromImage]}). Host: #{docker_api.connection}"
|
150
|
+
|
151
|
+
image = Docker::Image.create(options, nil, docker_api.connection)
|
152
|
+
end
|
153
|
+
|
154
|
+
def run_container(docker_api, instance_name)
|
155
|
+
create_options = @run_config['options'] || {}
|
156
|
+
|
157
|
+
if (!image_name_with_registry.include? ":")
|
158
|
+
create_options['Image'] = "#{image_name_with_registry}:#{image_version}"
|
159
|
+
else
|
160
|
+
create_options['Image'] = image_name_with_registry
|
161
|
+
end
|
162
|
+
create_options['name'] = instance_name
|
163
|
+
create_options['Labels'] = { deployer: @user, deploy_id: @deployment_id }
|
164
|
+
create_options['Tty'] = true if (@interact == true)
|
165
|
+
create_options['Entrypoint'] = ["/bin/bash"] if (@interact == true)
|
166
|
+
|
167
|
+
pp "Running container: #{instance_name}\nOptions: #{create_options}"
|
168
|
+
cli_command = "docker run --name #{instance_name}"
|
169
|
+
if (create_options['Env'] != nil)
|
170
|
+
create_options['Env'].each do |env|
|
171
|
+
cli_command += " -e #{env}"
|
172
|
+
end
|
173
|
+
end
|
174
|
+
if (create_options['HostConfig'] != nil)
|
175
|
+
host_config = create_options['HostConfig']
|
176
|
+
binds = host_config['Binds']
|
177
|
+
if (binds != nil)
|
178
|
+
binds.each do |bind|
|
179
|
+
cli_command += " -v #{bind}"
|
180
|
+
end
|
181
|
+
end
|
182
|
+
links = host_config['Links']
|
183
|
+
if (links != nil)
|
184
|
+
links.each do |link|
|
185
|
+
cli_command += " --link #{link}"
|
186
|
+
end
|
187
|
+
end
|
188
|
+
ports = host_config['PortBindings']
|
189
|
+
ports.keys.each do |port|
|
190
|
+
container_port = port.split("/").first
|
191
|
+
host_port = container_port
|
192
|
+
port_binds = ports[port]
|
193
|
+
port_binds.each do |bind|
|
194
|
+
host_port = bind['HostPort'] if (bind['HostPort'] != nil)
|
195
|
+
cli_command += " -p #{host_port}:#{container_port}"
|
196
|
+
end
|
197
|
+
if (port_binds.length == 0)
|
198
|
+
cli_command += " -p #{host_port}:#{container_port}"
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
cli_command += " -d"
|
203
|
+
cli_command += " #{create_options['Image']}"
|
204
|
+
cli_command += " #{create_options['Entrypoint']}" if (create_options['Entrypoint'] != nil)
|
205
|
+
puts "CLI Command: #{cli_command}"
|
206
|
+
|
207
|
+
@api_container = Docker::Container.create(create_options, docker_api.connection)
|
208
|
+
puts @api_container.start
|
209
|
+
if (@interact)
|
210
|
+
pp "=================================================================="
|
211
|
+
pp "CONTAINER STARTED FOR INTERACTION - ENTRYPOINT NOT CALLED"
|
212
|
+
pp "To attach: docker exec -it '#{instance_name}' bash"
|
213
|
+
pp "=================================================================="
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
|
218
|
+
def kill_previous_containers_in_cluster(docker_api, instance_name)
|
219
|
+
pp "Killing and removing containers with same name: #{instance_name}"
|
220
|
+
@api_container = nil
|
221
|
+
begin
|
222
|
+
@api_container = Docker::Container.get(instance_name, {}, docker_api.connection)
|
223
|
+
puts "Killing and removing container: #{instance_name} in #{docker_api.connection}"
|
224
|
+
@api_container.kill()
|
225
|
+
rescue Docker::Error::NotFoundError => not_found_error
|
226
|
+
puts "No container with name \"#{instance_name}\" running. No need to kill."
|
227
|
+
end
|
228
|
+
|
229
|
+
if (@api_container)
|
230
|
+
begin
|
231
|
+
pp "Removing container: #{instance_name}"
|
232
|
+
@api_container.remove() if (@api_container != nil)
|
233
|
+
rescue Docker::Error::NotFoundError => remove_error
|
234
|
+
puts "Didn't find image to remove: #{instance_name}"
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
|
240
|
+
def image_name_with_registry
|
241
|
+
image_name = @image_name
|
242
|
+
if (registry != nil) && (!@run_untagged)
|
243
|
+
registry_without_protocol = registry.split("://").last
|
244
|
+
image_name = "#{registry_without_protocol}/#{@image_name}"
|
245
|
+
end
|
246
|
+
return image_name
|
247
|
+
end
|
248
|
+
|
249
|
+
def container_state
|
250
|
+
return @api_container.json['State']
|
251
|
+
end
|
252
|
+
|
253
|
+
def wait_for_completion
|
254
|
+
while (container_state()["Running"] == true)
|
255
|
+
sleep 1
|
256
|
+
puts "Waiting for container #{run_name} to finish."
|
257
|
+
end
|
258
|
+
exit_code = container_state()['ExitCode']
|
259
|
+
raise "Container failed (#{image_name_with_registry()}) Exit code: #{exit_code}" if (exit_code != 0)
|
260
|
+
end
|
261
|
+
|
262
|
+
|
263
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
FROM ruby:2.1.5
|
2
|
+
|
3
|
+
|
4
|
+
ENV GIT_REPO_ADDRESS <<GIT_REPO_ADDRESS>>
|
5
|
+
ENV DOCKER_IMAGE true
|
6
|
+
ENV APP_HOME /application
|
7
|
+
ENV RAILS_ENV production
|
8
|
+
|
9
|
+
|
10
|
+
RUN apt-get update && apt-get install -y --force-yes \
|
11
|
+
autoconf \
|
12
|
+
build-essential \
|
13
|
+
cmake \
|
14
|
+
pkg-config \
|
15
|
+
libssl-dev \
|
16
|
+
libyaml-dev \
|
17
|
+
libreadline6-dev \
|
18
|
+
zlib1g-dev \
|
19
|
+
libffi-dev \
|
20
|
+
libncurses5-dev \
|
21
|
+
libgdbm3 \
|
22
|
+
libgdbm-dev \
|
23
|
+
libsqlite3-dev \
|
24
|
+
libmysqlclient-dev \
|
25
|
+
libv8-dev \
|
26
|
+
# telnet \
|
27
|
+
mysql-client \
|
28
|
+
git \
|
29
|
+
netcat \
|
30
|
+
wget && \
|
31
|
+
gem install --no-document bundler && \
|
32
|
+
echo "Set up ssh credentials for gitlab, so we can clone olex at docker image run time." && \
|
33
|
+
mkdir /root/.ssh
|
34
|
+
|
35
|
+
|
36
|
+
# COPY files/rails_application.tar.gz /application
|
37
|
+
COPY files/ssh/* /root/.ssh/
|
38
|
+
|
39
|
+
RUN echo "RUNNING CONTAINER ENTRYPOINT" && \
|
40
|
+
rm -rf "$APP_HOME" && \
|
41
|
+
git clone "$GIT_REPO_ADDRESS" "$APP_HOME" &&\
|
42
|
+
cd "$APP_HOME" && \
|
43
|
+
bundle install --without test development
|
44
|
+
|
45
|
+
EXPOSE 3000
|
46
|
+
|
47
|
+
# COPY entrypoint.sh /entrypoint.sh
|
48
|
+
# ENTRYPOINT ["/entrypoint.sh"]
|
49
|
+
# CMD ["/application/rails","s"]
|
@@ -0,0 +1,46 @@
|
|
1
|
+
FROM ruby:2.1.5
|
2
|
+
|
3
|
+
ENV SQL_HOST <<SQL_HOST>>
|
4
|
+
ENV SQL_HOST_PORT 3306
|
5
|
+
|
6
|
+
ENV DOCKER_IMAGE true
|
7
|
+
ENV APP_HOME /application
|
8
|
+
ENV RAILS_ENV production
|
9
|
+
|
10
|
+
|
11
|
+
RUN apt-get update && apt-get install -y --force-yes \
|
12
|
+
autoconf \
|
13
|
+
build-essential \
|
14
|
+
cmake \
|
15
|
+
pkg-config \
|
16
|
+
libssl-dev \
|
17
|
+
libyaml-dev \
|
18
|
+
libreadline6-dev \
|
19
|
+
zlib1g-dev \
|
20
|
+
libffi-dev \
|
21
|
+
libncurses5-dev \
|
22
|
+
libgdbm3 \
|
23
|
+
libgdbm-dev \
|
24
|
+
libsqlite3-dev \
|
25
|
+
libmysqlclient-dev \
|
26
|
+
libv8-dev \
|
27
|
+
mysql-client \
|
28
|
+
netcat \
|
29
|
+
wget && \
|
30
|
+
gem install --no-document bundler &&\
|
31
|
+
mkdir -p "$APP_HOME" &&\
|
32
|
+
gem install puma
|
33
|
+
|
34
|
+
COPY files/rails_application.tar.gz "$APP_HOME"
|
35
|
+
|
36
|
+
RUN echo "PREPARING APPLICATION" && \
|
37
|
+
cd "$APP_HOME" &&\
|
38
|
+
tar xzf rails_application.tar.gz && \
|
39
|
+
bundle install --without test development
|
40
|
+
|
41
|
+
COPY files/database.yml "$APP_HOME/config"
|
42
|
+
|
43
|
+
EXPOSE 3000
|
44
|
+
COPY wait_for_port.sh /wait_for_port.sh
|
45
|
+
COPY entrypoint.sh /entrypoint.sh
|
46
|
+
ENTRYPOINT ["/entrypoint.sh"]
|
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
cd "$APP_HOME"
|
3
|
+
|
4
|
+
echo "================ Waiting for MySQL's port to respond"
|
5
|
+
|
6
|
+
/bin/bash /wait_for_port.sh "$SQL_HOST" "$SQL_HOST_PORT"
|
7
|
+
|
8
|
+
echo "================ Migrating Openlogic database"
|
9
|
+
rake db:create db:migrate
|
10
|
+
|
11
|
+
# echo "================ Starting memcache - oh no, two long running processes in the same container."
|
12
|
+
# memcached -d -uroot
|
13
|
+
|
14
|
+
|
15
|
+
rails s -d Puma -b 0.0.0.0 -p 3000
|
16
|
+
tail -100f ./log/production.log
|
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
class InitializeProject
|
4
|
+
def app_docker_path
|
5
|
+
project_dir = FileUtils.pwd
|
6
|
+
docker_dir = "#{project_dir}/docker"
|
7
|
+
FileUtils.mkdir_p("#{docker_dir}/files")
|
8
|
+
return docker_dir
|
9
|
+
end
|
10
|
+
|
11
|
+
def fill_in_file_param(file_path, param_name, param_value)
|
12
|
+
new_content = nil
|
13
|
+
File.open(file_path, "r") do |file|
|
14
|
+
content = file.read
|
15
|
+
search_str = "<<#{param_name}>>"
|
16
|
+
index = content.index(search_str)
|
17
|
+
content_start = content[0..(index - 1)]
|
18
|
+
content_end = content[(index + search_str.length), content.length]
|
19
|
+
new_content = content_start + param_value + content_end
|
20
|
+
end
|
21
|
+
File.open(file_path, "w") do |file|
|
22
|
+
file.write(new_content)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def create_configuration
|
27
|
+
#Use directory name as default for image name.
|
28
|
+
default_image_name = FileUtils.pwd.split('/').last
|
29
|
+
default_image_name = default_image_name.split('_').join("-")
|
30
|
+
default_image_name = default_image_name.split(' ').join("-")
|
31
|
+
|
32
|
+
puts "Creating configurations."
|
33
|
+
puts "Enter image name of rails app (#{default_image_name}):"
|
34
|
+
image_name = STDIN.gets.chomp
|
35
|
+
if (image_name.length == 0)
|
36
|
+
image_name = default_image_name
|
37
|
+
end
|
38
|
+
|
39
|
+
db_run_time_name = image_name + "-db"
|
40
|
+
|
41
|
+
docker_dir = app_docker_path()
|
42
|
+
FileUtils.mkdir_p("#{docker_dir}/files")
|
43
|
+
|
44
|
+
this_dir = File.dirname(__FILE__)
|
45
|
+
docker_file_path = "#{docker_dir}/Dockerfile"
|
46
|
+
copy_docker_file = true
|
47
|
+
if (File.exist?(docker_file_path))
|
48
|
+
puts "Dockerfile already exists in #{docker_dir}. Overwrite? (y/n)"
|
49
|
+
overwrite = STDIN.gets.chomp
|
50
|
+
if (overwrite.downcase == "n")
|
51
|
+
copy_docker_file = false
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
if (copy_docker_file)
|
56
|
+
FileUtils.cp("#{this_dir}/image_files/DockerfileSelf", docker_file_path)
|
57
|
+
fill_in_file_param(docker_file_path, 'SQL_HOST', db_run_time_name)
|
58
|
+
puts "Copied standard Dockerfile to: #{docker_dir}"
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
copy_entry_file = true
|
63
|
+
entry_file_path = "#{docker_dir}/entrypoint.sh"
|
64
|
+
if (File.exist?(entry_file_path))
|
65
|
+
puts "Entrypoint.sh already exists in #{docker_dir}. Overwrite? (y/n)"
|
66
|
+
overwrite = STDIN.gets.chomp
|
67
|
+
if (overwrite.downcase == "n")
|
68
|
+
copy_entry_file = false
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
if (copy_entry_file)
|
73
|
+
FileUtils.cp("#{this_dir}/image_files/entrypoint.sh", "#{docker_dir}/entrypoint.sh")
|
74
|
+
puts "Copied entry point file to: #{docker_dir}"
|
75
|
+
end
|
76
|
+
|
77
|
+
FileUtils.cp("#{this_dir}/image_files/wait_for_port.sh", "#{docker_dir}/wait_for_port.sh")
|
78
|
+
|
79
|
+
|
80
|
+
main_configuration = {
|
81
|
+
registry: "https://my.registry.com:5000",
|
82
|
+
build: {
|
83
|
+
name: image_name
|
84
|
+
},
|
85
|
+
run: {
|
86
|
+
name: image_name,
|
87
|
+
options: {
|
88
|
+
"Env" => [
|
89
|
+
"IS_DOCKER=true"
|
90
|
+
],
|
91
|
+
"HostConfig" => {
|
92
|
+
"Links" => ["#{db_run_time_name}:#{db_run_time_name}"],
|
93
|
+
"PortBindings" => {
|
94
|
+
"3000/tcp" => [
|
95
|
+
{"HostIp" => "", "HostPort" => "3000"}
|
96
|
+
]
|
97
|
+
}
|
98
|
+
}
|
99
|
+
}
|
100
|
+
}
|
101
|
+
}
|
102
|
+
|
103
|
+
sql_configuration = {
|
104
|
+
run: {
|
105
|
+
name: db_run_time_name,
|
106
|
+
image_name: "percona:5.6",
|
107
|
+
options: {
|
108
|
+
"Env" => [
|
109
|
+
"MYSQL_ROOT_PASSWORD=password"
|
110
|
+
],
|
111
|
+
"HostConfig" => {
|
112
|
+
"PortBindings" => {
|
113
|
+
"3306/tcp" => []
|
114
|
+
}
|
115
|
+
}
|
116
|
+
}
|
117
|
+
}
|
118
|
+
}
|
119
|
+
|
120
|
+
|
121
|
+
configs = [{sql: sql_configuration}, {rails_app: main_configuration}]
|
122
|
+
|
123
|
+
output = JSON.pretty_generate(configs)
|
124
|
+
config_file_path = "#{app_docker_path}/docker-rails.json"
|
125
|
+
File.open(config_file_path, "w") do |f|
|
126
|
+
f.write(output)
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module LaunchSupport
|
2
|
+
|
3
|
+
def is_port_open?(ip, port)
|
4
|
+
begin
|
5
|
+
Timeout::timeout(1) do
|
6
|
+
begin
|
7
|
+
puts "Connecting to #{ip}: #{port}"
|
8
|
+
s = TCPSocket.new(ip, port)
|
9
|
+
s.close
|
10
|
+
return true
|
11
|
+
rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
|
12
|
+
return false
|
13
|
+
end
|
14
|
+
end
|
15
|
+
rescue Timeout::Error
|
16
|
+
end
|
17
|
+
return false
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
def wait_for_short_lived_image_to_complete(image_run_name)
|
22
|
+
done = false
|
23
|
+
while (!done)
|
24
|
+
#puts "Inspecting image: #{image_run_name}"
|
25
|
+
output = `docker inspect #{image_run_name}`
|
26
|
+
#puts "Output: #{output}"
|
27
|
+
json = JSON.parse(output)
|
28
|
+
state = json.first['State']
|
29
|
+
is_running = state['Running']
|
30
|
+
exit_code = state['ExitCode']
|
31
|
+
puts "Waiting for short-lived container to complete: \"#{image_run_name}\""
|
32
|
+
if (exit_code == 0) && (is_running == false)
|
33
|
+
done = true
|
34
|
+
elsif (exit_code != 0)
|
35
|
+
raise "Container failed: #{image_run_name} - Run: docker logs -f #{image_run_name}"
|
36
|
+
else
|
37
|
+
sleep 3
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def wait_for_port(ip, port)
|
43
|
+
while (!is_port_open?(ip, port))
|
44
|
+
puts "Port not ready: #{ip}:#{port}"
|
45
|
+
sleep 3
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
def host
|
51
|
+
output = `boot2docker ip`
|
52
|
+
if (output.strip.length == 0) || (output.include?("command not found")) || (output.include?("is not running"))
|
53
|
+
docker_machine_active = `docker-machine active`
|
54
|
+
docker_machine_active = docker_machine_active[0..(docker_machine_active.length - 2)]
|
55
|
+
output = `docker-machine url #{docker_machine_active}`
|
56
|
+
address = output.split("//")[1].split(":").first
|
57
|
+
return address
|
58
|
+
else
|
59
|
+
return output.strip
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require_relative "../support/docker_rails_config_reader"
|
2
|
+
require_relative "../support/docker_rails_app_creator"
|
3
|
+
|
4
|
+
|
5
|
+
namespace :docker do
|
6
|
+
|
7
|
+
|
8
|
+
desc "Build docker image of this project"
|
9
|
+
task :build => :environment do
|
10
|
+
config_reader = DockerRailsConfigReader.new
|
11
|
+
config_reader.definitions.each do |definition|
|
12
|
+
definition_name = definition.keys.first
|
13
|
+
definition_value = definition[definition_name]
|
14
|
+
if (definition_value['build'])
|
15
|
+
builder = DockerRailsAppCreator.new(definition_value)
|
16
|
+
builder.docker_host = "tcp://127.0.0.1:2375"
|
17
|
+
builder.docker_host_secure = true
|
18
|
+
builder.build_it
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
desc "Push docker image to repo"
|
24
|
+
task :push => :environment do
|
25
|
+
config_reader = DockerRailsConfigReader.new
|
26
|
+
config_reader.definitions.each do |definition|
|
27
|
+
definition_name = definition.keys.first
|
28
|
+
definition_value = definition[definition_name]
|
29
|
+
if (definition_value['build'])
|
30
|
+
builder = DockerRailsAppCreator.new(definition_value)
|
31
|
+
builder.docker_host = "tcp://127.0.0.1:2375"
|
32
|
+
builder.docker_host_secure = true
|
33
|
+
registry = definition_value['registry']
|
34
|
+
if (registry)
|
35
|
+
builder.tag_it(registry)
|
36
|
+
builder.push_it(registry)
|
37
|
+
else
|
38
|
+
puts "No registry definited. Ignoring push command."
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require_relative "../support/docker_rails_app_creator"
|
2
|
+
require_relative "../support/initialize_project"
|
3
|
+
|
4
|
+
|
5
|
+
namespace :docker do
|
6
|
+
|
7
|
+
desc "Build docker image of this project"
|
8
|
+
task :install => :environment do
|
9
|
+
initializer = InitializeProject.new
|
10
|
+
initializer.create_configuration()
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
data/lib/tasks/run.rake
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require_relative "../support/docker_rails_app_creator"
|
2
|
+
|
3
|
+
namespace :docker do
|
4
|
+
|
5
|
+
desc "Run Docker image"
|
6
|
+
task :run => :environment do
|
7
|
+
config_reader = DockerRailsConfigReader.new
|
8
|
+
config_reader.definitions.each do |definition|
|
9
|
+
definition_name = definition.keys.first
|
10
|
+
definition_value = definition[definition_name]
|
11
|
+
if (definition_value['run'])
|
12
|
+
docker_runner = DockerRunner.new(definition_value)
|
13
|
+
docker_runner.docker_host = "tcp://127.0.0.1:2375"
|
14
|
+
docker_runner.docker_host_secure = true
|
15
|
+
docker_runner.run
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
desc "Run Local Docker image"
|
22
|
+
task :run_local => :environment do
|
23
|
+
config_reader = DockerRailsConfigReader.new
|
24
|
+
config_reader.definitions.each do |definition|
|
25
|
+
definition_name = definition.keys.first
|
26
|
+
definition_value = definition[definition_name]
|
27
|
+
if (definition_value['run'])
|
28
|
+
docker_runner = DockerRunner.new(definition_value)
|
29
|
+
docker_runner.docker_host = "tcp://127.0.0.1:2375"
|
30
|
+
docker_runner.docker_host_secure = true
|
31
|
+
docker_runner.run_untagged = true
|
32
|
+
docker_runner.run
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
end
|
metadata
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: docker-rails-app
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.6
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Mike Moore
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-01-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.9'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.9'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: docker-api
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.31'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.31'
|
55
|
+
description: Puts your rails app into a Docker image
|
56
|
+
email:
|
57
|
+
- m.moore.denver@gmail.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- bin/console
|
63
|
+
- bin/setup
|
64
|
+
- lib/docker_rails_app.rb
|
65
|
+
- lib/docker_rails_app/import_gem_rake_tasks.rb
|
66
|
+
- lib/docker_rails_app/version.rb
|
67
|
+
- lib/support/docker_api.rb
|
68
|
+
- lib/support/docker_image_creator.rb
|
69
|
+
- lib/support/docker_rails_app_creator.rb
|
70
|
+
- lib/support/docker_rails_config_reader.rb
|
71
|
+
- lib/support/docker_registry.rb
|
72
|
+
- lib/support/docker_runner.rb
|
73
|
+
- lib/support/image_files/DockerfileRepo
|
74
|
+
- lib/support/image_files/DockerfileSelf
|
75
|
+
- lib/support/image_files/entrypoint.sh
|
76
|
+
- lib/support/image_files/wait_for_file.sh
|
77
|
+
- lib/support/image_files/wait_for_port.sh
|
78
|
+
- lib/support/initialize_project.rb
|
79
|
+
- lib/support/launch_support.rb
|
80
|
+
- lib/tasks/deploy.rake
|
81
|
+
- lib/tasks/initialize.rake
|
82
|
+
- lib/tasks/run.rake
|
83
|
+
homepage:
|
84
|
+
licenses:
|
85
|
+
- MIT
|
86
|
+
metadata: {}
|
87
|
+
post_install_message:
|
88
|
+
rdoc_options: []
|
89
|
+
require_paths:
|
90
|
+
- lib
|
91
|
+
- lib/docker_rails_app
|
92
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
requirements: []
|
103
|
+
rubyforge_project:
|
104
|
+
rubygems_version: 2.4.5.1
|
105
|
+
signing_key:
|
106
|
+
specification_version: 4
|
107
|
+
summary: Puts your rails app into a Docker image
|
108
|
+
test_files: []
|