Find the first registry mirror on each host. If we find any, pull the images on one host per mirror, then do the remainder concurrently. The initial pulls will seed the mirrors ensuring that we pull the image from Docker Hub once each. This works best if there is only one mirror on each host.
95 lines
2.2 KiB
Ruby
95 lines
2.2 KiB
Ruby
|
|
class Kamal::Commands::Builder::Base < Kamal::Commands::Base
|
|
class BuilderError < StandardError; end
|
|
|
|
ENDPOINT_DOCKER_HOST_INSPECT = "'{{.Endpoints.docker.Host}}'"
|
|
|
|
delegate :argumentize, to: Kamal::Utils
|
|
delegate :args, :secrets, :dockerfile, :target, :local_arch, :local_host, :remote_arch, :remote_host, :cache_from, :cache_to, :ssh, to: :builder_config
|
|
|
|
def clean
|
|
docker :image, :rm, "--force", config.absolute_image
|
|
end
|
|
|
|
def pull
|
|
docker :pull, config.absolute_image
|
|
end
|
|
|
|
def build_options
|
|
[ *build_tags, *build_cache, *build_labels, *build_args, *build_secrets, *build_dockerfile, *build_target, *build_ssh ]
|
|
end
|
|
|
|
def build_context
|
|
config.builder.context
|
|
end
|
|
|
|
def validate_image
|
|
pipe \
|
|
docker(:inspect, "-f", "'{{ .Config.Labels.service }}'", config.absolute_image),
|
|
any(
|
|
[ :grep, "-x", config.service ],
|
|
"(echo \"Image #{config.absolute_image} is missing the 'service' label\" && exit 1)"
|
|
)
|
|
end
|
|
|
|
def context_hosts
|
|
:true
|
|
end
|
|
|
|
def config_context_hosts
|
|
[]
|
|
end
|
|
|
|
def first_mirror
|
|
docker(:info, "--format '{{index .RegistryConfig.Mirrors 0}}'")
|
|
end
|
|
|
|
private
|
|
def build_tags
|
|
[ "-t", config.absolute_image, "-t", config.latest_image ]
|
|
end
|
|
|
|
def build_cache
|
|
if cache_to && cache_from
|
|
[ "--cache-to", cache_to,
|
|
"--cache-from", cache_from ]
|
|
end
|
|
end
|
|
|
|
def build_labels
|
|
argumentize "--label", { service: config.service }
|
|
end
|
|
|
|
def build_args
|
|
argumentize "--build-arg", args, sensitive: true
|
|
end
|
|
|
|
def build_secrets
|
|
argumentize "--secret", secrets.collect { |secret| [ "id", secret ] }
|
|
end
|
|
|
|
def build_dockerfile
|
|
if Pathname.new(File.expand_path(dockerfile)).exist?
|
|
argumentize "--file", dockerfile
|
|
else
|
|
raise BuilderError, "Missing #{dockerfile}"
|
|
end
|
|
end
|
|
|
|
def build_target
|
|
argumentize "--target", target if target.present?
|
|
end
|
|
|
|
def build_ssh
|
|
argumentize "--ssh", ssh if ssh.present?
|
|
end
|
|
|
|
def builder_config
|
|
config.builder
|
|
end
|
|
|
|
def context_host(builder_name)
|
|
docker :context, :inspect, builder_name, "--format", ENDPOINT_DOCKER_HOST_INSPECT
|
|
end
|
|
end
|