dockerfile-rails 1.4.2 → 1.5.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: 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