dockerfile-rails 1.3.0 → 1.4.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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5d1b0d5e237b0a8c33a3b1263d34590db8912967420863332ad0b2c8f5661e5f
|
4
|
+
data.tar.gz: 000fd8db20304bc2ba8623aaa1a4bd19870ec4143cacc3cb6ea31b8690510782
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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
|
-
|
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
|
-
<%
|
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
|
-
<%
|
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.
|
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-
|
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/
|
54
|
+
homepage: https://github.com/fly-apps/dockerfile-rails
|
54
55
|
licenses:
|
55
56
|
- MIT
|
56
57
|
metadata:
|
57
|
-
homepage_uri: https://github.com/
|
58
|
+
homepage_uri: https://github.com/fly-apps/dockerfile-rails
|
58
59
|
post_install_message:
|
59
60
|
rdoc_options: []
|
60
61
|
require_paths:
|