Add support for volumes

This commit is contained in:
Chris de Bruin
2023-01-21 14:21:04 +01:00
parent 885fd5d2c9
commit 2dc0f7cb66
5 changed files with 39 additions and 14 deletions

View File

@@ -96,6 +96,15 @@ If the referenced secret ENVs are missing, the configuration will be halted with
Note: Marking an ENV as secret currently only redacts its value in the output for MRSK. The ENV is still injected in the clear into the container at runtime. Note: Marking an ENV as secret currently only redacts its value in the output for MRSK. The ENV is still injected in the clear into the container at runtime.
### Adding volumes
You can add custom volumes into the app containers using `volumes`:
```yaml
volumes:
- "/local/path:/container/path"
```
### Splitting servers into different roles ### Splitting servers into different roles
If your application uses separate hosts for running jobs or other roles beyond the default web running, you can specify these hosts and their custom entrypoint command like so: If your application uses separate hosts for running jobs or other roles beyond the default web running, you can specify these hosts and their custom entrypoint command like so:

View File

@@ -10,6 +10,7 @@ class Mrsk::Commands::App < Mrsk::Commands::Base
"--name", config.service_with_version, "--name", config.service_with_version,
*rails_master_key_arg, *rails_master_key_arg,
*role.env_args, *role.env_args,
*config.volumes,
*role.label_args, *role.label_args,
config.absolute_image, config.absolute_image,
role.cmd role.cmd
@@ -43,6 +44,7 @@ class Mrsk::Commands::App < Mrsk::Commands::Base
("-it" if interactive), ("-it" if interactive),
*rails_master_key_arg, *rails_master_key_arg,
*config.env_args, *config.env_args,
*config.volumes,
config.service_with_version, config.service_with_version,
*command *command
end end
@@ -53,6 +55,7 @@ class Mrsk::Commands::App < Mrsk::Commands::Base
"--rm", "--rm",
*rails_master_key_arg, *rails_master_key_arg,
*config.env_args, *config.env_args,
*config.volumes,
config.absolute_image, config.absolute_image,
*command *command
end end

View File

@@ -40,7 +40,6 @@ class Mrsk::Configuration
ensure_required_keys_present if validate ensure_required_keys_present if validate
end end
def roles def roles
@roles ||= role_names.collect { |role_name| Role.new(role_name, config: self) } @roles ||= role_names.collect { |role_name| Role.new(role_name, config: self) }
end end
@@ -61,7 +60,6 @@ class Mrsk::Configuration
roles.select(&:running_traefik?).flat_map(&:hosts) roles.select(&:running_traefik?).flat_map(&:hosts)
end end
def version def version
@version @version
end end
@@ -78,7 +76,6 @@ class Mrsk::Configuration
"#{service}-#{version}" "#{service}-#{version}"
end end
def env_args def env_args
if config.env.present? if config.env.present?
argumentize_env_with_secrets(config.env) argumentize_env_with_secrets(config.env)
@@ -87,6 +84,12 @@ class Mrsk::Configuration
end end
end end
def volumes
return unless config.volumes.present?
config.volumes.map { |volume| "--volume #{volume}" }
end
def ssh_user def ssh_user
config.ssh_user || "root" config.ssh_user || "root"
end end
@@ -110,11 +113,11 @@ class Mrsk::Configuration
service_with_version: service_with_version, service_with_version: service_with_version,
env_args: env_args, env_args: env_args,
ssh_options: ssh_options, ssh_options: ssh_options,
builder: config.builder builder: config.builder,
volumes: volumes
}.compact }.compact
end end
private private
attr_accessor :config attr_accessor :config

View File

@@ -15,6 +15,13 @@ class CommandsAppTest < ActiveSupport::TestCase
[:docker, :run, "-d", "--restart unless-stopped", "--name", "app-missing", "-e", "RAILS_MASTER_KEY=456", "--label", "service=app", "--label", "role=web", "--label", "traefik.http.routers.app.rule='PathPrefix(`/`)'", "--label", "traefik.http.services.app.loadbalancer.healthcheck.path=/up", "--label", "traefik.http.services.app.loadbalancer.healthcheck.interval=1s", "--label", "traefik.http.middlewares.app.retry.attempts=3", "--label", "traefik.http.middlewares.app.retry.initialinterval=500ms", "dhh/app:missing"], @app.run [:docker, :run, "-d", "--restart unless-stopped", "--name", "app-missing", "-e", "RAILS_MASTER_KEY=456", "--label", "service=app", "--label", "role=web", "--label", "traefik.http.routers.app.rule='PathPrefix(`/`)'", "--label", "traefik.http.services.app.loadbalancer.healthcheck.path=/up", "--label", "traefik.http.services.app.loadbalancer.healthcheck.interval=1s", "--label", "traefik.http.middlewares.app.retry.attempts=3", "--label", "traefik.http.middlewares.app.retry.initialinterval=500ms", "dhh/app:missing"], @app.run
end end
test "run with volumes" do
@config[:volumes] = ["/local/path:/container/path" ]
assert_equal \
[:docker, :run, "-d", "--restart unless-stopped", "--name", "app-missing", "-e", "RAILS_MASTER_KEY=456", "--volume /local/path:/container/path", "--label", "service=app", "--label", "role=web", "--label", "traefik.http.routers.app.rule='PathPrefix(`/`)'", "--label", "traefik.http.services.app.loadbalancer.healthcheck.path=/up", "--label", "traefik.http.services.app.loadbalancer.healthcheck.interval=1s", "--label", "traefik.http.middlewares.app.retry.attempts=3", "--label", "traefik.http.middlewares.app.retry.initialinterval=500ms", "dhh/app:missing"], @app.run
end
test "run with" do test "run with" do
assert_equal \ assert_equal \
[ :docker, :run, "--rm", "-e", "RAILS_MASTER_KEY=456", "dhh/app:missing", "bin/rails", "db:setup" ], [ :docker, :run, "--rm", "-e", "RAILS_MASTER_KEY=456", "dhh/app:missing", "bin/rails", "db:setup" ],

View File

@@ -9,7 +9,8 @@ class ConfigurationTest < ActiveSupport::TestCase
service: "app", image: "dhh/app", service: "app", image: "dhh/app",
registry: { "username" => "dhh", "password" => "secret" }, registry: { "username" => "dhh", "password" => "secret" },
env: { "REDIS_URL" => "redis://x/y" }, env: { "REDIS_URL" => "redis://x/y" },
servers: [ "1.1.1.1", "1.1.1.2" ] servers: [ "1.1.1.1", "1.1.1.2" ],
volumes: ["/local/path:/container/path"]
} }
@config = Mrsk::Configuration.new(@deploy) @config = Mrsk::Configuration.new(@deploy)
@@ -84,15 +85,14 @@ class ConfigurationTest < ActiveSupport::TestCase
assert_equal "app-missing", @config.service_with_version assert_equal "app-missing", @config.service_with_version
end end
test "env args" do test "env args" do
assert_equal [ "-e", "REDIS_URL=redis://x/y" ], @config.env_args assert_equal [ "-e", "REDIS_URL=redis://x/y" ], @config.env_args
end end
test "env args with clear and secrets" do test "env args with clear and secrets" do
ENV["PASSWORD"] = "secret123" ENV["PASSWORD"] = "secret123"
config = Mrsk::Configuration.new(@deploy.tap { |c| c.merge!({ config = Mrsk::Configuration.new(@deploy.tap { |c| c.merge!({
env: { "clear" => { "PORT" => "3000" }, "secret" => [ "PASSWORD" ] } env: { "clear" => { "PORT" => "3000" }, "secret" => [ "PASSWORD" ] }
}) }) }) })
assert_equal [ "-e", "PASSWORD=secret123", "-e", "PORT=3000" ], config.env_args assert_equal [ "-e", "PASSWORD=secret123", "-e", "PORT=3000" ], config.env_args
@@ -103,8 +103,8 @@ class ConfigurationTest < ActiveSupport::TestCase
test "env args with only secrets" do test "env args with only secrets" do
ENV["PASSWORD"] = "secret123" ENV["PASSWORD"] = "secret123"
config = Mrsk::Configuration.new(@deploy.tap { |c| c.merge!({ config = Mrsk::Configuration.new(@deploy.tap { |c| c.merge!({
env: { "secret" => [ "PASSWORD" ] } env: { "secret" => [ "PASSWORD" ] }
}) }) }) })
assert_equal [ "-e", "PASSWORD=secret123" ], config.env_args assert_equal [ "-e", "PASSWORD=secret123" ], config.env_args
@@ -114,8 +114,8 @@ class ConfigurationTest < ActiveSupport::TestCase
end end
test "env args with missing secret" do test "env args with missing secret" do
config = Mrsk::Configuration.new(@deploy.tap { |c| c.merge!({ config = Mrsk::Configuration.new(@deploy.tap { |c| c.merge!({
env: { "secret" => [ "PASSWORD" ] } env: { "secret" => [ "PASSWORD" ] }
}) }) }) })
assert_raises(KeyError) do assert_raises(KeyError) do
@@ -134,6 +134,9 @@ class ConfigurationTest < ActiveSupport::TestCase
assert_equal "456", @config.master_key assert_equal "456", @config.master_key
end end
test "volumes" do
assert_equal ["--volume /local/path:/container/path"], @config.volumes
end
test "erb evaluation of yml config" do test "erb evaluation of yml config" do
config = Mrsk::Configuration.create_from Pathname.new(File.expand_path("fixtures/deploy.erb.yml", __dir__)) config = Mrsk::Configuration.create_from Pathname.new(File.expand_path("fixtures/deploy.erb.yml", __dir__))
@@ -159,6 +162,6 @@ class ConfigurationTest < ActiveSupport::TestCase
end end
test "to_h" do test "to_h" do
assert_equal({ :roles=>["web"], :hosts=>["1.1.1.1", "1.1.1.2"], :primary_host=>"1.1.1.1", :version=>"missing", :repository=>"dhh/app", :absolute_image=>"dhh/app:missing", :service_with_version=>"app-missing", :env_args=>["-e", "REDIS_URL=redis://x/y"], :ssh_options=>{:user=>"root", :auth_methods=>["publickey"]} }, @config.to_h) assert_equal({ :roles=>["web"], :hosts=>["1.1.1.1", "1.1.1.2"], :primary_host=>"1.1.1.1", :version=>"missing", :repository=>"dhh/app", :absolute_image=>"dhh/app:missing", :service_with_version=>"app-missing", :env_args=>["-e", "REDIS_URL=redis://x/y"], :ssh_options=>{:user=>"root", :auth_methods=>["publickey"]}, :volumes=>["--volume /local/path:/container/path"] }, @config.to_h)
end end
end end