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: https://github.com/ComputeStacks/controller/blob/main/doc/order-flow-docs.md – 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: https://github.com/ComputeStacks/controller/blob/main/app/workers/container_workers/provision_worker.rb
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
rescue Docker::Error::ConflictError => e
For a container, runtime_config is defined here:
For an SFTP/SSH container, it’s defined here:
rescue
false
end
##
# Remove the container and remove port forwarding
def delete_now!(audit)
c = self.docker_client
return true if c.nil?
c.stop
c.delete
rescue => e
return true if e.message =~ /already in progress/
ExceptionAlertService.new(e, '8d81bcafa05a4391').perform
SystemEvent.create!(
message: "Error deleting SFTP container: #{self.name}",
log_level: 'warn',
data: {
'name' => self.name,
'node' => self.node&.id,
'error' => e.message
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)
event = GlobalID::Locator.locate event_id
begin
container = GlobalID::Locator.locate container_id
rescue ActiveRecord::RecordNotFound
event.fail! "Unknown container"
return
end
return unless event.start!
This file has been truncated. show original
Running commands inside of a container
se = SystemEvent.create!(
message: "Docker Connection Error: #{self.node&.region.name}",
log_level: 'warn',
data: { message: nil, count: 0 },
event_code: ec
) if se.nil?
data = se.data
data[:message] = e.message
data[:count] = data[:count] + 1
se.update_attribute :data, data
rescue Excon::Error::Socket => e
# Unable to connect due to _missing_ tls certs on docker
ec = '06daa76c88d5f72a'
se = SystemEvent.find_by(event_code: ec)
se = SystemEvent.create!(
message: "Missing Docker TLS Cert on Node: #{self.node&.region.name}",
log_level: 'warn',
data: { message: nil, count: 0 },
event_code: ec
) if se.nil?
data = se.data