hetzner-k3s 0.6.2.pre1 → 0.6.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +3 -3
- data/README.md +10 -0
- data/cluster_config.yaml.example +10 -0
- data/hetzner-k3s.gemspec +1 -1
- data/lib/hetzner/k3s/cluster.rb +98 -3
- data/lib/hetzner/k3s/configuration.rb +12 -13
- data/lib/hetzner/k3s/version.rb +1 -1
- data/lib/hetzner/utils.rb +3 -0
- metadata +8 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 873c76ec7a993a8c890f72c8158daa82597eb994e3f5e70c9b53d98604903f38
|
4
|
+
data.tar.gz: d0b1f622ff21728d1bb6b41b2a373eca693121a0eb619776adf9590ef926f80a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4bdc7f2fa5f6ef40bcd1e089d89b26c228b77fe3c06fb4af884910e4fe69fb6ad67951160a4ecdbcb6f076adbc16521bfd45b661644e7f6b927ba002e5a3ba67
|
7
|
+
data.tar.gz: 94a8f6b3df49db94d7412d5f350ce3f996980f0741e694a8b91a7ff0c71783cdaa12b4263cab31395288497dd3c790be45ca62e00f844d9df863a13b3623de79
|
data/Gemfile.lock
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
hetzner-k3s (0.6.
|
4
|
+
hetzner-k3s (0.6.1)
|
5
5
|
bcrypt_pbkdf
|
6
6
|
childprocess
|
7
7
|
ed25519
|
8
8
|
httparty
|
9
|
-
net-ssh
|
9
|
+
net-ssh
|
10
10
|
sshkey
|
11
11
|
thor
|
12
12
|
|
@@ -25,7 +25,7 @@ GEM
|
|
25
25
|
mime-types-data (~> 3.2015)
|
26
26
|
mime-types-data (3.2022.0105)
|
27
27
|
multi_xml (0.6.0)
|
28
|
-
net-ssh (
|
28
|
+
net-ssh (7.0.1)
|
29
29
|
parallel (1.20.1)
|
30
30
|
parser (3.1.2.1)
|
31
31
|
ast (~> 2.4.1)
|
data/README.md
CHANGED
@@ -138,10 +138,20 @@ schedule_workloads_on_masters: false
|
|
138
138
|
masters:
|
139
139
|
instance_type: cpx21
|
140
140
|
instance_count: 3
|
141
|
+
# labels:
|
142
|
+
# purpose: master
|
143
|
+
# size: cpx21
|
144
|
+
# taints:
|
145
|
+
# something: value1:NoSchedule
|
141
146
|
worker_node_pools:
|
142
147
|
- name: small
|
143
148
|
instance_type: cpx21
|
144
149
|
instance_count: 4
|
150
|
+
# labels:
|
151
|
+
# purpose: worker
|
152
|
+
# size: cpx21
|
153
|
+
# taints:
|
154
|
+
# something: GpuWorkloadsOnly:NoSchedule
|
145
155
|
- name: big
|
146
156
|
instance_type: cpx31
|
147
157
|
instance_count: 2
|
data/cluster_config.yaml.example
CHANGED
@@ -15,10 +15,20 @@ schedule_workloads_on_masters: false
|
|
15
15
|
masters:
|
16
16
|
instance_type: cpx21
|
17
17
|
instance_count: 3
|
18
|
+
# labels:
|
19
|
+
# purpose: master
|
20
|
+
# size: cpx21
|
21
|
+
# taints:
|
22
|
+
# something: value1:NoSchedule
|
18
23
|
worker_node_pools:
|
19
24
|
- name: small
|
20
25
|
instance_type: cpx21
|
21
26
|
instance_count: 4
|
27
|
+
# labels:
|
28
|
+
# purpose: worker
|
29
|
+
# size: cpx21
|
30
|
+
# taints:
|
31
|
+
# something: GpuWorkloadsOnly:NoSchedule
|
22
32
|
- name: big
|
23
33
|
instance_type: cpx31
|
24
34
|
instance_count: 2
|
data/hetzner-k3s.gemspec
CHANGED
@@ -24,7 +24,7 @@ Gem::Specification.new do |spec|
|
|
24
24
|
spec.add_dependency 'childprocess'
|
25
25
|
spec.add_dependency 'ed25519'
|
26
26
|
spec.add_dependency 'httparty'
|
27
|
-
spec.add_dependency 'net-ssh'
|
27
|
+
spec.add_dependency 'net-ssh'
|
28
28
|
spec.add_dependency 'sshkey'
|
29
29
|
spec.add_dependency 'thor'
|
30
30
|
spec.add_development_dependency 'rubocop'
|
data/lib/hetzner/k3s/cluster.rb
CHANGED
@@ -51,6 +51,9 @@ class Cluster
|
|
51
51
|
|
52
52
|
sleep 10
|
53
53
|
|
54
|
+
label_nodes
|
55
|
+
taint_nodes
|
56
|
+
|
54
57
|
deploy_cloud_controller_manager
|
55
58
|
deploy_csi_driver
|
56
59
|
deploy_system_upgrade_controller
|
@@ -294,6 +297,82 @@ class Cluster
|
|
294
297
|
threads.each(&:join) unless threads.empty?
|
295
298
|
end
|
296
299
|
|
300
|
+
def label_nodes
|
301
|
+
check_kubectl
|
302
|
+
|
303
|
+
if master_definitions_for_create.first[:labels]
|
304
|
+
master_labels = master_definitions_for_create.first[:labels].map{ |k, v| "#{k}=#{v}" }.join(' ')
|
305
|
+
master_node_names = []
|
306
|
+
|
307
|
+
master_definitions_for_create.each do |master|
|
308
|
+
master_node_names << "#{configuration['cluster_name']}-#{master[:instance_type]}-#{master[:instance_id]}"
|
309
|
+
end
|
310
|
+
|
311
|
+
master_node_names = master_node_names.join(' ')
|
312
|
+
|
313
|
+
cmd = "kubectl label --overwrite nodes #{master_node_names} #{master_labels}"
|
314
|
+
|
315
|
+
run cmd, kubeconfig_path: kubeconfig_path
|
316
|
+
end
|
317
|
+
|
318
|
+
workers = []
|
319
|
+
|
320
|
+
worker_node_pools.each do |worker_node_pool|
|
321
|
+
workers += worker_node_pool_definitions(worker_node_pool)
|
322
|
+
end
|
323
|
+
|
324
|
+
return unless workers.any?
|
325
|
+
|
326
|
+
workers.each do |worker|
|
327
|
+
next unless worker[:labels]
|
328
|
+
|
329
|
+
worker_labels = worker[:labels].map{ |k, v| "#{k}=#{v}" }.join(' ')
|
330
|
+
worker_node_name = "#{configuration['cluster_name']}-#{worker[:instance_type]}-#{worker[:instance_id]}"
|
331
|
+
|
332
|
+
cmd = "kubectl label --overwrite nodes #{worker_node_name} #{worker_labels}"
|
333
|
+
|
334
|
+
run cmd, kubeconfig_path: kubeconfig_path
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
def taint_nodes
|
339
|
+
check_kubectl
|
340
|
+
|
341
|
+
if master_definitions_for_create.first[:taints]
|
342
|
+
master_taints = master_definitions_for_create.first[:taints].map{ |k, v| "#{k}=#{v}" }.join(' ')
|
343
|
+
master_node_names = []
|
344
|
+
|
345
|
+
master_definitions_for_create.each do |master|
|
346
|
+
master_node_names << "#{configuration['cluster_name']}-#{master[:instance_type]}-#{master[:instance_id]}"
|
347
|
+
end
|
348
|
+
|
349
|
+
master_node_names = master_node_names.join(' ')
|
350
|
+
|
351
|
+
cmd = "kubectl taint --overwrite nodes #{master_node_names} #{master_taints}"
|
352
|
+
|
353
|
+
run cmd, kubeconfig_path: kubeconfig_path
|
354
|
+
end
|
355
|
+
|
356
|
+
workers = []
|
357
|
+
|
358
|
+
worker_node_pools.each do |worker_node_pool|
|
359
|
+
workers += worker_node_pool_definitions(worker_node_pool)
|
360
|
+
end
|
361
|
+
|
362
|
+
return unless workers.any?
|
363
|
+
|
364
|
+
workers.each do |worker|
|
365
|
+
next unless worker[:taints]
|
366
|
+
|
367
|
+
worker_taints = worker[:taints].map{ |k, v| "#{k}=#{v}" }.join(' ')
|
368
|
+
worker_node_name = "#{configuration['cluster_name']}-#{worker[:instance_type]}-#{worker[:instance_id]}"
|
369
|
+
|
370
|
+
cmd = "kubectl taint --overwrite nodes #{worker_node_name} #{worker_taints}"
|
371
|
+
|
372
|
+
run cmd, kubeconfig_path: kubeconfig_path
|
373
|
+
end
|
374
|
+
end
|
375
|
+
|
297
376
|
def deploy_cloud_controller_manager
|
298
377
|
check_kubectl
|
299
378
|
|
@@ -480,6 +559,14 @@ class Cluster
|
|
480
559
|
@master_instance_type ||= masters_config['instance_type']
|
481
560
|
end
|
482
561
|
|
562
|
+
def master_labels
|
563
|
+
@master_labels ||= masters_config['labels']
|
564
|
+
end
|
565
|
+
|
566
|
+
def master_taints
|
567
|
+
@master_taints ||= masters_config['taints']
|
568
|
+
end
|
569
|
+
|
483
570
|
def masters_count
|
484
571
|
@masters_count ||= masters_config['instance_count']
|
485
572
|
end
|
@@ -510,7 +597,9 @@ class Cluster
|
|
510
597
|
ssh_key_id: ssh_key_id,
|
511
598
|
image: image,
|
512
599
|
additional_packages: additional_packages,
|
513
|
-
additional_post_create_commands: additional_post_create_commands
|
600
|
+
additional_post_create_commands: additional_post_create_commands,
|
601
|
+
labels: master_labels,
|
602
|
+
taints: master_taints
|
514
603
|
}
|
515
604
|
end
|
516
605
|
|
@@ -535,6 +624,8 @@ class Cluster
|
|
535
624
|
worker_instance_type = worker_node_pool['instance_type']
|
536
625
|
worker_count = worker_node_pool['instance_count']
|
537
626
|
worker_location = worker_node_pool['location'] || masters_location
|
627
|
+
labels = worker_node_pool['labels']
|
628
|
+
taints = worker_node_pool['taints']
|
538
629
|
|
539
630
|
definitions = []
|
540
631
|
|
@@ -549,7 +640,9 @@ class Cluster
|
|
549
640
|
ssh_key_id: ssh_key_id,
|
550
641
|
image: image,
|
551
642
|
additional_packages: additional_packages,
|
552
|
-
additional_post_create_commands: additional_post_create_commands
|
643
|
+
additional_post_create_commands: additional_post_create_commands,
|
644
|
+
labels: labels,
|
645
|
+
taints: taints
|
553
646
|
}
|
554
647
|
end
|
555
648
|
|
@@ -576,8 +669,10 @@ class Cluster
|
|
576
669
|
servers = []
|
577
670
|
|
578
671
|
threads = server_configs.map do |server_config|
|
672
|
+
config = server_config.reject! { |k, _v| %i[labels taints].include?(k) }
|
673
|
+
|
579
674
|
Thread.new do
|
580
|
-
servers << Hetzner::Server.new(hetzner_client: hetzner_client, cluster_name: cluster_name).create(**
|
675
|
+
servers << Hetzner::Server.new(hetzner_client: hetzner_client, cluster_name: cluster_name).create(**config)
|
581
676
|
end
|
582
677
|
end
|
583
678
|
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module Hetzner
|
4
4
|
class Configuration
|
5
5
|
GITHUB_DELIM_LINKS = ','
|
6
|
-
GITHUB_LINK_REGEX = /<([^>]+)>; rel="([^"]+)"
|
6
|
+
GITHUB_LINK_REGEX = /<([^>]+)>; rel="([^"]+)"/.freeze
|
7
7
|
|
8
8
|
attr_reader :hetzner_client
|
9
9
|
|
@@ -92,8 +92,6 @@ module Hetzner
|
|
92
92
|
configuration
|
93
93
|
end
|
94
94
|
|
95
|
-
private_class_method
|
96
|
-
|
97
95
|
def self.fetch_releases(url)
|
98
96
|
response = HTTParty.get(url)
|
99
97
|
[response, JSON.parse(response.body).map { |hash| hash['name'] }]
|
@@ -196,7 +194,7 @@ module Hetzner
|
|
196
194
|
|
197
195
|
unless invalid_ranges.empty?
|
198
196
|
invalid_ranges.each do |_network|
|
199
|
-
errors <<
|
197
|
+
errors << "Please use the CIDR notation for the #{access_type} networks to avoid ambiguity"
|
200
198
|
end
|
201
199
|
end
|
202
200
|
|
@@ -210,19 +208,17 @@ module Hetzner
|
|
210
208
|
false
|
211
209
|
end
|
212
210
|
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
211
|
+
return if current_ip_network
|
212
|
+
|
213
|
+
case access_type
|
214
|
+
when 'SSH'
|
215
|
+
errors << "Your current IP #{current_ip} is not included into any of the #{access_type} networks you've specified, so we won't be able to SSH into the nodes "
|
216
|
+
when 'API'
|
217
|
+
errors << "Your current IP #{current_ip} is not included into any of the #{access_type} networks you've specified, so we won't be able to connect to the Kubernetes API"
|
220
218
|
end
|
221
219
|
end
|
222
220
|
|
223
|
-
|
224
221
|
def validate_ssh_allowed_networks
|
225
|
-
return
|
226
222
|
validate_networks('ssh_allowed_networks', 'SSH')
|
227
223
|
end
|
228
224
|
|
@@ -441,6 +437,9 @@ module Hetzner
|
|
441
437
|
instance_group_errors << "#{instance_group_type} has an invalid instance count"
|
442
438
|
end
|
443
439
|
|
440
|
+
instance_group_errors << "#{instance_group_type} has an invalid labels format - a hash is expected" if !instance_group['labels'].nil? && !instance_group['labels'].is_a?(Hash)
|
441
|
+
instance_group_errors << "#{instance_group_type} has an invalid taints format - a hash is expected" if !instance_group['taints'].nil? && !instance_group['taints'].is_a?(Hash)
|
442
|
+
|
444
443
|
errors << instance_group_errors
|
445
444
|
end
|
446
445
|
|
data/lib/hetzner/k3s/version.rb
CHANGED
data/lib/hetzner/utils.rb
CHANGED
@@ -89,6 +89,9 @@ module Utils
|
|
89
89
|
# p [e.class, e.message]
|
90
90
|
# retries += 1
|
91
91
|
# retry unless retries > 15 || e.message =~ /Bad file descriptor/
|
92
|
+
rescue Timeout::Error, IOError, Errno::EBADF
|
93
|
+
retries += 1
|
94
|
+
retry unless retries > 15
|
92
95
|
rescue Net::SSH::Disconnect => e
|
93
96
|
retries += 1
|
94
97
|
retry unless retries > 15 || e.message =~ /Too many authentication failures/
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hetzner-k3s
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.2
|
4
|
+
version: 0.6.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Vito Botta
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-08-
|
11
|
+
date: 2022-08-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bcrypt_pbkdf
|
@@ -70,16 +70,16 @@ dependencies:
|
|
70
70
|
name: net-ssh
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- -
|
73
|
+
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version:
|
75
|
+
version: '0'
|
76
76
|
type: :runtime
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- -
|
80
|
+
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version:
|
82
|
+
version: '0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: sshkey
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -177,9 +177,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
177
177
|
version: 2.7.1
|
178
178
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
179
179
|
requirements:
|
180
|
-
- - "
|
180
|
+
- - ">="
|
181
181
|
- !ruby/object:Gem::Version
|
182
|
-
version:
|
182
|
+
version: '0'
|
183
183
|
requirements: []
|
184
184
|
rubygems_version: 3.1.2
|
185
185
|
signing_key:
|