dockerfile-rails 1.0.18 → 1.1.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
  SHA256:
3
- metadata.gz: 9cc1cc395215fe473533ab4418d6e9949a5f58d2a366c2e8d49d29ee2f8e65d8
4
- data.tar.gz: 9e5a602abb603a024c08ce9e7cd0a4ebb393cfcb92b15fcbc2efd2302ea5d2d4
3
+ metadata.gz: d20c08de9e4419da64806a66f96edfeb7180e09eca15d1c8bd4a52cbf8372be9
4
+ data.tar.gz: e6f11bdbc4a56eb235de642a156124e9a84e179bef99a2e16842c419278b8d84
5
5
  SHA512:
6
- metadata.gz: 30fceacbbc93b16c8f9f3e6e850dfe372d76675407239f4fec6e26fedc4d956a614a2b6d3c88cacd5cf0085ce06c20709b7c2885954796fe0b7f3e1f63c97cf9
7
- data.tar.gz: dbd788b1bbf86b86950d95cfa4f6222e43a1359e3453bbe26c275b0ac451d5a00e1b8a038498d3cc8a554b567c35f27a1c5c143ff5deaed6d197fa7309f0f1ce
6
+ metadata.gz: 9d170c27b085983ea7f58b9ecf0c02ea229d3e43494483f9c4165fe4acad1dedd6b66e4edfaddac73ea08b2157e21a6129f33079e51b98a43c9b00eea5eb5776
7
+ data.tar.gz: 872b30f56d771d92ec2acac229ff42e8dea97f9971961d17c11dc517b9b7905d31127e395d2e450bdbe87700cdc70bce4a58ded23740a50d08dd747382c02905
data/DEMO.md CHANGED
@@ -5,24 +5,58 @@ If you have Rails and Docker installed on your machine, running each of these de
5
5
  Rails provides a _smoke test_ for new applications that makes sure that you have your software configured correctly enough to serve a page. The following deploys that smoke test in production. Once done take a look at the `Dockerfile` file produced.
6
6
 
7
7
  ```bash
8
- rails new welcome --minimal
9
- cd welcome
8
+ rails new demo --minimal
9
+ cd demo
10
10
  echo 'Rails.application.routes.draw { root "rails/welcome#index" }' > config/routes.rb
11
- bundle add dockerfile-rails --group development
11
+ bundle add dockerfile-rails --optimistic --group development
12
12
  bin/rails generate dockerfile
13
- docker buildx build . -t rails-welcome
14
- docker run -p 3000:3000 -e RAILS_MASTER_KEY=$(cat config/master.key) rails-welcome
13
+ docker buildx build . -t rails-demo
14
+ docker run -p 3000:3000 -e RAILS_MASTER_KEY=$(cat config/master.key) rails-demo
15
+ ```
16
+
17
+ # Demo 2 - Neofetch
18
+
19
+ Similar in spirit to the previous demo, but installs and runs Linux commands to show container status.
20
+
21
+ ```bash
22
+ rails new demo --minimal
23
+ cd demo
24
+ echo 'Rails.application.routes.draw { root "neofetch#get" }' > config/routes.rb
25
+
26
+ cat << 'EOF' > app/controllers/neofetch_controller.rb
27
+ require 'open3'
28
+
29
+ class NeofetchController < ApplicationController
30
+ def get
31
+ Open3.pipeline_r('neofetch', 'ansi2html') do |out, threads|
32
+ # adjust to a two column layout
33
+ html = out.read
34
+ .sub(/body \{/, "\\0display: grid; justify-items: center; " +
35
+ "font-size: 2vw; grid-template-columns: auto auto; ")
36
+ .sub(/<\/b>\n\s*/, "</b></pre>\n<pre>")
37
+ .gsub(/^\s+(<|---)/, '\1')
38
+
39
+ render html: html.html_safe
40
+ end
41
+ end
42
+ end
43
+ EOF
44
+
45
+ bundle add dockerfile-rails --optimistic --group development
46
+ bin/rails generate dockerfile --add neofetch colorized-logs
47
+ docker buildx build . -t rails-demo
48
+ docker run -p 3000:3000 -e RAILS_MASTER_KEY=$(cat config/master.key) rails-demo
15
49
  ```
16
50
 
17
51
  Add `--load` to the `buildx` command if you want to save the image to local Docker.
18
52
 
19
- # Demo 2 - Action Cable and Active Record
53
+ # Demo 3 - Action Cable and Active Record
20
54
 
21
55
  Real applications involve a network of services. The following demo makes use of PostgreSQL and Redis to display a welcome screen with a live, updating, visitors counter. Once done, take a look at the `docker-compose.yml` file produced.
22
56
 
23
57
  ```bash
24
- rails new welcome --database postgresql
25
- cd welcome
58
+ rails new demo --database postgresql
59
+ cd demo
26
60
 
27
61
  bin/rails generate model Visitor counter:integer
28
62
  bin/rails generate controller Visitors counter
@@ -87,7 +121,7 @@ cat << 'EOF' > config/routes.rb
87
121
  Rails.application.routes.draw { root "visitors#counter" }
88
122
  EOF
89
123
 
90
- bundle add dockerfile-rails --group development
124
+ bundle add dockerfile-rails --optimistic --group development
91
125
  bin/rails generate dockerfile --compose
92
126
 
93
127
  export RAILS_MASTER_KEY=$(cat config/master.key)
@@ -95,14 +129,14 @@ docker compose build
95
129
  docker compose up
96
130
  ```
97
131
 
98
- # Demo 3 - API only
132
+ # Demo 4 - API only
99
133
 
100
134
  This demo deploys a [Create React App](https://create-react-app.dev/) client and a Rails API-only server. Ruby and Rails version information is retrieved from the server and displayed below a spinning React logo. Note that the build process installs the
101
135
  node moddules and ruby gems in parallel.
102
136
 
103
137
  ```bash
104
- rails new welcome --api
105
- cd welcome
138
+ rails new demo --api
139
+ cd demo
106
140
  npx -y create-react-app client
107
141
 
108
142
  bin/rails generate controller Api versions
@@ -149,22 +183,22 @@ function App() {
149
183
  export default App;
150
184
  EOF
151
185
 
152
- bundle add dockerfile-rails --group development
186
+ bundle add dockerfile-rails --optimistic --group development
153
187
  bin/rails generate dockerfile
154
188
 
155
- docker buildx build . -t rails-welcome
156
- docker run -p 3000:3000 -e RAILS_MASTER_KEY=$(cat config/master.key) rails-welcome
189
+ docker buildx build . -t rails-demo
190
+ docker run -p 3000:3000 -e RAILS_MASTER_KEY=$(cat config/master.key) rails-demo
157
191
  ```
158
192
 
159
- # Demo 4 - Bunding Javascript (esbuild)
193
+ # Demo 5 - Bunding Javascript (esbuild)
160
194
 
161
195
  While optional, bundling Javascript is a popular choice, and starting with
162
196
  Rails 7 there are three options: esbuild, rollup, and webpack. The
163
197
  the following demonstrates Rails 7 with esbuild:
164
198
 
165
199
  ```bash
166
- rails new welcome --javascript esbuild
167
- cd welcome
200
+ rails new demo --javascript esbuild
201
+ cd demo
168
202
 
169
203
  yarn add react react-dom
170
204
  bin/rails generate controller Time index
@@ -269,21 +303,21 @@ cat <<-"EOF" > config/routes.rb
269
303
  Rails.application.routes.draw { root "time#index" }
270
304
  EOF
271
305
 
272
- bundle add dockerfile-rails --group development
306
+ bundle add dockerfile-rails --optimistic --group development
273
307
  bin/rails generate dockerfile
274
308
 
275
- docker buildx build . -t rails-welcome
276
- docker run -p 3000:3000 -e RAILS_MASTER_KEY=$(cat config/master.key) rails-welcome
309
+ docker buildx build . -t rails-demo
310
+ docker run -p 3000:3000 -e RAILS_MASTER_KEY=$(cat config/master.key) rails-demo
277
311
  ```
278
312
 
279
- # Demo 5 - Grover / puppeteer / Chrome
313
+ # Demo 6 - Grover / puppeteer / Chrome
280
314
 
281
315
  This demo runs only on Intel hardware as Google doesn't supply Chrome
282
316
  binaries for Linux on ARM.
283
317
 
284
318
  ```bash
285
- rails new welcome --minimal
286
- cd welcome
319
+ rails new demo --minimal
320
+ cd demo
287
321
  bundle add grover
288
322
  npm install puppeteer
289
323
 
@@ -298,8 +332,8 @@ class GroverController < ApplicationController
298
332
  end
299
333
  EOF
300
334
 
301
- bundle add dockerfile-rails --group development
335
+ bundle add dockerfile-rails --optimistic --group development
302
336
  bin/rails generate dockerfile
303
- docker buildx build . -t rails-welcome
304
- docker run -p 3000:3000 -e RAILS_MASTER_KEY=$(cat config/master.key) rails-welcome
337
+ docker buildx build . -t rails-demo
338
+ docker run -p 3000:3000 -e RAILS_MASTER_KEY=$(cat config/master.key) rails-demo
305
339
  ```
data/MOTIVATION.md ADDED
@@ -0,0 +1,58 @@
1
+ # Ruby on Rails developer profile
2
+
3
+ Let's start with the target audience of Ruby on Rails, which we can infer from the [web site](https://rubyonrails.org/).
4
+
5
+ > Learn just what you need to get started, then keep leveling up as you go. Ruby on Rails scales from HELLO WORLD to IPO.
6
+
7
+ It is fair to conclude from this that a typical Ruby on Rails developer meets some or all of the following characteristics:
8
+
9
+ * member of a small team
10
+ * business subject matter experts
11
+ * knowledgeable of, or recently introduced to, the Ruby programming language
12
+
13
+ # Docker developer profile
14
+
15
+ To illustrate the target audience of Rails Dockerfiles, I'm going to succinctly state some rather basic background information that is necessary to confidently make changes to the Rails 7.1 generated Dockerfiles:
16
+
17
+ > Most [official Ruby dockerhub images](https://hub.docker.com/_/ruby)
18
+ > are based on Debian [bullseye](https://www.debian.org/releases/bullseye/),
19
+ > which provides a [large number of packages](https://packages.debian.org/stable/)
20
+ > that you can install.
21
+ > Simply find the packages that you need and add them to the `apt-get install` line
22
+ > in the relevant [build stage](https://docs.docker.com/build/building/multi-stage/).
23
+
24
+ # Intersection of the prior two groups
25
+
26
+ Based on my experiences at [fly.io](https://fly.io/), the overlap between the members of the first group and the set of people that understand the paragraph in the second section isn't as large as you might think or hope.
27
+
28
+ The purpose of the Dockerfile generator is to help bridge that gap.
29
+
30
+ A usage scenario is that a team is formed. They create an application. When they started they were provided with a Dockerfile that is capable of deploying a HELLO WORLD application. After several months of effort they are ready to deploy. Undoubtedly they made at least one change that will require a modification to the Dockerfile, and find that they don't have the skills necessary to to make that change.
31
+
32
+ Make no mistake about it, we are talking about intelligent, motivated people. Just ones that may have never used a Debian Linux operating system before.
33
+
34
+ # Value Proposition
35
+
36
+ The goal is, whenever possible, have the following command bring the Dockerfile and associated files up to date with the current application:
37
+
38
+ ```cmd
39
+ bin/rails generate dockerfile
40
+ ```
41
+
42
+ Being able to rerun this command means that each invocation can focus on installing only what is necessary or selected to run this application, and not install other things that may (or may not) be useful later.
43
+
44
+ While a laudable goad, it clearly is unattainable. So a second goal is to make solutions to common problems be via one liners that can be shared via FAQs, Stack Overflow, Discourse, Discord, Slack or whatever.
45
+
46
+ Some examples can be found in [Fly.io's FAQ](https://fly.io/docs/rails/getting-started/dockerfiles/). The hope is that this generator becomes widely adopted and similar pages adapted to different target audiences pop up everywhere. That makers of gems with special deployment needs produce pull requests to make it easier for Rails applications that make use of their gems to be deployed.
47
+
48
+ Of course some will use this only as a starting point and make their own changes. We welcome that. Advanced users who need to run it again can use techniques like `git add --patch` to select which changes they want to keep. Really advanced users will contribute back changes to this gem so that they can avoid the need to patch in the future.
49
+
50
+ # Futures
51
+
52
+ This can go in many directions. Some thoughts.
53
+
54
+ * While the number of popular gems with special installation requirements is finite, it may make sense to evolve a plug-in architecture where gems take ownership of their own requirements. [Kuby](https://getkuby.io/) has a plugin system, so we should too.
55
+
56
+ * [Create React App](https://reactjs.org/docs/create-a-new-react-app.html) has (had? I can't really be sure if this project is going to revive) an interesting approach. Configuration files are invisible until you eject. I'd love to see a [future where Dockerfiles were invisible and generated on deploy](https://fly.io/ruby-dispatch/dockerfile-less-deploys/).
57
+
58
+ * CLIs are wonderful, but many have become spoiled by point and click dashboards. Changing the problem from "anything you can put into a Dockerfile" to a set of options that can be expressed in a YAML file should enable such dashboards to be created.
data/README.md CHANGED
@@ -7,6 +7,12 @@ Provides a Rails generator to produce Dockerfiles and related files. This is be
7
7
  * Will set `.node_version`, `packageManager` and install gems if needed to deploy your application.
8
8
  * Can produce a `docker-compose.yml` file for locally testing your configuration before deploying.
9
9
 
10
+ For more background:
11
+
12
+ * [Motivation](./MOTIVATION.md) - why this generator was created and what problems it is meant to solve
13
+ * [Demos](./DEMO.md) - scripts to copy and paste into an empty directory to launch demo apps
14
+ * [Test Results](./test/results) - expected outputs for each test
15
+
10
16
  ## Usage
11
17
 
12
18
  ```
@@ -14,29 +20,29 @@ bundle add dockerfile-rails --optimistic --group development
14
20
  bin/rails generate dockerfile
15
21
  ```
16
22
 
17
- General option:
23
+ ### General option:
18
24
 
19
25
  * `--force` - overwrite existing files
20
26
 
21
- Runtime Optimizations:
27
+ ### Runtime Optimizations:
22
28
 
23
29
  * `--fullstaq` - use [fullstaq](https://fullstaqruby.org/) [images](https://github.com/evilmartians/fullstaq-ruby-docker) on [quay.io](https://quay.io/repository/evl.ms/fullstaq-ruby?tab=tags&tag=latest)
24
30
  * `--jemalloc` - use [jemalloc](https://jemalloc.net/) memory allocator
25
31
  * `--swap=n` - allocate swap space. See [falloc options](https://man7.org/linux/man-pages/man1/fallocate.1.html#OPTIONS) for suffixes
26
32
  * `--yjit` - enable [YJIT](https://github.com/ruby/ruby/blob/master/doc/yjit/yjit.md) optimizing compiler
27
33
 
28
- Build optimizations:
34
+ ### Build optimizations:
29
35
 
30
36
  * `--cache` - use build caching to speed up builds
31
37
  * `--parallel` - use multi-stage builds to install gems and node modules in parallel
32
38
 
33
- Features:
39
+ ### Add a Feature:
34
40
 
35
41
  * `--ci` - include test gems in deployed image
36
42
  * `--compose` - generate a `docker-compose.yml` file
37
43
  * `--nginx` - serve static files via [nginx](https://www.nginx.com/)
38
44
 
39
- Dependencies:
45
+ ### Add a Database:
40
46
 
41
47
  Generally the dockerfile generator will be able to determine what dependencies you
42
48
  are actually using. But should you be using DATABASE_URL, for example, at runtime
@@ -47,7 +53,18 @@ additional support may be needed:
47
53
  * `--redis` - add redis libraries
48
54
  * `--sqlite3` - add sqlite3 libraries
49
55
 
50
- Configuration:
56
+ ### Add a package/environment variable/build argument:
57
+
58
+ Not all of your needs can be determined by scanning your application. For example, I like to add [vim](https://www.vim.org/) and [procps](https://packages.debian.org/bullseye/procps).
59
+
60
+ * `--add package...` - add one or more debian packages
61
+ * `--arg=name:value` - add a [build argument](https://docs.docker.com/engine/reference/builder/#arg)
62
+ * `--env=name:value` - add an environment variable
63
+ * `--remove package...` - remove package from "to be added" list
64
+
65
+ Each of these can be tailored to a specific build phase by adding `-base`, `-build`, or `-deploy` after the flag name (e.g `--env-build:`). If no such suffix is found, the default for arg is `-base`, and the default for the rest is `-deploy`. Removal of an arg or environment variable is done by leaving the value blank.
66
+
67
+ ### Configuration:
51
68
 
52
69
  * `--bin-cd` - adjust binstubs to set current working directory
53
70
  * `--label=name:value` - specify docker label. Can be used multiple times. See [LABEL](https://docs.docker.com/engine/reference/builder/#label) for detail
@@ -83,12 +100,11 @@ If you are running a single test, the following environment variables settings m
83
100
 
84
101
  ## Links
85
102
 
86
- Many of the following links relate to the current development status with respect to Rails 7.1 and will be removed once that is resolved.
103
+ The following links relate to the current development status with respect to Rails 7.1 and will be removed once that is resolved.
87
104
 
88
- * [Demos](./DEMO.md) - scripts to copy and paste into an empty directory to launch demo apps
89
- * [Test Results](./test/results) - expected outputs for each test
90
105
  * [Preparations for Rails 7.1](https://community.fly.io/t/preparations-for-rails-7-1/9512) - [Fly.io](https://fly.io/)'s plans and initial discussions with DHH
91
106
  * [Rails Dockerfile futures](https://discuss.rubyonrails.org/t/rails-dockerfile-futures/82091/1) - rationale for a generator
92
107
  * [Fly Cookbooks](https://fly.io/docs/rails/cookbooks/) - deeper dive into Dockerfile design choices
93
108
  * [app/templates/Dockerfile.tt](https://github.com/rails/rails/blob/main/railties/lib/rails/generators/rails/app/templates/Dockerfile.tt) - current Rails 7.1 template
94
109
  * Fly.io [Cut over to Rails Dockerfile Generator on Sunday 29 Jan 2023](https://community.fly.io/t/cut-over-to-rails-dockerfile-generator-on-sunday-29-jan-2023/10350)
110
+ * Fly.io [FAQ](https://fly.io/docs/rails/getting-started/dockerfiles/)
data/Rakefile CHANGED
@@ -1,17 +1,19 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "bundler/gem_tasks"
2
4
 
3
5
  # Run `rake release` to release a new version of the gem.
4
6
 
5
- require 'rake/testtask'
7
+ require "rake/testtask"
6
8
  Rake::TestTask.new do |t|
7
9
  t.libs << "test"
8
- t.test_files = FileList['test/test*.rb']
10
+ t.test_files = FileList["test/test*.rb"]
9
11
  t.verbose = true
10
12
  end
11
13
 
12
14
  namespace :test do
13
15
  task :capture do
14
- ENV['TEST_CAPTURE'] = 'true'
16
+ ENV["TEST_CAPTURE"] = "true"
15
17
  Rake::Task[:test].invoke
16
18
  end
17
19
  end
@@ -1,26 +1,27 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DockerfileRails
2
4
  module Scanner
3
5
  def scan_rails_app
4
-
5
6
  ### ruby gems ###
6
7
 
7
8
  @gemfile = []
8
9
  @git = false
9
10
 
10
- if File.exist? 'Gemfile.lock'
11
- parser = Bundler::LockfileParser.new(Bundler.read_file('Gemfile.lock'))
11
+ if File.exist? "Gemfile.lock"
12
+ parser = Bundler::LockfileParser.new(Bundler.read_file("Gemfile.lock"))
12
13
  @gemfile += parser.specs.map { |spec, version| spec.name }
13
- @git ||= ENV['RAILS_ENV'] != 'test' && parser.specs.any? do |spec|
14
+ @git ||= ENV["RAILS_ENV"] != "test" && parser.specs.any? do |spec|
14
15
  spec.source.instance_of? Bundler::Source::Git
15
16
  end
16
17
  end
17
-
18
- if File.exist? 'Gemfile'
18
+
19
+ if File.exist? "Gemfile"
19
20
  begin
20
- gemfile_definition = Bundler::Definition.build('Gemfile', nil, [])
21
+ gemfile_definition = Bundler::Definition.build("Gemfile", nil, [])
21
22
  @gemfile += gemfile_definition.dependencies.map(&:name)
22
23
 
23
- unless ENV['RAILS_ENV'] == 'test'
24
+ unless ENV["RAILS_ENV"] == "test"
24
25
  @git = !gemfile_definition.spec_git_paths.empty?
25
26
  end
26
27
  rescue => error
@@ -28,53 +29,53 @@ module DockerfileRails
28
29
  end
29
30
  end
30
31
 
31
- @anycable = @gemfile.include? 'anycable-rails'
32
- @vips = @gemfile.include? 'ruby-vips'
33
- @bootstrap = @gemfile.include? 'bootstrap'
34
- @puppeteer = @gemfile.include? 'puppeteer'
35
- @bootsnap = @gemfile.include? 'bootsnap'
32
+ @anycable = @gemfile.include? "anycable-rails"
33
+ @vips = @gemfile.include? "ruby-vips"
34
+ @bootstrap = @gemfile.include? "bootstrap"
35
+ @puppeteer = @gemfile.include? "puppeteer"
36
+ @bootsnap = @gemfile.include? "bootsnap"
36
37
 
37
38
  ### database ###
38
39
 
39
- database = YAML.load_file('config/database.yml', aliases: true).
40
- dig('production', 'adapter') rescue nil
40
+ database = YAML.load_file("config/database.yml", aliases: true).
41
+ dig("production", "adapter") rescue nil
41
42
 
42
- if database == 'sqlite3'
43
+ if database == "sqlite3"
43
44
  @sqlite3 = true
44
- elsif database == 'postgresql'
45
+ elsif database == "postgresql"
45
46
  @postgresql = true
46
- elsif database == 'mysql' or database == 'mysql2'
47
+ elsif (database == "mysql") || (database == "mysql2")
47
48
  @mysql = true
48
- elsif database == 'sqlserver'
49
+ elsif database == "sqlserver"
49
50
  @sqlserver = true
50
51
  end
51
52
 
52
- @sqlite3 = true if @gemfile.include? 'sqlite3'
53
- @postgresql = true if @gemfile.include? 'pg'
54
- @mysql = true if @gemfile.include? 'mysql2'
53
+ @sqlite3 = true if @gemfile.include? "sqlite3"
54
+ @postgresql = true if @gemfile.include? "pg"
55
+ @mysql = true if @gemfile.include? "mysql2"
55
56
 
56
57
  ### node modules ###
57
58
 
58
59
  @package_json = []
59
60
 
60
- if File.exist? 'package.json'
61
- @package_json += JSON.load_file('package.json')['dependencies'].keys rescue []
61
+ if File.exist? "package.json"
62
+ @package_json += JSON.load_file("package.json")["dependencies"].keys rescue []
62
63
  end
63
64
 
64
- @puppeteer ||= @package_json.include? 'puppeteer'
65
+ @puppeteer ||= @package_json.include? "puppeteer"
65
66
 
66
67
  ### cable/redis ###
67
68
 
68
- @cable = ! Dir['app/channels/*.rb'].empty?
69
+ @cable = ! Dir["app/channels/*.rb"].empty?
69
70
 
70
71
  if @cable
71
72
  @redis_cable = true
72
- if (YAML.load_file('config/cable.yml').dig('production', 'adapter') rescue '').include? 'any_cable'
73
+ if (YAML.load_file("config/cable.yml").dig("production", "adapter") rescue "").include? "any_cable"
73
74
  @anycable = true
74
75
  end
75
76
  end
76
77
 
77
- if (IO.read('config/environments/production.rb') =~ /redis/i rescue false)
78
+ if (IO.read("config/environments/production.rb") =~ /redis/i rescue false)
78
79
  @redis_cache = true
79
80
  end
80
81
 
@@ -1,5 +1,7 @@
1
- require 'rails'
2
- require 'dockerfile-rails/scanner'
1
+ # frozen_string_literal: true
2
+
3
+ require "rails"
4
+ require "dockerfile-rails/scanner"
3
5
 
4
6
  class DockerRailsRailtie < Rails::Railtie
5
- end
7
+ end