Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Configure dns replicas #30

Merged
merged 11 commits into from
Mar 6, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion cluster.example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ hosts:
private_address: 10.10.1.3
role: worker
network:
dns_replicas: 3
service_cidr: 10.96.0.0/12
pod_network_cidr: 10.32.0.0/12
trusted_subnets:
Expand All @@ -31,4 +32,4 @@ addons:
enabled: true
interval: 7d
kured:
enabled: true
enabled: true
15 changes: 14 additions & 1 deletion lib/kupo/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,21 @@

module Kupo
class Config < Dry::Struct
HOSTS_PER_DNS_REPLICA = 10

attribute :hosts, Types::Coercible::Array.of(Kupo::Configuration::Host)
attribute :network, Kupo::Configuration::Network
attribute :addons, Kupo::Types::Hash

# @return [Integer]
def dns_replicas
if network.dns_replicas
return network.dns_replicas
elsif hosts.length == 1
return 1
else
return 1 + (hosts.length / HOSTS_PER_DNS_REPLICA.to_f).ceil
end
end
end
end
end
14 changes: 13 additions & 1 deletion lib/kupo/config_schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ class ConfigSchema
# @return [Dry::Validation::Schema]
def self.build
Dry::Validation.Form do
configure do
def self.messages
super.merge(
en: { errors: {network_dns_replicas: "network.dns_replicas cannot be larger than the number of hosts"}}
)
end
end
required(:hosts).each do
schema do
required(:address).filled
Expand All @@ -18,12 +25,17 @@ def self.build
end
end
optional(:network).schema do
optional(:dns_replicas).filled(:int?, gt?: 0)
optional(:service_cidr).filled(:str?)
optional(:pod_network_cidr).filled(:str?)
optional(:trusted_subnets).each(type?: String)
end
optional(:addons).filled

validate(network_dns_replicas: [:network, :hosts]) do |network, hosts|
!network[:dns_replicas] || network[:dns_replicas] <= hosts.length
end
end
end
end
end
end
3 changes: 2 additions & 1 deletion lib/kupo/configuration/network.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ module Kupo::Configuration
class Network < Dry::Struct
constructor_type :schema

attribute :dns_replicas, Kupo::Types::Int
attribute :service_cidr, Kupo::Types::String.default('10.96.0.0/12')
attribute :pod_network_cidr, Kupo::Types::String.default('10.32.0.0/12')
attribute :trusted_subnets, Kupo::Types::Array.member(Kupo::Types::String)
end
end
end
47 changes: 40 additions & 7 deletions lib/kupo/kube.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,38 @@ def entities
@entities
end

def entity_for_resource(resource)
name = Kubeclient::ClientMixin.underscore_entity(resource.kind.to_s)
definition = entities[name]

fail "Unknown entity for resource #{resource.kind} => #{name}" unless definition

definition
end

def apis(options= {})
response = rest_client.get(@headers)
format_response(options[:as] || @as, response.body)
end

# @param resource [Kubeclient::Resource]
# @return [Kubeclient::Resource]
def update_resource(resource)
definition = entity_for_resource(resource)

old_resource = get_entity(definition.resource_name, resource.metadata.name, resource.metadata.namespace)
resource.metadata.resourceVersion = old_resource.metadata.resourceVersion
merged_resource = Kubeclient::Resource.new(old_resource.to_h.deep_merge!(resource.to_h, {overwrite_arrays: true}))
update_entity(definition.resource_name, merged_resource)
end

# @param resource [Kubeclient::Resource]
# @return [Kubeclient::Resource]
def create_resource(resource)
definition = entity_for_resource(resource)

create_entity(resource.kind, definition.resource_name, resource)
end
end

RESOURCE_LABEL = 'kupo.kontena.io/stack'.freeze
Expand Down Expand Up @@ -100,17 +128,22 @@ def self.prune_stack(host, stack, checksum)
# @return [Kubeclient::Resource]
def self.apply_resource(host, resource)
resource_client = self.client(host, resource.apiVersion)

begin
definition = resource_client.entities[underscore_entity(resource.kind.to_s)]
old_resource = resource_client.get_entity(definition.resource_name, resource.metadata.name, resource.metadata.namespace)
resource.metadata.resourceVersion = old_resource.metadata.resourceVersion
merged_resource = Kubeclient::Resource.new(old_resource.to_h.deep_merge!(resource.to_h, {overwrite_arrays: true}))
resource_client.update_entity(definition.resource_name, merged_resource)
resource_client.update_resource(resource)
rescue Kubeclient::ResourceNotFoundError
resource_client.create_entity(resource.kind, definition.resource_name, resource)
resource_client.create_resource(resource)
end
end

# @param host [String]
# @param resource [Kubeclient::Resource]
# @return [Kubeclient::Resource]
def self.update_resource(host, resource)
resource_client = self.client(host, resource.apiVersion)
resource_client.update_resource(resource)
end

# @param host [String]
# @param resource [Kubeclient::Resource]
# @return [Kubeclient::Resource]
Expand Down Expand Up @@ -149,4 +182,4 @@ def self.parse_resource_file(path, vars = {})
def self.underscore_entity(kind)
Kubeclient::ClientMixin.underscore_entity(kind.to_s)
end
end
end
3 changes: 2 additions & 1 deletion lib/kupo/phases/configure_client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
module Kupo::Phases
class ConfigureClient < Base

# @param master [Kupo::Configuration::Host]
def initialize(master)
@master = master
end
Expand All @@ -26,4 +27,4 @@ def config_dir
File.join(Dir.home, '.kupo')
end
end
end
end
99 changes: 99 additions & 0 deletions lib/kupo/phases/configure_dns.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
require_relative 'base'

module Kupo::Phases
class ConfigureDNS < Base
# @param master [Kupo::Configuration::Node]
# @param config [Kupo::Config]
def initialize(master, config)
@master = master
@config = config
end

def call
patch_kubedns(
replicas: @config.dns_replicas,
max_surge: self.max_surge,
max_unavailable: self.max_unavailable,
)
end

# @return [Integer]
def max_surge
replicas = @config.dns_replicas
nodes = @config.hosts.length

if replicas == nodes
# cannot create any extra replicas
0
elsif nodes <= replicas * 1.5
# at most one per extra node
nodes - replicas
else
# half
(replicas * 0.5).floor
end
end

# @return [Integer]
def max_unavailable
replicas = @config.dns_replicas

if replicas == 1
# must allow taking down all replicas
1
else
# half
(replicas * 0.5).floor
end
end

# @param replicas [Integer]
# @param nodes [Integer]
def patch_kubedns(replicas: , max_surge: , max_unavailable: )
logger.info(@master.address) { "Patching kube-dns addon with #{replicas} replicas (max-surge #{max_surge}, max-unavailable #{max_unavailable})..." }

kube_client = Kupo::Kube.update_resource(@master.address, Kubeclient::Resource.new({
apiVersion: 'extensions/v1beta1',
kind: 'Deployment',
metadata: {
namespace: 'kube-system',
name: 'kube-dns',
},
spec: {
replicas: replicas,
strategy: {
type: "RollingUpdate",
rollingUpdate: {
maxSurge: max_surge, # must be zero for a two-node cluster
maxUnavailable: max_unavailable, # must be at least one, even for a single-node cluster
},
},
template: {
spec: {
affinity: {
podAntiAffinity: {
requiredDuringSchedulingIgnoredDuringExecution: [
{
labelSelector: {
matchExpressions: [
{
key: "k8s-app",
operator: "In",
values: [
"kube-dns",
],
},
],
},
topologyKey: "kubernetes.io/hostname",
},
],
},
},
},
},
},
}))
end
end
end
3 changes: 2 additions & 1 deletion lib/kupo/phases/configure_host.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class ConfigureHost < Base
name: 'kubernetes', version: '1.9.3', license: 'Apache License 2.0'
))

# @param host [Kupo::Configuration::Host]
def initialize(host)
@host = host
@ssh = Kupo::SSH::Client.for_host(@host)
Expand Down Expand Up @@ -41,4 +42,4 @@ def exec_script(script)
end
end
end
end
end
4 changes: 2 additions & 2 deletions lib/kupo/phases/configure_kubelet.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ class ConfigureKubelet < Base

DROPIN_PATH = "/etc/systemd/system/kubelet.service.d/5-kupo.conf".freeze

# @param master [Kupo::Configuration::Host]
# @param host [Kupo::Configuration::Host]
def initialize(host)
@host = host
@ssh = Kupo::SSH::Client.for_host(@host)
Expand Down Expand Up @@ -37,4 +37,4 @@ def build_systemd_dropin
config + args.join(' ') + "'"
end
end
end
end
4 changes: 3 additions & 1 deletion lib/kupo/phases/configure_master.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
module Kupo::Phases
class ConfigureMaster < Base

# @param master [Kupo::Configuration::Host]
# @param config [Kupo::Configuration::Network]
def initialize(master, config)
@master = master
@config = config
Expand Down Expand Up @@ -68,4 +70,4 @@ def upgrade
end
end
end
end
end
3 changes: 2 additions & 1 deletion lib/kupo/phases/configure_metrics.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class ConfigureMetrics < Base
name: 'heapster', version: '1.5.1', license: 'Apache License 2.0'
))

# @param master [Kupo::Configuration::Host]
def initialize(master)
@master = master
end
Expand All @@ -22,4 +23,4 @@ def call
Kupo::Kube.apply_stack(@master.address, 'heapster', {version: '1.5.1'})
end
end
end
end
4 changes: 3 additions & 1 deletion lib/kupo/phases/configure_network.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ class ConfigureNetwork < Base
name: 'weave', version: '2.2.0', license: 'Apache License 2.0'
))

# @param master [Kupo::Configuration::Host]
# @param config [Kupo::Configuration::Network]
def initialize(master, config)
@master = master
@config = config
Expand Down Expand Up @@ -49,4 +51,4 @@ def generate_password
SecureRandom.hex(24)
end
end
end
end
4 changes: 3 additions & 1 deletion lib/kupo/phases/join_node.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
module Kupo::Phases
class JoinNode < Base

# @param host [Kupo::Configuration::Host]
# @param master [Kupo::Configuration::Host]
def initialize(host, master)
@host = host
@master = master
Expand Down Expand Up @@ -33,4 +35,4 @@ def call
end
end
end
end
end
3 changes: 2 additions & 1 deletion lib/kupo/phases/validate_host.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ module Kupo::Phases
class ValidateHost
include Kupo::Phases::Logging

# @param host [Kupo::Configuration::Host]
def initialize(host)
@host = host
end
Expand All @@ -18,4 +19,4 @@ def call
end
end
end
end
end
1 change: 1 addition & 0 deletions lib/kupo/up_command.rb
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ def handle_masters(master, config)
Phases::ConfigureKubelet.new(master).call
Phases::ConfigureMaster.new(master, config.network).call
Phases::ConfigureClient.new(master).call
Phases::ConfigureDNS.new(master, config).call
Phases::ConfigureNetwork.new(master, config.network).call
Phases::ConfigureMetrics.new(master).call
end
Expand Down
Loading