Files
kamal/lib/kamal/commands/accessory.rb
Donal McBreen 94bf090657 Copy env files to remote hosts
Setting env variables in the docker arguments requires having them on
the deploy host.

Instead we'll add two new commands `kamal env push` and
`kamal env delete` which will manage copying the environment as .env
files to the remote host.

Docker will pick up the file with `--env-file <path-to-file>`. Env files
will be stored under `<kamal run directory>/env`.

Running `kamal env push` will create env files for each role and
accessory, and traefik if required.

`kamal envify` has been updated to also push the env files.

By avoiding using `kamal envify` and creating the local and remote
secrets manually, you can now avoid accessing secrets needed
for the docker runtime environment locally. You will still need build
secrets.

One thing to note - the Docker doesn't parse the environment variables
in the env file, one result of this is that you can't specify multi-line
values - see https://github.com/moby/moby/issues/12997.

We maybe need to look docker config or docker secrets longer term to get
around this.

Hattip to @kevinmcconnell - this was all his idea.
2023-09-06 14:33:13 +01:00

114 lines
2.5 KiB
Ruby

class Kamal::Commands::Accessory < Kamal::Commands::Base
attr_reader :accessory_config
delegate :service_name, :image, :hosts, :port, :files, :directories, :cmd,
:publish_args, :env_args, :volume_args, :label_args, :option_args, to: :accessory_config
def initialize(config, name:)
super(config)
@accessory_config = config.accessory(name)
end
def run
docker :run,
"--name", service_name,
"--detach",
"--restart", "unless-stopped",
*config.logging_args,
*publish_args,
*env_args,
*volume_args,
*label_args,
*option_args,
image,
cmd
end
def start
docker :container, :start, service_name
end
def stop
docker :container, :stop, service_name
end
def info
docker :ps, *service_filter
end
def logs(since: nil, lines: nil, grep: nil)
pipe \
docker(:logs, service_name, (" --since #{since}" if since), (" --tail #{lines}" if lines), "--timestamps", "2>&1"),
("grep '#{grep}'" if grep)
end
def follow_logs(grep: nil)
run_over_ssh \
pipe \
docker(:logs, service_name, "--timestamps", "--tail", "10", "--follow", "2>&1"),
(%(grep "#{grep}") if grep)
end
def execute_in_existing_container(*command, interactive: false)
docker :exec,
("-it" if interactive),
service_name,
*command
end
def execute_in_new_container(*command, interactive: false)
docker :run,
("-it" if interactive),
"--rm",
*env_args,
*volume_args,
image,
*command
end
def execute_in_existing_container_over_ssh(*command)
run_over_ssh execute_in_existing_container(*command, interactive: true)
end
def execute_in_new_container_over_ssh(*command)
run_over_ssh execute_in_new_container(*command, interactive: true)
end
def run_over_ssh(command)
super command, host: hosts.first
end
def ensure_local_file_present(local_file)
if !local_file.is_a?(StringIO) && !Pathname.new(local_file).exist?
raise "Missing file: #{local_file}"
end
end
def remove_service_directory
[ :rm, "-rf", service_name ]
end
def remove_container
docker :container, :prune, "--force", *service_filter
end
def remove_image
docker :image, :rm, "--force", image
end
def make_env_directory
make_directory accessory_config.host_env_directory
end
def remove_env_file
[:rm, "-f", accessory_config.host_env_file_path]
end
private
def service_filter
[ "--filter", "label=service=#{service_name}" ]
end
end