kubernetes_helper 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 +51 -20
- data/lib/kubernetes_helper/version.rb +3 -1
- data/lib/templates/README.md +96 -0
- data/lib/templates/_sidekiq_alive_gem.yml.erb +18 -0
- data/lib/templates/cd.sh +46 -0
- data/lib/templates/deployment.yml +118 -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 +41 -0
- metadata +25 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c95b3029857b4b9793c337abb65f8d983376db3055bd411b8982907cce9b5a1d
|
4
|
+
data.tar.gz: '08a11127589a60bd3fc340c11a2ddecd635a44347dd77506686d932093a53f4f'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 05e61bc79a77cbce7894430788ccfdddfceb3ac17041453f55dda0809ba42b8f50ab970dc72a566726f5548b1df3aa9bff068ef98adfd21e867d729b0bed316f
|
7
|
+
data.tar.gz: 5464337442b676f531ff14f294652ebe43270110f054dcba401045e5e75b92352ac1432ebb7b281bf84cd91c87c0f1ee9984ed0578d535287926b6751f1e446c
|
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,9 +51,9 @@ 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)
|
@@ -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,96 @@
|
|
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
|
+
- name: Staging deployment
|
92
|
+
env: # Env variable saved in github that contains gcloud credential (json format)
|
93
|
+
KB_AUTH_TOKEN: ${{ secrets.BETA_GOOGLE_AUTH }}
|
94
|
+
run: DEPLOY_ENV=beta kubernetes_helper run_deployment 'cd.sh'
|
95
|
+
if: ${{ !contains(fromJson('["main", "master"]'), env.DEPLOY_BRANCH) }}
|
96
|
+
```
|
@@ -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,46 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
set -e
|
3
|
+
# expected ENV VAR "KB_AUTH_TOKEN"
|
4
|
+
|
5
|
+
SCRIPT_DIR=`dirname "$(realpath -s "$0")"`
|
6
|
+
|
7
|
+
DEPLOYMENTS="<%=[deployment.name, deployment.job_name].join(',')%>"
|
8
|
+
IMAGE_NAME="<%=continuous_deployment.image_name%>"
|
9
|
+
CLUSTER_NAME="<%=continuous_deployment.cluster_name%>"
|
10
|
+
PROJECT_NAME="<%=continuous_deployment.project_name%>"
|
11
|
+
CLUSTER_REGION="<%=continuous_deployment.cluster_region%>"
|
12
|
+
DOCKER_BUILD_CMD="<%=continuous_deployment.docker_build_cmd%>"
|
13
|
+
|
14
|
+
CI_COMMIT_SHA=$(git rev-parse --verify HEAD)
|
15
|
+
DEPLOY_NAME="${IMAGE_NAME}:${CI_COMMIT_SHA}"
|
16
|
+
LATEST_NAME="${IMAGE_NAME}:latest"
|
17
|
+
AUTH_PATH="$SCRIPT_DIR/k8s-auth-token.json"
|
18
|
+
echo $KB_AUTH_TOKEN >> $AUTH_PATH
|
19
|
+
|
20
|
+
## ***** GOOGLE CONNECTOR
|
21
|
+
# Download and install Google Cloud SDK
|
22
|
+
if [ -z "$(which gcloud)" ]; then
|
23
|
+
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
|
24
|
+
fi
|
25
|
+
|
26
|
+
# Connect to cluster
|
27
|
+
gcloud auth activate-service-account --key-file $AUTH_PATH --project $PROJECT_NAME
|
28
|
+
gcloud docker --authorize-only --project $PROJECT_NAME
|
29
|
+
gcloud container clusters get-credentials $CLUSTER_NAME --region $CLUSTER_REGION
|
30
|
+
## ***** END GOOGLE CONNECTOR
|
31
|
+
|
32
|
+
|
33
|
+
## Build and push containers
|
34
|
+
docker $DOCKER_BUILD_CMD -t $DEPLOY_NAME .
|
35
|
+
docker tag $DEPLOY_NAME $LATEST_NAME
|
36
|
+
docker push $DEPLOY_NAME
|
37
|
+
docker push $LATEST_NAME
|
38
|
+
|
39
|
+
## Apply deployments
|
40
|
+
IFS=',' read -r -a deployments <<< "$DEPLOYMENTS"
|
41
|
+
for deployment in "${deployments[@]}"; do
|
42
|
+
[ -z "$deployment" ] && continue # if empty value
|
43
|
+
|
44
|
+
kubectl set image deployment/$deployment $deployment=$DEPLOY_NAME
|
45
|
+
[ "$deployment" = "${deployments[0]}" ] && kubectl rollout status deployment/$deployment
|
46
|
+
done
|
@@ -0,0 +1,118 @@
|
|
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
|
+
|
50
|
+
- &cloudsql_container
|
51
|
+
image: gcr.io/cloudsql-docker/gce-proxy:1.09 # Cloud sql proxy
|
52
|
+
name: cloudsql-proxy
|
53
|
+
command: ["/cloud_sql_proxy", "--dir=/cloudsql",
|
54
|
+
"-instances=<%=deployment.cloud_sql_instance%>",
|
55
|
+
"-credential_file=/secrets/cloudsql/credentials.json"]
|
56
|
+
volumeMounts:
|
57
|
+
- name: cloudsql-creds
|
58
|
+
mountPath: /secrets/cloudsql
|
59
|
+
readOnly: true
|
60
|
+
|
61
|
+
- &logs_container # print to stdout all log files
|
62
|
+
name: print-logs
|
63
|
+
image: busybox
|
64
|
+
command: [/bin/sh, -c, 'until find log/*.log; do sleep 1; done; tail -n+1 -f log/*.log']
|
65
|
+
volumeMounts:
|
66
|
+
- *log_volume
|
67
|
+
|
68
|
+
volumes:
|
69
|
+
- name: cloudsql-creds
|
70
|
+
secret:
|
71
|
+
secretName: '<%=deployment.cloud_secret_name%>'
|
72
|
+
- name: applog
|
73
|
+
emptyDir: {}
|
74
|
+
|
75
|
+
<% if deployment.job_name %>
|
76
|
+
- apiVersion: apps/v1
|
77
|
+
kind: Deployment
|
78
|
+
metadata:
|
79
|
+
name: &job_app_name <%=deployment.job_name%>
|
80
|
+
spec:
|
81
|
+
<<: *default_spec
|
82
|
+
replicas: 1
|
83
|
+
selector:
|
84
|
+
matchLabels:
|
85
|
+
name: *job_app_name
|
86
|
+
template:
|
87
|
+
metadata:
|
88
|
+
labels:
|
89
|
+
name: *job_app_name
|
90
|
+
spec:
|
91
|
+
<<: *template_spec
|
92
|
+
containers:
|
93
|
+
- <<: *app_container
|
94
|
+
name: *job_app_name
|
95
|
+
<% if deployment.job_command %>
|
96
|
+
command: [ "/bin/bash", "-c", "<%= deployment.job_command %>" ]
|
97
|
+
<% end %>
|
98
|
+
|
99
|
+
<% if deployment.job_sidekiq_alive_gem %>
|
100
|
+
<%= include_template "_sidekiq_alive_gem.yml.erb" %>
|
101
|
+
<% else %>
|
102
|
+
ports: [ ]
|
103
|
+
<% if (deployment.job_services || []).any? %>
|
104
|
+
livenessProbe: &liveness_probe
|
105
|
+
exec:
|
106
|
+
command: [ /bin/sh, -c,
|
107
|
+
'if [ $(ps -ef | grep "<%= deployment.job_services.join("\|") %>" | grep -v "grep" | wc -l) -lt <%= deployment.job_services.count %> ]; then
|
108
|
+
echo "Some required services are not running"; exit 1;
|
109
|
+
fi' ]
|
110
|
+
initialDelaySeconds: 120
|
111
|
+
periodSeconds: 30
|
112
|
+
readinessProbe: *liveness_probe
|
113
|
+
<% end %>
|
114
|
+
<% end %>
|
115
|
+
|
116
|
+
- *cloudsql_container
|
117
|
+
- <<: *logs_container
|
118
|
+
<% 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,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
is_beta = ENV['DEPLOY_ENV'] == 'beta'
|
4
|
+
app_name = is_beta ? 'my_beta_app' : 'my_app'
|
5
|
+
settings = {
|
6
|
+
deployment: {
|
7
|
+
name: app_name,
|
8
|
+
replicas: is_beta ? 1 : 2,
|
9
|
+
cloud_secret_name: "#{is_beta ? 'beta' : 'production'}-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_beta ? 'beta.myapp.com' : '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
|
+
},
|
30
|
+
secrets: {
|
31
|
+
name: "#{app_name}-secrets"
|
32
|
+
},
|
33
|
+
service: {
|
34
|
+
name: app_name,
|
35
|
+
port_name: 'http-port', # max 15 characters
|
36
|
+
backend_port_name: 'b-port', # max 15 characters
|
37
|
+
config_name: "#{app_name}-backend-config"
|
38
|
+
}
|
39
|
+
}
|
40
|
+
|
41
|
+
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.0
|
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-03 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,14 @@ 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/_sidekiq_alive_gem.yml.erb
|
44
|
+
- lib/templates/cd.sh
|
45
|
+
- lib/templates/deployment.yml
|
46
|
+
- lib/templates/ingress.yml
|
47
|
+
- lib/templates/secrets.yml
|
48
|
+
- lib/templates/service.yml
|
49
|
+
- lib/templates/settings.rb
|
28
50
|
homepage: https://github.com/owen2345/kubernetes_helper
|
29
51
|
licenses:
|
30
52
|
- MIT
|