dockerfile-rails 1.3.0 → 1.4.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: 8780a8a7015d339452edf4dff330981a748ad72c72081e0cfa473c835121637c
4
- data.tar.gz: ab37e68fe9d3f82f9368e45738a12f171eaaabcff8b311451d89bdbce1217d95
3
+ metadata.gz: 5d1b0d5e237b0a8c33a3b1263d34590db8912967420863332ad0b2c8f5661e5f
4
+ data.tar.gz: 000fd8db20304bc2ba8623aaa1a4bd19870ec4143cacc3cb6ea31b8690510782
5
5
  SHA512:
6
- metadata.gz: 8a1bce2d42a5916ae7bf4cc49f23d0b9077533e1447015f35bfd4835397438a8bb4bc13e48a774a7e80130cf0f99dada597fda1fa0cada1674e52073d7846fc1
7
- data.tar.gz: 9793fdc06ffe7a84a1e0f40282570ea5e4ad6e08514ff8210f805254a093208cc4b98f683c44fce299dc0b71ff04c2418b847c5e33f05da407cefd617412521b
6
+ metadata.gz: 64b8702f00462a318af21238617528682be3831da82471bff0172ef9ef98d7e4a6a10346ffe297e87e76cc5d4b2699bf56b79d9257f1eee3c8cc24bc56012037
7
+ data.tar.gz: 9a9dc774d388e4276b08bbcdcce9ffd676800df7bb86b4cac34e6795fd0ee6f24ba2a57df393f7948f738a9bdafe8a1ed8073c0b91d9e6a2f9f94349a7d14fe4
data/README.md CHANGED
@@ -52,6 +52,7 @@ Generally the dockerfile generator will be able to determine what dependencies y
52
52
  are actually using. But should you be using DATABASE_URL, for example, at runtime
53
53
  additional support may be needed:
54
54
 
55
+ * `--litefs` - use [LiteFS](https://fly.io/docs/litefs/)
55
56
  * `--mysql` - add mysql libraries
56
57
  * `--postgresql` - add postgresql libraries
57
58
  * `--redis` - add redis libraries
@@ -110,9 +111,9 @@ If you are running a single test, the following environment variables settings m
110
111
  * `TEST_CAPTURE=1` will capture test results.
111
112
  * `TEST_KEEP=1` will leave the test app behind for inspection after the test completes.
112
113
 
113
- ## Links
114
+ ## Historical Links
114
115
 
115
- The following links relate to the current development status with respect to Rails 7.1 and will be removed once that is resolved.
116
+ The following links relate to the coordination between this package and Rails 7.1.
116
117
 
117
118
  * [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
118
119
  * [Rails Dockerfile futures](https://discuss.rubyonrails.org/t/rails-dockerfile-futures/82091/1) - rationale for a generator
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "erb"
4
+ require "json"
4
5
  require_relative "../dockerfile-rails/scanner.rb"
5
6
 
6
7
  class DockerfileGenerator < Rails::Generators::Base
@@ -15,6 +16,7 @@ class DockerfileGenerator < Rails::Generators::Base
15
16
  "jemalloc" => false,
16
17
  "label" => {},
17
18
  "link" => true,
19
+ "litefs" => false,
18
20
  "lock" => true,
19
21
  "max-idle" => nil,
20
22
  "mysql" => false,
@@ -111,6 +113,9 @@ class DockerfileGenerator < Rails::Generators::Base
111
113
  class_option :sqlite3, aliases: "--sqlite", type: :boolean, default: OPTION_DEFAULTS.sqlite3,
112
114
  desc: "include sqlite3 libraries"
113
115
 
116
+ class_option :litefs, type: :boolean, default: OPTION_DEFAULTS.litefs,
117
+ desc: "replicate sqlite3 databases using litefs"
118
+
114
119
  class_option :postgresql, aliases: "--postgres", type: :boolean, default: OPTION_DEFAULTS.postgresql,
115
120
  desc: "include postgresql libraries"
116
121
 
@@ -233,6 +238,12 @@ class DockerfileGenerator < Rails::Generators::Base
233
238
 
234
239
  template "docker-compose.yml.erb", "docker-compose.yml" if options.compose
235
240
 
241
+ if using_litefs?
242
+ template "litefs.yml.erb", "config/litefs.yml"
243
+
244
+ fly_attach_consul
245
+ end
246
+
236
247
  if @gemfile.include?("vite_ruby")
237
248
  package = JSON.load_file("package.json")
238
249
  unless package.dig("scripts", "build")
@@ -296,6 +307,10 @@ private
296
307
  options.root?
297
308
  end
298
309
 
310
+ def using_litefs?
311
+ options.litefs?
312
+ end
313
+
299
314
  def using_node?
300
315
  return @using_node if @using_node != nil
301
316
  @using_node = File.exist? "package.json"
@@ -495,6 +510,9 @@ private
495
510
  packages << "default-mysql-client" if options.mysql? || @mysql
496
511
  packages << "libjemalloc2" if options.jemalloc? && !options.fullstaq?
497
512
 
513
+ # litefs
514
+ packages += ["ca-certificates", "fuse3", "sudo"] if options.litefs?
515
+
498
516
  # ActiveStorage preview support
499
517
  packages << "libvips" if @gemfile.include? "ruby-vips"
500
518
 
@@ -601,13 +619,21 @@ private
601
619
  def deploy_env
602
620
  env = {}
603
621
 
604
- env["PORT"] = "3001" if options.nginx? && !using_passenger?
622
+ env["PORT"] = "3001" if (options.nginx? && !using_passenger?) || using_litefs?
605
623
 
606
624
  if Rails::VERSION::MAJOR < 7 || Rails::VERSION::STRING.start_with?("7.0")
607
625
  env["RAILS_LOG_TO_STDOUT"] = "1"
608
626
  env["RAILS_SERVE_STATIC_FILES"] = "true" unless options.nginx?
609
627
  end
610
628
 
629
+ if deploy_database == "sqlite3"
630
+ if using_litefs?
631
+ env["DATABASE_URL"] = "sqlite3:///litefs/production.sqlite3"
632
+ else
633
+ env["DATABASE_URL"] = "sqlite3:///data/production.sqlite3"
634
+ end
635
+ end
636
+
611
637
  if options.yjit?
612
638
  env["RUBY_YJIT_ENABLE"] = "1"
613
639
  end
@@ -639,7 +665,7 @@ private
639
665
 
640
666
  env.merge! @@vars["base"] if @@vars["base"]
641
667
 
642
- env.map { |key, value| "#{key}=#{value.inspect}" }
668
+ env.map { |key, value| "#{key}=#{value.inspect}" }.sort
643
669
  end
644
670
 
645
671
  def base_args
@@ -716,9 +742,11 @@ private
716
742
  end
717
743
 
718
744
  def deploy_database
719
- if options.postgresql? || @postgresql
745
+ # note: as database can be overridden at runtime via DATABASE_URL,
746
+ # use presence of "pg" or "mysql2" in the bundle as evidence of intent.
747
+ if options.postgresql? || @postgresql || @gemfile.include?("pg")
720
748
  "postgresql"
721
- elsif options.mysql? || @mysql
749
+ elsif options.mysql? || @mysql || @gemfile.include?("mysql2")
722
750
  "mysql"
723
751
  else
724
752
  "sqlite3"
@@ -853,4 +881,32 @@ private
853
881
  rescue ArgumentError
854
882
  nil
855
883
  end
884
+
885
+ # if running on fly v2, make a best effort to attach consul
886
+ def fly_attach_consul
887
+ # certainly not fly unless there is a fly.toml
888
+ return unless File.exist? "fly.toml"
889
+
890
+ # Check fly.toml to guess if v1 or v2
891
+ toml = File.read("fly.toml")
892
+ return if toml.include?("enable_consul") # v1-ism
893
+ return unless toml.include?("primary_region") # v2
894
+
895
+ # see if flyctl is in the path
896
+ paths = ENV["PATH"].split(File::PATH_SEPARATOR)
897
+ cmds = %w(flyctl)
898
+ exts = ENV["PATHEXT"] ? ENV["PATHEXT"].split(";") : [""]
899
+ flyctl = Enumerator.product(paths, cmds, exts).
900
+ map { |path, cmd, ext| File.join(path, "#{cmd}#{ext}") }.
901
+ find { |path| File.executable? path }
902
+ return unless flyctl
903
+
904
+ # see if secret is already set?
905
+ secrets = JSON.parse(`#{flyctl} secrets list --json`)
906
+ return if secrets.any? { |secret| secret["Name"] == "FLY_CONSUL_URL" }
907
+
908
+ # attach consul
909
+ say_status "execute", "flyctl consul attach", :green
910
+ system "#{flyctl} consul attach"
911
+ end
856
912
  end
@@ -134,6 +134,12 @@ RUN SECRET_KEY_BASE<%= Rails::VERSION::MAJOR<7 || Rails::VERSION::STRING.start_w
134
134
  # Final stage for app image
135
135
  FROM base
136
136
 
137
+ <% end -%>
138
+ <% if using_litefs? -%>
139
+ # Install, configure litefs
140
+ COPY --from=flyio/litefs:0.4.0 /usr/local/bin/litefs /usr/local/bin/litefs
141
+ COPY<% if options.link? %> --link<% end %> config/litefs.yml /etc/litefs.yml
142
+
137
143
  <% end -%>
138
144
  <% unless deploy_args.empty? -%>
139
145
  # Deployment build arguments
@@ -166,7 +172,11 @@ COPY --from=client /rails/<%= api_client_dir %>/build /rails/public
166
172
  <% end -%>
167
173
 
168
174
  <% end -%>
169
- <% unless run_as_root? -%>
175
+ <% if run_as_root? -%>
176
+ <% if deploy_database == 'sqlite3' -%>
177
+ RUN mkdir /data
178
+ <% end -%>
179
+ <% else -%>
170
180
  # Run and own only the runtime files as a non-root user for security
171
181
  <% if options.compose? -%>
172
182
  ARG UID=1000 \
@@ -182,11 +192,23 @@ RUN useradd rails --create-home --shell /bin/bash && \
182
192
  <% if deploy_packages.include?("sudo") && options.sudo? -%>
183
193
  sed -i 's/env_reset/env_keep="*"/' /etc/sudoers && \
184
194
  <% end -%>
195
+ <% if deploy_database == 'sqlite3' -%>
196
+ mkdir /data<% if using_litefs? %> /litefs<% end %> && \
197
+ chown -R rails:rails <%= Dir[*%w(db log storage tmp)].join(" ") %> /data<% if using_litefs? %> /litefs<% end %>
198
+ <% else -%>
185
199
  chown -R rails:rails <%= Dir[*%w(db log storage tmp)].join(" ") %>
186
- <% unless options.swap? or using_passenger? -%>
200
+ <% end -%>
201
+ <% unless options.swap? or using_passenger? or using_litefs? -%>
187
202
  USER rails:rails
188
203
  <% end -%>
189
204
 
205
+ <% end -%>
206
+ <% if using_litefs? and !run_as_root? -%>
207
+ # Authorize rails user to launch litefs
208
+ COPY <<-"EOF" /etc/sudoers.d/rails
209
+ rails ALL=(root) /usr/local/bin/litefs
210
+ EOF
211
+
190
212
  <% end -%>
191
213
  <% unless deploy_env.empty? -%>
192
214
  # Deployment options
@@ -210,9 +232,15 @@ EOF
210
232
 
211
233
  # Start the server by default, this can be overwritten at runtime
212
234
  EXPOSE 3000
235
+ <% if deploy_database == 'sqlite3' -%>
236
+ VOLUME /data
237
+ <% end -%>
213
238
  CMD ["foreman", "start", "--procfile=Procfile.prod"]
214
239
  <% else -%>
215
240
  # Start the server by default, this can be overwritten at runtime
216
241
  EXPOSE 3000
242
+ <% if deploy_database == 'sqlite3' -%>
243
+ VOLUME /data
244
+ <% end -%>
217
245
  CMD <%= procfile.values.first.split(" ").inspect %>
218
246
  <% end -%>
@@ -14,11 +14,21 @@ if [ $UID -eq 0 ]; then
14
14
  <%= @space %>echo 10 > /proc/sys/vm/swappiness
15
15
  <%= @space %>swapon /swapfile
16
16
  <%= @space %>echo 1 > /proc/sys/vm/overcommit_memory
17
+ <% if using_litefs? -%>
18
+
19
+ <%= @space %># mount litefs
20
+ <%= @space %>litefs mount &
21
+ <% end -%>
17
22
  <% unless run_as_root? or using_passenger? -%>
23
+
18
24
  exec su rails $0 $@
19
25
  fi
20
26
  <% end -%>
21
27
 
28
+ <% elsif using_litefs? -%>
29
+ # mount litefs
30
+ <% unless run_as_root? %>sudo -E <% end %>litefs mount &
31
+
22
32
  <% end -%>
23
33
  <% if options.prepare -%>
24
34
  <% if procfile.size > 1 -%>
@@ -26,7 +36,7 @@ fi
26
36
  if [ "${*}" == "foreman start --procfile=Procfile.prod" ]; then
27
37
  <% else -%>
28
38
  # If running the rails server then create or migrate existing database
29
- if [ "${*}" == <%= procfile.values.first.inspect %> ]; then
39
+ if [ "${*}" == <%= procfile.values.first.inspect %> <% if using_litefs? %>-a "$FLY_REGION" == "$PRIMARY_REGION" <%end%>]; then
30
40
  <% end -%>
31
41
  <% if options.precompile == "defer" -%>
32
42
  ./bin/rails assets:precompile
@@ -0,0 +1,116 @@
1
+ # based on: https://github.com/superfly/litefs/blob/main/cmd/litefs/etc/litefs.yml
2
+
3
+ # The FUSE section handles settings on the FUSE file system. FUSE
4
+ # provides a layer for intercepting SQLite transactions on the
5
+ # primary node so they can be shipped to replica nodes transparently.
6
+ fuse:
7
+ # Required. This is the mount directory that applications will
8
+ # use to access their SQLite databases.
9
+ dir: "/litefs"
10
+
11
+ # Set this flag to true to allow non-root users to access mount.
12
+ # You must set the "user_allow_other" option in /etc/fuse.conf first.
13
+ allow-other: false
14
+
15
+ # The debug flag enables debug logging of all FUSE API calls.
16
+ # This will produce a lot of logging. Not for general use.
17
+ debug: false
18
+
19
+ # The data section specifies where internal LiteFS data is stored
20
+ # and how long to retain the transaction files.
21
+ #
22
+ # Transaction files are used to ship changes to replica nodes so
23
+ # they should persist long enough for replicas to retrieve them,
24
+ # even in the face of a short network interruption or a redeploy.
25
+ # Under high load, these files can grow large so it's not advised
26
+ # to extend retention too long.
27
+ data:
28
+ # Path to internal data storage.
29
+ dir: "/data"
30
+
31
+ # Duration to keep LTX files. Latest LTX file is always kept.
32
+ retention: "10m"
33
+
34
+ # Frequency with which to check for LTX files to delete.
35
+ retention-monitor-interval: "1m"
36
+
37
+ # If true, then LiteFS will not wait until the node becomes the
38
+ # primary or connects to the primary before starting the subprocess.
39
+ skip-sync: false
40
+
41
+ # If true, then LiteFS will not exit if there is a validation
42
+ # issue on startup. This can be useful for debugging issues as
43
+ # it avoids constantly restarting the node on ephemeral hosting.
44
+ exit-on-error: false
45
+
46
+ # This section defines settings for the LiteFS HTTP API server.
47
+ # This API server is how nodes communicate with each other.
48
+ http:
49
+ # Specifies the bind address of the HTTP API server.
50
+ addr: ":20202"
51
+
52
+ # This section defines settings for the option HTTP proxy.
53
+ # This proxy can handle primary forwarding & replica consistency
54
+ # for applications that use a single SQLite database.
55
+ proxy:
56
+ # Specifies the bind address of the proxy server.
57
+ addr: ":3000"
58
+
59
+ # The hostport of the target application.
60
+ target: "localhost:3001"
61
+
62
+ # The name of the database used for TXID tracking.
63
+ db: "production.sqlite3"
64
+
65
+ # If true, enables verbose logging of requests by the proxy.
66
+ debug: false
67
+
68
+ # List of paths that are ignored by the proxy. The asterisk is
69
+ # the only available wildcard. These requests are passed
70
+ # through to the target as-is.
71
+ passthrough: []
72
+
73
+ # The lease section defines how LiteFS creates a cluster and
74
+ # implements leader election. For dynamic clusters, use the
75
+ # "consul". This allows the primary to change automatically when
76
+ # the current primary goes down. For a simpler setup, use
77
+ # "static" which assigns a single node to be the primary and does
78
+ # not failover.
79
+ lease:
80
+ # Required. Must be either "consul" or "static".
81
+ type: "consul"
82
+
83
+ # Required. The URL for this node's LiteFS API.
84
+ # Should match HTTP port.
85
+ advertise-url: "http://${HOSTNAME}.vm.${FLY_APP_NAME}.internal:20202"
86
+
87
+ # Specifies whether the node can become the primary. If using
88
+ # "static" leasing, this should be set to true on the primary
89
+ # and false on the replicas.
90
+ candidate: ${FLY_REGION == PRIMARY_REGION}
91
+
92
+ # A Consul server provides leader election and ensures that the
93
+ # responsibility of the primary node can be moved in the event
94
+ # of a deployment or a failure.
95
+ consul:
96
+ # Required. The base URL of the Consul server.
97
+ url: "${FLY_CONSUL_URL}"
98
+
99
+ # Required. The key used for obtaining a lease by the primary.
100
+ # This must be unique for each cluster of LiteFS servers
101
+ key: "litefs/${FLY_APP_NAME}"
102
+
103
+ # Length of time before a lease expires. The primary will
104
+ # automatically renew the lease while it is alive, however,
105
+ # if it fails to renew in time then a new primary may be
106
+ # elected after the TTL. This only occurs for unexpected loss
107
+ # of the leader as normal operation will allow the leader to
108
+ # handoff the lease to another replica without downtime.
109
+ #
110
+ # Consul does not allow a TTL of less than 10 seconds.
111
+ ttl: "10s"
112
+
113
+ # Length of time after the lease expires before a candidate
114
+ # can become leader. This buffer is intended to prevent
115
+ # overlap in leadership due to clock skew or in-flight calls.
116
+ lock-delay: "1s"
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.3.0
4
+ version: 1.4.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-05-18 00:00:00.000000000 Z
11
+ date: 2023-05-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -49,12 +49,13 @@ files:
49
49
  - lib/generators/templates/docker-entrypoint.erb
50
50
  - lib/generators/templates/dockerfile.yml.erb
51
51
  - lib/generators/templates/dockerignore.erb
52
+ - lib/generators/templates/litefs.yml.erb
52
53
  - lib/generators/templates/node-version.erb
53
- homepage: https://github.com/rubys/dockerfile-rails
54
+ homepage: https://github.com/fly-apps/dockerfile-rails
54
55
  licenses:
55
56
  - MIT
56
57
  metadata:
57
- homepage_uri: https://github.com/rubys/dockerfile-rails
58
+ homepage_uri: https://github.com/fly-apps/dockerfile-rails
58
59
  post_install_message:
59
60
  rdoc_options: []
60
61
  require_paths: