dockerfile-rails 1.4.2 → 1.5.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
  SHA256:
3
- metadata.gz: b9cd11ebc9f7480d2cd29942b3dbb771ddd98377291a93aa27c70317bab0114e
4
- data.tar.gz: 95611b26453984a5e51d2606321c3fdef93cf41b42a23b39f515a1e21ff97e5f
3
+ metadata.gz: 4478af556f6059702ab4b1fce65ab4735a024299796bdebce3014730f3d86220
4
+ data.tar.gz: 941e1e7a2fd88238d3ee9dd7fe16ffb2e290e10568fd1ca2ed3e0001d5aceed8
5
5
  SHA512:
6
- metadata.gz: 76d6de186f304dc03e775de367c0b9b17e53b8eaf2b74738fa4cc8f6323fb84e3cc235a357f8c4d0bc2c3957b8e07411e96523d6052c12a58ab8aa89963f781f
7
- data.tar.gz: addd1bd0774d6ec14f92811d8ba0ff5616c089c73e72a7d06a9e5fdd2b0a68dfca490fff760d973fd7ff3c6c80e4dd755deed439165a4f43d91cbb336ec3f420
6
+ metadata.gz: ed8adae939c867d565049530df18915c49f0cbd775cc9b909733960ea8b3075b9185132eaf1454e501f7ea211a3f903dca44ce394f20fe356168154d8c2165dd
7
+ data.tar.gz: a289a97a457eedd708e9449172b5191685d5f120de3b04df18d6e35950131f681972bf009953967120e32d949b4aede461ac0fb675e14fff8858ccf38de7d522
data/README.md CHANGED
@@ -75,11 +75,27 @@ Not all of your needs can be determined by scanning your application. For examp
75
75
  [autocrlf](https://git-scm.com/book/en/v2/Customizing-Git-Git-Configuration#_core_autocrlf) enabled or may not be able to set bin stubs as executable.
76
76
  * `--label=name:value` - specify docker label. Can be used multiple times. See [LABEL](https://docs.docker.com/engine/reference/builder/#label) for detail
77
77
  * `--no-prepare` - omit `db:prepare`. Useful for cloud platforms with [release](https://devcenter.heroku.com/articles/release-phase) phases
78
+ * `--passenger` - use [Phusion Passenger](https://www.phusionpassenger.com/) under [nginx](https://www.nginx.com/)
78
79
  * `--platform=s` - specify target platform. See [FROM](https://docs.docker.com/engine/reference/builder/#from) for details
80
+ * `--variant=s` - dockerhub ruby variant, defaults to `slim`. See [docker official images](https://hub.docker.com/_/ruby) for list.
79
81
  * `--precompile=defer` - may be needed when your configuration requires access to secrets that are not available at build time. Results in larger images and slower deployments.
80
82
  * `--root` - run application as root
81
83
  * `--windows` - make Dockerfile work for Windows users that may have set `git config --global core.autocrlf true`
82
84
 
85
+ ### Advanced Customization:
86
+
87
+ There may be times where feature detection plus flags just aren't enough. As an example, you may wish to configure and run multiple processes.
88
+
89
+ * `--instructions=path` - a dockerfile fragment to be inserted into the final document.
90
+ * `--migration=cmd` - a replacement (generally a script) for `db:prepare`/`db:migrate`.
91
+ * `--procfile=path` - a [Procfile](https://github.com/ddollar/foreman#foreman) to use in place of launching Rails directly.
92
+
93
+ Like with environment variables, packages, and build args, `--instructions` can be tailored to a specific build phase by adding `-base`, `-build`, or `-deploy` after the flag name, with the default being `-deploy`.
94
+
95
+ Additionaly, if the instructions start with a [shebang](https://en.wikipedia.org/wiki/Shebang_(Unix)) instead the file being treated as a Dockerfile fragment, the file is treated as a script and a `RUN` statement is added to your Dockerfile instead.
96
+
97
+ ---
98
+
83
99
  Options are saved between runs into `config/dockerfile.yml`. To invert a boolean options, add or remove a `no-` prefix from the option name.
84
100
 
85
101
  ## Testing
@@ -19,6 +19,7 @@ class DockerfileGenerator < Rails::Generators::Base
19
19
  "litefs" => false,
20
20
  "lock" => true,
21
21
  "max-idle" => nil,
22
+ "migrate" => "",
22
23
  "mysql" => false,
23
24
  "nginx" => false,
24
25
  "parallel" => false,
@@ -27,11 +28,14 @@ class DockerfileGenerator < Rails::Generators::Base
27
28
  "postgresql" => false,
28
29
  "precompile" => nil,
29
30
  "prepare" => true,
31
+ "procfile" => "",
30
32
  "redis" => false,
33
+ "registry" => "",
31
34
  "root" => false,
32
35
  "sqlite3" => false,
33
36
  "sudo" => false,
34
37
  "swap" => nil,
38
+ "variant" => "slim",
35
39
  "windows" => false,
36
40
  "yjit" => false,
37
41
  }.then { |hash| Struct.new(*hash.keys.map(&:to_sym)).new(*hash.values) }
@@ -42,6 +46,7 @@ class DockerfileGenerator < Rails::Generators::Base
42
46
  @@packages = { "base" => [], "build" => [], "deploy" => [] }
43
47
  @@vars = { "base" => {}, "build" => {}, "deploy" => {} }
44
48
  @@args = { "base" => {}, "build" => {}, "deploy" => {} }
49
+ @@instructions = { "base" => nil, "build" => nil, "deploy" => nil }
45
50
 
46
51
  # load defaults from config file
47
52
  if File.exist? "config/dockerfile.yml"
@@ -70,6 +75,12 @@ class DockerfileGenerator < Rails::Generators::Base
70
75
  end
71
76
  end
72
77
 
78
+ if options[:instructions]
79
+ options[:instructions].each do |stage, value|
80
+ @@instructions[stage.to_s] = value
81
+ end
82
+ end
83
+
73
84
  @@labels = options[:label].stringify_keys if options.include? :label
74
85
  end
75
86
  end
@@ -125,6 +136,12 @@ class DockerfileGenerator < Rails::Generators::Base
125
136
  class_option :platform, type: :string, default: OPTION_DEFAULTS.platform,
126
137
  desc: "image platform (example: linux/arm64)"
127
138
 
139
+ class_option :registry, type: :string, default: OPTION_DEFAULTS.registry,
140
+ desc: "docker registry to use (example: registry.docker.com/library/)"
141
+
142
+ class_option :variant, type: :string, default: OPTION_DEFAULTS.variant,
143
+ desc: "dockerhub image variant (example: slim-bullseye)"
144
+
128
145
  class_option :jemalloc, type: :boolean, default: OPTION_DEFAULTS.jemalloc,
129
146
  desc: "use jemalloc alternative malloc implementation"
130
147
 
@@ -152,6 +169,13 @@ class DockerfileGenerator < Rails::Generators::Base
152
169
  class_option :sudo, type: :boolean, default: OPTION_DEFAULTS.sudo,
153
170
  desc: "Install and configure sudo to enable running as rails with full environment"
154
171
 
172
+ class_option "migrate", type: :string, default: OPTION_DEFAULTS.migrate,
173
+ desc: "custom migration/db:prepare script"
174
+
175
+ class_option "procfile", type: :string, default: OPTION_DEFAULTS.procfile,
176
+ desc: "custom procfile to start services"
177
+
178
+
155
179
  class_option "add-base", type: :array, default: [],
156
180
  desc: "additional packages to install for both build and deploy"
157
181
 
@@ -191,6 +215,16 @@ class DockerfileGenerator < Rails::Generators::Base
191
215
  desc: "additional build arguments to set for deployment"
192
216
 
193
217
 
218
+ class_option "instructions-base", type: :string, default: "",
219
+ desc: "additional instructions to add to the base stage"
220
+
221
+ class_option "instructions-build", type: :string, default: "",
222
+ desc: "additional instructions to add to the build stage"
223
+
224
+ class_option "instructions-deploy", aliases: "--instructions", type: :string, default: "",
225
+ desc: "additional instructions to add to the final stage"
226
+
227
+
194
228
  def generate_app
195
229
  source_paths.push File.expand_path("./templates", __dir__)
196
230
 
@@ -216,11 +250,15 @@ class DockerfileGenerator < Rails::Generators::Base
216
250
  @@args[phase].merge! options["arg-#{phase}"]
217
251
  @@args[phase].delete_if { |key, value| value.blank? }
218
252
  @@args.delete phase if @@args[phase].empty?
253
+
254
+ @@instructions[phase] ||= options["instructions-#{phase}"]
255
+ @@instructions.delete phase if @@instructions[phase].empty?
219
256
  end
220
257
 
221
258
  @dockerfile_config["packages"] = @@packages
222
259
  @dockerfile_config["envs"] = @@vars
223
260
  @dockerfile_config["args"] = @@args
261
+ @dockerfile_config["instructions"] = @@instructions
224
262
 
225
263
  scan_rails_app
226
264
 
@@ -267,7 +305,7 @@ class DockerfileGenerator < Rails::Generators::Base
267
305
  end
268
306
 
269
307
  @dockerfile_config = (@dockerfile_config.to_a - BASE_DEFAULTS.to_h.stringify_keys.to_a).to_h
270
- %w(packages envs args).each do |key|
308
+ %w(packages envs args instructions).each do |key|
271
309
  @dockerfile_config.delete key if @dockerfile_config[key].empty?
272
310
  end
273
311
 
@@ -451,6 +489,9 @@ private
451
489
  packages += %w(libjpeg-dev libpng-dev libtiff-dev libwebp-dev)
452
490
  end
453
491
 
492
+ # Passenger
493
+ packages << "passenger" if using_passenger?
494
+
454
495
  packages.sort.uniq
455
496
  end
456
497
 
@@ -516,10 +557,12 @@ private
516
557
  packages += @@packages["deploy"] if @@packages["deploy"]
517
558
 
518
559
  # start with databases: sqlite3, postgres, mysql
519
- packages << "libsqlite3-0" if options.sqlite3? || @sqlite3
520
560
  packages << "postgresql-client" if options.postgresql? || @postgresql
521
561
  packages << "default-mysql-client" if options.mysql? || @mysql
522
562
  packages << "libjemalloc2" if options.jemalloc? && !options.fullstaq?
563
+ if options.sqlite3? || @sqlite3
564
+ packages << "libsqlite3-0" unless packages.include? "sqlite3"
565
+ end
523
566
 
524
567
  # litefs
525
568
  packages += ["ca-certificates", "fuse3", "sudo"] if options.litefs?
@@ -542,7 +585,7 @@ private
542
585
  end
543
586
 
544
587
  # Passenger
545
- packages += %w(passenger libnginx-mod-http-passenger) if using_passenger?
588
+ packages << "libnginx-mod-http-passenger" if using_passenger?
546
589
 
547
590
  # nginx
548
591
  packages << "nginx" if options.nginx? || using_passenger?
@@ -550,28 +593,49 @@ private
550
593
  # sudo
551
594
  packages << "sudo" if options.sudo?
552
595
 
596
+ if !options.procfile.blank? || (procfile.size > 1)
597
+ packages << "ruby-foreman"
598
+ end
599
+
553
600
  packages.sort
554
601
  end
555
602
 
556
- def deploy_repos
603
+ def base_repos
557
604
  repos = []
558
605
  packages = []
559
606
 
560
- if using_puppeteer? && deploy_packages.include?("google-chrome-stable")
607
+ if using_passenger?
561
608
  packages += %w(gnupg curl)
562
609
  repos += [
563
610
  "curl https://oss-binaries.phusionpassenger.com/auto-software-signing-gpg-key.txt |",
564
- " gpg --dearmor > /etc/apt/trusted.gpg.d/google-archive.gpg &&",
565
- 'echo "deb http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list'
611
+ " gpg --dearmor > /etc/apt/trusted.gpg.d/phusion.gpg &&",
612
+ "bash -c 'echo deb https://oss-binaries.phusionpassenger.com/apt/passenger $(source /etc/os-release; echo $VERSION_CODENAME) main > /etc/apt/sources.list.d/passenger.list'"
566
613
  ]
567
614
  end
568
615
 
569
- if using_passenger?
616
+ if repos.empty?
617
+ ""
618
+ else
619
+ packages.sort!.uniq!
620
+ unless packages.empty?
621
+ repos.unshift "apt-get update -qq &&",
622
+ "apt-get install --no-install-recommends -y #{packages.join(" ")} &&"
623
+ end
624
+
625
+ repos.join(" \\\n ") + " && \\\n "
626
+ end
627
+ end
628
+
629
+ def deploy_repos
630
+ repos = []
631
+ packages = []
632
+
633
+ if using_puppeteer? && deploy_packages.include?("google-chrome-stable")
570
634
  packages += %w(gnupg curl)
571
635
  repos += [
572
- "curl https://oss-binaries.phusionpassenger.com/auto-software-signing-gpg-key.txt |",
573
- " gpg --dearmor > /etc/apt/trusted.gpg.d/phusion.gpg &&",
574
- "bash -c 'echo deb https://oss-binaries.phusionpassenger.com/apt/passenger $(source /etc/os-release; echo $VERSION_CODENAME) main > /etc/apt/sources.list.d/passenger.list'"
636
+ "curl https://dl-ssl.google.com/linux/linux_signing_key.pub |",
637
+ " gpg --dearmor > /etc/apt/trusted.gpg.d/google-archive.gpg &&",
638
+ 'echo "deb http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list'
575
639
  ]
576
640
  end
577
641
 
@@ -674,7 +738,7 @@ private
674
738
  env.merge! @@args["deploy"].to_h { |key, value| [key, "$#{key}"] }
675
739
  end
676
740
 
677
- env.merge! @@vars["base"] if @@vars["base"]
741
+ env.merge! @@vars["deploy"] if @@vars["deploy"]
678
742
 
679
743
  env.map { |key, value| "#{key}=#{value.inspect}" }.sort
680
744
  end
@@ -718,6 +782,42 @@ private
718
782
  args
719
783
  end
720
784
 
785
+ def base_instructions
786
+ return nil unless @@instructions["base"]
787
+
788
+ instructions = IO.read @@instructions["base"]
789
+
790
+ if instructions.start_with? "#!"
791
+ instructions = "# custom instructions\nRUN #{@instructions["base"].strip}"
792
+ end
793
+
794
+ instructions.html_safe
795
+ end
796
+
797
+ def build_instructions
798
+ return nil unless @@instructions["build"]
799
+
800
+ instructions = IO.read @@instructions["build"]
801
+
802
+ if instructions.start_with? "#!"
803
+ instructions = "# custom build instructions\nRUN #{@instructions["build"].strip}"
804
+ end
805
+
806
+ instructions.html_safe
807
+ end
808
+
809
+ def deploy_instructions
810
+ return nil unless @@instructions["deploy"]
811
+
812
+ instructions = IO.read @@instructions["deploy"]
813
+
814
+ if instructions.start_with? "#!"
815
+ instructions = "# custom deploy instructions\nRUN #{@instructions["deploy"].strip}"
816
+ end
817
+
818
+ instructions.html_safe
819
+ end
820
+
721
821
  def binfile_fixups
722
822
  # binfiles may have OS specific paths to ruby. Normalize them.
723
823
  shebangs = Dir["bin/*"].map { |file| IO.read(file).lines.first }.join
@@ -838,10 +938,12 @@ private
838
938
  end
839
939
 
840
940
  def dbprep_command
841
- if Rails::VERSION::MAJOR >= 6
842
- "db:prepare"
941
+ if !options.migrate.blank?
942
+ options.migrate
943
+ elsif Rails::VERSION::MAJOR >= 6
944
+ "./bin/rails db:prepare"
843
945
  else
844
- "db:migrate"
946
+ "./bin/rails db:migrate"
845
947
  end
846
948
  end
847
949
 
@@ -8,9 +8,9 @@ ARG RUBY_VERSION=<%= RUBY_VERSION %>
8
8
 
9
9
  <% end -%>
10
10
  <% if options.fullstaq -%>
11
- FROM <%= platform %>quay.io/evl.ms/fullstaq-ruby:${RUBY_VERSION}-<%= options.jemalloc ? 'jemalloc-' : '' %>slim<% unless options.precompile == "defer" %> as base<% end %>
11
+ FROM <%= platform %>quay.io/evl.ms/fullstaq-ruby:${RUBY_VERSION}-<%= options.jemalloc ? 'jemalloc-' : '' %><%= options.variant %><% unless options.precompile == "defer" %> as base<% end %>
12
12
  <% else -%>
13
- FROM <%= platform %>registry.docker.com/library/ruby:$RUBY_VERSION-slim<% unless options.precompile == "defer" %> as base<% end %>
13
+ FROM <%= platform %><%= options.registry %>ruby:$RUBY_VERSION-<%= options.variant %><% unless options.precompile == "defer" %> as base<% end %>
14
14
  <% end -%>
15
15
 
16
16
  <% unless options.label.empty? -%>
@@ -36,12 +36,16 @@ RUN gem update --system --no-document && \
36
36
 
37
37
  <% unless base_requirements.empty? -%>
38
38
  # Install packages needed to install <%= base_requirements %>
39
- <%= render partial: 'apt_install', locals: {packages: base_packages, clean: true, repos: ''} %>
39
+ <%= render partial: 'apt_install', locals: {packages: base_packages, clean: true, repos: base_repos} %>
40
40
 
41
41
  <% end -%>
42
42
  <% if using_execjs? -%>
43
43
  <%= render partial: 'install_node', locals: {yarn_version: nil} %>
44
44
 
45
+ <% end -%>
46
+ <% if base_instructions -%>
47
+ <%= base_instructions %>
48
+
45
49
  <% end -%>
46
50
  <% unless options.precompile == "defer" -%>
47
51
 
@@ -98,10 +102,17 @@ RUN bundle install<% if depend_on_bootsnap? -%> && \
98
102
  bundle exec bootsnap precompile --gemfile<% end %> && \
99
103
  rm -rf ~/.bundle/ $BUNDLE_PATH/ruby/*/cache $BUNDLE_PATH/ruby/*/bundler/gems/*/.git
100
104
 
105
+ <% end -%>
106
+ <% if using_passenger? -%>
107
+ # Compile passenger native support
108
+ RUN passenger-config build-native-support
109
+
101
110
  <% end -%>
102
111
  <% if parallel? -%>
103
112
  # Copy node modules
104
113
  COPY --from=node /rails/node_modules /rails/node_modules
114
+ COPY --from=node /usr/local/node /usr/local/node
115
+ ENV PATH=/usr/local/node/bin:$PATH
105
116
 
106
117
  <% elsif using_node? -%>
107
118
  <%= render partial: 'npm_install', locals: {sources: Dir[*%w(package.json package-lock.json yarn.lock)]} %>
@@ -110,6 +121,10 @@ COPY --from=node /rails/node_modules /rails/node_modules
110
121
  # Copy application code
111
122
  COPY<% if options.link? %> --link<% end %> . .
112
123
 
124
+ <% if build_instructions -%>
125
+ <%= build_instructions %>
126
+
127
+ <% end -%>
113
128
  <% if depend_on_bootsnap? -%>
114
129
  # Precompile bootsnap code for faster boot times
115
130
  RUN bundle exec bootsnap precompile app/ lib/
@@ -165,6 +180,11 @@ RUN gem install foreman
165
180
  # Copy built artifacts: gems, application
166
181
  COPY --from=build /usr/local/bundle /usr/local/bundle
167
182
  COPY --from=build /rails /rails
183
+ <% if using_passenger? -%>
184
+
185
+ # Copy passenger native support
186
+ COPY --from=build /root/.passenger/native_support /root/.passenger/native_support
187
+ <% end -%>
168
188
  <% if api_client_dir -%>
169
189
 
170
190
  # Copy built client
@@ -202,6 +222,10 @@ RUN useradd rails --create-home --shell /bin/bash && \
202
222
  USER rails:rails
203
223
  <% end -%>
204
224
 
225
+ <% end -%>
226
+ <% if deploy_instructions -%>
227
+ <%= deploy_instructions.strip %>
228
+
205
229
  <% end -%>
206
230
  <% if using_litefs? and !run_as_root? -%>
207
231
  # Authorize rails user to launch litefs
@@ -237,7 +261,9 @@ EXPOSE 3000
237
261
  VOLUME /data
238
262
  <% end -%>
239
263
  <% unless fly_processes -%>
240
- <% if procfile.size > 1 -%>
264
+ <% if !options.procfile.blank? -%>
265
+ CMD ["foreman", "start", "--procfile=<%= options.procfile %>"]
266
+ <% elsif procfile.size > 1 -%>
241
267
  CMD ["foreman", "start", "--procfile=Procfile.prod"]
242
268
  <% else -%>
243
269
  CMD <%= procfile.values.first.split(" ").inspect %>
@@ -25,4 +25,5 @@ RUN echo "daemon off;" >> /etc/nginx/nginx.conf && \
25
25
  <% if options['max-idle'] -%>
26
26
  chmod +sx /etc/nginx/sites-enabled/hook_detached_process && \
27
27
  <% end -%>
28
+ sed -i 's/user www-data/user rails/' /etc/nginx/nginx.conf && \
28
29
  mkdir /var/run/passenger-instreg
@@ -31,7 +31,9 @@ fi
31
31
 
32
32
  <% end -%>
33
33
  <% if options.prepare -%>
34
- <% if procfile.size > 1 -%>
34
+ <% if !options.procfile.blank? -%>
35
+ if [ "${*}" == "foreman start --procfile=<%= options.procfile %>" ]; then
36
+ <% elsif procfile.size > 1 -%>
35
37
  # If running the production procfile then create or migrate existing database
36
38
  if [ "${*}" == "foreman start --procfile=Procfile.prod" ]; then
37
39
  <% else -%>
@@ -41,7 +43,7 @@ if [ "${*}" == <%= procfile.values.first.inspect %> <% if using_litefs? %>-a "$F
41
43
  <% if options.precompile == "defer" -%>
42
44
  ./bin/rails assets:precompile
43
45
  <% end -%>
44
- ./bin/rails <%= dbprep_command %>
46
+ <%= dbprep_command %>
45
47
  fi
46
48
 
47
49
  <% elsif !options.swap -%>
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dockerfile-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.2
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Ruby
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-06-08 00:00:00.000000000 Z
11
+ date: 2023-06-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails