Responding to a direct message question sent to me:
I have read the source code. I couldn’t find the part how it communicates with the OS and docker. Can you share links for related files?
First off, I should mention that I recommend using an IDE that allows for quick navigation to defined variables, methods, classes, etc. I use RubyMine, but there are many others that can support this through plugins (vscode, sublime, vim, emacs, etc). That way as you’re exploring the source code, you can quickly find where something is defined. Even GitHub’s web UI has some limited support for this.
There is no single file that handles all docker communication. Instead, you’ll want to inspect the Deployment::Container model to understand all it’s attributes and methods.
To see how a container is provisioned, please reference this doc: controller/order-flow-docs.md at main · ComputeStacks/controller · GitHub – each bullet point is a separate class/file.
If the class ends in Service , then you’ll find it under app/services. If it ends in Worker , then you’ll find it under app/workers.
To answer your question about how we talk to Docker, we use a combination of services, workers, and model methods.
Examples:
Creating a container:
This is kicked off by our ContainerWorkers::ProvisionWorker job: controller/provision_worker.rb at main · ComputeStacks/controller · GitHub
Container is built here:
def metadata_env_params
[
%W(METADATA_SERVICE http://metadata.internal:8500/v1/kv/projects/#{deployment.token}),
%W(METADATA_URL http://metadata.internal:8500/v1/kv/projects/#{deployment.token}/metadata?raw=true),
%W(METADATA_AUTH #{deployment.consul_auth_key})
]
end
# This is used by both Container and SFTP.
def build!(event)
build_client = if self.kind_of? Deployment::Container
runtime_config event&.audit
elsif self.kind_of? Deployment::Sftp
build_command
else
nil
end
return false if build_client.nil?
Docker::Container.create(build_client, node.client).is_a? Docker::Container
end
For a container, runtime_config is defined here:
For an SFTP/SSH container, it’s defined here:
audit: audit,
event_code: '8d81bcafa05a4391'
)
false
else
true
ensure
NetworkWorkers::TrashPolicyWorker.perform_async(region.id, name) if region
end
def build_command
# Generate ingress rule
setup_ingress_rule! if ingress_rule.nil?
# Ensure we are able to get an IP
return nil if local_ip.blank?
return nil if deployment.nil?
loki_labels = ['container_name={{.Name}}']
Once it’s built, we start it using the StartWorker:
module ContainerWorkers
class StartWorker
include Sidekiq::Worker
sidekiq_options retry: 1
# @param [String] container_id Global ID
# @param [String] event_id Global
def perform(container_id, event_id)
return if event_id.nil?
container = GlobalID::Locator.locate container_id
event = GlobalID::Locator.locate event_id
return unless event.start!
result = Timeout::timeout(30) do
container.start! event
end
if result
This file has been truncated. show original
Running commands inside of a container
data = se.data
data[:message] = e.message
data[:count] = data[:count] + 1
se.update_attribute :data, data
rescue
nil
end
# @param [Array] command
# @param [EventLog] event
def container_exec!(command, event, timeout = 10)
result = []
docker_client.exec(command, wait: timeout) do |f,d|
result << d
end
event.event_details.create!(
event_code: '',
data: result.join('')
)
end