kubernetes_helper 1.16.0 → 1.19.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bd1b1fbd529561166b5e90b3ece98cd5f9abb81d1d652dcd52d62179daddbd14
4
- data.tar.gz: a6bb05e8553de13d43d7b9bc9c46ea5aa1dc03e1adca3fc286cb7b7ed73609ff
3
+ metadata.gz: 3d37444885845a0d47f9824c6b9e220f278ae7db62de9cc7d3222d3ea91da753
4
+ data.tar.gz: 64834c2950efa2394c032adfacdd13b8dcb392d7a5346a6101fb7c7c04e30c92
5
5
  SHA512:
6
- metadata.gz: 5fde4038a234dafaa435aa6aca47348a090bb79d53a3ba3357a3d632b1f85a849322b70851da89674412abe5d679a72feeb30ac0b86b2de83f4dd9bc3224fb8d
7
- data.tar.gz: 89ca63330472ad00a1b06004be34c43b7de2582a509247c75d605c5aa6743b64fd653d51fe3459eb1a9d24071faf18a1632663946d274c2ff7dd425a5dc7f220
6
+ metadata.gz: aa17228790e2b026d284272ae7312d9a241d00646be1fb904b863fec037c266d95e853932d3d4c62147db54e9b167d30a89191f50d8d7ae5da74605b963f7100
7
+ data.tar.gz: 65a3991a40379500a37789b37af86c258d472d627a48e95f108366050ff9300f7cc4851981e3723092074dbe161d2366935022df629447117a6cce0e7d137609
data/README.md CHANGED
@@ -22,7 +22,7 @@ Configuration and customization can be done for multiple environments and at any
22
22
  Note: The local template will be used instead of the default one.
23
23
 
24
24
  3. Install/setup the application on kubernetes
25
- Open [.kubernetes/README.md](lib/templates/README.md) to see the instructions (customize the file according to your project and keep it updated)
25
+ Open [.kubernetes/README.md](lib/templates/README.md) to see the instructions (customize the file according to your project and keep it updated in your repository)
26
26
 
27
27
 
28
28
  ## Settings API
@@ -49,15 +49,24 @@ Configuration and customization can be done for multiple environments and at any
49
49
  - `deployment.logs_resources` (Hash, optional): Configure depending on the app requirements. Default: `{ cpu: { max: '200m', min: '50m' }, mem: { max: '200Mi', min: '50Mi' } }`
50
50
 
51
51
  ### Application deployment.yml for jobs or services without internet interaction (Optional)
52
- - `deployment.job_name` (String, optional): Job deployment name (Note: Underscores are not accepted). Sample: `my-app-job`. Note: This deployment is created only if this value is present
53
- - `deployment.job_command` (String, optional): Bash command to be used for job container. Sample: `bundle exec sidekiq`
54
- - `deployment.job_sidekiq_alive_gem` (Boolean, default false): If true will add liveness checker settings using `sidekiq_alive_gem` (`sidekiq_alive` gem needs to be present in your Gemfile)
55
- - `deployment.job_services` (Array, Optional, only `job_sidekiq_alive_gem` or `job_services` is allowed): List of linux service names that are required for a healthy job container. Sample: `['sidekiq', 'cron']`
56
- - `deployment.job_resources` (Hash, optional): Configure depending on the job app requirements. Sample: `{ cpu: { max: '1', min: '500m' }, mem: { max: '1Gi', min: '500Mi' } }`
52
+ - `deployment.job_apps[].name` (String, optional): Job deployment name (Note: Underscores are not accepted). Sample: `my-app-job`. Note: This deployment is created only if this value is present
53
+ - `deployment.job_apps[].command` (String, optional): Bash command to be used for job container. Sample: `bundle exec sidekiq`
54
+ - `deployment.job_apps[].sidekiq_alive_gem` (Boolean, default false): If true will add liveness checker settings using `sidekiq_alive_gem` (`sidekiq_alive` gem needs to be present in your Gemfile)
55
+ - `deployment.job_apps[].services` (Array, Optional): List of linux service names that are required for a healthy job container. Sample: `['sidekiq', 'cron']`. Note: This will be ignored if `sidekiq_alive_gem` was defined.
56
+ - `deployment.job_apps[].resources` (Hash, optional): Configure depending on the job app requirements. Sample: `{ cpu: { max: '1', min: '500m' }, mem: { max: '1Gi', min: '500Mi' } }`
57
+
58
+ ### Required settings for Cronjob apps (Note: Cronjobs do not support `sidekiq_alive_gem` and `services`)
59
+ - `deployment.job_apps[].schedule` (String): Cron schedule. Sample: `*/5 * * * *`
60
+ - `deployment.job_apps[].kind` (String, default `Deployment`): Kind of job application [`Deployment` or `CronJob`]
61
+ - `deployment.job_apps[].concurrency_policy` (String, default `Forbid`): [Documentation](https://kubernetes.io/docs/tasks/job/automated-tasks-with-cron-jobs/#concurrency-policy)
62
+ - `deployment.job_apps[].suspend` (String, default `false`): If `true` then marks as finished the job application (stops creating new pods).
57
63
 
58
64
  ### Applications secrets.yml (Optional)
59
65
  - `secrets.name` (String): K8s secrets name where env vars will be saved and fetched from. Sample: `my-app-secrets`
60
-
66
+ - `secrets.import_all_secrets` (Boolean, default false):
67
+ - `true`: Allows k8s to auto import all secrets from `secrets.yml` as env values for the apps (No longer needed to update `deployment.yml` everytime there is a new env var)
68
+ - `false`: Permits to the gem to auto include each secret from `secrets.yml -> data` as env value for the apps (base64 encoded values. Requires to update `deployment.yml` everytime there is a new env var)
69
+
61
70
  ### Application service.yml (Optional)
62
71
  - `service.name`: K8s service name. Sample: `my-app-service`
63
72
  - `service.port_name` (String, default `http-port`): Http port name to connect between k8s ingress and service. Sample: `http-port`. Note: max 15 characters
@@ -88,7 +97,7 @@ Configuration and customization can be done for multiple environments and at any
88
97
  - `continuous_deployment.update_deployment` (Boolean, default: false): If true permits to re-generate and update the k8s deployment(s) before applying the new version (new docker image)
89
98
 
90
99
  ### Gem templating partials
91
- - `_container_extra_settings.yml` Partial template to add custom container settings. Receives `pod` as local variable (`web` | `job` | `cloudsql` | `logs`). Sample:
100
+ - `_container_extra_settings.yml` Partial template to add custom container settings. Receives `pod` as local variable (`web` | `job` | `cloudsql` | `logs`) and `pod_name`. Sample:
92
101
  ```yaml
93
102
  <% if locals[:pod] == 'job' %>
94
103
  resources:
@@ -100,7 +109,7 @@ Configuration and customization can be done for multiple environments and at any
100
109
  memory: 1Gi
101
110
  <% end %>
102
111
  ```
103
- - `_custom_containers.yml` Partial template to add extra containers (Receives `pod` as local variable: `web` | `job`). Sample:
112
+ - `_custom_containers.yml` Partial template to add extra containers (Receives `pod` as local variable: `web` | `job`) and `pod_name`. Sample:
104
113
  ```yaml
105
114
  <% if locals[:pod] == 'job' %>
106
115
  - name: scraper
@@ -67,7 +67,7 @@ module KubernetesHelper
67
67
  def import_secrets(path, secrets_name)
68
68
  path = KubernetesHelper.settings_path(path)
69
69
  data = YAML.load(File.read(path)) # rubocop:disable Security/YAMLLoad
70
- data['data'].keys.map do |secret|
70
+ (data['data'] || {}).keys.map do |secret|
71
71
  {
72
72
  'name' => secret.upcase,
73
73
  'valueFrom' => { 'secretKeyRef' => { 'name' => secrets_name, 'key' => secret } }
@@ -78,6 +78,7 @@ module KubernetesHelper
78
78
  def render_template(template_name, locals = {})
79
79
  path = KubernetesHelper.settings_path(template_name, use_template: true)
80
80
  text = "\n#{File.read(path)}"
81
+ text = text.gsub("\n", "\n#{' ' * locals[:tab]}") if locals[:tab]
81
82
  replace_config_variables(text, locals)
82
83
  end
83
84
 
@@ -94,12 +95,13 @@ module KubernetesHelper
94
95
 
95
96
  # parse secrets auto importer
96
97
  def parse_import_secrets(document) # rubocop:disable Metrics/AbcSize
97
- containers = document.dig('spec', 'template', 'spec', 'containers') || []
98
+ cronjob_containers = document.dig('spec', 'jobTemplate', 'spec', 'template', 'spec', 'containers')
99
+ containers = document.dig('spec', 'template', 'spec', 'containers') || cronjob_containers || []
98
100
  containers.each do |container|
99
101
  container['env'] = (container['env'] || [])
100
- container['env'] = container['env'] + static_env_vars if container.delete('static_env')
102
+ container['env'] = (container['env'] + static_env_vars).uniq if container.delete('static_env')
101
103
  if container['import_secrets']
102
- container['env'] = container['env'] + import_secrets(*container['import_secrets'])
104
+ container['env'] = (container['env'] + import_secrets(*container['import_secrets'])).uniq
103
105
  container.delete('import_secrets')
104
106
  end
105
107
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module KubernetesHelper
4
- VERSION = '1.16.0'
4
+ VERSION = '1.19.0'
5
5
  end
@@ -25,7 +25,8 @@ module KubernetesHelper
25
25
  deployment: {
26
26
  log_container: true,
27
27
  log_folder: '/app/log',
28
- external_secrets: {}
28
+ external_secrets: {},
29
+ job_apps: settings[:job_apps] || job_apps_from_old_settings(settings)
29
30
  },
30
31
  service: {
31
32
  port_name: 'http-port',
@@ -75,4 +76,18 @@ module KubernetesHelper
75
76
  FileUtils.cp(templates_path(name), path) unless File.exist?(path)
76
77
  end
77
78
  end
79
+
80
+ def self.job_apps_from_old_settings(settings)
81
+ return [] unless settings[:deployment][:job_name]
82
+
83
+ [
84
+ {
85
+ name: settings[:deployment][:job_name],
86
+ command: settings[:deployment][:job_command],
87
+ services: settings[:deployment][:job_services],
88
+ resources: settings[:deployment][:job_resources],
89
+ sidekiq_alive_gem: settings[:deployment][:job_sidekiq_alive_gem]
90
+ }
91
+ ]
92
+ end
78
93
  end
@@ -25,9 +25,8 @@
25
25
  DEPLOY_ENV=beta kubernetes_helper run_command "kubectl create secret generic <%=deployment.cloud_secret_name%> --from-file=credentials.json=<path-to-downloaded/credentials.json>"
26
26
  ```
27
27
 
28
- - Register manually env vars (values must be encrypted using base64)
28
+ - Register manually env vars
29
29
  Open and register secret values in `.kubernetes/secrets.yml`
30
- Note: Enter base64 encoded values
31
30
  ```bash
32
31
  DEPLOY_ENV=beta kubernetes_helper run_yml 'secrets.yml' 'kubectl create'
33
32
  # kubectl get secrets # to list all secrets registered
@@ -0,0 +1,40 @@
1
+ - apiVersion: batch/v1
2
+ kind: CronJob
3
+ metadata:
4
+ name: &cronjob_name <%= locals[:job_app][:name] %>
5
+ spec:
6
+ schedule: "<%= locals[:job_app][:schedule] %>"
7
+ concurrencyPolicy: "<%= locals[:job_app][:concurrency_policy] || 'Forbid' %>"
8
+ suspend: <%= locals[:job_app][:suspend] || false %>
9
+ # startingDeadlineSeconds: 200
10
+ jobTemplate:
11
+ spec:
12
+ template:
13
+ spec:
14
+ <<: *template_spec
15
+ restartPolicy: OnFailure
16
+ containers:
17
+ - <<: *app_container
18
+ name: *cronjob_name
19
+ <% if locals[:job_app][:command] %>
20
+ command: [ "/bin/bash", "-c", "<%= locals[:job_app][:command] %>" ]
21
+ <% end %>
22
+ <% if locals[:job_app][:resources] %>
23
+ <%= include_template "_resources.yml", locals[:job_app][:resources].merge(tab: 2) %>
24
+ <% end %>
25
+ livenessProbe: null
26
+ readinessProbe: null
27
+ <%= include_template "_container_extra_settings.yml", { pod: 'job', pod_name: locals[:job_app][:name], tab: 2 } %>
28
+
29
+ <% if deployment.cloud_secret_name %>
30
+ - *cloudsql_container
31
+ <% end %>
32
+
33
+ <% if deployment.log_container %>
34
+ - <<: *logs_container
35
+ <% end %>
36
+
37
+ <%= include_template "_custom_containers.yml", { pod: 'job', pod_name: locals[:job_app][:name], tab: 2 } %>
38
+
39
+ volumes:
40
+ <%= include_template "_volumes.yml", { pod: 'job', pod_name: locals[:job_app][:name], tab: 2 } %>
@@ -0,0 +1,47 @@
1
+ - apiVersion: apps/v1
2
+ kind: Deployment
3
+ metadata:
4
+ name: &job_app_name <%= locals[:job_app][:name] %>
5
+ spec:
6
+ replicas: 1
7
+ selector:
8
+ matchLabels:
9
+ name: *job_app_name
10
+ strategy:
11
+ type: Recreate
12
+ minReadySeconds: 10
13
+ template:
14
+ metadata:
15
+ labels:
16
+ name: *job_app_name
17
+ spec:
18
+ <<: *template_spec
19
+ containers:
20
+ - <<: *app_container
21
+ name: *job_app_name
22
+ <% if locals[:job_app][:command] %>
23
+ command: [ "/bin/bash", "-c", "<%= locals[:job_app][:command] %>" ]
24
+ <% end %>
25
+ <% if locals[:job_app][:resources] %>
26
+ <%= include_template "_resources.yml", locals[:job_app][:resources] %>
27
+ <% end %>
28
+ <%= include_template "_container_extra_settings.yml", { pod: 'job', pod_name: locals[:job_app][:name] } %>
29
+
30
+ <% if locals[:job_app][:sidekiq_alive_gem] %>
31
+ <%= include_template "_sidekiq_alive_gem.yml" %>
32
+ <% else %>
33
+ <%= include_template "_job_liveness.yml" %>
34
+ <% end %>
35
+
36
+ <% if deployment.cloud_secret_name %>
37
+ - *cloudsql_container
38
+ <% end %>
39
+
40
+ <% if deployment.log_container %>
41
+ - <<: *logs_container
42
+ <% end %>
43
+
44
+ <%= include_template "_custom_containers.yml", { pod: 'job', pod_name: locals[:job_app][:name] } %>
45
+
46
+ volumes:
47
+ <%= include_template "_volumes.yml", { pod: 'job', pod_name: locals[:job_app][:name] } %>
@@ -18,4 +18,4 @@
18
18
  <% end %>
19
19
  <% end %>
20
20
 
21
- <%= include_template "_custom_volumes.yml", { pod: locals[:pod] } %>
21
+ <%= include_template "_custom_volumes.yml", { pod: locals[:pod], tab: locals[:tab] } %>
data/lib/templates/cd.sh CHANGED
@@ -5,7 +5,7 @@ set -e
5
5
  SCRIPT_DIR=`dirname "$(realpath -s "$0")"` # app_dir/.kubernetes/
6
6
  cd "$SCRIPT_DIR/../" # project directory
7
7
 
8
- DEPLOYMENTS="<%=[deployment.job_name, deployment.name].join(',')%>"
8
+ DEPLOYMENTS="<%=(deployment.job_apps.map { |a| a[:name] } + [deployment.name]).join(',')%>"
9
9
  IMAGE_NAME="<%=continuous_deployment.image_name%>"
10
10
  CLUSTER_NAME="<%=continuous_deployment.cluster_name%>"
11
11
  PROJECT_NAME="<%=continuous_deployment.project_name%>"
@@ -21,7 +21,7 @@ LATEST_NAME="${IMAGE_NAME}:<%= continuous_deployment.image_tag || 'latest' %>"
21
21
 
22
22
  ## Update new secrets defined in secrets.yml as ENV vars for deployments
23
23
  <% if continuous_deployment.update_deployment %>
24
- kubernetes_helper run_yml 'deployment.yml' 'kubectl apply'
24
+ DEPLOY_IMAGE_TAG=$CI_COMMIT_SHA kubernetes_helper run_yml 'deployment.yml' 'kubectl apply'
25
25
  <% end %>
26
26
 
27
27
  ## Apply deployments
@@ -3,7 +3,7 @@ documents:
3
3
  kind: Deployment
4
4
  metadata:
5
5
  name: &app_name <%=deployment.name%>
6
- spec: &default_spec
6
+ spec:
7
7
  replicas: <%=deployment.replicas%>
8
8
  selector:
9
9
  matchLabels:
@@ -12,8 +12,8 @@ documents:
12
12
  type: RollingUpdate
13
13
  rollingUpdate:
14
14
  maxSurge: 1
15
- maxUnavailable: 1
16
- minReadySeconds: 5
15
+ maxUnavailable: 0
16
+ minReadySeconds: 10
17
17
  template:
18
18
  metadata:
19
19
  labels:
@@ -21,13 +21,21 @@ documents:
21
21
  spec: &template_spec
22
22
  containers:
23
23
  - &app_container
24
- image: '<%= continuous_deployment.image_name %>:<%= continuous_deployment.image_tag || "latest" %>'
24
+ image: '<%= continuous_deployment.image_name %>:<%= ENV['DEPLOY_IMAGE_TAG'] || continuous_deployment.image_tag || "latest" %>'
25
25
  <% if deployment.command %>
26
26
  command: ["/bin/bash", "-c", "<%= deployment.command %>"]
27
27
  <% end %>
28
28
  name: *app_name
29
+
29
30
  static_env: true
31
+ <% if secrets.import_all_secrets %>
32
+ envFrom:
33
+ - secretRef:
34
+ name: <%= secrets.name %>
35
+ <% else %>
30
36
  import_secrets: ['secrets.yml', '<%=secrets.name%>']
37
+ <% end %>
38
+
31
39
  ports:
32
40
  - containerPort: &port <%= deployment.app_port || 3000 %>
33
41
  name: '<%=service.backend_port_name || 'b-port'%>'
@@ -98,53 +106,9 @@ documents:
98
106
  volumes:
99
107
  <%= include_template "_volumes.yml", { pod: 'web' } %>
100
108
 
101
-
102
- <% if deployment.job_name %>
103
- - apiVersion: apps/v1
104
- kind: Deployment
105
- metadata:
106
- name: &job_app_name <%=deployment.job_name%>
107
- spec:
108
- <<: *default_spec
109
- replicas: 1
110
- selector:
111
- matchLabels:
112
- name: *job_app_name
113
- template:
114
- metadata:
115
- labels:
116
- name: *job_app_name
117
- spec:
118
- <<: *template_spec
119
- containers:
120
- - <<: *app_container
121
- name: *job_app_name
122
- <% if deployment.job_command %>
123
- command: [ "/bin/bash", "-c", "<%= deployment.job_command %>" ]
124
- <% end %>
125
- <% if deployment.job_resources %>
126
- <%= include_template "_resources.yml", deployment.job_resources %>
127
- <% end %>
128
- <%= include_template "_container_extra_settings.yml", { pod: 'job' } %>
129
-
130
- <% if deployment.job_sidekiq_alive_gem %>
131
- <%= include_template "_sidekiq_alive_gem.yml" %>
132
- <% else %>
133
- <%= include_template "_job_liveness.yml" %>
134
- <% end %>
135
-
136
- <% if deployment.cloud_secret_name %>
137
- - *cloudsql_container
138
- <% end %>
139
-
140
- <% if deployment.log_container %>
141
- - <<: *logs_container
142
- <% end %>
143
-
144
- <%= include_template "_custom_containers.yml", { pod: 'job' } %>
145
-
146
- volumes:
147
- <%= include_template "_volumes.yml", { pod: 'job' } %>
109
+ <% deployment.job_apps.each do |job_app| %>
110
+ <%= include_template '_jobs_pod.yml', job_app: job_app if job_app[:kind] != 'CronJob' %>
111
+ <%= include_template '_cronjobs_pod.yml', job_app: job_app if job_app[:kind] == 'CronJob' %>
148
112
  <% end %>
149
113
 
150
114
  <% if deployment.replicas_range %>
@@ -1,4 +1,3 @@
1
- # Every Value has to be base64 encoded
2
1
  # IMPORTANT: For security reason, never ever commit secret values, only keys
3
2
 
4
3
  apiVersion: v1
@@ -6,6 +5,6 @@ kind: Secret
6
5
  metadata:
7
6
  name: '<%=secrets.name%>'
8
7
  type: Opaque
9
- data:
10
- my_key1: "based_64_value_encoded"
11
- my_key2: "based_64_value_encoded"
8
+ stringData:
9
+ MY_KEY1: "my value1"
10
+ MY_KEY2: "my value2"
@@ -12,13 +12,18 @@ settings = {
12
12
  env_vars: {}, # Sample: { 'CUSTOM_VAR' => 'value' }
13
13
  # command: '', # custom container command (default empty to be managed by Dockerfile)
14
14
  # liveness_path: '/check_liveness', # nil if not exist
15
- # job_name: "#{app_name}-job", # enable if there is any background service
16
- # job_command: 'bundle exec sidekiq -C config/sidekiq.yml',
17
- # job_services: ['sidekiq', 'cron'] # list of linux services needed.
18
15
  # custom_volumes: { my_volume: { kind: 'hostPath', mount_path: '/', settings: { path: '..', type: 'Directory' } } }
16
+ job_apps: [
17
+ # {
18
+ # name: "#{app_name}-job", # enable if there is any background service
19
+ # command: 'bundle exec sidekiq -C config/sidekiq.yml',
20
+ # services: ['sidekiq', 'cron'] # list of linux services needed.
21
+ # }
22
+ ]
19
23
  },
20
24
  secrets: {
21
- name: "#{app_name}-secrets"
25
+ name: "#{app_name}-secrets",
26
+ import_all_secrets: true
22
27
  },
23
28
  service: {
24
29
  name: app_name,
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kubernetes_helper
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.16.0
4
+ version: 1.19.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - owen2345
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-04-28 00:00:00.000000000 Z
11
+ date: 2022-07-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: erb
@@ -44,9 +44,11 @@ files:
44
44
  - lib/templates/_cd_digital.sh
45
45
  - lib/templates/_cd_google.sh
46
46
  - lib/templates/_container_extra_settings.yml
47
+ - lib/templates/_cronjobs_pod.yml
47
48
  - lib/templates/_custom_containers.yml
48
49
  - lib/templates/_custom_volumes.yml
49
50
  - lib/templates/_job_liveness.yml
51
+ - lib/templates/_jobs_pod.yml
50
52
  - lib/templates/_replicas.yml
51
53
  - lib/templates/_resources.yml
52
54
  - lib/templates/_sidekiq_alive_gem.yml