mina-kubernetes 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 1f1fd603c840045e6402d4eee5e82b997a3e31459b2e33f904bff8541cf4ce42
4
+ data.tar.gz: b31401cfce0e729fabbc51e0aa37841a7b6e907639fc5fa572046ac4e3916924
5
+ SHA512:
6
+ metadata.gz: 83b16882b97e8b5a1e2bfd13a2143955443c39d9fb3166c457457510cffd375e32b468a1d4fba608e0822425ebd61d9abd40a12a38fbcc037ea6d6707ad0abd4
7
+ data.tar.gz: 8cfc7cc45cb7dbf508a97ad3c3c6ecff2d094530672a3fb38676426d25448a2d676a0e362d45507cbf89066caa06db971864cfbf26878f360446f5c117f54ca3
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ pkg/
data/README.md ADDED
@@ -0,0 +1,55 @@
1
+ # mina-kubernetes
2
+ Plugin for the [mina](https://github.com/mina-deploy/mina) deployment tool to streamline deployment of resources to Kubernetes cluster, using the [kubernetes-deploy](https://github.com/Shopify/kubernetes-deploy) gem and [mina-multistage](https://github.com/endoze/mina-multistage) plugin.
3
+
4
+ Requires local Docker and [kubectl](https://cloud.google.com/kubernetes-engine/docs/quickstart) with authentication set up to connect to the destination Kubernetes cluster.
5
+
6
+ ## Usage
7
+
8
+ Add `mina-kubernetes` to your local Gemfile.
9
+
10
+ Create a configuration file for mina in `config/deploy.rb` like the one below:
11
+ ```ruby
12
+ require "mina/default"
13
+ require "mina/kubernetes"
14
+
15
+ task :deploy do
16
+ invoke :"kubernetes:deploy"
17
+ end
18
+ ```
19
+
20
+ Add the following variables to your stage configuration i.e. `config/deploy/production.rb`:
21
+ ```ruby
22
+ set :app_name, "my_app"
23
+ set :image_repository, "gcr.io/project-id/myapp"
24
+ set :kubernetes_cluster, "kubernetes_cluster_name"
25
+ set :kubernetes_user, "kubernetes_user_name"
26
+ ```
27
+
28
+ If `set :image_tag, "my_image_tag"` is also defined, it'll be used to deploy the image tagged with this tag on the repository. Otherwise you'll be prompted to pick a branch from current working Git repository and the image to deploy will be assumed to be tagged with the Git commit hash, i.e. `gcr.io/project-123456/my_app:abcd1234`.
29
+
30
+ Optional configuration (showing default values):
31
+ ```ruby
32
+ set :kube_config, "~/.kube/config"
33
+ ```
34
+
35
+ Then create `*.yml.erb` Kubernetes resource definition files in the stage folder, i.e. `config/deploy/production/app.yml.erb`. Occurences of `<%= image_repo %>` and `<%= current_sha %>` in these files will be dynamically replaced on deploy by the image repository URL and the latest commit hash of the selected branch on its git origin.
36
+
37
+ When you run `mina production deploy`, a namespace labelled `my_app-production` will be created on the Kubernetes cluster and set as a local kubectl context. Then the resources are applied to the cluster after checking/waiting for the image to be available on the repository.
38
+
39
+ ### Tasks available
40
+
41
+ #### `kubernetes:deploy`
42
+
43
+ Creates namespace on cluster and assigns it to a local kubectl context, prompts for git branch if no image tag specified, applies all resources to cluster after checking tagged image is available.
44
+
45
+ #### `kubernetes:bash`
46
+
47
+ Prompts for branch unless image tag is set, then spins up a temporary pod with the image and opens up a remote bash terminal.
48
+
49
+ #### `kubernetes:command`
50
+
51
+ Prompts for branch unless image tag is set, then spins up a temporary pod with the image and run command given by task variable `command`, for instance with `set :command, "rails console"`. Environment variables can also be given by defining`env_hash`, i.e. `set :env_hash, {"RAILS_ENV" => "production", "MY_VAR" => "abcd123"}`
52
+
53
+ #### `kubernetes:delete`
54
+
55
+ Confirms and delete all resources on cluster under namespace `app_name-stage`.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,108 @@
1
+ require "tty-prompt"
2
+ require "tty-spinner"
3
+ require "securerandom"
4
+ require "json"
5
+ require "base64"
6
+
7
+ # required by mina
8
+ set :execution_mode, :pretty
9
+
10
+ # default for kubernetes-deploy
11
+ set :kube_config, "~/.kube/config"
12
+
13
+ namespace :kubernetes do
14
+
15
+ set :namespace, fetch(:app_name)
16
+ set :context, "#{fetch(:namespace)}-#{fetch(:stage)}"
17
+
18
+ task :deploy do
19
+ desc "Set image tag to be latest commit of prompted branch (unless provided) then applies resources to cluster"
20
+ set_tag_from_branch_commit unless fetch(:image_tag)
21
+ wait_until_image_ready(fetch(:image_tag))
22
+ create_namespace_on_cluster
23
+ set_local_config_context
24
+ apply_kubernetes_resources
25
+ end
26
+
27
+ task :bash do
28
+ desc "Spins up temporary pod with image and opens remote interactive bash"
29
+ set_tag_from_branch_commit unless fetch(:image_tag)
30
+ wait_until_image_ready(fetch(:image_tag))
31
+ run_terminal_command("bash")
32
+ end
33
+
34
+ task :command do
35
+ desc "Spins up temporary pod with image and runs given command in interactive shell, passing given environment variable"
36
+ set_tag_from_branch_commit unless fetch(:image_tag)
37
+ wait_until_image_ready(fetch(:image_tag))
38
+ run_terminal_command(fetch(:command), fetch(:env_hash))
39
+ end
40
+
41
+ task :delete do
42
+ desc "Delete all resources in namespace on cluster"
43
+ if TTY::Prompt.new.yes?("This will delete all resources in namespace #{fetch(:namespace)} on cluster #{fetch(:kubernetes_cluster)}, are you sure?")
44
+ run :local do
45
+ comment "Deleting all resources in #{fetch(:namespace)}..."
46
+ command "kubectl delete namespace #{fetch(:namespace)} --cluster=#{fetch(:kubernetes_cluster)}"
47
+ comment "Removing local config context..."
48
+ command "kubectl config unset contexts.#{fetch(:context)}"
49
+ end
50
+ end
51
+ end
52
+
53
+ end
54
+
55
+ private
56
+
57
+ def set_tag_from_branch_commit
58
+ run :local do
59
+ comment "Updating Git branches..."
60
+ end
61
+ remote_branches = `git fetch --prune && git branch -r --no-merged master --sort=-committerdate | grep origin`.split("\n").collect { |b| b.strip.gsub("origin/", "") }.reject { |b| b == "master" }
62
+ set :branch, TTY::Prompt.new.select("Which branch?", ["master"].concat(remote_branches))
63
+ set :image_tag, `git rev-parse origin/#{fetch(:branch)}`.split("\n")[0]
64
+ end
65
+
66
+ def create_namespace_on_cluster
67
+ run :local do
68
+ comment "Create/update namespace on Kubernetes cluster..."
69
+ command "kubectl create namespace #{fetch(:namespace)} --dry-run -o yaml | kubectl apply -f - --cluster=#{fetch(:kubernetes_cluster)}"
70
+ end
71
+ end
72
+
73
+ def set_local_config_context
74
+ run :local do
75
+ comment "Set up local Kubernetes config context..."
76
+ command "kubectl config set-context #{fetch(:context)} --namespace=#{fetch(:namespace)} --cluster=#{fetch(:kubernetes_cluster)} --user=#{fetch(:kubernetes_user)}"
77
+ end
78
+ end
79
+
80
+ def wait_until_image_ready(commit)
81
+ run :local do
82
+ comment "Check image #{fetch(:image_repo)}:#{commit} is available..."
83
+ end
84
+ spinner = TTY::Spinner.new
85
+ spinner.auto_spin
86
+ while !image_available?(commit)
87
+ sleep 5
88
+ end
89
+ spinner.stop
90
+ end
91
+
92
+ def image_available?(commit)
93
+ system("docker manifest inspect #{fetch(:image_repo)}:#{commit} > /dev/null") == true
94
+ end
95
+
96
+ def run_terminal_command(command, env_hash = {})
97
+ env = env_hash.collect{|k,v| "--env #{k}=#{v}" }.join(" ")
98
+ label = command.downcase.gsub(" ", "-").gsub(":", "-")
99
+ # using system instead of mina's command so tty opens successfully
100
+ system "kubectl run #{label}-#{SecureRandom.hex(4)} --rm -i --tty --restart=Never --context=#{fetch(:context)} --image #{fetch(:image_repo)}:#{fetch(:image_tag)} #{env} -- #{command}"
101
+ end
102
+
103
+ def apply_kubernetes_resources
104
+ run :local do
105
+ comment "Apply all Kubernetes resources..."
106
+ command "REVISION=#{fetch(:image_tag)} KUBECONFIG=#{fetch(:kube_config)} ENVIRONMENT=#{fetch(:stage)} kubernetes-deploy --bindings=image_repo=#{fetch(:image_repo)},image_tag=#{fetch(:image_tag)},namespace=#{fetch(:namespace)} #{fetch(:namespace)} #{fetch(:context)}"
107
+ end
108
+ end
@@ -0,0 +1,5 @@
1
+ module Mina
2
+ module Kubernetes
3
+ VERSION = "1.0.1"
4
+ end
5
+ end
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'mina/kubernetes/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'mina-kubernetes'
8
+ spec.version = Mina::Kubernetes::VERSION
9
+ spec.authors = ['Antoine Sabourin']
10
+ spec.email = ['antoine@streem.com.au']
11
+
12
+ spec.summary = %q{Mina plugin to streamline deployment of resources to Kubernetes cluster}
13
+ spec.description = %q{Mina plugin to streamline deployment of resources to Kubernetes cluster}
14
+ spec.homepage = 'https://github.com/streemau/mina-kubernetes'
15
+ spec.license = 'MIT'
16
+
17
+ spec.files = `git ls-files -z`.split("\x0")
18
+ spec.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ spec.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_development_dependency 'bundler', '~> 1.11'
23
+ spec.add_development_dependency 'rake', '~> 10.0'
24
+
25
+ spec.add_runtime_dependency 'mina', '~> 1.0'
26
+ spec.add_runtime_dependency 'mina-multistage', '~> 1.0'
27
+ spec.add_runtime_dependency 'kubernetes-deploy'
28
+ spec.add_runtime_dependency 'tty-prompt'
29
+ spec.add_runtime_dependency 'tty-spinner'
30
+ end
metadata ADDED
@@ -0,0 +1,147 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mina-kubernetes
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Antoine Sabourin
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-05-20 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.11'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.11'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: mina
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: mina-multistage
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: kubernetes-deploy
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: tty-prompt
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: tty-spinner
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: Mina plugin to streamline deployment of resources to Kubernetes cluster
112
+ email:
113
+ - antoine@streem.com.au
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - ".gitignore"
119
+ - README.md
120
+ - Rakefile
121
+ - lib/mina/kubernetes.rb
122
+ - lib/mina/kubernetes/version.rb
123
+ - mina-kubernetes.gemspec
124
+ homepage: https://github.com/streemau/mina-kubernetes
125
+ licenses:
126
+ - MIT
127
+ metadata: {}
128
+ post_install_message:
129
+ rdoc_options: []
130
+ require_paths:
131
+ - lib
132
+ required_ruby_version: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ required_rubygems_version: !ruby/object:Gem::Requirement
138
+ requirements:
139
+ - - ">="
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ requirements: []
143
+ rubygems_version: 3.0.3
144
+ signing_key:
145
+ specification_version: 4
146
+ summary: Mina plugin to streamline deployment of resources to Kubernetes cluster
147
+ test_files: []