Add role concern with specialized cmds for job running
This commit is contained in:
@@ -9,15 +9,18 @@ class Mrsk::Commands::App < Mrsk::Commands::Base
|
||||
docker :pull, config.absolute_image
|
||||
end
|
||||
|
||||
def run
|
||||
def run(role: :web)
|
||||
role = config.role(role)
|
||||
|
||||
docker :run,
|
||||
"-d",
|
||||
"--restart unless-stopped",
|
||||
"--name", config.service_with_version,
|
||||
"-e", redact("RAILS_MASTER_KEY=#{config.master_key}"),
|
||||
*config.envs,
|
||||
*config.labels,
|
||||
config.absolute_image
|
||||
*config.env_args,
|
||||
*role.label_args,
|
||||
config.absolute_image,
|
||||
role.cmd
|
||||
end
|
||||
|
||||
def start
|
||||
@@ -39,7 +42,7 @@ class Mrsk::Commands::App < Mrsk::Commands::Base
|
||||
def exec(*command)
|
||||
docker :exec,
|
||||
"-e", redact("RAILS_MASTER_KEY=#{config.master_key}"),
|
||||
*config.envs,
|
||||
*config.env_args,
|
||||
config.service_with_version,
|
||||
*command
|
||||
end
|
||||
|
||||
@@ -1,14 +1,21 @@
|
||||
require "active_support/ordered_options"
|
||||
require "active_support/core_ext/string/inquiry"
|
||||
require "erb"
|
||||
|
||||
class Mrsk::Configuration
|
||||
delegate :service, :image, :env, :registry, :ssh_user, to: :config, allow_nil: true
|
||||
delegate :service, :image, :servers, :env, :registry, :ssh_user, to: :config, allow_nil: true
|
||||
|
||||
def self.load_file(file)
|
||||
if file.exist?
|
||||
new YAML.load(ERB.new(IO.read(file)).result).symbolize_keys
|
||||
else
|
||||
raise "Configuration file not found in #{file}"
|
||||
class << self
|
||||
def load_file(file)
|
||||
if file.exist?
|
||||
new YAML.load(ERB.new(IO.read(file)).result).symbolize_keys
|
||||
else
|
||||
raise "Configuration file not found in #{file}"
|
||||
end
|
||||
end
|
||||
|
||||
def argumentize(argument, attributes)
|
||||
attributes.flat_map { |k, v| [ argument, "#{k}=#{v}" ] }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -17,11 +24,39 @@ class Mrsk::Configuration
|
||||
ensure_required_keys_present
|
||||
end
|
||||
|
||||
|
||||
def roles
|
||||
@roles ||= role_names.collect { |role_name| Role.new(role_name, config: self) }
|
||||
end
|
||||
|
||||
def role(name)
|
||||
roles.detect { |r| r.name == name.to_s }
|
||||
end
|
||||
|
||||
def hosts
|
||||
ENV["HOSTS"] || config.servers
|
||||
hosts =
|
||||
case
|
||||
when ENV["HOSTS"]
|
||||
ENV["HOSTS"].split(",")
|
||||
when ENV["ROLES"]
|
||||
role_names = ENV["ROLES"].split(",")
|
||||
roles.select { |r| role_names.include?(r.name) }.flat_map(&:hosts)
|
||||
else
|
||||
roles.flat_map(&:hosts)
|
||||
end
|
||||
|
||||
if hosts.any?
|
||||
hosts
|
||||
else
|
||||
raise ArgumentError, "No hosts found"
|
||||
end
|
||||
end
|
||||
|
||||
def primary_host
|
||||
role(:web).hosts.first
|
||||
end
|
||||
|
||||
|
||||
def version
|
||||
@version ||= ENV["VERSION"] || `git rev-parse HEAD`.strip
|
||||
end
|
||||
@@ -38,18 +73,9 @@ class Mrsk::Configuration
|
||||
"#{service}-#{version}"
|
||||
end
|
||||
|
||||
def envs
|
||||
parameterize "-e", env if env.present?
|
||||
end
|
||||
|
||||
def labels
|
||||
parameterize "--label", \
|
||||
"service" => service,
|
||||
"traefik.http.routers.#{service}.rule" => "'PathPrefix(`/`)'",
|
||||
"traefik.http.services.#{service}.loadbalancer.healthcheck.path" => "/up",
|
||||
"traefik.http.services.#{service}.loadbalancer.healthcheck.interval" => "1s",
|
||||
"traefik.http.middlewares.#{service}.retry.attempts" => "3",
|
||||
"traefik.http.middlewares.#{service}.retry.initialinterval" => "500ms"
|
||||
def env_args
|
||||
self.class.argumentize "-e", config.env if config.env.present?
|
||||
end
|
||||
|
||||
def ssh_options
|
||||
@@ -60,6 +86,7 @@ class Mrsk::Configuration
|
||||
ENV["RAILS_MASTER_KEY"] || File.read(Rails.root.join("config/master.key"))
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
attr_accessor :config
|
||||
|
||||
@@ -73,7 +100,9 @@ class Mrsk::Configuration
|
||||
end
|
||||
end
|
||||
|
||||
def parameterize(param, hash)
|
||||
hash.flat_map { |k, v| [ param, "#{k}=#{v}" ] }
|
||||
def role_names
|
||||
config.servers.is_a?(Array) ? [ "web" ] : config.servers.keys.sort
|
||||
end
|
||||
end
|
||||
|
||||
require "mrsk/configuration/role"
|
||||
|
||||
63
lib/mrsk/configuration/role.rb
Normal file
63
lib/mrsk/configuration/role.rb
Normal file
@@ -0,0 +1,63 @@
|
||||
class Mrsk::Configuration::Role
|
||||
delegate :argumentize, to: Mrsk::Configuration
|
||||
|
||||
attr_accessor :name
|
||||
|
||||
def initialize(name, config:)
|
||||
@name, @config = name.inquiry, config
|
||||
end
|
||||
|
||||
def hosts
|
||||
@hosts ||= extract_hosts_from_config
|
||||
end
|
||||
|
||||
def label_args
|
||||
argumentize "--label", labels
|
||||
end
|
||||
|
||||
def cmd
|
||||
specializations["cmd"]
|
||||
end
|
||||
|
||||
private
|
||||
attr_accessor :config
|
||||
|
||||
def extract_hosts_from_config
|
||||
if config.servers.is_a?(Array)
|
||||
config.servers
|
||||
else
|
||||
servers = config.servers[name]
|
||||
servers.is_a?(Array) ? servers : servers["hosts"]
|
||||
end
|
||||
end
|
||||
|
||||
def labels
|
||||
if name.web?
|
||||
default_labels.merge(traefik_labels)
|
||||
else
|
||||
default_labels
|
||||
end
|
||||
end
|
||||
|
||||
def default_labels
|
||||
{ "service" => config.service, "role" => name }
|
||||
end
|
||||
|
||||
def traefik_labels
|
||||
{
|
||||
"traefik.http.routers.#{config.service}.rule" => "'PathPrefix(`/`)'",
|
||||
"traefik.http.services.#{config.service}.loadbalancer.healthcheck.path" => "/up",
|
||||
"traefik.http.services.#{config.service}.loadbalancer.healthcheck.interval" => "1s",
|
||||
"traefik.http.middlewares.#{config.service}.retry.attempts" => "3",
|
||||
"traefik.http.middlewares.#{config.service}.retry.initialinterval" => "500ms"
|
||||
}
|
||||
end
|
||||
|
||||
def specializations
|
||||
if config.servers.is_a?(Array) || config.servers[name].is_a?(Array)
|
||||
{ }
|
||||
else
|
||||
config.servers[name].without("hosts")
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -19,15 +19,17 @@ namespace :mrsk do
|
||||
|
||||
desc "Run app on servers (or start them if they've already been run)"
|
||||
task :run do
|
||||
on(MRSK_CONFIG.hosts) do |host|
|
||||
begin
|
||||
execute *app.run
|
||||
rescue SSHKit::Command::Failed => e
|
||||
if e.message =~ /already in use/
|
||||
puts "Container with same version already deployed on #{host}, starting that instead"
|
||||
execute *app.start, host: host
|
||||
else
|
||||
raise
|
||||
MRSK_CONFIG.roles.each do |role|
|
||||
on(MRSK_CONFIG.role(role).hosts) do |host|
|
||||
begin
|
||||
execute *app.run(role: role)
|
||||
rescue SSHKit::Command::Failed => e
|
||||
if e.message =~ /already in use/
|
||||
puts "Container with same version already deployed on #{host}, starting that instead"
|
||||
execute *app.start, host: host
|
||||
else
|
||||
raise
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -64,13 +66,13 @@ namespace :mrsk do
|
||||
|
||||
desc "Execute a custom task on the first defined server"
|
||||
task :once do
|
||||
on(MRSK_CONFIG.hosts.first) { |host| puts capture(*app.exec(ENV["CMD"])) }
|
||||
on(MRSK_CONFIG.primary_host) { |host| puts capture(*app.exec(ENV["CMD"])) }
|
||||
end
|
||||
|
||||
namespace :once do
|
||||
desc "Execute Rails command on the first defined server, like CMD='runner \"puts %(Hello World)\""
|
||||
task :rails do
|
||||
on(MRSK_CONFIG.hosts.first) { puts capture(*app.exec("bin/rails", ENV["CMD"])) }
|
||||
on(MRSK_CONFIG.primary_host) { puts capture(*app.exec("bin/rails", ENV["CMD"])) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace :mrsk do
|
||||
namespace :registry do
|
||||
desc "Login to the registry locally and remotely"
|
||||
task :login do
|
||||
run_locally { execute *registry.login }
|
||||
run_locally { execute *registry.login }
|
||||
on(MRSK_CONFIG.hosts) { execute *registry.login }
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user