kubernetes_helper 0.2.1 → 0.3.3
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 +4 -4
- data/README.md +7 -7
- data/Rakefile +1 -1
- data/exe/kubernetes_helper +12 -16
- data/lib/kubernetes_helper.rb +23 -4
- data/lib/kubernetes_helper/core.rb +52 -21
- data/lib/kubernetes_helper/version.rb +3 -1
- data/lib/templates/README.md +97 -0
- data/lib/templates/_replicas.yml.erb +12 -0
- data/lib/templates/_sidekiq_alive_gem.yml.erb +18 -0
- data/lib/templates/cd.sh +49 -0
- data/lib/templates/deployment.yml +125 -0
- data/lib/templates/ingress.yml +33 -0
- data/lib/templates/secrets.yml +11 -0
- data/lib/templates/service.yml +27 -0
- data/lib/templates/settings.rb +42 -0
- metadata +26 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c24816e7925c930deb198ab8b10b9f820ad4f5f23b4b06ee5e65d8d1d0e82208
|
4
|
+
data.tar.gz: '06395250bc71d298cfcd7d56409fe98e1a4ecd614ee79e24d7dc9cdbf01d1d1b'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0a59e813c49a519036e6532537a9d194626395fdf0e5cee6c751f32cfb3e4c5fdff5454ae67dfe0ce500ec2f2c3317915aec8ed9c2f85b175a101e58b2d0d9ad
|
7
|
+
data.tar.gz: 915c6cebb2e9f5829274d564c449d5c57ae3aa06ef524002c41e48920379d4126e6da444a9a08dc69df4492ec541c825484d2d579ef39e4e01e325e9dc627417
|
data/README.md
CHANGED
@@ -22,16 +22,16 @@ Or install it yourself as:
|
|
22
22
|
|
23
23
|
## Usage
|
24
24
|
|
25
|
-
TODO: Write usage instructions here
|
26
|
-
|
27
|
-
## Development
|
28
|
-
|
29
|
-
|
30
25
|
## TODO
|
31
26
|
- Documentation
|
32
|
-
-
|
33
|
-
-
|
27
|
+
- Include conditional blocks
|
28
|
+
- Include hardcoded env values
|
29
|
+
- Tasks
|
30
|
+
- Add docs to include partials using `include_template 'sample.yml.erb'`
|
34
31
|
- Rake verify files
|
32
|
+
- Add one_step_configuration.sh
|
33
|
+
- Fix if/end_if for blocks
|
34
|
+
- Ability to copy specific template
|
35
35
|
|
36
36
|
## Contributing
|
37
37
|
|
data/Rakefile
CHANGED
data/exe/kubernetes_helper
CHANGED
@@ -4,34 +4,30 @@ require 'kubernetes_helper'
|
|
4
4
|
|
5
5
|
case ARGV[0]
|
6
6
|
# Parse variables and run provided command.
|
7
|
-
# Sample: DEPLOY_ENV=beta rake kubernetes_helper:run_command
|
7
|
+
# Sample: DEPLOY_ENV=beta rake kubernetes_helper:run_command
|
8
|
+
# "gcloud compute addresses create \#{ingress.ip_name} --global"'
|
8
9
|
when 'run_command'
|
9
10
|
KubernetesHelper::Core.new(ENV['DEPLOY_ENV']).run_command(ARGV[1])
|
10
|
-
|
11
11
|
# Run the deployment script.
|
12
|
-
# Sample: DEPLOY_ENV=beta
|
12
|
+
# Sample: DEPLOY_ENV=beta kubernetes_helper run_deployment "cd_gcloud.sh"
|
13
13
|
when 'run_deployment'
|
14
|
-
script_path = KubernetesHelper.settings_path(ARGV[1])
|
15
|
-
KubernetesHelper::Core.new(ENV['DEPLOY_ENV']).
|
16
|
-
|
14
|
+
script_path = KubernetesHelper.settings_path(ARGV[1], use_template: true)
|
15
|
+
KubernetesHelper::Core.new(ENV['DEPLOY_ENV']).run_script(script_path)
|
17
16
|
# Parses kubernetes yml files (supporting multiple documents, Config variables replacement, include secrets).
|
18
|
-
# Sample: DEPLOY_ENV=beta
|
17
|
+
# Sample: DEPLOY_ENV=beta kubernetes_helper run_deployment "deployment.yml" "kubectl create"
|
19
18
|
when 'run_yml'
|
20
19
|
output_path = KubernetesHelper.settings_path('tmp_result.yml')
|
21
20
|
KubernetesHelper::Core
|
22
21
|
.new(ENV['DEPLOY_ENV'])
|
23
|
-
.parse_yml_file(KubernetesHelper.settings_path(ARGV[1]), output_path)
|
22
|
+
.parse_yml_file(KubernetesHelper.settings_path(ARGV[1], use_template: true), output_path)
|
24
23
|
KubernetesHelper.run_cmd("#{ARGV[2]} -f #{output_path}")
|
25
|
-
|
26
24
|
# Generate template files
|
27
|
-
when 'generate
|
28
|
-
|
29
|
-
|
30
|
-
# Verify yml files for possible errors.
|
31
|
-
# Sample: DEPLOY_ENV=beta rake kubernetes_helper:verify_yml_files
|
25
|
+
when 'generate_templates' # Sample: kubernetes_helper generate basic
|
26
|
+
mode = ARGV[1] || 'basic'
|
27
|
+
KubernetesHelper.copy_templates(mode)
|
32
28
|
when 'verify_yml'
|
33
|
-
|
34
|
-
|
29
|
+
# Verify yml files for possible errors.
|
30
|
+
# TODO: ...
|
35
31
|
else
|
36
32
|
puts 'Invalid command'
|
37
33
|
end
|
data/lib/kubernetes_helper.rb
CHANGED
@@ -14,15 +14,18 @@ module KubernetesHelper
|
|
14
14
|
|
15
15
|
# @param env_name (String)
|
16
16
|
# @return [Hash]
|
17
|
-
def self.load_settings
|
17
|
+
def self.load_settings
|
18
18
|
config_file = File.join(settings_path, 'settings.rb')
|
19
19
|
load config_file
|
20
|
-
settings
|
20
|
+
settings
|
21
21
|
end
|
22
22
|
|
23
|
-
def self.settings_path(file_name = nil)
|
23
|
+
def self.settings_path(file_name = nil, use_template: false)
|
24
24
|
path = File.join(Dir.pwd, FOLDER_NAME)
|
25
|
-
|
25
|
+
if file_name
|
26
|
+
app_path = File.join(path, file_name)
|
27
|
+
path = use_template && !File.exist?(app_path) ? templates_path(file_name) : app_path
|
28
|
+
end
|
26
29
|
path
|
27
30
|
end
|
28
31
|
|
@@ -30,4 +33,20 @@ module KubernetesHelper
|
|
30
33
|
res = Kernel.system cmd
|
31
34
|
Kernel.abort("::::::::CD: failed running command: #{title || cmd} ==> #{caller}") if res != true
|
32
35
|
end
|
36
|
+
|
37
|
+
def self.templates_path(file_name = nil)
|
38
|
+
path = File.join(File.expand_path(__dir__), 'templates')
|
39
|
+
file_name ? File.join(path, file_name) : path
|
40
|
+
end
|
41
|
+
|
42
|
+
# @param mode (basic, advanced)
|
43
|
+
def self.copy_templates(mode)
|
44
|
+
FileUtils.mkdir(settings_path) unless Dir.exist?(settings_path)
|
45
|
+
files = %w[README.md secrets.yml settings.rb]
|
46
|
+
files += %w[deployment.yml cd.sh ingress.yml service.yml] if mode == 'advanced'
|
47
|
+
files.each do |name|
|
48
|
+
path = settings_path(name)
|
49
|
+
FileUtils.cp(templates_path(name), path) unless File.exist?(path)
|
50
|
+
end
|
51
|
+
end
|
33
52
|
end
|
@@ -2,20 +2,33 @@
|
|
2
2
|
|
3
3
|
require 'yaml'
|
4
4
|
require 'json'
|
5
|
+
require 'erb'
|
6
|
+
# require 'byebug' rescue nil
|
7
|
+
|
5
8
|
module KubernetesHelper
|
9
|
+
class ErbBinding < OpenStruct
|
10
|
+
def get_binding # rubocop:disable Naming/AccessorMethodName:
|
11
|
+
binding
|
12
|
+
end
|
13
|
+
|
14
|
+
def include_template(name)
|
15
|
+
render_template.call(name)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
6
19
|
class Core
|
7
20
|
# @return [Hash]
|
8
21
|
attr_accessor :config_values
|
9
22
|
|
10
|
-
# @param
|
11
|
-
def initialize(
|
12
|
-
|
13
|
-
@config_values = KubernetesHelper.load_settings(env_name)
|
23
|
+
# @param _env_name (String)
|
24
|
+
def initialize(_env_name)
|
25
|
+
@config_values = KubernetesHelper.load_settings
|
14
26
|
end
|
15
27
|
|
16
28
|
def parse_yml_file(file_path, output_path)
|
17
29
|
parsed_content = replace_config_variables(File.read(file_path))
|
18
|
-
|
30
|
+
File.open(output_path, 'w+') { |f| f << parsed_content } # save as draft to be reviewed if failed
|
31
|
+
old_yaml = YAML.load_stream(parsed_content)
|
19
32
|
json_data = old_yaml.to_json # fix to skip anchors
|
20
33
|
yml_data = JSON.parse(json_data)
|
21
34
|
export_documents(yml_data, output_path)
|
@@ -24,9 +37,13 @@ module KubernetesHelper
|
|
24
37
|
# @param text (String)
|
25
38
|
# Sample: replicas: '#{deployment.replicas}'
|
26
39
|
def replace_config_variables(text)
|
27
|
-
|
28
|
-
|
29
|
-
end
|
40
|
+
values = config_values.map do |key, value| # rubocop:disable Style/HashTransformValues
|
41
|
+
[key, value.is_a?(Hash) ? OpenStruct.new(value) : value]
|
42
|
+
end.to_h
|
43
|
+
values[:render_template] = method(:render_template)
|
44
|
+
bind = ErbBinding.new(values).get_binding
|
45
|
+
template = ERB.new(text)
|
46
|
+
template.result(bind)
|
30
47
|
end
|
31
48
|
|
32
49
|
def run_command(command)
|
@@ -34,13 +51,13 @@ module KubernetesHelper
|
|
34
51
|
KubernetesHelper.run_cmd(command)
|
35
52
|
end
|
36
53
|
|
37
|
-
def
|
54
|
+
def run_script(script_path)
|
38
55
|
content = replace_config_variables(File.read(script_path))
|
39
|
-
tmp_file = KubernetesHelper.settings_path('
|
56
|
+
tmp_file = KubernetesHelper.settings_path('tmp_script.sh')
|
40
57
|
File.write(tmp_file, content)
|
41
58
|
KubernetesHelper.run_cmd("chmod +x #{tmp_file}")
|
42
59
|
KubernetesHelper.run_cmd(tmp_file)
|
43
|
-
File.delete(tmp_file)
|
60
|
+
# File.delete(tmp_file) # keep tmp script for analysis purpose
|
44
61
|
end
|
45
62
|
|
46
63
|
private
|
@@ -58,20 +75,26 @@ module KubernetesHelper
|
|
58
75
|
end
|
59
76
|
end
|
60
77
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
78
|
+
def render_template(template_name)
|
79
|
+
path = KubernetesHelper.settings_path(template_name, use_template: true)
|
80
|
+
text = "\n#{File.read(path)}"
|
81
|
+
replace_config_variables(text)
|
82
|
+
end
|
83
|
+
|
84
|
+
def static_env_vars
|
85
|
+
(config_values.dig(:deployment, :env_vars) || {}).map do |key, value|
|
86
|
+
{
|
87
|
+
'name' => key.to_s,
|
88
|
+
'value' => value
|
89
|
+
}
|
67
90
|
end
|
68
|
-
parent
|
69
91
|
end
|
70
92
|
|
71
93
|
# parse secrets auto importer
|
72
94
|
def parse_import_secrets(document)
|
73
95
|
containers = document.dig('spec', 'template', 'spec', 'containers') || []
|
74
96
|
containers.each do |container|
|
97
|
+
container['env'] = (container['env'] || []) + static_env_vars
|
75
98
|
if container['import_secrets']
|
76
99
|
container['env'] = container['env'] + import_secrets(*container['import_secrets'])
|
77
100
|
container.delete('import_secrets')
|
@@ -80,13 +103,21 @@ module KubernetesHelper
|
|
80
103
|
end
|
81
104
|
|
82
105
|
def export_documents(yml_data, file_path)
|
83
|
-
documents = yml_data.delete('documents') || Array(yml_data)
|
84
106
|
File.open(file_path, 'w+') do |f|
|
85
|
-
|
107
|
+
parse_documents(yml_data).each do |document|
|
86
108
|
parse_import_secrets(document)
|
87
|
-
f
|
109
|
+
f.write(document.to_yaml)
|
88
110
|
end
|
89
111
|
end
|
90
112
|
end
|
113
|
+
|
114
|
+
# @return [Array<Hash>]
|
115
|
+
def parse_documents(yml_data)
|
116
|
+
documents = []
|
117
|
+
Array(yml_data).each do |document|
|
118
|
+
document['documents'] ? documents.push(*document['documents']) : documents.push(document)
|
119
|
+
end
|
120
|
+
documents
|
121
|
+
end
|
91
122
|
end
|
92
123
|
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# Kubernetes app configuration
|
2
|
+
|
3
|
+
## Configure a new application environment
|
4
|
+
- Create the project on Gcloud
|
5
|
+
- Set the project where to work on
|
6
|
+
`gcloud config set project my-project`
|
7
|
+
|
8
|
+
- Create the cluster (Only if not exist)
|
9
|
+
`gcloud container clusters create my-cluster`
|
10
|
+
`# gcloud container clusters list --region europe-west4-a # to list clusters`
|
11
|
+
|
12
|
+
- Use the cluster/project as default
|
13
|
+
`gcloud container clusters get-credentials my-cluster --zone europe-west4-a`
|
14
|
+
|
15
|
+
- Install helper for the next commands
|
16
|
+
`gem install kubernetes_helper`
|
17
|
+
|
18
|
+
- Verify or update k8s settings in .kubernetes/settings.rb
|
19
|
+
|
20
|
+
- Register shared cloudsql proxy configuration (only if not exists)
|
21
|
+
```bash
|
22
|
+
DEPLOY_ENV=beta kubernetes_helper run_command "kubectl create secret generic <%=deployment.cloud_secret_name%> --from-file=credentials.json=<path-to-downloaded/credentials.json>"
|
23
|
+
```
|
24
|
+
|
25
|
+
- Register manually env vars (values must be encrypted using base64)
|
26
|
+
Open and register secret values in `.kubernetes/secrets.yml`
|
27
|
+
Note: Enter base64 encoded values
|
28
|
+
```bash
|
29
|
+
DEPLOY_ENV=beta kubernetes_helper run_yml 'secrets.yml' 'kubectl create'
|
30
|
+
# kubectl get secrets # to list all secrets registered
|
31
|
+
```
|
32
|
+
|
33
|
+
- Create deployment to run application
|
34
|
+
```bash
|
35
|
+
DEPLOY_ENV=beta kubernetes_helper run_yml 'deployment.yml' 'kubectl create'
|
36
|
+
# kubectl get deployment # to list deployments
|
37
|
+
```
|
38
|
+
|
39
|
+
- Create service to connect pods and ingress
|
40
|
+
```bash
|
41
|
+
DEPLOY_ENV=beta kubernetes_helper run_yml 'service.yml' 'kubectl create'
|
42
|
+
# kubectl get services # to list all registered services
|
43
|
+
```
|
44
|
+
|
45
|
+
- Create the public ip address (only if static ip is required)
|
46
|
+
```bash
|
47
|
+
DEPLOY_ENV=beta kubernetes_helper run_command "gcloud compute addresses create <%=ingress.ip_name%> --global"
|
48
|
+
# gcloud compute addresses list # to list static ips generated
|
49
|
+
# Copy new external ip generated by the previous command and point your domain to it
|
50
|
+
```
|
51
|
+
|
52
|
+
- Register ingress to receive external http calls (includes ssl certificates if defined)
|
53
|
+
```bash
|
54
|
+
DEPLOY_ENV=beta kubernetes_helper run_yml 'ingress.yml' 'kubectl create'
|
55
|
+
# kubectl get ingress # to list all registered ingresses
|
56
|
+
# kubectl get ManagedCertificate # to list all certificates
|
57
|
+
# Domain and ssl propagation can take more than 10 minutes
|
58
|
+
# You can start accessing to the app using the generated ip address
|
59
|
+
# `kubectl get ManagedCertificate` # to see the status of ssl provisionning
|
60
|
+
```
|
61
|
+
|
62
|
+
## Apply any k8s setting changes
|
63
|
+
- Secrets
|
64
|
+
Open kubernetes secrets and add/edit/remove values and then save it
|
65
|
+
`kubectl edit secret ...`
|
66
|
+
Once secrets were updated, then restart all related pods, see: https://medium.com/devops-dudes/how-to-propagate-a-change-in-kubernetes-secrets-by-restarting-dependent-pods-b71231827656
|
67
|
+
|
68
|
+
- Other settings
|
69
|
+
```bash
|
70
|
+
DEPLOY_ENV=beta kubernetes_helper run_yml 'deployment.yml' 'kubectl apply'
|
71
|
+
```
|
72
|
+
|
73
|
+
## Configure continuous deployment for github actions
|
74
|
+
* Go to github repository settings
|
75
|
+
* Register a new secret variable with content downloaded from https://console.cloud.google.com/iam-admin/serviceaccounts
|
76
|
+
(Make sure to attach a "Editor", "Storage Admin" and "Kubernetes engine cluster admin" role to the service account)
|
77
|
+
```bash
|
78
|
+
beta: BETA_CLOUD_TOKEN=<secret content here>
|
79
|
+
production: PROD_CLOUD_TOKEN=<secret content here>
|
80
|
+
```
|
81
|
+
|
82
|
+
* Add action to run deployment:
|
83
|
+
```bash
|
84
|
+
env:
|
85
|
+
KB_AUTH_TOKEN: secrets.BETA_CLOUD_TOKEN
|
86
|
+
run: DEPLOY_ENV=beta kubernetes_helper run_deployment 'cd.sh'
|
87
|
+
```
|
88
|
+
|
89
|
+
* Sample:
|
90
|
+
```yml
|
91
|
+
- run: sudo gem install kubernetes_helper
|
92
|
+
- name: Staging deployment
|
93
|
+
env: # Env variable saved in github that contains gcloud credential (json format)
|
94
|
+
KB_AUTH_TOKEN: ${{ secrets.BETA_GOOGLE_AUTH }}
|
95
|
+
run: DEPLOY_ENV=beta kubernetes_helper run_deployment 'cd.sh'
|
96
|
+
if: ${{ !contains(fromJson('["main", "master"]'), env.DEPLOY_BRANCH) }}
|
97
|
+
```
|
@@ -0,0 +1,12 @@
|
|
1
|
+
- apiVersion: autoscaling/v1
|
2
|
+
kind: HorizontalPodAutoscaler
|
3
|
+
metadata:
|
4
|
+
name: <%= "#{deployment.name}-replicas" %>
|
5
|
+
spec:
|
6
|
+
scaleTargetRef:
|
7
|
+
apiVersion: apps/v1
|
8
|
+
kind: Deployment
|
9
|
+
name: <%= deployment.name %>
|
10
|
+
minReplicas: <%= deployment.replicas_range[0] %>
|
11
|
+
maxReplicas: <%= deployment.replicas_range[1] %>
|
12
|
+
targetCPUUtilizationPercentage: 50
|
@@ -0,0 +1,18 @@
|
|
1
|
+
ports:
|
2
|
+
- containerPort: &sidekiq_alive_port 7433
|
3
|
+
livenessProbe: &sidekiq_liveness
|
4
|
+
httpGet:
|
5
|
+
path: /
|
6
|
+
port: *sidekiq_alive_port
|
7
|
+
initialDelaySeconds: 80 # app specific. Time your sidekiq takes to start processing.
|
8
|
+
timeoutSeconds: 5 # can be much less
|
9
|
+
readinessProbe: *sidekiq_liveness
|
10
|
+
lifecycle:
|
11
|
+
preStop:
|
12
|
+
exec:
|
13
|
+
# SIGTERM triggers a quick exit; gracefully terminate instead
|
14
|
+
command: [
|
15
|
+
"/bin/bash",
|
16
|
+
"-c",
|
17
|
+
"SIDEKIQ_PID=$(ps aux | grep sidekiq | grep busy | awk '{ print $2 }') && kill -SIGTERM $SIDEKIQ_PID",
|
18
|
+
]
|
data/lib/templates/cd.sh
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
set -e
|
3
|
+
# expected ENV VAR "KB_AUTH_TOKEN"
|
4
|
+
|
5
|
+
SCRIPT_DIR=`dirname "$(realpath -s "$0")"` # app_dir/.kubernetes/
|
6
|
+
cd "$SCRIPT_DIR/../" # project directory
|
7
|
+
|
8
|
+
DEPLOYMENTS="<%=[deployment.job_name, deployment.name].join(',')%>"
|
9
|
+
IMAGE_NAME="<%=continuous_deployment.image_name%>"
|
10
|
+
CLUSTER_NAME="<%=continuous_deployment.cluster_name%>"
|
11
|
+
PROJECT_NAME="<%=continuous_deployment.project_name%>"
|
12
|
+
CLUSTER_REGION="<%=continuous_deployment.cluster_region%>"
|
13
|
+
DOCKER_BUILD_CMD="<%=continuous_deployment.docker_build_cmd || 'build -f Dockerfile'%>"
|
14
|
+
|
15
|
+
CI_COMMIT_SHA=$(git rev-parse --verify HEAD)
|
16
|
+
DEPLOY_NAME="${IMAGE_NAME}:${CI_COMMIT_SHA}"
|
17
|
+
LATEST_NAME="${IMAGE_NAME}:latest"
|
18
|
+
AUTH_PATH="$SCRIPT_DIR/k8s-auth-token.json"
|
19
|
+
|
20
|
+
rm -f -- $AUTH_PATH
|
21
|
+
echo $KB_AUTH_TOKEN >> $AUTH_PATH
|
22
|
+
|
23
|
+
## ***** GOOGLE CONNECTOR
|
24
|
+
# Download and install Google Cloud SDK
|
25
|
+
if [ -z "$(which gcloud)" ]; then
|
26
|
+
export CLOUDSDK_CORE_DISABLE_PROMPTS=1; curl https://sdk.cloud.google.com | bash && source /home/runner/google-cloud-sdk/path.bash.inc && gcloud --quiet components update kubectl
|
27
|
+
fi
|
28
|
+
|
29
|
+
# Connect to cluster
|
30
|
+
gcloud auth activate-service-account --key-file $AUTH_PATH --project $PROJECT_NAME
|
31
|
+
gcloud docker --authorize-only --project $PROJECT_NAME
|
32
|
+
gcloud container clusters get-credentials $CLUSTER_NAME --region $CLUSTER_REGION
|
33
|
+
## ***** END GOOGLE CONNECTOR
|
34
|
+
|
35
|
+
|
36
|
+
## Build and push containers
|
37
|
+
docker $DOCKER_BUILD_CMD -t $DEPLOY_NAME .
|
38
|
+
docker tag $DEPLOY_NAME $LATEST_NAME
|
39
|
+
docker push $DEPLOY_NAME
|
40
|
+
docker push $LATEST_NAME
|
41
|
+
|
42
|
+
## Apply deployments
|
43
|
+
IFS=',' read -r -a deployments <<< "$DEPLOYMENTS"
|
44
|
+
for deployment in "${deployments[@]}"; do
|
45
|
+
[ -z "$deployment" ] && continue # if empty value
|
46
|
+
|
47
|
+
kubectl set image deployment/$deployment $deployment=$DEPLOY_NAME
|
48
|
+
[ "$deployment" = "${deployments[0]}" ] && kubectl rollout status deployment/$deployment || true
|
49
|
+
done
|
@@ -0,0 +1,125 @@
|
|
1
|
+
documents:
|
2
|
+
- apiVersion: apps/v1
|
3
|
+
kind: Deployment
|
4
|
+
metadata:
|
5
|
+
name: &app_name <%=deployment.name%>
|
6
|
+
spec: &default_spec
|
7
|
+
replicas: <%=deployment.replicas%>
|
8
|
+
selector:
|
9
|
+
matchLabels:
|
10
|
+
name: *app_name
|
11
|
+
strategy:
|
12
|
+
type: RollingUpdate
|
13
|
+
rollingUpdate:
|
14
|
+
maxSurge: 1
|
15
|
+
maxUnavailable: 1
|
16
|
+
minReadySeconds: 5
|
17
|
+
template:
|
18
|
+
metadata:
|
19
|
+
labels:
|
20
|
+
name: *app_name
|
21
|
+
spec: &template_spec
|
22
|
+
containers:
|
23
|
+
- &app_container
|
24
|
+
image: '<%=continuous_deployment.image_name%>:latest'
|
25
|
+
<% if deployment.command %>
|
26
|
+
command: ["/bin/bash", "-c", "<%= deployment.command %>"]
|
27
|
+
<% end %>
|
28
|
+
name: *app_name
|
29
|
+
import_secrets: ['secrets.yml', '<%=secrets.name%>']
|
30
|
+
ports:
|
31
|
+
- containerPort: &port 3000
|
32
|
+
name: '<%=service.backend_port_name%>'
|
33
|
+
|
34
|
+
<% if deployment.liveness_path %>
|
35
|
+
livenessProbe: &liveness_probe
|
36
|
+
httpGet:
|
37
|
+
path: <%=deployment.liveness_path%>
|
38
|
+
port: *port
|
39
|
+
initialDelaySeconds: 50
|
40
|
+
timeoutSeconds: 3
|
41
|
+
periodSeconds: 15
|
42
|
+
readinessProbe: *liveness_probe
|
43
|
+
<% end %>
|
44
|
+
|
45
|
+
volumeMounts:
|
46
|
+
- &log_volume
|
47
|
+
name: applog
|
48
|
+
mountPath: /app/log
|
49
|
+
- &cloud_credentials_volume
|
50
|
+
name: gcloud-creds
|
51
|
+
mountPath: /secrets/gcloud
|
52
|
+
readOnly: true
|
53
|
+
|
54
|
+
- &cloudsql_container
|
55
|
+
image: gcr.io/cloudsql-docker/gce-proxy:1.09 # Cloud sql proxy
|
56
|
+
name: cloudsql-proxy
|
57
|
+
command: ["/cloud_sql_proxy", "--dir=/cloudsql",
|
58
|
+
"-instances=<%=deployment.cloud_sql_instance%>",
|
59
|
+
"-credential_file=/secrets/gcloud/credentials.json"]
|
60
|
+
volumeMounts:
|
61
|
+
- *cloud_credentials_volume
|
62
|
+
|
63
|
+
- &logs_container # print to stdout all log files
|
64
|
+
name: print-logs
|
65
|
+
image: busybox
|
66
|
+
command: [/bin/sh, -c, 'until find log/*.log; do sleep 1; done; tail -n+1 -f log/*.log']
|
67
|
+
volumeMounts:
|
68
|
+
- *log_volume
|
69
|
+
|
70
|
+
terminationGracePeriodSeconds: 120
|
71
|
+
volumes:
|
72
|
+
- name: gcloud-creds
|
73
|
+
secret:
|
74
|
+
secretName: '<%=deployment.cloud_secret_name%>'
|
75
|
+
- name: applog
|
76
|
+
emptyDir: {}
|
77
|
+
|
78
|
+
<% if deployment.job_name %>
|
79
|
+
- apiVersion: apps/v1
|
80
|
+
kind: Deployment
|
81
|
+
metadata:
|
82
|
+
name: &job_app_name <%=deployment.job_name%>
|
83
|
+
spec:
|
84
|
+
<<: *default_spec
|
85
|
+
replicas: 1
|
86
|
+
selector:
|
87
|
+
matchLabels:
|
88
|
+
name: *job_app_name
|
89
|
+
template:
|
90
|
+
metadata:
|
91
|
+
labels:
|
92
|
+
name: *job_app_name
|
93
|
+
spec:
|
94
|
+
<<: *template_spec
|
95
|
+
containers:
|
96
|
+
- <<: *app_container
|
97
|
+
name: *job_app_name
|
98
|
+
<% if deployment.job_command %>
|
99
|
+
command: [ "/bin/bash", "-c", "<%= deployment.job_command %>" ]
|
100
|
+
<% end %>
|
101
|
+
|
102
|
+
<% if deployment.job_sidekiq_alive_gem %>
|
103
|
+
<%= include_template "_sidekiq_alive_gem.yml.erb" %>
|
104
|
+
<% else %>
|
105
|
+
ports: [ ]
|
106
|
+
<% if (deployment.job_services || []).any? %>
|
107
|
+
livenessProbe: &liveness_probe
|
108
|
+
exec:
|
109
|
+
command: [ /bin/sh, -c,
|
110
|
+
'if [ $(ps -ef | grep "<%= deployment.job_services.join("\|") %>" | grep -v "grep" | wc -l) -lt <%= deployment.job_services.count %> ]; then
|
111
|
+
echo "Some required services are not running"; exit 1;
|
112
|
+
fi' ]
|
113
|
+
initialDelaySeconds: 120
|
114
|
+
periodSeconds: 30
|
115
|
+
readinessProbe: *liveness_probe
|
116
|
+
<% end %>
|
117
|
+
<% end %>
|
118
|
+
|
119
|
+
- *cloudsql_container
|
120
|
+
- <<: *logs_container
|
121
|
+
<% end %>
|
122
|
+
|
123
|
+
<% if deployment.replicas_range %>
|
124
|
+
<%= include_template "_replicas.yml.erb" %>
|
125
|
+
<% end %>
|
@@ -0,0 +1,33 @@
|
|
1
|
+
<% if ingress.domain_name %>
|
2
|
+
apiVersion: networking.gke.io/v1beta1
|
3
|
+
kind: ManagedCertificate
|
4
|
+
metadata:
|
5
|
+
name: '<%=ingress.certificate_name%>'
|
6
|
+
spec:
|
7
|
+
domains: # does not support for willcard domains
|
8
|
+
- '<%=ingress.domain_name%>'
|
9
|
+
<% end %>
|
10
|
+
|
11
|
+
---
|
12
|
+
|
13
|
+
apiVersion: extensions/v1beta1
|
14
|
+
kind: Ingress
|
15
|
+
metadata:
|
16
|
+
name: '<%=ingress.name%>'
|
17
|
+
annotations:
|
18
|
+
kubernetes.io/ingress.class: "gce"
|
19
|
+
kubernetes.io/ingress.allow-http: "true"
|
20
|
+
ingress.kubernetes.io/ssl-redirect: "true"
|
21
|
+
|
22
|
+
<% if ingress.ip_name %>
|
23
|
+
kubernetes.io/ingress.global-static-ip-name: "<%=ingress.ip_name%>"
|
24
|
+
<% end %>
|
25
|
+
|
26
|
+
<% if ingress.domain_name %>
|
27
|
+
networking.gke.io/managed-certificates: '<%=ingress.certificate_name%>'
|
28
|
+
<% end %>
|
29
|
+
|
30
|
+
spec:
|
31
|
+
backend:
|
32
|
+
serviceName: '<%=service.name%>'
|
33
|
+
servicePort: '<%=service.port_name%>'
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# Every Value has to be base64 encoded
|
2
|
+
# IMPORTANT: For security reason, never ever commit secret values, only keys
|
3
|
+
|
4
|
+
apiVersion: v1
|
5
|
+
kind: Secret
|
6
|
+
metadata:
|
7
|
+
name: '<%=secrets.name%>'
|
8
|
+
type: Opaque
|
9
|
+
data:
|
10
|
+
my_key1: "based_64_value_encoded"
|
11
|
+
my_key2: "based_64_value_encoded"
|
@@ -0,0 +1,27 @@
|
|
1
|
+
---
|
2
|
+
# used to increase request timeout
|
3
|
+
apiVersion: cloud.google.com/v1beta1
|
4
|
+
kind: BackendConfig
|
5
|
+
metadata:
|
6
|
+
name: '<%=service.config_name%>'
|
7
|
+
spec:
|
8
|
+
timeoutSec: 1800
|
9
|
+
|
10
|
+
---
|
11
|
+
|
12
|
+
|
13
|
+
kind: Service
|
14
|
+
apiVersion: v1
|
15
|
+
metadata:
|
16
|
+
name: '<%=service.name%>'
|
17
|
+
annotations:
|
18
|
+
beta.cloud.google.com/backend-config: '{"ports": {"80":"<%=service.config_name%>"}}'
|
19
|
+
spec:
|
20
|
+
selector:
|
21
|
+
name: '<%=deployment.name%>'
|
22
|
+
type: NodePort
|
23
|
+
ports:
|
24
|
+
- port: 80
|
25
|
+
protocol: TCP
|
26
|
+
name: '<%=service.port_name%>'
|
27
|
+
targetPort: '<%=service.backend_port_name%>'
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
is_production = ENV['DEPLOY_ENV'] == 'production'
|
4
|
+
app_name = is_production ? 'my_app' : 'my_beta_app'
|
5
|
+
settings = {
|
6
|
+
deployment: {
|
7
|
+
name: app_name,
|
8
|
+
replicas: is_production ? 2 : 1,
|
9
|
+
cloud_secret_name: "#{is_production ? 'production' : 'beta'}-cloud-secret",
|
10
|
+
cloud_sql_instance: 'xxx:xxx:xxx=tcp:5432', # 5432 => postgres, 3306 => mysql
|
11
|
+
env_vars: {}, # Sample: { 'CUSTOM_VAR' => 'value' }
|
12
|
+
# command: '', # custom container command (default empty to be managed by Dockerfile)
|
13
|
+
# liveness_path: '/check_liveness', # nil if not exist
|
14
|
+
# job_name: "#{app_name}-job", # enable if there is any background service
|
15
|
+
# job_command: 'bundle exec sidekiq -C config/sidekiq.yml',
|
16
|
+
# job_services: ['sidekiq', 'cron'] # list of linux services needed.
|
17
|
+
},
|
18
|
+
ingress: {
|
19
|
+
name: "#{app_name}-ingress",
|
20
|
+
ip_name: "#{app_name}-static-ip", # nil if static ip is not necessary
|
21
|
+
certificate_name: "#{app_name}-lets-encrypt", # nil if ssl is not required
|
22
|
+
domain_name: is_production ? 'myapp.com' : 'beta.myapp.com' # nil if domain is not required
|
23
|
+
},
|
24
|
+
continuous_deployment: {
|
25
|
+
image_name: "gcr.io/my-account/#{app_name}",
|
26
|
+
project_name: 'my-project-name',
|
27
|
+
cluster_name: 'my-cluster-name',
|
28
|
+
cluster_region: 'europe-west4-a',
|
29
|
+
docker_build_cmd: 'build -f Dockerfile'
|
30
|
+
},
|
31
|
+
secrets: {
|
32
|
+
name: "#{app_name}-secrets"
|
33
|
+
},
|
34
|
+
service: {
|
35
|
+
name: app_name,
|
36
|
+
port_name: 'http-port', # max 15 characters
|
37
|
+
backend_port_name: 'b-port', # max 15 characters
|
38
|
+
config_name: "#{app_name}-backend-config"
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
KubernetesHelper.settings(settings)
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kubernetes_helper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- owen2345
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
12
|
-
dependencies:
|
11
|
+
date: 2021-08-05 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: erb
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
description: ''
|
14
28
|
email:
|
15
29
|
- owenperedo@gmail.com
|
@@ -25,6 +39,15 @@ files:
|
|
25
39
|
- lib/kubernetes_helper/core.rb
|
26
40
|
- lib/kubernetes_helper/railtie.rb
|
27
41
|
- lib/kubernetes_helper/version.rb
|
42
|
+
- lib/templates/README.md
|
43
|
+
- lib/templates/_replicas.yml.erb
|
44
|
+
- lib/templates/_sidekiq_alive_gem.yml.erb
|
45
|
+
- lib/templates/cd.sh
|
46
|
+
- lib/templates/deployment.yml
|
47
|
+
- lib/templates/ingress.yml
|
48
|
+
- lib/templates/secrets.yml
|
49
|
+
- lib/templates/service.yml
|
50
|
+
- lib/templates/settings.rb
|
28
51
|
homepage: https://github.com/owen2345/kubernetes_helper
|
29
52
|
licenses:
|
30
53
|
- MIT
|