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:
|
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:
|