First
This commit is contained in:
8
lib/mrsk.rb
Normal file
8
lib/mrsk.rb
Normal file
@@ -0,0 +1,8 @@
|
||||
module Mrsk
|
||||
end
|
||||
|
||||
require "mrsk/version"
|
||||
require "mrsk/engine"
|
||||
|
||||
require "mrsk/configuration"
|
||||
require "mrsk/commands"
|
||||
6
lib/mrsk/commands.rb
Normal file
6
lib/mrsk/commands.rb
Normal file
@@ -0,0 +1,6 @@
|
||||
module Mrsk::Commands
|
||||
end
|
||||
|
||||
require "mrsk/commands/app"
|
||||
require "mrsk/commands/traefik"
|
||||
require "mrsk/commands/registry"
|
||||
28
lib/mrsk/commands/app.rb
Normal file
28
lib/mrsk/commands/app.rb
Normal file
@@ -0,0 +1,28 @@
|
||||
class Mrsk::Commands::App
|
||||
attr_accessor :config
|
||||
|
||||
def initialize(config)
|
||||
@config = config
|
||||
end
|
||||
|
||||
def push
|
||||
# TODO: Run 'docker buildx create --use' when needed
|
||||
"docker buildx build --push --platform=linux/amd64,linux/arm64 -t #{config.image_with_version} ."
|
||||
end
|
||||
|
||||
def pull
|
||||
"docker pull #{config.image_with_version}"
|
||||
end
|
||||
|
||||
def start
|
||||
"docker run -d --rm --name #{config.service_with_version} #{config.envs} #{config.labels} #{config.image_with_version}"
|
||||
end
|
||||
|
||||
def stop
|
||||
"docker ps -q --filter label=service=#{config.service} | xargs docker stop"
|
||||
end
|
||||
|
||||
def info
|
||||
"docker ps --filter label=service=#{config.service}"
|
||||
end
|
||||
end
|
||||
10
lib/mrsk/commands/registry.rb
Normal file
10
lib/mrsk/commands/registry.rb
Normal file
@@ -0,0 +1,10 @@
|
||||
class Mrsk::Commands::Registry
|
||||
def login
|
||||
if (user = ENV["DOCKER_USER"]).present? && (password = ENV["DOCKER_PASSWORD"]).present?
|
||||
# FIXME: Find a way to hide PW so it's not shown on terminal
|
||||
"docker login -u #{user} -p #{password}"
|
||||
else
|
||||
raise ArgumentError, "Missing DOCKER_USER or DOCKER_PASSWORD in ENV"
|
||||
end
|
||||
end
|
||||
end
|
||||
17
lib/mrsk/commands/traefik.rb
Normal file
17
lib/mrsk/commands/traefik.rb
Normal file
@@ -0,0 +1,17 @@
|
||||
class Mrsk::Commands::Traefik
|
||||
def start
|
||||
"docker run --name traefik " +
|
||||
"--rm -d " +
|
||||
"-p 80:80 " +
|
||||
"-v /var/run/docker.sock:/var/run/docker.sock " +
|
||||
"traefik --providers.docker"
|
||||
end
|
||||
|
||||
def stop
|
||||
"docker container stop traefik"
|
||||
end
|
||||
|
||||
def info
|
||||
"docker ps --filter name=traefik"
|
||||
end
|
||||
end
|
||||
55
lib/mrsk/configuration.rb
Normal file
55
lib/mrsk/configuration.rb
Normal file
@@ -0,0 +1,55 @@
|
||||
class Mrsk::Configuration
|
||||
attr_accessor :service, :image, :servers, :env, :ssh_user
|
||||
|
||||
def self.load_file(file)
|
||||
if file.exist?
|
||||
new **YAML.load_file(file).symbolize_keys!
|
||||
else
|
||||
raise "Configuration file not found in #{file}"
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(service:, image:, servers:, env: {}, ssh_user: "root")
|
||||
@service, @image, @servers, @env, @ssh_user = service, image, servers, env, ssh_user
|
||||
end
|
||||
|
||||
def servers
|
||||
ENV["SERVERS"] || @servers
|
||||
end
|
||||
|
||||
def version
|
||||
@version ||= ENV["VERSION"] || `git rev-parse HEAD`.strip
|
||||
end
|
||||
|
||||
def image_with_version
|
||||
"#{image}:#{version}"
|
||||
end
|
||||
|
||||
def service_with_version
|
||||
"#{service}-#{version}"
|
||||
end
|
||||
|
||||
def envs
|
||||
parameterize "-e", \
|
||||
{ "RAILS_MASTER_KEY" => master_key }.merge(env)
|
||||
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"
|
||||
end
|
||||
|
||||
private
|
||||
def parameterize(param, hash)
|
||||
hash.collect { |k, v| "#{param} #{k}=#{v}" }.join(" ")
|
||||
end
|
||||
|
||||
def master_key
|
||||
ENV["RAILS_MASTER_KEY"] || File.read(Rails.root.join("config/master.key"))
|
||||
end
|
||||
end
|
||||
4
lib/mrsk/engine.rb
Executable file
4
lib/mrsk/engine.rb
Executable file
@@ -0,0 +1,4 @@
|
||||
module Mrsk
|
||||
class Engine < ::Rails::Engine
|
||||
end
|
||||
end
|
||||
3
lib/mrsk/version.rb
Normal file
3
lib/mrsk/version.rb
Normal file
@@ -0,0 +1,3 @@
|
||||
module Mrsk
|
||||
VERSION = "0.0.1"
|
||||
end
|
||||
31
lib/tasks/mrsk/app.rake
Normal file
31
lib/tasks/mrsk/app.rake
Normal file
@@ -0,0 +1,31 @@
|
||||
require_relative "setup"
|
||||
|
||||
app = Mrsk::Commands::App.new(MRSK_CONFIG)
|
||||
|
||||
namespace :mrsk do
|
||||
namespace :app do
|
||||
desc "Build and push app image to servers"
|
||||
task :push do
|
||||
run_locally { execute app.push }
|
||||
on(MRSK_CONFIG.servers) { execute app.pull }
|
||||
end
|
||||
|
||||
desc "Start app on servers"
|
||||
task :start do
|
||||
on(MRSK_CONFIG.servers) { execute app.start }
|
||||
end
|
||||
|
||||
desc "Stop app on servers"
|
||||
task :stop do
|
||||
on(MRSK_CONFIG.servers) { execute app.stop, raise_on_non_zero_exit: false }
|
||||
end
|
||||
|
||||
desc "Restart app on servers"
|
||||
task restart: %i[ stop start ]
|
||||
|
||||
desc "Display information about app containers"
|
||||
task :info do
|
||||
on(MRSK_CONFIG.servers) { |host| puts "Host: #{host}\n" + capture(app.info) + "\n\n" }
|
||||
end
|
||||
end
|
||||
end
|
||||
12
lib/tasks/mrsk/mrsk.rake
Normal file
12
lib/tasks/mrsk/mrsk.rake
Normal file
@@ -0,0 +1,12 @@
|
||||
namespace :mrsk do
|
||||
desc "Push the latest version of the app, ensure Traefik is running, then restart app"
|
||||
task deploy: [ "app:push", "traefik:start", "app:restart" ]
|
||||
|
||||
desc "Display information about Traefik and app containers"
|
||||
task info: [ "traefik:info", "app:info" ]
|
||||
|
||||
desc "Create config stub"
|
||||
task :init do
|
||||
Rails.root.join("config/deploy.yml")
|
||||
end
|
||||
end
|
||||
17
lib/tasks/mrsk/registry.rake
Normal file
17
lib/tasks/mrsk/registry.rake
Normal file
@@ -0,0 +1,17 @@
|
||||
require_relative "setup"
|
||||
|
||||
registry = Mrsk::Commands::Registry.new
|
||||
|
||||
namespace :mrsk do
|
||||
namespace :registry do
|
||||
desc "Login to the registry using ENV['DOCKER_USER'] and ENV['DOCKER_PASSWORD']"
|
||||
task :login do
|
||||
if ENV["DOCKER_USER"].present? && ENV["DOCKER_PASSWORD"].present?
|
||||
run_locally { execute registry.login }
|
||||
on(MRSK_CONFIG.servers) { execute registry.login }
|
||||
else
|
||||
puts "Skipping login due to missing ENV['DOCKER_USER'] and ENV['DOCKER_PASSWORD']"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
10
lib/tasks/mrsk/setup.rb
Normal file
10
lib/tasks/mrsk/setup.rb
Normal file
@@ -0,0 +1,10 @@
|
||||
require "sshkit"
|
||||
require "sshkit/dsl"
|
||||
|
||||
include SSHKit::DSL
|
||||
|
||||
MRSK_CONFIG = Mrsk::Configuration.load_file(Rails.root.join("config/deploy.yml"))
|
||||
|
||||
SSHKit::Backend::Netssh.configure do |ssh|
|
||||
ssh.ssh_options = { user: MRSK_CONFIG.ssh_user, auth_methods: [ "publickey" ] }
|
||||
end
|
||||
25
lib/tasks/mrsk/traefik.rake
Normal file
25
lib/tasks/mrsk/traefik.rake
Normal file
@@ -0,0 +1,25 @@
|
||||
require_relative "setup"
|
||||
|
||||
traefik = Mrsk::Commands::Traefik.new
|
||||
|
||||
namespace :mrsk do
|
||||
namespace :traefik do
|
||||
desc "Start Traefik"
|
||||
task :start do
|
||||
on(MRSK_CONFIG.servers) { execute traefik.start, raise_on_non_zero_exit: false }
|
||||
end
|
||||
|
||||
desc "Stop Traefik"
|
||||
task :stop do
|
||||
on(MRSK_CONFIG.servers) { execute traefik.stop, raise_on_non_zero_exit: false }
|
||||
end
|
||||
|
||||
desc "Restart Traefik"
|
||||
task restart: %i[ stop start ]
|
||||
|
||||
desc "Display information about Traefik containers"
|
||||
task :info do
|
||||
on(MRSK_CONFIG.servers) { |host| puts "Host: #{host}\n" + capture(traefik.info) + "\n\n" }
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user