Merge pull request #981 from igor-alexandrov/proxy-accessories
Proxy for accessories
This commit is contained in:
@@ -18,6 +18,11 @@ class Kamal::Cli::Accessory < Kamal::Cli::Base
|
||||
execute *accessory.ensure_env_directory
|
||||
upload! accessory.secrets_io, accessory.secrets_path, mode: "0600"
|
||||
execute *accessory.run
|
||||
|
||||
if accessory.running_proxy?
|
||||
target = capture_with_info(*accessory.container_id_for(container_name: accessory.service_name, only_running: true)).strip
|
||||
execute *accessory.deploy(target: target)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -75,6 +80,10 @@ class Kamal::Cli::Accessory < Kamal::Cli::Base
|
||||
on(hosts) do
|
||||
execute *KAMAL.auditor.record("Started #{name} accessory"), verbosity: :debug
|
||||
execute *accessory.start
|
||||
if accessory.running_proxy?
|
||||
target = capture_with_info(*accessory.container_id_for(container_name: accessory.service_name, only_running: true)).strip
|
||||
execute *accessory.deploy(target: target)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -87,6 +96,11 @@ class Kamal::Cli::Accessory < Kamal::Cli::Base
|
||||
on(hosts) do
|
||||
execute *KAMAL.auditor.record("Stopped #{name} accessory"), verbosity: :debug
|
||||
execute *accessory.stop, raise_on_non_zero_exit: false
|
||||
|
||||
if accessory.running_proxy?
|
||||
target = capture_with_info(*accessory.container_id_for(container_name: accessory.service_name, only_running: true)).strip
|
||||
execute *accessory.remove if target
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
class Kamal::Commands::Accessory < Kamal::Commands::Base
|
||||
include Proxy
|
||||
|
||||
attr_reader :accessory_config
|
||||
delegate :service_name, :image, :hosts, :port, :files, :directories, :cmd,
|
||||
:network_args, :publish_args, :env_args, :volume_args, :label_args, :option_args,
|
||||
:secrets_io, :secrets_path, :env_directory,
|
||||
:secrets_io, :secrets_path, :env_directory, :proxy, :running_proxy?,
|
||||
to: :accessory_config
|
||||
delegate :proxy_container_name, to: :config
|
||||
|
||||
|
||||
def initialize(config, name:)
|
||||
super(config)
|
||||
|
||||
16
lib/kamal/commands/accessory/proxy.rb
Normal file
16
lib/kamal/commands/accessory/proxy.rb
Normal file
@@ -0,0 +1,16 @@
|
||||
module Kamal::Commands::Accessory::Proxy
|
||||
delegate :proxy_container_name, to: :config
|
||||
|
||||
def deploy(target:)
|
||||
proxy_exec :deploy, service_name, *proxy.deploy_command_args(target: target)
|
||||
end
|
||||
|
||||
def remove
|
||||
proxy_exec :remove, service_name
|
||||
end
|
||||
|
||||
private
|
||||
def proxy_exec(*command)
|
||||
docker :exec, proxy_container_name, "kamal-proxy", *command
|
||||
end
|
||||
end
|
||||
@@ -5,7 +5,7 @@ class Kamal::Configuration::Accessory
|
||||
|
||||
delegate :argumentize, :optionize, to: Kamal::Utils
|
||||
|
||||
attr_reader :name, :accessory_config, :env
|
||||
attr_reader :name, :accessory_config, :env, :proxy
|
||||
|
||||
def initialize(name, config:)
|
||||
@name, @config, @accessory_config = name.inquiry, config, config.raw_config["accessories"][name]
|
||||
@@ -20,6 +20,8 @@ class Kamal::Configuration::Accessory
|
||||
config: accessory_config.fetch("env", {}),
|
||||
secrets: config.secrets,
|
||||
context: "accessories/#{name}/env"
|
||||
|
||||
initialize_proxy if running_proxy?
|
||||
end
|
||||
|
||||
def service_name
|
||||
@@ -106,6 +108,17 @@ class Kamal::Configuration::Accessory
|
||||
accessory_config["cmd"]
|
||||
end
|
||||
|
||||
def running_proxy?
|
||||
@accessory_config["proxy"].present?
|
||||
end
|
||||
|
||||
def initialize_proxy
|
||||
@proxy = Kamal::Configuration::Proxy.new \
|
||||
config: config,
|
||||
proxy_config: accessory_config["proxy"],
|
||||
context: "accessories/#{name}/proxy"
|
||||
end
|
||||
|
||||
private
|
||||
attr_accessor :config
|
||||
|
||||
|
||||
@@ -98,3 +98,7 @@ accessories:
|
||||
# Defaults to kamal:
|
||||
network: custom
|
||||
|
||||
# Proxy
|
||||
#
|
||||
proxy:
|
||||
...
|
||||
@@ -39,7 +39,10 @@ class CommandsAccessoryTest < ActiveSupport::TestCase
|
||||
"busybox" => {
|
||||
"service" => "custom-busybox",
|
||||
"image" => "busybox:latest",
|
||||
"host" => "1.1.1.7"
|
||||
"host" => "1.1.1.7",
|
||||
"proxy" => {
|
||||
"host" => "busybox.example.com"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -166,6 +169,18 @@ class CommandsAccessoryTest < ActiveSupport::TestCase
|
||||
new_command(:mysql).remove_image.join(" ")
|
||||
end
|
||||
|
||||
test "deploy" do
|
||||
assert_equal \
|
||||
"docker exec kamal-proxy kamal-proxy deploy custom-busybox --target=\"172.1.0.2:80\" --host=\"busybox.example.com\" --deploy-timeout=\"30s\" --drain-timeout=\"30s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"",
|
||||
new_command(:busybox).deploy(target: "172.1.0.2").join(" ")
|
||||
end
|
||||
|
||||
test "remove" do
|
||||
assert_equal \
|
||||
"docker exec kamal-proxy kamal-proxy remove custom-busybox",
|
||||
new_command(:busybox).remove.join(" ")
|
||||
end
|
||||
|
||||
private
|
||||
def new_command(accessory)
|
||||
Kamal::Commands::Accessory.new(Kamal::Configuration.new(@config), name: accessory)
|
||||
|
||||
@@ -63,6 +63,9 @@ class ConfigurationAccessoryTest < ActiveSupport::TestCase
|
||||
"options" => {
|
||||
"cpus" => "4",
|
||||
"memory" => "2GB"
|
||||
},
|
||||
"proxy" => {
|
||||
"host" => "monitoring.example.com"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -161,4 +164,9 @@ class ConfigurationAccessoryTest < ActiveSupport::TestCase
|
||||
@deploy[:accessories]["mysql"]["network"] = "database"
|
||||
assert_equal [ "--network", "database" ], @config.accessory(:mysql).network_args
|
||||
end
|
||||
|
||||
test "proxy" do
|
||||
assert @config.accessory(:monitoring).running_proxy?
|
||||
assert_equal [ "monitoring.example.com" ], @config.accessory(:monitoring).proxy.hosts
|
||||
end
|
||||
end
|
||||
|
||||
@@ -20,6 +20,7 @@ COPY *.sh .
|
||||
COPY app/ app/
|
||||
COPY app_with_roles/ app_with_roles/
|
||||
COPY app_with_traefik/ app_with_traefik/
|
||||
COPY app_with_proxied_accessory/ app_with_proxied_accessory/
|
||||
|
||||
RUN rm -rf /root/.ssh
|
||||
RUN ln -s /shared/ssh /root/.ssh
|
||||
@@ -30,6 +31,7 @@ RUN git config --global user.name "Deployer"
|
||||
RUN cd app && git init && git add . && git commit -am "Initial version"
|
||||
RUN cd app_with_roles && git init && git add . && git commit -am "Initial version"
|
||||
RUN cd app_with_traefik && git init && git add . && git commit -am "Initial version"
|
||||
RUN cd app_with_proxied_accessory && git init && git add . && git commit -am "Initial version"
|
||||
|
||||
HEALTHCHECK --interval=1s CMD pgrep sleep
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
FROM registry:4443/nginx:1-alpine-slim
|
||||
|
||||
COPY default.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
ARG COMMIT_SHA
|
||||
RUN echo $COMMIT_SHA > /usr/share/nginx/html/version
|
||||
RUN mkdir -p /usr/share/nginx/html/versions && echo "version" > /usr/share/nginx/html/versions/$COMMIT_SHA
|
||||
RUN mkdir -p /usr/share/nginx/html/versions && echo "hidden" > /usr/share/nginx/html/versions/.hidden
|
||||
RUN echo "Up!" > /usr/share/nginx/html/up
|
||||
@@ -0,0 +1,44 @@
|
||||
service: app_with_proxied_accessory
|
||||
image: app_with_proxied_accessory
|
||||
servers:
|
||||
- vm1
|
||||
env:
|
||||
clear:
|
||||
CLEAR_TOKEN: 4321
|
||||
CLEAR_TAG: ""
|
||||
HOST_TOKEN: "${HOST_TOKEN}"
|
||||
asset_path: /usr/share/nginx/html/versions
|
||||
proxy:
|
||||
host: 127.0.0.1
|
||||
registry:
|
||||
server: registry:4443
|
||||
username: root
|
||||
password: root
|
||||
builder:
|
||||
driver: docker
|
||||
arch: <%= Kamal::Utils.docker_arch %>
|
||||
args:
|
||||
COMMIT_SHA: <%= `git rev-parse HEAD` %>
|
||||
accessories:
|
||||
busybox:
|
||||
service: custom-busybox
|
||||
image: registry:4443/busybox:1.36.0
|
||||
cmd: sh -c 'echo "Starting busybox..."; trap exit term; while true; do sleep 1; done'
|
||||
roles:
|
||||
- web
|
||||
netcat:
|
||||
service: netcat
|
||||
image: registry:4443/busybox:1.36.0
|
||||
cmd: >
|
||||
sh -c 'echo "Starting netcat..."; while true; do echo -e "HTTP/1.1 200 OK\r\nContent-Length: 11\r\n\r\nHello Ruby" | nc -l -p 80; done'
|
||||
roles:
|
||||
- web
|
||||
port: 12345:80
|
||||
proxy:
|
||||
host: netcat
|
||||
ssl: false
|
||||
healthcheck:
|
||||
interval: 1
|
||||
timeout: 1
|
||||
path: "/"
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name localhost;
|
||||
|
||||
location / {
|
||||
root /usr/share/nginx/html;
|
||||
index index.html index.htm;
|
||||
}
|
||||
|
||||
# redirect server error pages to the static page /50x.html
|
||||
#
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
location = /50x.html {
|
||||
root /usr/share/nginx/html;
|
||||
}
|
||||
}
|
||||
63
test/integration/proxied_accessory_test.rb
Normal file
63
test/integration/proxied_accessory_test.rb
Normal file
@@ -0,0 +1,63 @@
|
||||
require_relative "integration_test"
|
||||
|
||||
class ProxiedAccessoryTest < IntegrationTest
|
||||
test "boot, stop, start, restart, logs, remove" do
|
||||
@app = "app_with_proxied_accessory"
|
||||
|
||||
kamal :deploy
|
||||
|
||||
kamal :accessory, :boot, :netcat
|
||||
assert_accessory_running :netcat
|
||||
assert_netcat_is_up
|
||||
|
||||
kamal :accessory, :stop, :netcat
|
||||
assert_accessory_not_running :netcat
|
||||
assert_netcat_not_found
|
||||
|
||||
kamal :accessory, :start, :netcat
|
||||
assert_accessory_running :netcat
|
||||
assert_netcat_is_up
|
||||
|
||||
kamal :accessory, :restart, :netcat
|
||||
assert_accessory_running :netcat
|
||||
assert_netcat_is_up
|
||||
|
||||
kamal :accessory, :remove, :netcat, "-y"
|
||||
assert_accessory_not_running :netcat
|
||||
assert_netcat_not_found
|
||||
end
|
||||
|
||||
private
|
||||
def assert_accessory_running(name)
|
||||
assert_match /registry:4443\/busybox:1.36.0 "sh -c 'echo \\"Start/, accessory_details(name)
|
||||
end
|
||||
|
||||
def assert_accessory_not_running(name)
|
||||
assert_no_match /registry:4443\/busybox:1.36.0 "sh -c 'echo \\"Start/, accessory_details(name)
|
||||
end
|
||||
|
||||
def accessory_details(name)
|
||||
kamal :accessory, :details, name, capture: true
|
||||
end
|
||||
|
||||
def assert_netcat_is_up
|
||||
response = netcat_response
|
||||
debug_response_code(response, "200")
|
||||
assert_equal "200", response.code
|
||||
end
|
||||
|
||||
def assert_netcat_not_found
|
||||
response = netcat_response
|
||||
debug_response_code(response, "404")
|
||||
assert_equal "404", response.code
|
||||
end
|
||||
|
||||
def netcat_response
|
||||
uri = URI.parse("http://127.0.0.1:12345/up")
|
||||
http = Net::HTTP.new(uri.host, uri.port)
|
||||
request = Net::HTTP::Get.new(uri)
|
||||
request["Host"] = "netcat"
|
||||
|
||||
http.request(request)
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user