@spine-event-engine/deployment-gke 2.0.0-snapshot.11

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.
@@ -0,0 +1,303 @@
1
+ locals {
2
+ labels = {
3
+ "app.kubernetes.io/part-of" = "spine-application"
4
+ }
5
+ }
6
+
7
+ resource "kubernetes_config_map_v1" "runtime" {
8
+ metadata {
9
+ name = "spine-runtime"
10
+ namespace = var.namespace
11
+ labels = local.labels
12
+ }
13
+
14
+ data = {
15
+ APPLICATION_PORT = tostring(var.application_port)
16
+ APPLICATION_PROCESS_COUNT = tostring(var.application_process_count)
17
+ BACKEND_DISCOVERY_PORT = tostring(var.application_port)
18
+ BACKEND_DISCOVERY_SERVICE = "application.${var.namespace}.svc.cluster.local"
19
+ DELIVERY_SERVER_URL = "http://delivery.${var.namespace}.svc.cluster.local:${var.delivery_port}"
20
+ DELIVERY_SHARD_COUNT = tostring(var.delivery_shard_count)
21
+ GATEWAY_PORT = tostring(var.gateway_port)
22
+ NODE_ENV = "production"
23
+ }
24
+ }
25
+
26
+ resource "kubernetes_service_v1" "application" {
27
+ metadata {
28
+ name = "application"
29
+ namespace = var.namespace
30
+ labels = local.labels
31
+ }
32
+
33
+ spec {
34
+ cluster_ip = "None"
35
+ publish_not_ready_addresses = false
36
+ selector = merge(local.labels, { "app.kubernetes.io/component" = "application" })
37
+
38
+ port {
39
+ name = "grpc"
40
+ port = var.application_port
41
+ target_port = "coordinator"
42
+ }
43
+ }
44
+ }
45
+
46
+ resource "kubernetes_service_v1" "gateway" {
47
+ metadata {
48
+ name = "gateway"
49
+ namespace = var.namespace
50
+ labels = local.labels
51
+ }
52
+
53
+ spec {
54
+ selector = merge(local.labels, { "app.kubernetes.io/component" = "gateway" })
55
+
56
+ port {
57
+ name = "gateway"
58
+ port = var.gateway_port
59
+ target_port = "gateway"
60
+ }
61
+ }
62
+ }
63
+
64
+ resource "kubernetes_service_v1" "delivery" {
65
+ metadata {
66
+ name = "delivery"
67
+ namespace = var.namespace
68
+ labels = local.labels
69
+ }
70
+
71
+ spec {
72
+ selector = merge(local.labels, { "app.kubernetes.io/component" = "delivery" })
73
+
74
+ port {
75
+ name = "grpc"
76
+ port = var.delivery_port
77
+ target_port = "grpc"
78
+ }
79
+ }
80
+ }
81
+
82
+ resource "kubernetes_deployment_v1" "application" {
83
+ metadata {
84
+ name = "application"
85
+ namespace = var.namespace
86
+ labels = local.labels
87
+ }
88
+
89
+ lifecycle {
90
+ precondition {
91
+ condition = var.autoscaling_min_replicas <= var.autoscaling_max_replicas
92
+ error_message = "Autoscaling minimum replicas must not exceed the maximum."
93
+ }
94
+ }
95
+
96
+ spec {
97
+ replicas = var.autoscaling_enabled ? null : tostring(var.application_replicas)
98
+
99
+ selector {
100
+ match_labels = merge(local.labels, { "app.kubernetes.io/component" = "application" })
101
+ }
102
+
103
+ template {
104
+ metadata {
105
+ labels = merge(local.labels, { "app.kubernetes.io/component" = "application" })
106
+ }
107
+
108
+ spec {
109
+ service_account_name = var.service_account_name
110
+
111
+ container {
112
+ name = "application"
113
+ image = var.application_image
114
+
115
+ port {
116
+ name = "coordinator"
117
+ container_port = var.application_port
118
+ }
119
+
120
+ env {
121
+ name = "HOST"
122
+ value = "0.0.0.0"
123
+ }
124
+
125
+ env {
126
+ name = "PORT"
127
+ value = tostring(var.application_port)
128
+ }
129
+
130
+ env_from {
131
+ config_map_ref {
132
+ name = kubernetes_config_map_v1.runtime.metadata[0].name
133
+ }
134
+ }
135
+
136
+ env_from {
137
+ secret_ref {
138
+ name = var.application_secret_name
139
+ }
140
+ }
141
+
142
+ readiness_probe {
143
+ tcp_socket {
144
+ port = "coordinator"
145
+ }
146
+ }
147
+ }
148
+ }
149
+ }
150
+ }
151
+ }
152
+
153
+ resource "kubernetes_deployment_v1" "gateway" {
154
+ metadata {
155
+ name = "gateway"
156
+ namespace = var.namespace
157
+ labels = local.labels
158
+ }
159
+
160
+ spec {
161
+ replicas = 1
162
+
163
+ selector {
164
+ match_labels = merge(local.labels, { "app.kubernetes.io/component" = "gateway" })
165
+ }
166
+
167
+ template {
168
+ metadata {
169
+ labels = merge(local.labels, { "app.kubernetes.io/component" = "gateway" })
170
+ }
171
+
172
+ spec {
173
+ service_account_name = var.service_account_name
174
+
175
+ container {
176
+ name = "gateway"
177
+ image = var.gateway_image
178
+
179
+ port {
180
+ name = "gateway"
181
+ container_port = var.gateway_port
182
+ }
183
+
184
+ env {
185
+ name = "HOST"
186
+ value = "0.0.0.0"
187
+ }
188
+
189
+ env {
190
+ name = "PORT"
191
+ value = tostring(var.gateway_port)
192
+ }
193
+
194
+ env_from {
195
+ config_map_ref {
196
+ name = kubernetes_config_map_v1.runtime.metadata[0].name
197
+ }
198
+ }
199
+
200
+ env_from {
201
+ secret_ref {
202
+ name = var.gateway_secret_name
203
+ }
204
+ }
205
+
206
+ readiness_probe {
207
+ tcp_socket {
208
+ port = "gateway"
209
+ }
210
+ }
211
+ }
212
+ }
213
+ }
214
+ }
215
+ }
216
+
217
+ resource "kubernetes_deployment_v1" "delivery" {
218
+ metadata {
219
+ name = "delivery"
220
+ namespace = var.namespace
221
+ labels = local.labels
222
+ }
223
+
224
+ spec {
225
+ replicas = 1
226
+
227
+ selector {
228
+ match_labels = merge(local.labels, { "app.kubernetes.io/component" = "delivery" })
229
+ }
230
+
231
+ template {
232
+ metadata {
233
+ labels = merge(local.labels, { "app.kubernetes.io/component" = "delivery" })
234
+ }
235
+
236
+ spec {
237
+ service_account_name = var.service_account_name
238
+
239
+ container {
240
+ name = "delivery"
241
+ image = var.delivery_image
242
+
243
+ port {
244
+ name = "grpc"
245
+ container_port = var.delivery_port
246
+ }
247
+
248
+ env {
249
+ name = "HOST"
250
+ value = "0.0.0.0"
251
+ }
252
+
253
+ env {
254
+ name = "PORT"
255
+ value = tostring(var.delivery_port)
256
+ }
257
+
258
+ readiness_probe {
259
+ tcp_socket {
260
+ port = "grpc"
261
+ }
262
+ }
263
+ }
264
+ }
265
+ }
266
+ }
267
+ }
268
+
269
+ resource "kubernetes_horizontal_pod_autoscaler_v2" "application" {
270
+ count = var.autoscaling_enabled ? 1 : 0
271
+
272
+ metadata {
273
+ name = "application"
274
+ namespace = var.namespace
275
+ labels = local.labels
276
+ }
277
+
278
+ spec {
279
+ min_replicas = var.autoscaling_min_replicas
280
+ max_replicas = var.autoscaling_max_replicas
281
+
282
+ scale_target_ref {
283
+ api_version = "apps/v1"
284
+ kind = "Deployment"
285
+ name = kubernetes_deployment_v1.application.metadata[0].name
286
+ }
287
+
288
+ metric {
289
+ type = "External"
290
+
291
+ external {
292
+ metric {
293
+ name = var.autoscaling_metric
294
+ }
295
+
296
+ target {
297
+ type = "AverageValue"
298
+ average_value = var.autoscaling_target
299
+ }
300
+ }
301
+ }
302
+ }
303
+ }
@@ -0,0 +1,27 @@
1
+ # Create these Secrets separately. Terraform deliberately never receives their values.
2
+ application_secret_name = "my-application-runtime"
3
+ gateway_secret_name = "my-gateway-runtime"
4
+
5
+ # Replace every image with an immutable image published by your delivery pipeline.
6
+ application_image = "REGION-docker.pkg.dev/PROJECT/spine/application@sha256:REPLACE"
7
+ gateway_image = "REGION-docker.pkg.dev/PROJECT/spine/gateway@sha256:REPLACE"
8
+ delivery_image = "REGION-docker.pkg.dev/PROJECT/spine/simple-delivery@sha256:REPLACE"
9
+
10
+ # Choose a context created by `gcloud container clusters get-credentials`.
11
+ kubeconfig_context = "gke_PROJECT_REGION_CLUSTER"
12
+
13
+ # This value controls manual capacity while autoscaling_enabled is false.
14
+ application_replicas = 2
15
+
16
+ # Set both values deliberately. One Pod starts this many complete application
17
+ # children, while the application builds its contexts with this many Delivery shards.
18
+ application_process_count = 2
19
+ delivery_shard_count = 2
20
+
21
+ # The template creates no HPA unless you explicitly enable it. Select values
22
+ # that match an external metric adapter already operated by your platform team.
23
+ autoscaling_enabled = false
24
+ autoscaling_metric = "requests_per_second"
25
+ autoscaling_target = "10"
26
+ autoscaling_min_replicas = 1
27
+ autoscaling_max_replicas = 8
@@ -0,0 +1,191 @@
1
+ variable "kubeconfig_path" {
2
+ description = "Path to the operator's kubeconfig file for the existing GKE cluster."
3
+ type = string
4
+ default = "~/.kube/config"
5
+ }
6
+
7
+ variable "kubeconfig_context" {
8
+ description = "Kubeconfig context for the target GKE cluster."
9
+ type = string
10
+
11
+ validation {
12
+ condition = trimspace(var.kubeconfig_context) != ""
13
+ error_message = "Kubeconfig context must not be empty."
14
+ }
15
+ }
16
+
17
+ variable "namespace" {
18
+ description = "Existing Kubernetes namespace that receives the private topology."
19
+ type = string
20
+ default = "spine-app"
21
+
22
+ validation {
23
+ condition = trimspace(var.namespace) != ""
24
+ error_message = "Namespace must not be empty."
25
+ }
26
+ }
27
+
28
+ variable "service_account_name" {
29
+ description = "Existing Kubernetes ServiceAccount used by every workload in this template."
30
+ type = string
31
+ default = "default"
32
+
33
+ validation {
34
+ condition = trimspace(var.service_account_name) != ""
35
+ error_message = "ServiceAccount name must not be empty."
36
+ }
37
+ }
38
+
39
+ variable "application_image" {
40
+ description = "Immutable image reference for the application-node process."
41
+ type = string
42
+
43
+ validation {
44
+ condition = trimspace(var.application_image) != ""
45
+ error_message = "Application image must not be empty."
46
+ }
47
+ }
48
+
49
+ variable "gateway_image" {
50
+ description = "Immutable image reference for the standalone Gateway process."
51
+ type = string
52
+
53
+ validation {
54
+ condition = trimspace(var.gateway_image) != ""
55
+ error_message = "Gateway image must not be empty."
56
+ }
57
+ }
58
+
59
+ variable "delivery_image" {
60
+ description = "Immutable image reference for the simple in-memory delivery server."
61
+ type = string
62
+
63
+ validation {
64
+ condition = trimspace(var.delivery_image) != ""
65
+ error_message = "Delivery image must not be empty."
66
+ }
67
+ }
68
+
69
+ variable "application_replicas" {
70
+ description = "Number of identical application nodes when optional autoscaling is disabled."
71
+ type = number
72
+ default = 2
73
+
74
+ validation {
75
+ condition = var.application_replicas >= 0 && floor(var.application_replicas) == var.application_replicas
76
+ error_message = "Application replicas must be zero or greater."
77
+ }
78
+ }
79
+
80
+ variable "application_process_count" {
81
+ description = "Number of complete application replicas started in each application Pod."
82
+ type = number
83
+
84
+ validation {
85
+ condition = var.application_process_count >= 1 && floor(var.application_process_count) == var.application_process_count
86
+ error_message = "Application process count must be a positive integer."
87
+ }
88
+ }
89
+
90
+ variable "delivery_shard_count" {
91
+ description = "Delivery shard count passed explicitly to each application image's context assembly."
92
+ type = number
93
+
94
+ validation {
95
+ condition = var.delivery_shard_count >= 1 && floor(var.delivery_shard_count) == var.delivery_shard_count
96
+ error_message = "Delivery shard count must be a positive integer."
97
+ }
98
+ }
99
+
100
+ variable "application_port" {
101
+ description = "Private native gRPC port exposed by each application node."
102
+ type = number
103
+ default = 8080
104
+
105
+ validation {
106
+ condition = var.application_port >= 1 && var.application_port <= 65535 && floor(var.application_port) == var.application_port
107
+ error_message = "Application port must be an integer from 1 through 65535."
108
+ }
109
+ }
110
+
111
+ variable "gateway_port" {
112
+ description = "Private browser Gateway port exposed to an operator-managed edge."
113
+ type = number
114
+ default = 8081
115
+
116
+ validation {
117
+ condition = var.gateway_port >= 1 && var.gateway_port <= 65535 && floor(var.gateway_port) == var.gateway_port
118
+ error_message = "Gateway port must be an integer from 1 through 65535."
119
+ }
120
+ }
121
+
122
+ variable "delivery_port" {
123
+ description = "Private gRPC port exposed by the simple delivery server."
124
+ type = number
125
+ default = 8484
126
+
127
+ validation {
128
+ condition = var.delivery_port >= 1 && var.delivery_port <= 65535 && floor(var.delivery_port) == var.delivery_port
129
+ error_message = "Delivery port must be an integer from 1 through 65535."
130
+ }
131
+ }
132
+
133
+ variable "application_secret_name" {
134
+ description = "Name of an existing Secret containing application-selected configuration."
135
+ type = string
136
+
137
+ validation {
138
+ condition = trimspace(var.application_secret_name) != ""
139
+ error_message = "Application Secret name must not be empty."
140
+ }
141
+ }
142
+
143
+ variable "gateway_secret_name" {
144
+ description = "Name of an existing Secret containing Gateway session and identity configuration."
145
+ type = string
146
+
147
+ validation {
148
+ condition = trimspace(var.gateway_secret_name) != ""
149
+ error_message = "Gateway Secret name must not be empty."
150
+ }
151
+ }
152
+
153
+ variable "autoscaling_enabled" {
154
+ description = "Creates the module's optional external-metric HPA when true; never combine it with KEDA."
155
+ type = bool
156
+ default = false
157
+ }
158
+
159
+ variable "autoscaling_metric" {
160
+ description = "External metric name selected by the operator when autoscaling is enabled."
161
+ type = string
162
+ default = "requests_per_second"
163
+ }
164
+
165
+ variable "autoscaling_target" {
166
+ description = "Target average external-metric value selected by the operator."
167
+ type = string
168
+ default = "10"
169
+ }
170
+
171
+ variable "autoscaling_min_replicas" {
172
+ description = "Minimum application-node replicas selected by the operator for the optional HPA."
173
+ type = number
174
+ default = 1
175
+
176
+ validation {
177
+ condition = var.autoscaling_min_replicas >= 1 && floor(var.autoscaling_min_replicas) == var.autoscaling_min_replicas
178
+ error_message = "Autoscaling minimum replicas must be a positive integer."
179
+ }
180
+ }
181
+
182
+ variable "autoscaling_max_replicas" {
183
+ description = "Maximum application-node replicas selected by the operator for the optional HPA."
184
+ type = number
185
+ default = 8
186
+
187
+ validation {
188
+ condition = var.autoscaling_max_replicas >= 1 && floor(var.autoscaling_max_replicas) == var.autoscaling_max_replicas
189
+ error_message = "Autoscaling maximum replicas must be a positive integer."
190
+ }
191
+ }
@@ -0,0 +1,15 @@
1
+ terraform {
2
+ required_version = ">= 1.6.0"
3
+
4
+ required_providers {
5
+ kubernetes = {
6
+ source = "hashicorp/kubernetes"
7
+ version = "~> 3.2"
8
+ }
9
+ }
10
+ }
11
+
12
+ provider "kubernetes" {
13
+ config_path = var.kubeconfig_path
14
+ config_context = var.kubeconfig_context
15
+ }