docker-rails 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4daf7ed396ab33b4baccadbe1a1f888af9a3271d
4
+ data.tar.gz: 7a38191133060c00417437db6ba84e93d3f936a5
5
+ SHA512:
6
+ metadata.gz: 8d8ffca0992dbbbd4edfd75b36de681f018933d497f1b9cd37d05edb0cd59471c06fd15136de6e031867f928904732c8570f45e219c69b714a5e24f94cd2cdd3
7
+ data.tar.gz: 49cea1c9d37dcb37d519e3db6d0345185f6fc6cb6dac30c0a6f1d17fa708a7de2bf7df8cbd397f5daea0e0555046dc1a3f1a86d8b9df5562e888e148c4f863e7
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ docker-rails
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-2.2.2
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in docker-rails.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Kevin Ross
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,142 @@
1
+ # Docker::Rails
2
+
3
+ A simplified pattern to execute rails applications within Docker (with a CI build emphasis).
4
+
5
+ Features:
6
+ - cached global bundler data volume (automatic) based on ruby version
7
+ - interpolates `docker-compose.yml` making CI builds much easier
8
+ - starts `db` container first, and continues with `web` once `db` is ready
9
+ - cleans up `db` and `web` containers once completed
10
+
11
+
12
+ **Very much a work in progress - contributions welcome**
13
+ Open to pull requests, while this starts off as one-person's environment, it can be expanded to suit many different configurations.
14
+
15
+ Needs:
16
+ - remove hardcoded ip for db ip resolution
17
+ - remove or default hardcoded BUILD_NAME
18
+ - expand to different db status detection as needed
19
+
20
+ ## Installation
21
+
22
+ Add this line to your application's Gemfile:
23
+
24
+ gem 'docker-rails'
25
+
26
+ And then execute:
27
+
28
+ $ bundle
29
+
30
+ Or install it yourself as:
31
+
32
+ $ gem install docker-rails
33
+
34
+ ## Usage
35
+
36
+ ### 1. Add a Dockerfile
37
+
38
+ ```bash
39
+ FROM atlashealth/ruby:2.2.2
40
+
41
+ ENV DEBIAN_FRONTEND noninteractive
42
+
43
+ # For building, nokogiri support, capybara-webkit, mysql client
44
+ # Clean up APT when done.
45
+ RUN apt-get update -qq && \
46
+ apt-get install -qy build-essential libxml2-dev libxslt1-dev \
47
+ g++ qt5-default libqt5webkit5-dev xvfb libmysqlclient-dev && \
48
+
49
+ # cleanup
50
+ apt-get clean && \
51
+ cd /var/lib/apt/lists && rm -fr *Release* *Sources* *Packages* && \
52
+ truncate -s 0 /var/log/*log
53
+
54
+ # https://github.com/docker/docker/issues/4032
55
+ ENV DEBIAN_FRONTEND newt
56
+
57
+ ADD . /project
58
+ WORKDIR /project
59
+ RUN ["chmod", "+x", "/project/scripts/*"]
60
+ ```
61
+
62
+ ### 2. Add a docker-compose.yml
63
+
64
+ Environment variables will be interpolated, so feel free to use them.
65
+
66
+ ```yaml
67
+ web:
68
+ build: .
69
+ working_dir: /project/spec/dummy
70
+ command: /project/script/start
71
+ ports:
72
+ - "3000:3000"
73
+ links:
74
+ - db
75
+ volumes:
76
+ - .:/project
77
+ links:
78
+ - db
79
+ volumes_from:
80
+ # Mount the gems data volume container for cached bundler gem files
81
+ - #{GEMS_VOLUME_NAME}
82
+ environment:
83
+ # Tell bundler where to get the files
84
+ - GEM_HOME=#{GEMS_VOLUME_PATH}
85
+
86
+ db:
87
+ image: library/mysql:5.7.6
88
+ ports:
89
+ - "3306:3306"
90
+ environment:
91
+ - MYSQL_ALLOW_EMPTY_PASSWORD=true
92
+ ```
93
+
94
+ ### 3. Add a startup script
95
+
96
+ TODO: verify a good sample
97
+
98
+ ```bash
99
+ #!/usr/bin/env bash
100
+
101
+ echo "Bundling gems"
102
+ bundle install --jobs 4 --retry 3
103
+
104
+ echo "Generating Spring binstubs"
105
+ bundle exec spring binstub --all
106
+
107
+ echo "Clearing logs"
108
+ bin/rake log:clear
109
+
110
+ echo "Setting up new db if one doesn't exist"
111
+ bin/rake db:version || { bundle exec rake db:setup; }
112
+
113
+ echo "Removing contents of tmp dirs"
114
+ bin/rake tmp:clear
115
+
116
+ echo "Starting app server"
117
+ bundle exec rails s -p 3000
118
+
119
+ # or use foreman
120
+ # gem install foreman
121
+ # foreman start
122
+ ```
123
+
124
+ ### 4. Run it
125
+
126
+ `bundle exec docker-rails`
127
+
128
+ ### 5. Submit pull requests!
129
+
130
+ This is starting off simple, but again, we welcome pulls to make this and the process of using docker for rails much easier.
131
+
132
+
133
+ ## Contributing
134
+
135
+ 1. Fork it ( https://github.com/[my-github-username]/docker-rails/fork )
136
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
137
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
138
+ 4. Push to the branch (`git push origin my-new-feature`)
139
+ 5. Create a new Pull Request
140
+
141
+ ## License and Attributions
142
+ MIT license, inspired by many but certainly a [useful blog post by AtlasHealth](http://www.atlashealth.com/blog/2014/09/persistent-ruby-gems-docker-container).
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
data/bin/docker-rails ADDED
@@ -0,0 +1,148 @@
1
+ #!/usr/bin/env ruby
2
+
3
+
4
+ # compose cli
5
+ # https://docs.docker.com/v1.6/compose/cli/#environment-variables
6
+
7
+ # compose yml
8
+ # https://docs.docker.com/v1.6/compose/yml/
9
+
10
+ # remote api
11
+ # https://docs.docker.com/reference/api/docker_remote_api_v1.20
12
+
13
+
14
+ # enable local usage from cloned repo
15
+ root = File.expand_path('../..', __FILE__)
16
+ $LOAD_PATH << "#{root}/lib" if File.exist?("#{root}/Gemfile")
17
+
18
+ require 'docker/rails'
19
+
20
+ BUILD_NAME = '113' # temp should be passed in
21
+ ENV['BUILD_NAME'] = BUILD_NAME
22
+
23
+ # Discover ruby version from the Dockerfile image
24
+ IO.read('Dockerfile') =~ /^FROM \w+\/ruby:(\d+.\d+(?:.\d+))/
25
+ BUILD_RUBY_VERSION = $1
26
+
27
+ # Set as variable for interpolation
28
+ GEMS_VOLUME_PATH = "/gems/#{BUILD_RUBY_VERSION}"
29
+ GEMS_VOLUME_NAME = "gems-#{BUILD_RUBY_VERSION}"
30
+ ENV['GEMS_VOLUME_PATH'] = GEMS_VOLUME_PATH
31
+ ENV['GEMS_VOLUME_NAME'] = GEMS_VOLUME_NAME
32
+
33
+ # -----------
34
+ # Create global gems data volume to cache gems for this version of ruby
35
+ #
36
+ # Docker::Container.create('name' => 'foo-gems-2.2.2', 'Image' => 'busybox', 'Mounts' => [ { 'Destination' => '/gems/2.2.2' } ])
37
+ #
38
+ require 'docker'
39
+ begin
40
+ gems_container = Docker::Container.get(GEMS_VOLUME_NAME)
41
+ puts "Gem data volume container #{GEMS_VOLUME_NAME} already exists."
42
+ rescue Docker::Error::NotFoundError => e
43
+ gems_container = Docker::Container.create('name' => GEMS_VOLUME_NAME, 'Image' => 'busybox', 'Mounts' => [{'Destination' => GEMS_VOLUME_PATH}])
44
+ puts "Gem data volume container #{GEMS_VOLUME_NAME} created."
45
+ end
46
+ gems_container.streaming_logs(stdout: true) { |stream, chunk| puts "#{GEMS_VOLUME_NAME}: #{chunk}" }
47
+
48
+ # Read docker-compose.yml and rewrite with interpolated variables and BUILD_NAME
49
+ COMPOSE_FILENAME = "docker-compose-build-#{BUILD_NAME}.yml"
50
+ compose_config = Docker::Rails::ComposeConfig.interpolate_file(COMPOSE_FILENAME)
51
+
52
+ # convenience to execute docker-compose with file and project params
53
+ def xc(cmd)
54
+ cmd = "docker-compose -f #{COMPOSE_FILENAME} -p #{BUILD_NAME} #{cmd}"
55
+ puts "Running `#{cmd}`"
56
+ output =`#{cmd}`
57
+ result=$?.success?
58
+ output
59
+ end
60
+
61
+ # service_name i.e. 'db' or 'web'
62
+ def get_container_name(service_name)
63
+ output = xc "ps #{service_name}"
64
+ output =~ /^(\w+)/ # grab the name, only thing that is at the start of the line
65
+ $1
66
+ end
67
+
68
+ # http://blog.oddbit.com/2014/08/11/four-ways-to-connect-a-docker/
69
+ def get_ip_address(container_name)
70
+ cmd = "docker inspect --format '{{ .NetworkSettings.IPAddress }}' #{container_name}"
71
+ puts "Running `#{cmd}`"
72
+ output = `#{cmd}`
73
+ result=$?.success?
74
+ output
75
+ end
76
+
77
+ def up_container(service_name, options = '')
78
+ xc "up #{options} #{service_name}"
79
+ container_name = get_container_name(service_name)
80
+ puts "#{service_name}: container_name #{container_name}"
81
+
82
+ container = Docker::Container.get(container_name)
83
+ container.streaming_logs(stdout: true) { |stream, chunk| puts "#{service_name}: #{chunk}" }
84
+ # puts container
85
+
86
+ ip_address = get_ip_address(container_name)
87
+ [container, container_name, ip_address]
88
+ end
89
+
90
+ def destroy_container(container, container_name)
91
+ puts "Stopping and deleting #{container_name}..."
92
+ container.stop
93
+ container.delete(force: true)
94
+ end
95
+
96
+ # Start the db container
97
+ db_container, db_container_name, db_ip_address = *up_container('db', '-d')
98
+
99
+ # ping db to see if it is ready before continuing
100
+ require 'rubygems'
101
+ require 'active_record'
102
+
103
+ LOOP_LIMIT=60
104
+ puts "=> Waiting for confirmation of #{db_container_name} db service startup at #{db_ip_address}..."
105
+ LOOP_LIMIT.times do |i|
106
+ if i == LOOP_LIMIT - 1
107
+ puts 'Time out waiting for db to be up.'
108
+ #docker logs --follow=false $DB_CONTAINER
109
+ break
110
+ end
111
+
112
+ ActiveRecord::Base.establish_connection ({
113
+ adapter: 'mysql2',
114
+ # host: db_ip_address,
115
+ host: '192.168.99.100',
116
+ port: 3306,
117
+ username: 'root'})
118
+ # connected = ActiveRecord::Base.connection_pool.with_connection { |con| con.active? } rescue false
119
+ connected =
120
+ begin
121
+ ActiveRecord::Base.connection_pool.with_connection { |con| con.active? }
122
+ rescue => e
123
+ # puts "#{e.class.name}: #{e.message}"
124
+ false
125
+ end
126
+ printf '.'
127
+ if connected
128
+ printf 'connected.'
129
+ break
130
+ end
131
+ sleep 1
132
+ end
133
+ puts ''
134
+
135
+
136
+ # Start the web containers
137
+ web_container, web_container_name, web_ip_address = *up_container('web')
138
+
139
+
140
+ puts 'Cleaning up containers...'
141
+ destroy_container(db_container, db_container_name)
142
+ destroy_container(web_container, web_container_name)
143
+ puts "Done.\n\n\n"
144
+
145
+ # cleanup build interpolated docker-compose.yml
146
+ # File.delete COMPOSE_FILENAME if File.exists? COMPOSE_FILENAME
147
+
148
+ system 'docker ps -a'
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'docker/rails/version'
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = 'docker-rails'
8
+ s.version = Docker::Rails::VERSION
9
+ s.authors = ['Kevin Ross']
10
+ s.email = ['kevin.ross@alienfast.com']
11
+ s.summary = %q{A simplified pattern to execute rails applications within Docker (with a CI build emphasis)}
12
+ s.description = %q{}
13
+ s.homepage = ''
14
+ s.license = 'MIT'
15
+
16
+ s.files = `git ls-files -z`.split("\x0")
17
+ s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
19
+ s.require_paths = ['lib']
20
+
21
+ s.add_development_dependency 'bundler', '~> 1.6'
22
+ s.add_development_dependency 'rake'
23
+
24
+ s.add_dependency 'docker-api'
25
+ # s.add_dependency 'parallel_tests'
26
+ s.add_dependency 'dry-config', '>= 1.1.6'
27
+ end
@@ -0,0 +1,8 @@
1
+ require 'docker/rails/version'
2
+
3
+ module Docker
4
+ module Rails
5
+ end
6
+ end
7
+
8
+ require 'docker/rails/compose_config'
@@ -0,0 +1,14 @@
1
+ module Docker
2
+ module Rails
3
+ require 'dry/config'
4
+ class ComposeConfig < Dry::Config::Base
5
+ class << self
6
+ def interpolate_file(output_filename, input_filename = 'docker-compose.yml')
7
+ compose = ComposeConfig.new(symbolize: false)
8
+ compose.load!(nil, input_filename)
9
+ compose.write_yaml_file(output_filename)
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,5 @@
1
+ module Docker
2
+ module Rails
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,114 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: docker-rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Kevin Ross
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-09-10 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.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '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: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: dry-config
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: 1.1.6
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: 1.1.6
69
+ description: ''
70
+ email:
71
+ - kevin.ross@alienfast.com
72
+ executables:
73
+ - docker-rails
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - ".gitignore"
78
+ - ".ruby-gemset"
79
+ - ".ruby-version"
80
+ - Gemfile
81
+ - LICENSE.txt
82
+ - README.md
83
+ - Rakefile
84
+ - bin/docker-rails
85
+ - docker-rails.gemspec
86
+ - lib/docker/rails.rb
87
+ - lib/docker/rails/compose_config.rb
88
+ - lib/docker/rails/version.rb
89
+ homepage: ''
90
+ licenses:
91
+ - MIT
92
+ metadata: {}
93
+ post_install_message:
94
+ rdoc_options: []
95
+ require_paths:
96
+ - lib
97
+ required_ruby_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ required_rubygems_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ requirements: []
108
+ rubyforge_project:
109
+ rubygems_version: 2.4.8
110
+ signing_key:
111
+ specification_version: 4
112
+ summary: A simplified pattern to execute rails applications within Docker (with a
113
+ CI build emphasis)
114
+ test_files: []