kuby-anycable 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +9 -0
- data/LICENSE.txt +22 -0
- data/README.md +128 -0
- data/lib/kuby/anycable/go_plugin.rb +343 -0
- data/lib/kuby/anycable/packages.rb +35 -0
- data/lib/kuby/anycable/rpc_plugin.rb +276 -0
- data/lib/kuby/anycable/version.rb +7 -0
- data/lib/kuby/anycable.rb +13 -0
- data/lib/kuby-anycable.rb +3 -0
- metadata +85 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 5ef55763867f16f31e317359f70bf9514fe2b10622614abd67360a04cfd36dba
|
4
|
+
data.tar.gz: d3371b1cbf5659b83042d475f292d6dc29ea63f02ea2ed886ed7be0d53c81a9e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9132d1e3c8023d98752a510b8bc0794e1cace3dd46b1f3a687c76abe58c57d778aab9bbff02eafe7d4dbbe81cfdfad207d541b6d526048af3ff565f6f96c2bb1
|
7
|
+
data.tar.gz: aa2571946fc580e32c8844686b56ccfd0a01a9b9082424f82ad17edf3993cc43eaa965b670472609500edfd016b2550de1fa275b26c62c19976f7549c2f47777
|
data/CHANGELOG.md
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2021 Vladimir Dementyev
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
[](https://rubygems.org/gems/kuby-anycable)
|
2
|
+
|
3
|
+
# Kuby AnyCable
|
4
|
+
|
5
|
+
[Kuby][] plugin to deploy [AnyCable][] applications.
|
6
|
+
|
7
|
+
This plugin allows you to install all the required AnyCable components to a Kubernetes cluster.
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Add to your project:
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
# Gemfile
|
15
|
+
gem "kuby-anycable"
|
16
|
+
```
|
17
|
+
|
18
|
+
## Usage
|
19
|
+
|
20
|
+
Here is the minimal configuration:
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
# kuby.rb
|
24
|
+
|
25
|
+
require "kuby-anycable"
|
26
|
+
|
27
|
+
# ...
|
28
|
+
|
29
|
+
Kuby.define("my-app") do
|
30
|
+
environment(:production) do
|
31
|
+
#...
|
32
|
+
|
33
|
+
kubernetes do
|
34
|
+
add_plugin :rails_app do
|
35
|
+
# ...
|
36
|
+
end
|
37
|
+
|
38
|
+
add_plugin :anycable_rpc
|
39
|
+
add_plugin :anycable_go
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
```
|
44
|
+
|
45
|
+
What happens under the hood:
|
46
|
+
|
47
|
+
- RPC service definitions are created:
|
48
|
+
- The current `rails_app` image is used for the container.
|
49
|
+
- The `rails_app` Config Map is attached to the RPC container.
|
50
|
+
- AnyCable-Go service definitions are created:
|
51
|
+
- The latest stable image is used for `anycable-go`.
|
52
|
+
- Connected to the RPC service (using [DNS load balancing](https://docs.anycable.io/deployment/load_balancing?id=client-side-load-balancing) by default).
|
53
|
+
- Redis URL is inferred from the RPC service `ANYCABLE_REDIS_URL` or `REDIS_URL`.
|
54
|
+
- [Concurrency settings](https://docs.anycable.io/anycable-go/configuration?id=concurrency-settings) are adjusted according to the number of RPC servers and their concurrency settings.
|
55
|
+
|
56
|
+
Of course, you can customize the resources:
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
add_plugin :anycable_rpc do
|
60
|
+
replicas 2
|
61
|
+
# Provide Redis URL explicitly.
|
62
|
+
redis_url "redis://custom_url"
|
63
|
+
# Override gRPC server port (but why?)
|
64
|
+
port 50051
|
65
|
+
# Expose additional port named 'metrics'
|
66
|
+
# (e.g., if you use Prometheus exporter).
|
67
|
+
# Disabled by default.
|
68
|
+
metrics_port 3030
|
69
|
+
# Shortcut for ENV['ANYCABLE_RPC_SERVER_ARGS__MAX_CONNECTION_AGE_MS']
|
70
|
+
max_connection_age 300000
|
71
|
+
# Shortcut for ENV['ANYCABLE_RPC_POOL_SIZE']
|
72
|
+
rpc_pool_size 30
|
73
|
+
end
|
74
|
+
|
75
|
+
add_plugin :anycable_go do
|
76
|
+
replicas 2
|
77
|
+
# Provide Redis URL explicitly.
|
78
|
+
redis_url "redis://custom_url"
|
79
|
+
# Override web server port (but why?)
|
80
|
+
port 8081
|
81
|
+
# Metrics port (enabled by default and exposed as "metrics")
|
82
|
+
metric_port 5001
|
83
|
+
# Provide path to RPC server explicitly
|
84
|
+
rpc_host "my-app-rpc:50051"
|
85
|
+
# WebSocket endpoint path
|
86
|
+
ws_path "/cable"
|
87
|
+
# AnyCable-Go Dockerimage
|
88
|
+
image "anycable/anycable-go:1.1"
|
89
|
+
# Specify ENV['ANYCABLE_RPC_CONCURRENCY'] explicitly
|
90
|
+
rpc_concurrency nil
|
91
|
+
# Use a separate hostname for AnyCable-Go
|
92
|
+
# (disabled by default)
|
93
|
+
hostname nil
|
94
|
+
end
|
95
|
+
```
|
96
|
+
|
97
|
+
### Using with Alpine images
|
98
|
+
|
99
|
+
Installing Ruby deps on Apline images requires some special attention to gRPC-related gems (tl;dl we need to build them from source).
|
100
|
+
|
101
|
+
Kuby AnyCable comes with a special _package_, which installs everything for you (so you shouldn't use any hacks yourself). You need to add a single line:
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
Kuby.define("my-app") do
|
105
|
+
environment(:production) do
|
106
|
+
docker do
|
107
|
+
# ...
|
108
|
+
distro :apline
|
109
|
+
package_phase.add("anycable-build")
|
110
|
+
|
111
|
+
# ...
|
112
|
+
end
|
113
|
+
|
114
|
+
# ...
|
115
|
+
end
|
116
|
+
end
|
117
|
+
```
|
118
|
+
|
119
|
+
## Contributing
|
120
|
+
|
121
|
+
Bug reports and pull requests are welcome on GitHub at [https://github.com/palkan/kuby-anycable](https://github.com/palkan/kuby-anycable).
|
122
|
+
|
123
|
+
## License
|
124
|
+
|
125
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
126
|
+
|
127
|
+
[Kuby]: https://getkuby.io
|
128
|
+
[AnyCable]: https://anycable.io
|
@@ -0,0 +1,343 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kuby
|
4
|
+
module AnyCable
|
5
|
+
class GoPlugin < ::Kuby::Plugin
|
6
|
+
extend ::KubeDSL::ValueFields
|
7
|
+
|
8
|
+
ROLE = "ws"
|
9
|
+
|
10
|
+
value_fields :replicas
|
11
|
+
value_fields :redis_url
|
12
|
+
value_fields :port
|
13
|
+
value_fields :metrics_port
|
14
|
+
value_fields :rpc_host
|
15
|
+
value_fields :rpc_concurrency
|
16
|
+
value_fields :ws_path
|
17
|
+
value_fields :image
|
18
|
+
value_fields :hostname
|
19
|
+
|
20
|
+
DEFAULT_IMAGE = "anycable/anycable-go:1.1"
|
21
|
+
|
22
|
+
def after_initialize
|
23
|
+
@replicas = 1
|
24
|
+
@metrics_port = 5001
|
25
|
+
@rpc_host = nil
|
26
|
+
@rpc_concurrency = nil
|
27
|
+
@redis_url = nil
|
28
|
+
@ws_path = "/cable"
|
29
|
+
@port = 8081
|
30
|
+
@hostname = nil
|
31
|
+
@image = DEFAULT_IMAGE
|
32
|
+
end
|
33
|
+
|
34
|
+
def after_configuration
|
35
|
+
configure_rpc_host
|
36
|
+
configure_redis_url
|
37
|
+
configure_concurrency
|
38
|
+
|
39
|
+
if rails_spec
|
40
|
+
@hostname ||= rails_spec.hostname
|
41
|
+
configure_ingress(rails_spec.ingress, hostname)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def configure(&block)
|
46
|
+
instance_eval(&block) if block
|
47
|
+
end
|
48
|
+
|
49
|
+
def resources
|
50
|
+
@resources ||= [
|
51
|
+
service_account,
|
52
|
+
service,
|
53
|
+
config_map,
|
54
|
+
deployment
|
55
|
+
]
|
56
|
+
end
|
57
|
+
|
58
|
+
def configure_ingress(ingress, hostname)
|
59
|
+
spec = self
|
60
|
+
|
61
|
+
ingress.spec.rule do
|
62
|
+
host hostname
|
63
|
+
|
64
|
+
http do
|
65
|
+
path do
|
66
|
+
path spec.ws_path
|
67
|
+
|
68
|
+
backend do
|
69
|
+
service_name spec.service.metadata.name
|
70
|
+
service_port spec.service.spec.ports.first.port
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def service_account(&block)
|
78
|
+
context = self
|
79
|
+
|
80
|
+
@service_account ||= KubeDSL.service_account do
|
81
|
+
metadata do
|
82
|
+
name "#{context.selector_app}-#{ROLE}-sa"
|
83
|
+
namespace context.namespace.metadata.name
|
84
|
+
|
85
|
+
labels do
|
86
|
+
add :app, context.selector_app
|
87
|
+
add :role, ROLE
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
@service_account.instance_eval(&block) if block
|
93
|
+
@service_account
|
94
|
+
end
|
95
|
+
|
96
|
+
def service(&block)
|
97
|
+
spec = self
|
98
|
+
|
99
|
+
@service ||= KubeDSL.service do
|
100
|
+
metadata do
|
101
|
+
name "#{spec.selector_app}-#{ROLE}-svc"
|
102
|
+
namespace spec.namespace.metadata.name
|
103
|
+
|
104
|
+
labels do
|
105
|
+
add :app, spec.selector_app
|
106
|
+
add :role, ROLE
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
spec do
|
111
|
+
type "ClusterIP"
|
112
|
+
|
113
|
+
selector do
|
114
|
+
add :app, spec.selector_app
|
115
|
+
add :role, ROLE
|
116
|
+
end
|
117
|
+
|
118
|
+
port do
|
119
|
+
name "http"
|
120
|
+
port spec.port
|
121
|
+
protocol "TCP"
|
122
|
+
target_port "http"
|
123
|
+
end
|
124
|
+
|
125
|
+
if spec.metrics_port
|
126
|
+
port do
|
127
|
+
name "metrics"
|
128
|
+
port spec.metrics_port
|
129
|
+
protocol "TCP"
|
130
|
+
target_port "metrics"
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
@service.instance_eval(&block) if block
|
137
|
+
@service
|
138
|
+
end
|
139
|
+
|
140
|
+
def deployment(&block)
|
141
|
+
context = self
|
142
|
+
|
143
|
+
@deployment ||= KubeDSL.deployment do
|
144
|
+
metadata do
|
145
|
+
name "#{context.selector_app}-#{ROLE}"
|
146
|
+
namespace context.namespace.metadata.name
|
147
|
+
|
148
|
+
labels do
|
149
|
+
add :app, context.selector_app
|
150
|
+
add :role, ROLE
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
spec do
|
155
|
+
replicas context.replicas
|
156
|
+
|
157
|
+
selector do
|
158
|
+
match_labels do
|
159
|
+
add :app, context.selector_app
|
160
|
+
add :role, ROLE
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
strategy do
|
165
|
+
type "RollingUpdate"
|
166
|
+
|
167
|
+
rolling_update do
|
168
|
+
max_surge "25%"
|
169
|
+
max_unavailable 0
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
template do
|
174
|
+
metadata do
|
175
|
+
labels do
|
176
|
+
add :app, context.selector_app
|
177
|
+
add :role, ROLE
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
spec do
|
182
|
+
container(:ws) do
|
183
|
+
name "#{context.selector_app}-#{ROLE}"
|
184
|
+
image context.image
|
185
|
+
image_pull_policy "IfNotPresent"
|
186
|
+
|
187
|
+
port do
|
188
|
+
container_port context.port
|
189
|
+
name "http"
|
190
|
+
protocol "TCP"
|
191
|
+
end
|
192
|
+
|
193
|
+
if context.metrics_port
|
194
|
+
port do
|
195
|
+
container_port context.metrics_port
|
196
|
+
name "metrics"
|
197
|
+
protocol "TCP"
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
env_from do
|
202
|
+
config_map_ref do
|
203
|
+
name context.config_map.metadata.name
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
readiness_probe do
|
208
|
+
success_threshold 1
|
209
|
+
failure_threshold 3
|
210
|
+
initial_delay_seconds 15
|
211
|
+
period_seconds 10
|
212
|
+
timeout_seconds 3
|
213
|
+
|
214
|
+
tcp_socket do
|
215
|
+
port "http"
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
liveness_probe do
|
220
|
+
success_threshold 1
|
221
|
+
failure_threshold 3
|
222
|
+
initial_delay_seconds 90
|
223
|
+
period_seconds 10
|
224
|
+
timeout_seconds 3
|
225
|
+
|
226
|
+
tcp_socket do
|
227
|
+
port "http"
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
image_pull_secret do
|
233
|
+
name context.kubernetes.registry_secret.metadata.name
|
234
|
+
end
|
235
|
+
|
236
|
+
restart_policy "Always"
|
237
|
+
service_account_name context.service_account.metadata.name
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
@deployment.instance_eval(&block) if block
|
244
|
+
@deployment
|
245
|
+
end
|
246
|
+
|
247
|
+
def config_map(&block)
|
248
|
+
spec = self
|
249
|
+
|
250
|
+
@config_map ||= KubeDSL.config_map do
|
251
|
+
metadata do
|
252
|
+
name "#{spec.selector_app}-#{ROLE}-config"
|
253
|
+
namespace spec.namespace.metadata.name
|
254
|
+
end
|
255
|
+
|
256
|
+
data do
|
257
|
+
if spec.rpc_host
|
258
|
+
add "ANYCABLE_RPC_HOST", spec.rpc_host
|
259
|
+
end
|
260
|
+
|
261
|
+
if spec.redis_url
|
262
|
+
add "ANYCABLE_REDIS_URL", spec.redis_url
|
263
|
+
end
|
264
|
+
|
265
|
+
add "ANYCABLE_HOST", "0.0.0.0"
|
266
|
+
add "ANYCABLE_PORT", spec.port.to_s
|
267
|
+
|
268
|
+
if spec.metrics_port
|
269
|
+
add "ANYCABLE_METRICS_PORT", spec.metrics_port.to_s
|
270
|
+
add "ANYCABLE_METRICS_HTTP", "/metrics"
|
271
|
+
end
|
272
|
+
|
273
|
+
if spec.rpc_concurrency
|
274
|
+
add "ANYCABLE_RPC_CONCURRENCY", spec.rpc_concurrency.to_s
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
@config_map.instance_eval(&block) if block
|
280
|
+
@config_map
|
281
|
+
end
|
282
|
+
|
283
|
+
alias_method :env, :config_map
|
284
|
+
|
285
|
+
delegate :kubernetes, to: :environment
|
286
|
+
|
287
|
+
delegate :docker, to: :environment
|
288
|
+
|
289
|
+
delegate :selector_app, to: :kubernetes
|
290
|
+
|
291
|
+
delegate :namespace, to: :kubernetes
|
292
|
+
|
293
|
+
def rpc_spec
|
294
|
+
@rpc_spec ||= kubernetes.plugin(:anycable_rpc)
|
295
|
+
end
|
296
|
+
|
297
|
+
def rails_spec
|
298
|
+
@rails_spec ||= kubernetes.plugin(:rails_app)
|
299
|
+
end
|
300
|
+
|
301
|
+
def configure_rpc_host
|
302
|
+
return if config_map.data.get("ANYCABLE_RPC_HOST")
|
303
|
+
# Make it possible to avoid setting RPC host at all
|
304
|
+
return if rpc_host == false
|
305
|
+
|
306
|
+
return unless rpc_spec
|
307
|
+
|
308
|
+
config_map.data.add("ANYCABLE_RPC_HOST", "dns:///#{rpc_spec.service.metadata.name}:50051")
|
309
|
+
end
|
310
|
+
|
311
|
+
def configure_redis_url
|
312
|
+
return if config_map.data.get("REDIS_URL") || config_map.data.get("ANYCABLE_REDIS_URL")
|
313
|
+
# Make it possible to avoid setting Redis url at all
|
314
|
+
return if redis_url == false
|
315
|
+
|
316
|
+
# Try to lookup Redis url from the RPC and Web app specs
|
317
|
+
[rpc_spec, rails_spec].compact.detect do |spec|
|
318
|
+
%w[ANYCABLE_REDIS_URL REDIS_URL].detect do |env_key|
|
319
|
+
url = spec.config_map.data.get(env_key)
|
320
|
+
next unless url
|
321
|
+
|
322
|
+
config_map.data.add("ANYCABLE_REDIS_URL", url)
|
323
|
+
true
|
324
|
+
end
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
def configure_concurrency
|
329
|
+
return if config_map.data.get("ANYCABLE_RPC_CONCURRENCY")
|
330
|
+
return unless rpc_spec
|
331
|
+
|
332
|
+
rpc_pool_size = rpc_spec.config_map.data.get("ANYCABLE_RPC_POOL_SIZE")
|
333
|
+
return unless rpc_pool_size
|
334
|
+
|
335
|
+
rpc_replicas = rpc_spec.replicas
|
336
|
+
|
337
|
+
concurrency = ((rpc_pool_size.to_i * rpc_replicas) * 0.95 / replicas).round
|
338
|
+
|
339
|
+
config_map.data.add("ANYCABLE_RPC_CONCURRENCY", concurrency.to_s)
|
340
|
+
end
|
341
|
+
end
|
342
|
+
end
|
343
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kuby
|
4
|
+
module AnyCable
|
5
|
+
class Packages < Kuby::Docker::Packages::Package
|
6
|
+
def install_on_debian(_dockerfile)
|
7
|
+
# nothing specific
|
8
|
+
end
|
9
|
+
|
10
|
+
def install_on_alpine(dockerfile)
|
11
|
+
dockerfile.run("apk add --no-cache --update libc6-compat")
|
12
|
+
dockerfile.run("ln -s /lib/libc.musl-x86_64.so.1 /lib/ld-linux-x86-64.so.2")
|
13
|
+
|
14
|
+
if lockfile
|
15
|
+
protobuf_version = lockfile.specs.detect { |spec| spec.name == "google-protobuf" }&.version
|
16
|
+
dockerfile.run("gem install --platform ruby google-protobuf -v '#{protobuf_version}' -N") if protobuf_version
|
17
|
+
|
18
|
+
grpc_version = lockfile.specs.detect { |spec| spec.name == "grpc" }&.version
|
19
|
+
dockerfile.run("gem install --platform ruby grpc -v '#{grpc_version}' -N --ignore-dependencies && rm -rf /usr/local/bundle/gems/grpc-#{grpc_version}/src/ruby/ext") if grpc_version
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def lockfile
|
26
|
+
return @lockfile if instance_variable_defined?(:@lockfile)
|
27
|
+
|
28
|
+
@lockfile =
|
29
|
+
if File.file?("./Gemfile.lock")
|
30
|
+
Bundler::LockfileParser.new(Bundler.read_file("./Gemfile.lock"))
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,276 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kuby
|
4
|
+
module AnyCable
|
5
|
+
class RPCPlugin < ::Kuby::Plugin
|
6
|
+
extend ::KubeDSL::ValueFields
|
7
|
+
|
8
|
+
ROLE = "rpc"
|
9
|
+
|
10
|
+
value_fields :replicas
|
11
|
+
value_fields :redis_url
|
12
|
+
value_fields :port
|
13
|
+
value_fields :metrics_port
|
14
|
+
value_fields :max_connection_age
|
15
|
+
value_fields :rpc_pool_size
|
16
|
+
|
17
|
+
def after_initialize
|
18
|
+
@replicas = 1
|
19
|
+
@port = 50051
|
20
|
+
@metrics_port = nil
|
21
|
+
@max_connection_age = 300000
|
22
|
+
@rpc_pool_size = 30
|
23
|
+
end
|
24
|
+
|
25
|
+
def after_configuration
|
26
|
+
return unless rails_spec
|
27
|
+
|
28
|
+
deployment.spec.template.spec.container(:rpc).merge!(
|
29
|
+
rails_spec.deployment.spec.template.spec.container(:web), fields: [:env_from]
|
30
|
+
)
|
31
|
+
end
|
32
|
+
|
33
|
+
def configure(&block)
|
34
|
+
instance_eval(&block) if block
|
35
|
+
end
|
36
|
+
|
37
|
+
def before_deploy(manifest)
|
38
|
+
image_with_tag = "#{docker.image.image_url}:#{kubernetes.tag || Kuby::Docker::LATEST_TAG}"
|
39
|
+
|
40
|
+
deployment do
|
41
|
+
spec do
|
42
|
+
template do
|
43
|
+
spec do
|
44
|
+
container(:rpc) do
|
45
|
+
image image_with_tag
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def resources
|
54
|
+
@resources ||= [
|
55
|
+
service_account,
|
56
|
+
service,
|
57
|
+
config_map,
|
58
|
+
deployment
|
59
|
+
]
|
60
|
+
end
|
61
|
+
|
62
|
+
def service_account(&block)
|
63
|
+
context = self
|
64
|
+
|
65
|
+
@service_account ||= KubeDSL.service_account do
|
66
|
+
metadata do
|
67
|
+
name "#{context.selector_app}-#{ROLE}-sa"
|
68
|
+
namespace context.namespace.metadata.name
|
69
|
+
|
70
|
+
labels do
|
71
|
+
add :app, context.selector_app
|
72
|
+
add :role, ROLE
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
@service_account.instance_eval(&block) if block
|
78
|
+
@service_account
|
79
|
+
end
|
80
|
+
|
81
|
+
def service(&block)
|
82
|
+
spec = self
|
83
|
+
|
84
|
+
@service ||= KubeDSL.service do
|
85
|
+
metadata do
|
86
|
+
name "#{spec.selector_app}-#{ROLE}-svc"
|
87
|
+
namespace spec.namespace.metadata.name
|
88
|
+
|
89
|
+
labels do
|
90
|
+
add :app, spec.selector_app
|
91
|
+
add :role, ROLE
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
spec do
|
96
|
+
type "ClusterIP"
|
97
|
+
cluster_ip "None"
|
98
|
+
|
99
|
+
selector do
|
100
|
+
add :app, spec.selector_app
|
101
|
+
add :role, ROLE
|
102
|
+
end
|
103
|
+
|
104
|
+
port do
|
105
|
+
name "rpc"
|
106
|
+
port spec.port
|
107
|
+
protocol "TCP"
|
108
|
+
target_port "rpc"
|
109
|
+
end
|
110
|
+
|
111
|
+
if spec.metrics_port
|
112
|
+
port do
|
113
|
+
name "metrics"
|
114
|
+
port spec.metrics_port
|
115
|
+
protocol "TCP"
|
116
|
+
target_port "metrics"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
@service.instance_eval(&block) if block
|
123
|
+
@service
|
124
|
+
end
|
125
|
+
|
126
|
+
def deployment(&block)
|
127
|
+
context = self
|
128
|
+
|
129
|
+
@deployment ||= KubeDSL.deployment do
|
130
|
+
metadata do
|
131
|
+
name "#{context.selector_app}-#{ROLE}"
|
132
|
+
namespace context.namespace.metadata.name
|
133
|
+
|
134
|
+
labels do
|
135
|
+
add :app, context.selector_app
|
136
|
+
add :role, ROLE
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
spec do
|
141
|
+
replicas context.replicas
|
142
|
+
|
143
|
+
selector do
|
144
|
+
match_labels do
|
145
|
+
add :app, context.selector_app
|
146
|
+
add :role, ROLE
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
strategy do
|
151
|
+
type "RollingUpdate"
|
152
|
+
|
153
|
+
rolling_update do
|
154
|
+
max_surge "25%"
|
155
|
+
max_unavailable 0
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
template do
|
160
|
+
metadata do
|
161
|
+
labels do
|
162
|
+
add :app, context.selector_app
|
163
|
+
add :role, ROLE
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
spec do
|
168
|
+
container(:rpc) do
|
169
|
+
name "#{context.selector_app}-#{ROLE}"
|
170
|
+
image_pull_policy "IfNotPresent"
|
171
|
+
command %w[bundle exec anycable]
|
172
|
+
|
173
|
+
port do
|
174
|
+
container_port context.port
|
175
|
+
name "grpc"
|
176
|
+
protocol "TCP"
|
177
|
+
end
|
178
|
+
|
179
|
+
if context.metrics_port
|
180
|
+
port do
|
181
|
+
container_port context.metrics_port
|
182
|
+
name "metrics"
|
183
|
+
protocol "TCP"
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
env_from do
|
188
|
+
config_map_ref do
|
189
|
+
name context.config_map.metadata.name
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
readiness_probe do
|
194
|
+
success_threshold 1
|
195
|
+
failure_threshold 3
|
196
|
+
initial_delay_seconds 15
|
197
|
+
period_seconds 10
|
198
|
+
timeout_seconds 3
|
199
|
+
|
200
|
+
tcp_socket do
|
201
|
+
port "grpc"
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
liveness_probe do
|
206
|
+
success_threshold 1
|
207
|
+
failure_threshold 3
|
208
|
+
initial_delay_seconds 90
|
209
|
+
period_seconds 10
|
210
|
+
timeout_seconds 3
|
211
|
+
|
212
|
+
tcp_socket do
|
213
|
+
port "grpc"
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
image_pull_secret do
|
219
|
+
name context.kubernetes.registry_secret.metadata.name
|
220
|
+
end
|
221
|
+
|
222
|
+
restart_policy "Always"
|
223
|
+
service_account_name context.service_account.metadata.name
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
@deployment.instance_eval(&block) if block
|
230
|
+
@deployment
|
231
|
+
end
|
232
|
+
|
233
|
+
def config_map(&block)
|
234
|
+
spec = self
|
235
|
+
|
236
|
+
@config_map ||= KubeDSL.config_map do
|
237
|
+
metadata do
|
238
|
+
name "#{spec.selector_app}-#{ROLE}-config"
|
239
|
+
namespace spec.namespace.metadata.name
|
240
|
+
end
|
241
|
+
|
242
|
+
data do
|
243
|
+
add "ANYCABLE_RPC_HOST", "0.0.0.0:50051"
|
244
|
+
if spec.redis_url
|
245
|
+
add "ANYCABLE_REDIS_URL", spec.redis_url
|
246
|
+
end
|
247
|
+
if spec.max_connection_age
|
248
|
+
add "ANYCABLE_RPC_SERVER_ARGS__MAX_CONNECTION_AGE_MS", spec.max_connection_age.to_s
|
249
|
+
end
|
250
|
+
|
251
|
+
if spec.rpc_pool_size
|
252
|
+
add "ANYCABLE_RPC_POOL_SIZE", spec.rpc_pool_size.to_s
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
@config_map.instance_eval(&block) if block
|
258
|
+
@config_map
|
259
|
+
end
|
260
|
+
|
261
|
+
alias_method :env, :config_map
|
262
|
+
|
263
|
+
delegate :kubernetes, to: :environment
|
264
|
+
|
265
|
+
delegate :docker, to: :environment
|
266
|
+
|
267
|
+
delegate :selector_app, to: :kubernetes
|
268
|
+
|
269
|
+
delegate :namespace, to: :kubernetes
|
270
|
+
|
271
|
+
def rails_spec
|
272
|
+
@rails_spec ||= kubernetes.plugin(:rails_app)
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "kuby"
|
4
|
+
|
5
|
+
require "kuby/anycable/version"
|
6
|
+
require "kuby/anycable/rpc_plugin"
|
7
|
+
require "kuby/anycable/go_plugin"
|
8
|
+
require "kuby/anycable/packages"
|
9
|
+
|
10
|
+
Kuby.register_plugin(:anycable_rpc, Kuby::AnyCable::RPCPlugin)
|
11
|
+
Kuby.register_plugin(:anycable_go, Kuby::AnyCable::GoPlugin)
|
12
|
+
|
13
|
+
Kuby.register_package("anycable-build", Kuby::AnyCable::Packages)
|
metadata
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: kuby-anycable
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Vladimir Dementyev
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-11-24 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.15'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.15'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '13.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '13.0'
|
41
|
+
description: Kuby plugin to deploy AnyCable applications
|
42
|
+
email:
|
43
|
+
- dementiev.vm@gmail.com
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- CHANGELOG.md
|
49
|
+
- LICENSE.txt
|
50
|
+
- README.md
|
51
|
+
- lib/kuby-anycable.rb
|
52
|
+
- lib/kuby/anycable.rb
|
53
|
+
- lib/kuby/anycable/go_plugin.rb
|
54
|
+
- lib/kuby/anycable/packages.rb
|
55
|
+
- lib/kuby/anycable/rpc_plugin.rb
|
56
|
+
- lib/kuby/anycable/version.rb
|
57
|
+
homepage: http://github.com/anycable/kuby-anycable
|
58
|
+
licenses:
|
59
|
+
- MIT
|
60
|
+
metadata:
|
61
|
+
bug_tracker_uri: http://github.com/anycable/kuby-anycable/issues
|
62
|
+
changelog_uri: https://github.com/anycable/kuby-anycable/blob/master/CHANGELOG.md
|
63
|
+
documentation_uri: http://github.com/anycable/kuby-anycable
|
64
|
+
homepage_uri: http://github.com/anycable/kuby-anycable
|
65
|
+
source_code_uri: http://github.com/anycable/kuby-anycable
|
66
|
+
post_install_message:
|
67
|
+
rdoc_options: []
|
68
|
+
require_paths:
|
69
|
+
- lib
|
70
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '2.6'
|
75
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
80
|
+
requirements: []
|
81
|
+
rubygems_version: 3.2.22
|
82
|
+
signing_key:
|
83
|
+
specification_version: 4
|
84
|
+
summary: Kuby plugin to deploy AnyCable applications
|
85
|
+
test_files: []
|