tobsch-krane 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +7 -0
  2. data/.buildkite/pipeline.nightly.yml +43 -0
  3. data/.github/probots.yml +2 -0
  4. data/.gitignore +20 -0
  5. data/.rubocop.yml +17 -0
  6. data/.shopify-build/VERSION +1 -0
  7. data/.shopify-build/kubernetes-deploy.yml +53 -0
  8. data/1.0-Upgrade.md +185 -0
  9. data/CHANGELOG.md +431 -0
  10. data/CODE_OF_CONDUCT.md +46 -0
  11. data/CONTRIBUTING.md +164 -0
  12. data/Gemfile +16 -0
  13. data/ISSUE_TEMPLATE.md +25 -0
  14. data/LICENSE.txt +21 -0
  15. data/README.md +655 -0
  16. data/Rakefile +36 -0
  17. data/bin/ci +21 -0
  18. data/bin/setup +16 -0
  19. data/bin/test +47 -0
  20. data/dev.yml +28 -0
  21. data/dev/flamegraph-from-tests +35 -0
  22. data/exe/krane +5 -0
  23. data/krane.gemspec +44 -0
  24. data/lib/krane.rb +7 -0
  25. data/lib/krane/bindings_parser.rb +88 -0
  26. data/lib/krane/cli/deploy_command.rb +75 -0
  27. data/lib/krane/cli/global_deploy_command.rb +54 -0
  28. data/lib/krane/cli/krane.rb +91 -0
  29. data/lib/krane/cli/render_command.rb +41 -0
  30. data/lib/krane/cli/restart_command.rb +34 -0
  31. data/lib/krane/cli/run_command.rb +54 -0
  32. data/lib/krane/cli/version_command.rb +13 -0
  33. data/lib/krane/cluster_resource_discovery.rb +113 -0
  34. data/lib/krane/common.rb +23 -0
  35. data/lib/krane/concerns/template_reporting.rb +29 -0
  36. data/lib/krane/concurrency.rb +18 -0
  37. data/lib/krane/container_logs.rb +106 -0
  38. data/lib/krane/deferred_summary_logging.rb +95 -0
  39. data/lib/krane/delayed_exceptions.rb +14 -0
  40. data/lib/krane/deploy_task.rb +363 -0
  41. data/lib/krane/deploy_task_config_validator.rb +29 -0
  42. data/lib/krane/duration_parser.rb +27 -0
  43. data/lib/krane/ejson_secret_provisioner.rb +154 -0
  44. data/lib/krane/errors.rb +28 -0
  45. data/lib/krane/formatted_logger.rb +57 -0
  46. data/lib/krane/global_deploy_task.rb +210 -0
  47. data/lib/krane/global_deploy_task_config_validator.rb +12 -0
  48. data/lib/krane/kubeclient_builder.rb +156 -0
  49. data/lib/krane/kubectl.rb +120 -0
  50. data/lib/krane/kubernetes_resource.rb +621 -0
  51. data/lib/krane/kubernetes_resource/cloudsql.rb +43 -0
  52. data/lib/krane/kubernetes_resource/config_map.rb +22 -0
  53. data/lib/krane/kubernetes_resource/cron_job.rb +18 -0
  54. data/lib/krane/kubernetes_resource/custom_resource.rb +87 -0
  55. data/lib/krane/kubernetes_resource/custom_resource_definition.rb +98 -0
  56. data/lib/krane/kubernetes_resource/daemon_set.rb +90 -0
  57. data/lib/krane/kubernetes_resource/deployment.rb +213 -0
  58. data/lib/krane/kubernetes_resource/horizontal_pod_autoscaler.rb +65 -0
  59. data/lib/krane/kubernetes_resource/ingress.rb +18 -0
  60. data/lib/krane/kubernetes_resource/job.rb +60 -0
  61. data/lib/krane/kubernetes_resource/network_policy.rb +22 -0
  62. data/lib/krane/kubernetes_resource/persistent_volume_claim.rb +80 -0
  63. data/lib/krane/kubernetes_resource/pod.rb +269 -0
  64. data/lib/krane/kubernetes_resource/pod_disruption_budget.rb +23 -0
  65. data/lib/krane/kubernetes_resource/pod_set_base.rb +71 -0
  66. data/lib/krane/kubernetes_resource/pod_template.rb +20 -0
  67. data/lib/krane/kubernetes_resource/replica_set.rb +92 -0
  68. data/lib/krane/kubernetes_resource/resource_quota.rb +22 -0
  69. data/lib/krane/kubernetes_resource/role.rb +22 -0
  70. data/lib/krane/kubernetes_resource/role_binding.rb +22 -0
  71. data/lib/krane/kubernetes_resource/secret.rb +24 -0
  72. data/lib/krane/kubernetes_resource/service.rb +104 -0
  73. data/lib/krane/kubernetes_resource/service_account.rb +22 -0
  74. data/lib/krane/kubernetes_resource/stateful_set.rb +70 -0
  75. data/lib/krane/label_selector.rb +42 -0
  76. data/lib/krane/oj.rb +4 -0
  77. data/lib/krane/options_helper.rb +39 -0
  78. data/lib/krane/remote_logs.rb +60 -0
  79. data/lib/krane/render_task.rb +118 -0
  80. data/lib/krane/renderer.rb +118 -0
  81. data/lib/krane/resource_cache.rb +68 -0
  82. data/lib/krane/resource_deployer.rb +265 -0
  83. data/lib/krane/resource_watcher.rb +171 -0
  84. data/lib/krane/restart_task.rb +228 -0
  85. data/lib/krane/rollout_conditions.rb +103 -0
  86. data/lib/krane/runner_task.rb +212 -0
  87. data/lib/krane/runner_task_config_validator.rb +18 -0
  88. data/lib/krane/statsd.rb +65 -0
  89. data/lib/krane/task_config.rb +22 -0
  90. data/lib/krane/task_config_validator.rb +96 -0
  91. data/lib/krane/template_sets.rb +173 -0
  92. data/lib/krane/version.rb +4 -0
  93. data/pull_request_template.md +8 -0
  94. data/screenshots/deploy-demo.gif +0 -0
  95. data/screenshots/migrate-logs.png +0 -0
  96. data/screenshots/missing-secret-fail.png +0 -0
  97. data/screenshots/success.png +0 -0
  98. data/screenshots/test-output.png +0 -0
  99. metadata +375 -0
@@ -0,0 +1,46 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
6
+
7
+ ## Our Standards
8
+
9
+ Examples of behavior that contributes to creating a positive environment include:
10
+
11
+ * Using welcoming and inclusive language
12
+ * Being respectful of differing viewpoints and experiences
13
+ * Gracefully accepting constructive criticism
14
+ * Focusing on what is best for the community
15
+ * Showing empathy towards other community members
16
+
17
+ Examples of unacceptable behavior by participants include:
18
+
19
+ * The use of sexualized language or imagery and unwelcome sexual attention or advances
20
+ * Trolling, insulting/derogatory comments, and personal or political attacks
21
+ * Public or private harassment
22
+ * Publishing others' private information, such as a physical or electronic address, without explicit permission
23
+ * Other conduct which could reasonably be considered inappropriate in a professional setting
24
+
25
+ ## Our Responsibilities
26
+
27
+ Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
28
+
29
+ Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
30
+
31
+ ## Scope
32
+
33
+ This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
34
+
35
+ ## Enforcement
36
+
37
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at krane@shopify.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
38
+
39
+ Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
40
+
41
+ ## Attribution
42
+
43
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
44
+
45
+ [homepage]: http://contributor-covenant.org
46
+ [version]: http://contributor-covenant.org/version/1/4/
@@ -0,0 +1,164 @@
1
+ # Contributing to krane
2
+
3
+ :+1::tada: First off, thanks for taking the time to contribute! :tada::+1:
4
+
5
+ The following is a set of guidelines for contributing to krane. Please take a moment to read through them before submitting your first PR.
6
+
7
+
8
+ #### Table Of Contents
9
+
10
+ [Code of Conduct](#code-of-conduct)
11
+
12
+ [What should I know before I get started?](#what-should-i-know-before-i-get-started)
13
+ * [High-level design decisions](#high-level-design-decisions)
14
+ * [Feature acceptance policies](#feature-acceptance-policies)
15
+ * [Adding a new resource type](#contributing-a-new-resource-type)
16
+ * [Contributor License Agreement](#contributor-license-agreement)
17
+
18
+ [Development](#development)
19
+ * [Setup](#setup)
20
+ * [Running the test suite locally](#running-the-test-suite-locally)
21
+ * [Releasing a new version (Shopify employees)](#releasing-a-new-version-shopify-employees)
22
+ * [CI (External contributors)](#ci-external-contributors)
23
+ ## Code of Conduct
24
+
25
+ This project and everyone participating in it are governed by the [Code of Conduct](https://github.com/Shopify/krane/blob/master/CODE_OF_CONDUCT.md).
26
+ By participating, you are expected to uphold this code. Please report unacceptable
27
+ behavior to [krane@shopify.com](mailto:krane@shopify.com).
28
+
29
+ ## Maintainers
30
+
31
+ This project is currently under the stewardship of the Production Platform group at Shopify.
32
+ The two primary maintainers are @knverey and @dturn. Approval from at least one primary maintainer is
33
+ required for all significant feature proposals and code architecture changes. In general,
34
+ two people must approve all non-trivial PRs.
35
+
36
+ ## What should I know before I get started?
37
+
38
+ ### High-level design decisions
39
+
40
+ **Logging**
41
+
42
+ Since we are primarily a CLI tool, logging is our entire user interface. Please think carefully about the information you log. Is it clear? Is it logged at the right time? Is it helpful?
43
+
44
+ In particular, we need to ensure that every mutation we’ve done to the cluster is clearly described (and is something the operator wanted us to do!).
45
+
46
+ We handle Kubernetes secrets, so it is critical that changes do not cause the contents of any secrets in the template set to be logged.
47
+
48
+ **Project architecture**
49
+
50
+ The main interface of this project is our five tasks: `DeployTask`, `GlobalDeployTask`, `RestartTask`, `RunnerTask`, and `RenderTask`. The code in these classes should be high-level abstractions, with implementation details encapsulated in other classes. The public interface of these tasks is a `run` method (and a `run!` equivalent), the body of which should read like a set of phases and steps. Note that non-task classes are considered internal and we reserve the right to change their API at any time.
51
+
52
+ An important design principle of the tasks is that they should try to fail fast before touching the cluster if they will not succeed overall. Part of how we achieve this is by separating each task into phases, where the first phase simply gathers information and runs validations to determine what needs to be done and whether that will be able to succeed. In practice, this is the “Initializing <task>” phase for all tasks, plus the “Checking initial resource statuses” phase for DeployTask. Our users should be able to assume that these initial phases never modify their clusters.
53
+
54
+ **Thread safety**
55
+
56
+ This tool must be able to run concurrent deploys to different targets safely, including when used as a library. Each of those deploys will internally also use parallelism via ruby threads, as do our integration tests. This means all of our code must be thread-safe. Notably, our code must not modify the global namespace (e.g. environment variables, classes, class variables or constants), and all gems we depend on must also be thread-safe.
57
+
58
+ _Note_: Local tests do not run in parallel by default. To enable it, use `PARALLELIZE_ME=1 PARALLELISM=$NUM_THREADS`. Unit tests never run in parallel because they use mocha, which is not thread-safe (mocha cannot be used in integration tests).
59
+
60
+ **Performance and the sync cycle**
61
+
62
+ DeployTask must remain performant when given several hundred resources at a time, generating 1000+ pods. This means only `sync` methods can make calls to the Kubernetes API server during result verification. This both limits the number of API calls made and ensures a consistent view of the world within each polling cycle.
63
+
64
+
65
+
66
+ ### Feature acceptance policies
67
+
68
+ **Our mission**
69
+
70
+ This project's mission is to make it easy to ship changes to a Kubernetes namespace and understand the result. Features that introduce new classes of responsibility to the tool are not usually accepted.
71
+
72
+ Deploys can be a very tempting place to cram features. Imagine a proposed feature actually fits better elsewhere—where might that be? (Examples: validator in CI, custom controller, initializer, pre-processing step in the CD pipeline, or even Kubernetes core)
73
+
74
+ **Template rendering**
75
+
76
+ The basic ERB renderer included with the tool is intended as a convenience feature for a better out-of-the box experience. Providing complex rendering capabilities is outside the scope of this project's mission, and enhancements in this area may be rejected.
77
+
78
+ **Composability**
79
+
80
+ This project strives to be composable with other tools in the ecosystem, such as renderers and validators. The deploy task must work with any Kubernetes templates provided to it, no matter how they were generated.
81
+
82
+ **Universality**
83
+
84
+ This project is open-source. Features tied to any specific organization (including Shopify) will be rejected.
85
+
86
+
87
+ ### Contributing a new resource type
88
+
89
+ The list of fully supported types is effectively the list of classes found in `lib/krane/kubernetes_resource/`.
90
+
91
+ This gem uses subclasses of `KubernetesResource` to implement custom success/failure detection logic for each resource type. If no subclass exists for a type you're deploying, the gem simply assumes `kubectl apply` succeeded (and prints a warning about this assumption). We're always looking to support more types! Here are the basic steps for contributing a new one:
92
+
93
+ 1. Create a file for your type in `lib/krane/kubernetes_resource/`
94
+ 2. Create a new class that inherits from `KubernetesResource`. Minimally, it should implement the following methods:
95
+ * `sync` -- Gather the data you'll need to determine `deploy_succeeded?` and `deploy_failed?`. The superclass's implementation fetches the corresponding resource, parses it and stores it in `@instance_data`. You can define your own implementation if you need something else.
96
+ * `deploy_succeeded?`
97
+ * `deploy_failed?`
98
+ 3. Adjust the `TIMEOUT` constant to an appropriate value for this type.
99
+ 4. Add the new class to list of resources in
100
+ [`deploy_task.rb`](https://github.com/Shopify/krane/blob/master/lib/krane/deploy_task.rb#L8)
101
+ 5. Add the new resource to the [prune whitelist](https://github.com/Shopify/krane/blob/master/lib/krane/deploy_task.rb#L81)
102
+ 6. Add a basic example of the type to the hello-cloud [fixture set](https://github.com/Shopify/krane/tree/master/test/fixtures/hello-cloud) and appropriate assertions to `#assert_all_up` in [`hello_cloud.rb`](https://github.com/Shopify/krane/blob/master/test/helpers/fixture_sets/hello_cloud.rb). This will get you coverage in several existing tests, such as `test_full_hello_cloud_set_deploy_succeeds`.
103
+ 7. Add tests for any edge cases you foresee.
104
+
105
+ ### Contributor License Agreement
106
+
107
+ New contributors will be required to sign [Shopify's Contributor License Agreement (CLA)](https://cla.shopify.com/).
108
+ There are two versions of the CLA: one for individuals and one for organizations.
109
+
110
+ # Development
111
+
112
+ ## Setup
113
+
114
+ If you work for Shopify, just run `dev up`, but otherwise:
115
+
116
+ 1. [Install kubectl version 1.10.0 or higher](https://kubernetes.io/docs/user-guide/prereqs/) and make sure it is in your path
117
+ 2. [Install minikube](https://kubernetes.io/docs/getting-started-guides/minikube/#installation) (required to run the test suite)
118
+ 3. [Install any required minikube drivers](https://github.com/kubernetes/minikube/blob/master/docs/drivers.md) (on OS X, you may need the [hyperkit driver](https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#hyperkit-driver)
119
+ 4. Check out the repo
120
+ 5. Run `bin/setup` to install dependencies
121
+
122
+ To install this gem onto your local machine, run `bundle exec rake install`.
123
+
124
+
125
+
126
+ ## Running the test suite locally
127
+
128
+ Using minikube:
129
+
130
+ 1. Start [minikube](https://kubernetes.io/docs/getting-started-guides/minikube/#installation) (`minikube start [options]`).
131
+ 2. Make sure you have a context named "minikube" in your kubeconfig. Minikube adds this context for you when you run `minikube start`. You can check for it using `kubectl config get-contexts`.
132
+ 3. Run `bundle exec rake test` (or `dev test` if you work for Shopify).
133
+
134
+ Using another local cluster:
135
+
136
+ 1. Start your cluster.
137
+ 2. Put the name of the context you want to use in a file named `.local-context` in the root of this project. For example: `echo "dind" > .local-context`.
138
+ 3. Run `bundle exec rake test` (or `dev test` if you work for Shopify).
139
+
140
+ To make StatsD log what it would have emitted, run a test with `STATSD_ENV=development`.
141
+
142
+ To see the full-color output of a specific integration test, you can use `PRINT_LOGS=1`. For example: `PRINT_LOGS=1 bundle exec ruby -I test test/integration/krane_deploy_test.rb -n/test_name/`.
143
+
144
+
145
+ ![test-output](screenshots/test-output.png)
146
+
147
+
148
+ ## Releasing a new version (Shopify employees)
149
+
150
+ 1. On a new branch, create a new heading in CHANGELOG.md for your version and move the entries from "Next" under it. Leave the "Next" heading in the file (this helps with the diff for rebases after the release).
151
+ 1. Make sure CHANGELOG.md includes all user-facing changes since the last release. Things like test changes or refactors do not need to be included.
152
+ 1. Update the version number in `version.rb`.
153
+ 1. Commit your changes with message "Version x.y.z" and open a PR.
154
+ 1. After merging your PR, deploy via [Shipit](https://shipit.shopify.io/shopify/kubernetes-deploy/rubygems). Shipit will automatically tag the release and upload the gem to [rubygems.org](https://rubygems.org/gems/krane).
155
+
156
+ ## CI (External contributors)
157
+
158
+ Please make sure you run the tests locally before submitting your PR (see [Running the test suite locally](#running-the-test-suite-locally)). After reviewing your PR, a Shopify employee will trigger CI for you.
159
+
160
+ #### Employees: Triggering CI for a contributed PR
161
+
162
+ Go to the [krane pipeline](https://buildkite.com/shopify/kubernetes-deploy) and click "New Build". Use branch `external_contrib_ci` and the specific sha of the commit you want to build. Add `BUILDKITE_REFSPEC="refs/pull/${PR_NUM}/head"` in the Environment Variables section. Since CI is only visible to Shopify employees, you will need to provide any failing tests and output to the the contributor.
163
+
164
+ <img width="350" alt="build external contrib PR" src="https://screenshot.click/2017-11-07--163728_7ovek-wrpwq.png">
data/Gemfile ADDED
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+ source 'https://rubygems.org'
3
+
4
+ # Specify your gem's dependencies in krane.gemspec
5
+ gemspec
6
+
7
+ gem 'pry'
8
+ gem 'pry-byebug'
9
+ gem 'rubocop'
10
+ gem 'timecop'
11
+ gem 'byebug'
12
+ gem 'codecov', require: false
13
+ gem 'ruby-prof', require: false
14
+ gem 'ruby-prof-flamegraph', require: false
15
+ gem 'minitest-reporters'
16
+ gem 'yard', require: false
@@ -0,0 +1,25 @@
1
+ <!-- Please erase any parts of this template not applicable to your issue. -->
2
+
3
+ # Bug report
4
+
5
+ [Description of the bug]
6
+
7
+ **Expected behavior:** [What you expected to happen]
8
+
9
+ **Actual behavior:** [What actually happened]
10
+
11
+ **Version(s) affected:** [run `krane version`]
12
+
13
+ ### Steps to Reproduce
14
+
15
+ 1. [First Step]
16
+ 2. [Second Step]
17
+ 3. [and so on...]
18
+
19
+ # Feature request
20
+
21
+ - [ ] If the maintainers agree with the feature as described here, I intend to submit a Pull Request myself.<sup>1</sup>
22
+
23
+ **Proposal:** [provide details on the behaviour you'd like to see and why it would be useful]
24
+
25
+ <sup><small>1</small></sup> <sub>This is the quickest way to get a new feature! We reserve the right to close feature requests, even ones we like, if the proposer does not intend to contribute to the feature and it doesn't fit in our current roadmap.</sub>
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Kir Shatrov
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,655 @@
1
+ # krane [![Build status](https://badge.buildkite.com/61937e40a1fc69754d9d198be120543d6de310de2ba8d3cb0e.svg?branch=master)](https://buildkite.com/shopify/kubernetes-deploy) [![codecov](https://codecov.io/gh/Shopify/kubernetes-deploy/branch/master/graph/badge.svg)](https://codecov.io/gh/Shopify/kubernetes-deploy)
2
+
3
+ > This project used to be called `kubernetes-deploy`. Check out our [migration guide](https://github.com/Shopify/krane/blob/master/1.0-Upgrade.md) for more information including details about breaking changes.
4
+
5
+
6
+ `krane` is a command line tool that helps you ship changes to a Kubernetes namespace and understand the result. At Shopify, we use it within our much-beloved, open-source [Shipit](https://github.com/Shopify/shipit-engine#kubernetes) deployment app.
7
+
8
+ Why not just use the standard `kubectl apply` mechanism to deploy? It is indeed a fantastic tool; `krane` uses it under the hood! However, it leaves its users with some burning questions: _What just happened?_ _Did it work?_
9
+
10
+ Especially in a CI/CD environment, we need a clear, actionable pass/fail result for each deploy. Providing this was the foundational goal of `krane`, which has grown to support the following core features:
11
+
12
+ ​:eyes: Watches the changes you requested to make sure they roll out successfully.
13
+
14
+ :interrobang: Provides debug information for changes that failed.
15
+
16
+ :1234: Predeploys certain types of resources (e.g. ConfigMap, PersistentVolumeClaim) to make sure the latest version will be available when resources that might consume them (e.g. Deployment) are deployed.
17
+
18
+ :closed_lock_with_key: [Creates Kubernetes secrets from encrypted EJSON](#deploying-kubernetes-secrets-from-ejson), which you can safely commit to your repository
19
+
20
+ ​:running: [Running tasks at the beginning of a deploy](#running-tasks-at-the-beginning-of-a-deploy) using bare pods (example use case: Rails migrations)
21
+
22
+ If you need the ability to render dynamic values in templates before deploying, you can use [krane render](#krane-render). Alongside that, this repo also includes tools for [running tasks](#krane-run) and [restarting deployments](#krane-restart).
23
+
24
+
25
+
26
+ ![demo-deploy.gif](screenshots/deploy-demo.gif)
27
+
28
+
29
+
30
+ ![missing-secret-fail](screenshots/missing-secret-fail.png)
31
+
32
+
33
+ --------
34
+
35
+
36
+
37
+ ## Table of contents
38
+
39
+ **KRANE DEPLOY**
40
+ * [Prerequisites](#prerequisites)
41
+ * [Installation](#installation)
42
+ * [Usage](#usage)
43
+ * [Using templates and variables](#using-templates-and-variables)
44
+ * [Customizing behaviour with annotations](#customizing-behaviour-with-annotations)
45
+ * [Running tasks at the beginning of a deploy](#running-tasks-at-the-beginning-of-a-deploy)
46
+ * [Deploying Kubernetes secrets (from EJSON)](#deploying-kubernetes-secrets-from-ejson)
47
+ * [Deploying custom resources](#deploying-custom-resources)
48
+ * [Walk through the steps of a deployment](#deploy-walkthrough)
49
+
50
+ **KRANE GLOBAL DEPLOY**
51
+ * [Usage](#usage-1)
52
+
53
+ **KRANE RESTART**
54
+ * [Usage](#usage-2)
55
+
56
+ **KRANE RUN**
57
+ * [Prerequisites](#prerequisites-1)
58
+ * [Usage](#usage-3)
59
+
60
+ **KRANE RENDER**
61
+ * [Prerequisites](#prerequisites-2)
62
+ * [Usage](#usage-4)
63
+
64
+ **CONTRIBUTING**
65
+ * [Contributing](#contributing)
66
+ * [Code of Conduct](#code-of-conduct)
67
+ * [License](#license)
68
+
69
+
70
+ ----------
71
+
72
+
73
+
74
+ ## Prerequisites
75
+
76
+ * Ruby 2.4+
77
+ * Your cluster must be running Kubernetes v1.11.0 or higher<sup>1</sup>
78
+
79
+ <sup>1</sup> We run integration tests against these Kubernetes versions. You can find our
80
+ official compatibility chart below.
81
+
82
+ | Kubernetes version | Last officially supported in gem version |
83
+ | :----------------: | :-------------------: |
84
+ | 1.5 | 0.11.2 |
85
+ | 1.6 | 0.15.2 |
86
+ | 1.7 | 0.20.6 |
87
+ | 1.8 | 0.21.1 |
88
+ | 1.9 | 0.24.0 |
89
+ | 1.10 | 0.27.0 |
90
+
91
+ ## Installation
92
+
93
+ 1. [Install kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/#install-kubectl-binary-via-curl) (requires v1.11.0 or higher) and make sure it is available in your $PATH
94
+ 2. Set up your [kubeconfig file](https://kubernetes.io/docs/tasks/access-application-cluster/authenticate-across-clusters-kubeconfig/) for access to your cluster(s).
95
+ 3. `gem install krane`
96
+
97
+
98
+
99
+
100
+ ## Usage
101
+
102
+ `krane deploy <app's namespace> <kube context>`
103
+
104
+ *Environment variables:*
105
+
106
+ - `$KUBECONFIG`: points to one or multiple valid kubeconfig files that include the context you want to deploy to. File names are separated by colon for Linux and Mac, and semi-colon for Windows. If ommitted, will use the Kubernetes default of `~/.kube/config`.
107
+ - `$GOOGLE_APPLICATION_CREDENTIALS`: points to the credentials for an authenticated service account (required if your kubeconfig `user`'s auth provider is GCP)
108
+
109
+
110
+ *Options:*
111
+
112
+ Refer to `krane help` for the authoritative set of options.
113
+
114
+
115
+ - `--filenames / -f [PATHS]`: Accepts a list of directories and/or filenames to specify the set of directories/files that will be deployed.
116
+ - `--stdin`: Read from STDIN. Can be combined with `-f` Example: `cat templates_from_stdin/*.yml | krane deploy ns ctx -f path/to/dir path/to/file.yml --stdin`
117
+ - `--no-prune`: Skips pruning of resources that are no longer in your Kubernetes template set. Not recommended, as it allows your namespace to accumulate cruft that is not reflected in your deploy directory.
118
+ - `--global-timeout=duration`: Raise a timeout error if it takes longer than _duration_ for any
119
+ resource to deploy.
120
+ - `--selector`: Instructs krane to only prune resources which match the specified label selector, such as `environment=staging`. If you use this option, all resource templates must specify matching labels. See [Sharing a namespace](#sharing-a-namespace) below.
121
+ - `--no-verify-result`: Skip verification that workloads correctly deployed.
122
+ - `--protected-namespaces=default kube-system kube-public`: Fail validation if a deploy is targeted at a protected namespace.
123
+ - `--verbose-log-prefix`: Add [context][namespace] to the log prefix
124
+
125
+
126
+ > **NOTICE**: Deploy Secret resources at your own risk. Although we will fix any reported leak vectors with urgency, we cannot guarantee that sensitive information will never be logged.
127
+
128
+ ### Sharing a namespace
129
+
130
+ By default, krane will prune any resources in the target namespace which have the `kubectl.kubernetes.io/last-applied-configuration` annotation and are not a result of the current deployment process, on the assumption that there is a one-to-one relationship between application deployment and namespace, and that a deployment provisions all relevant resources in the namespace.
131
+
132
+ If you need to, you may specify `--no-prune` to disable all pruning behaviour, but this is not recommended.
133
+
134
+ If you need to share a namespace with resources which are managed by other tools or indeed other krane deployments, you can supply the `--selector` option, such that only resources with labels matching the selector are considered for pruning.
135
+
136
+ ### Using templates
137
+
138
+ All templates must be YAML formatted.
139
+ We recommended storing each app's templates in a single directory, `{app root}/config/deploy/{env}`. However, you may use multiple directories.
140
+
141
+ If you want dynamic templates, you may render ERB with `krane render` and then pipe that result to `krane deploy --stdin`. `krane deploy` supports using both `--filenames` and `--stdin` together.
142
+
143
+ ### Customizing behaviour with annotations
144
+ - `krane.shopify.io/timeout-override`: Override the tool's hard timeout for one specific resource. Both full ISO8601 durations and the time portion of ISO8601 durations are valid. Value must be between 1 second and 24 hours.
145
+ - _Example values_: 45s / 3m / 1h / PT0.25H
146
+ - _Compatibility_: all resource types
147
+ - `krane.shopify.io/required-rollout`: Modifies how much of the rollout needs to finish
148
+ before the deployment is considered successful.
149
+ - _Compatibility_: Deployment
150
+ - `full`: The deployment is successful when all pods in the new `replicaSet` are ready.
151
+ - `none`: The deployment is successful as soon as the new `replicaSet` is created for the deployment.
152
+ - `maxUnavailable`: The deploy is successful when minimum availability is reached in the new `replicaSet`.
153
+ In other words, the number of new pods that must be ready is equal to `spec.replicas` - `strategy.RollingUpdate.maxUnavailable`
154
+ (converted from percentages by rounding up, if applicable). This option is only valid for deployments
155
+ that use the `RollingUpdate` strategy.
156
+ - Percent (e.g. 90%): The deploy is successful when the number of new pods that are ready is equal to
157
+ `spec.replicas` * Percent.
158
+ - `krane.shopify.io/predeployed`: Causes a Custom Resource to be deployed in the pre-deploy phase.
159
+ - _Compatibility_: Custom Resource Definition
160
+ - _Default_: `true`
161
+ - `true`: The custom resource will be deployed in the pre-deploy phase.
162
+ - All other values: The custom resource will be deployed in the main deployment phase.
163
+
164
+
165
+ ### Running tasks at the beginning of a deploy
166
+
167
+ To run a task in your cluster at the beginning of every deploy, simply include a `Pod` template in your deploy directory. `krane` will first deploy any `ConfigMap` and `PersistentVolumeClaim` resources present in the provided templates, followed by any such pods. If the command run by one of these pods fails (i.e. exits with a non-zero status), the overall deploy will fail at this step (no other resources will be deployed).
168
+
169
+ *Requirements:*
170
+
171
+ * The pod's name should include `<%= deployment_id %>` to ensure that a unique name will be used on every deploy (the deploy will fail if a pod with the same name already exists).
172
+ * The pod's `spec.restartPolicy` must be set to `Never` so that it will be run exactly once. We'll fail the deploy if that run exits with a non-zero status.
173
+ * The pod's `spec.activeDeadlineSeconds` should be set to a reasonable value for the performed task (not required, but highly recommended)
174
+
175
+ A simple example can be found in the test fixtures: [test/fixtures/hello-cloud/unmanaged-pod-1.yml.erb](test/fixtures/hello-cloud/unmanaged-pod-1.yml.erb).
176
+
177
+ The logs of all pods run in this way will be printed inline. If there is only one pod, the logs will be streamed in real-time. If there are multiple, they will be fetched when the pod terminates.
178
+
179
+ ![migrate-logs](screenshots/migrate-logs.png)
180
+
181
+
182
+
183
+ ### Deploying Kubernetes secrets (from EJSON)
184
+
185
+ **Note: If you're a Shopify employee using our cloud platform, this setup has already been done for you. Please consult the CloudPlatform User Guide for usage instructions.**
186
+
187
+ Since their data is only base64 encoded, Kubernetes secrets should not be committed to your repository. Instead, `krane` supports generating secrets from an encrypted [ejson](https://github.com/Shopify/ejson) file in your template directory. Here's how to use this feature:
188
+
189
+ 1. Install the ejson gem: `gem install ejson`
190
+ 2. Generate a new keypair: `ejson keygen` (prints the keypair to stdout)
191
+ 3. Create a Kubernetes secret in your target namespace with the new keypair: `kubectl create secret generic ejson-keys --from-literal=YOUR_PUBLIC_KEY=YOUR_PRIVATE_KEY --namespace=TARGET_NAMESPACE`
192
+ >Warning: Do *not* use `apply` to create the `ejson-keys` secret. krane will fail if `ejson-keys` is prunable. This safeguard is to protect against the accidental deletion of your private keys.
193
+ 4. (optional but highly recommended) Back up the keypair somewhere secure, such as a password manager, for disaster recovery purposes.
194
+ 5. In your template directory (alongside your Kubernetes templates), create `secrets.ejson` with the format shown below. The `_type` key should have the value “kubernetes.io/tls” for TLS secrets and “Opaque” for all others. The `data` key must be a json object, but its keys and values can be whatever you need.
195
+
196
+ ```json
197
+ {
198
+ "_public_key": "YOUR_PUBLIC_KEY",
199
+ "kubernetes_secrets": {
200
+ "catphotoscom": {
201
+ "_type": "kubernetes.io/tls",
202
+ "data": {
203
+ "tls.crt": "cert-data-here",
204
+ "tls.key": "key-data-here"
205
+ }
206
+ },
207
+ "monitoring-token": {
208
+ "_type": "Opaque",
209
+ "data": {
210
+ "api-token": "token-value-here"
211
+ }
212
+ }
213
+ }
214
+ }
215
+ ```
216
+
217
+ 6. Encrypt the file: `ejson encrypt /PATH/TO/secrets.ejson`
218
+ 7. Commit the encrypted file and deploy. The deploy will create secrets from the data in the `kubernetes_secrets` key. The ejson file must be included in the resources passed to `--filenames` it can not be read through stdin.
219
+
220
+ **Note**: Since leading underscores in ejson keys are used to skip encryption of the associated value, `krane` will strip these leading underscores when it creates the keys for the Kubernetes secret data. For example, given the ejson data below, the `monitoring-token` secret will have keys `api-token` and `property` (_not_ `_property`):
221
+
222
+ ```json
223
+ {
224
+ "_public_key": "YOUR_PUBLIC_KEY",
225
+ "kubernetes_secrets": {
226
+ "monitoring-token": {
227
+ "_type": "kubernetes.io/tls",
228
+ "data": {
229
+ "api-token": "EJ[ENCRYPTED]",
230
+ "_property": "some unencrypted value"
231
+ }
232
+ }
233
+ }
234
+ ```
235
+
236
+ **A warning about using EJSON secrets with `--selector`**: when using EJSON to generate `Secret` resources and specifying a `--selector` for deployment, the labels from the selector are automatically added to the `Secret`. If _the same_ EJSON file is deployed to the same namespace using different selectors, this will cause the resource to thrash - even if the contents of the secret were the same, the resource has different labels on each deploy.
237
+
238
+ ### Deploying custom resources
239
+
240
+ By default, krane does not check the status of custom resources; it simply assumes that they deployed successfully. In order to meaningfully monitor the rollout of custom resources, krane supports configuring pass/fail conditions using annotations on CustomResourceDefinitions (CRDs).
241
+
242
+ *Requirements:*
243
+
244
+ * The custom resource must expose a `status` subresource with an `observedGeneration` field.
245
+ * The `krane.shopify.io/instance-rollout-conditions` annotation must be present on the CRD that defines the custom resource.
246
+ * (optional) The `krane.shopify.io/instance-timeout` annotation can be added to the CRD that defines the custom resource to override the global default timeout for all instances of that resource. This annotation can use ISO8601 format or unprefixed ISO8601 time components (e.g. '1H', '60S').
247
+
248
+ #### Specifying pass/fail conditions
249
+
250
+ The presence of a valid `krane.shopify.io/instance-rollout-conditions` annotation on a CRD will cause krane to monitor the rollout of all instances of that custom resource. Its value can either be `"true"` (giving you the defaults described in the next section) or a valid JSON string with the following format:
251
+ ```
252
+ '{
253
+ "success_conditions": [
254
+ { "path": <JsonPath expression>, "value": <target value> }
255
+ ... more success conditions
256
+ ],
257
+ "failure_conditions": [
258
+ { "path": <JsonPath expression>, "value": <target value> }
259
+ ... more failure conditions
260
+ ]
261
+ }'
262
+ ```
263
+
264
+ For all conditions, `path` must be a valid JsonPath expression that points to a field in the custom resource's status. `value` is the value that must be present at `path` in order to fulfill a condition. For a deployment to be successful, _all_ `success_conditions` must be fulfilled. Conversely, the deploy will be marked as failed if _any one of_ `failure_conditions` is fulfilled. `success_conditions` are mandatory, but `failure_conditions` can be omitted (the resource will simply time out if it never reaches a successful state).
265
+
266
+ In addition to `path` and `value`, a failure condition can also contain `error_msg_path` or `custom_error_msg`. `error_msg_path` is a JsonPath expression that points to a field you want to surface when a failure condition is fulfilled. For example, a status condition may expose a `message` field that contains a description of the problem it encountered. `custom_error_msg` is a string that can be used if your custom resource doesn't contain sufficient information to warrant using `error_msg_path`. Note that `custom_error_msg` has higher precedence than `error_msg_path` so it will be used in favor of `error_msg_path` when both fields are present.
267
+
268
+ **Warning:**
269
+
270
+ You **must** ensure that your custom resource controller sets `.status.observedGeneration` to match the observed `.metadata.generation` of the monitored resource once its sync is complete. If this does not happen, krane will not check success or failure conditions and the deploy will time out.
271
+
272
+ #### Example
273
+
274
+ As an example, the following is the default configuration that will be used if you set `krane.shopify.io/instance-rollout-conditions: "true"` on the CRD that defines the custom resources you wish to monitor:
275
+
276
+ ```
277
+ '{
278
+ "success_conditions": [
279
+ {
280
+ "path": "$.status.conditions[?(@.type == \"Ready\")].status",
281
+ "value": "True",
282
+ },
283
+ ],
284
+ "failure_conditions": [
285
+ {
286
+ "path": '$.status.conditions[?(@.type == \"Failed\")].status',
287
+ "value": "True",
288
+ "error_msg_path": '$.status.conditions[?(@.type == \"Failed\")].message',
289
+ },
290
+ ],
291
+ }'
292
+ ```
293
+
294
+ The paths defined here are based on the [typical status properties](https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md#typical-status-properties) as defined by the Kubernetes community. It expects the `status` subresource to contain a `conditions` array whose entries minimally specify `type`, `status`, and `message` fields.
295
+
296
+ You can see how these conditions relate to the following resource:
297
+
298
+ ```
299
+ apiVersion: stable.shopify.io/v1
300
+ kind: Example
301
+ metadata:
302
+ generation: 2
303
+ name: example
304
+ namespace: namespace
305
+ spec:
306
+ ...
307
+ status:
308
+ observedGeneration: 2
309
+ conditions:
310
+ - type: "Ready"
311
+ status: "False"
312
+ reason: "exampleNotReady"
313
+ message: "resource is not ready"
314
+ - type: "Failed"
315
+ status: "True"
316
+ reason: "exampleFailed"
317
+ message: "resource is failed"
318
+ ```
319
+
320
+ - `observedGeneration == metadata.generation`, so krane will check this resource's success and failure conditions.
321
+ - Since `$.status.conditions[?(@.type == "Ready")].status == "False"`, the resource is not considered successful yet.
322
+ - `$.status.conditions[?(@.type == "Failed")].status == "True"` means that a failure condition has been fulfilled and the resource is considered failed.
323
+ - Since `error_msg_path` is specified, krane will log the contents of `$.status.conditions[?(@.type == "Failed")].message`, which in this case is: `resource is failed`.
324
+
325
+ ### Deploy walkthrough
326
+
327
+ Let's walk through what happens when you run the `deploy` task with [this directory of templates](https://github.com/Shopify/krane/tree/master/test/fixtures/hello-cloud). This particular example uses ERB templates as well, so we'll use the [krane render](#krane-render) task to achieve that.
328
+
329
+ You can test this out for yourself by running the following command:
330
+
331
+ ```bash
332
+ krane render -f test/fixtures/hello-cloud --current-sha 1 | krane deploy my-namespace my-k8s-cluster --stdin
333
+ ```
334
+
335
+ As soon as you run this, you'll start seeing some output being streamed to STDERR.
336
+
337
+ #### Phase 1: Initializing deploy
338
+
339
+ In this phase, we:
340
+
341
+ - Perform basic validation to ensure we can proceed with the deploy. This includes checking if we can reach the context, if the context is valid, if the namespace exists within the context, and more. We try to validate as much as we can before trying to ship something because we want to avoid having an incomplete deploy in case of a failure (this is especially important because there's no rollback support).
342
+ - List out all the resources we want to deploy (as described in the template files we used).
343
+
344
+ #### Phase 2: Checking initial resource statuses
345
+
346
+ In this phase, we check resource statuses. For each resource listed in the previous step, we check Kubernetes for their status; in the first deploy this might show a bunch of items as "Not Found", but for the deploy of a new version, this is an example of what it could look like:
347
+
348
+ ```
349
+ Certificate/services-foo-tls Exists
350
+ Cloudsql/foo-production Provisioned
351
+ Deployment/jobs 3 replicas, 3 updatedReplicas, 3 availableReplicas
352
+ Deployment/web 3 replicas, 3 updatedReplicas, 3 availableReplicas
353
+ Ingress/web Created
354
+ Memcached/foo-production Healthy
355
+ Pod/db-migrate-856359 Unknown
356
+ Pod/upload-assets-856359 Unknown
357
+ Redis/foo-production Healthy
358
+ Service/web Selects at least 1 pod
359
+ ```
360
+
361
+ The next phase might be either "Predeploying priority resources" (if there's any) or "Deploying all resources". In this example we'll go through the former, as we do have predeployable resources.
362
+
363
+ #### Phase 3: Predeploying priority resources
364
+
365
+ This is the first phase that could modify the cluster.
366
+
367
+ In this phase we predeploy certain types of resources (e.g. `ConfigMap`, `PersistentVolumeClaim`, `Secret`, ...) to make sure the latest version will be available when resources that might consume them (e.g. `Deployment`) are deployed. This phase will be skipped if the templates don't include any resources that would need to be predeployed.
368
+
369
+ When this runs, we essentially run `kubectl apply` on those templates and periodically check the cluster for the current status of each resource so we can display error or success information. This will look different depending on the type of resource. If you're running the command described above, you should see something like this in the output:
370
+
371
+ ```
372
+ Deploying ConfigMap/hello-cloud-configmap-data (timeout: 30s)
373
+ Successfully deployed in 0.2s: ConfigMap/hello-cloud-configmap-data
374
+
375
+ Deploying PersistentVolumeClaim/hello-cloud-redis (timeout: 300s)
376
+ Successfully deployed in 3.3s: PersistentVolumeClaim/hello-cloud-redis
377
+
378
+ Deploying Role/role (timeout: 300s)
379
+ Don't know how to monitor resources of type Role. Assuming Role/role deployed successfully.
380
+ Successfully deployed in 0.2s: Role/role
381
+ ```
382
+
383
+ As you can see, different types of resources might have different timeout values and different success criteria; in some specific cases (such as with Role) we might not know how to confirm success or failure, so we use a higher timeout value and assume it did work.
384
+
385
+ #### Phase 4: Deploying all resources
386
+
387
+ In this phase, we:
388
+
389
+ - Deploy all resources found in the templates, including resources that were predeployed in the previous step (which should be treated as a no-op by Kubernetes). We deploy everything so the pruning logic (described below) doesn't remove any predeployed resources.
390
+ - Prune resources not found in the templates (you can disable this by using `--no-prune`).
391
+
392
+ Just like in the previous phase, we essentially run `kubectl apply` on those templates and periodically check the cluster for the current status of each resource so we can display error or success information.
393
+
394
+ If pruning is enabled (which, again, is the default), any [kind not listed in the blacklist](https://github.com/Shopify/krane/blob/master/lib/krane/cluster_resource_discovery.rb#L20) that we can find in the namespace but not in the templates will be removed. A particular message about pruning will be printed in the next phase if any resource matches this criteria.
395
+
396
+ #### Result
397
+
398
+ The result section will show:
399
+ - A global status: if **all** resources were deployed successfully, this will show up as "SUCCESS"; if at least one resource failed to deploy (due to an error or timeout), this will show up as "FAILURE".
400
+ - A list of resources and their individual status: this will show up as something like "Available", "Created", and "1 replica, 1 availableReplica, 1 readyReplica".
401
+
402
+ At this point the command also returns a status code:
403
+ - If it was a success, `0`
404
+ - If there was a timeout, `70`
405
+ - If any other failure happened, `1`
406
+
407
+ **On timeouts**: It's important to notice that a single resource timeout or a global deploy timeout doesn't necessarily mean that the operation failed. Since Kubernetes updates are asynchronous, maybe something was just too slow to return in the configured time; in those cases, usually running the deploy again might work (that should be a no-op for most - if not all - resources).
408
+
409
+ # krane global deploy
410
+
411
+ Ship non-namespaced resources to a cluster
412
+
413
+ krane global-deploy (accessible through the Ruby API as Krane::GlobalDeployTask) can deploy global (non-namespaced) resources such as PersistentVolume, Namespace, and CustomResourceDefinition.
414
+ Its interface is very similar to krane deploy.
415
+
416
+ ## Usage
417
+
418
+ `krane global-deploy <kube context>`
419
+
420
+ ```bash
421
+ $ cat my-template.yml
422
+ apiVersion: storage.k8s.io/v1
423
+ kind: StorageClass
424
+ metadata:
425
+ name: testing-storage-class
426
+ labels:
427
+ app: krane
428
+ provisioner: kubernetes.io/no-provisioner
429
+
430
+ $ krane global-deploy my-k8s-context -f my-template.yml --selector app=krane
431
+ ```
432
+
433
+ *Options:*
434
+
435
+ Refer to `krane global-deploy help` for the authoritative set of options.
436
+
437
+ - `--filenames / -if [PATHS]`: Accepts a list of directories and/or filenames to specify the set of directories/files that will be deployed
438
+ - `--stdin`: Read from STDIN. Can be combined with `-f`
439
+ - `--no-prune`: Skips pruning of resources that are no longer in your Kubernetes template set. Not recommended, as it allows your namespace to accumulate cruft that is not reflected in your deploy directory.
440
+ - `--selector`: Instructs krane to only prune resources which match the specified label selector, such as `environment=staging`. By using this option, all resource templates must specify matching labels. See [Sharing a namespace](#sharing-a-namespace) below.
441
+ - `--global-timeout=duration`: Raise a timeout error if it takes longer than _duration_ for any
442
+ resource to deploy.
443
+ - `--no-verify-result`: Skip verification that resources correctly deployed.
444
+
445
+ # krane restart
446
+
447
+ `krane restart` is a tool for restarting all of the pods in one or more deployments. It triggers the restart by touching the `RESTARTED_AT` environment variable in the deployment's podSpec. The rollout strategy defined for each deployment will be respected by the restart.
448
+
449
+ ## Usage
450
+
451
+ **Option 1: Specify the deployments you want to restart**
452
+
453
+ The following command will restart all pods in the `web` and `jobs` deployments:
454
+
455
+ `krane restart <kube namespace> <kube context> --deployments=web jobs`
456
+
457
+
458
+ **Option 2: Annotate the deployments you want to restart**
459
+
460
+ Add the annotation `shipit.shopify.io/restart` to all the deployments you want to target, like this:
461
+
462
+ ```yaml
463
+ apiVersion: apps/v1
464
+ kind: Deployment
465
+ metadata:
466
+ name: web
467
+ annotations:
468
+ shipit.shopify.io/restart: "true"
469
+ ```
470
+
471
+ With this done, you can use the following command to restart all of them:
472
+
473
+ `krane restart <kube namespace> <kube context>`
474
+
475
+ *Options:*
476
+
477
+ Refer to `krane help restart` for the authoritative set of options.
478
+
479
+ - `--selector`: Only restarts Deployments which match the specified Kubernetes resource selector.
480
+ - `--deployments`: Restart specific Deployment resources by name.
481
+ - `--global-timeout=duration`: Raise a timeout error if it takes longer than _duration_ for any
482
+ resource to restart.
483
+ - `--no-verify-result`: Skip verification that workloads correctly restarted.
484
+
485
+ # krane run
486
+
487
+ `krane run` is a tool for triggering a one-off job, such as a rake task, _outside_ of a deploy.
488
+
489
+
490
+
491
+ ## Prerequisites
492
+
493
+ * You've already deployed a [`PodTemplate`](https://v1-10.docs.kubernetes.io/docs/reference/generated/kubernetes-api/v1.11/#podtemplate-v1-core) object with field `template` containing a `Pod` specification that does not include the `apiVersion` or `kind` parameters. An example is provided in this repo in `test/fixtures/hello-cloud/template-runner.yml`.
494
+ * The `Pod` specification in that template has a container named `task-runner`.
495
+
496
+ Based on this specification `krane run` will create a new pod with the entrypoint of the `task-runner ` container overridden with the supplied arguments.
497
+
498
+
499
+
500
+ ## Usage
501
+
502
+ `krane run <kube namespace> <kube context> --arguments=<arguments> --command=<command> --template=<template name>`
503
+
504
+ *Options:*
505
+
506
+ * `--template=TEMPLATE`: Specifies the name of the PodTemplate to use (default is `task-runner-template` if this option is not set).
507
+ * `--env-vars=ENV_VARS`: Accepts a list of environment variables to be added to the pod template. For example, `--env-vars="ENV=VAL ENV2=VAL2"` will make `ENV` and `ENV2` available to the container.
508
+ * `--command=`: Override the default command in the container image.
509
+ * `--no-verify-result`: Skip verification of pod success
510
+ * `--global-timeout=duration`: Raise a timeout error if the pod runs for longer than the specified duration
511
+ * `--arguments:`: Override the default arguments for the command with a space-separated list of arguments
512
+
513
+
514
+ # krane render
515
+
516
+ `krane render` is a tool for rendering ERB templates to raw Kubernetes YAML. It's useful for outputting YAML that can be passed to other tools, for validation or introspection purposes.
517
+
518
+
519
+ ## Prerequisites
520
+
521
+ * `krane render` does __not__ require a running cluster or an active kubernetes context, which is nice if you want to run it in a CI environment, potentially alongside something like https://github.com/garethr/kubeval to make sure your configuration is sound.
522
+
523
+ ## Usage
524
+
525
+ To render all templates in your template dir, run:
526
+
527
+ ```
528
+ krane render -f ./path/to/template/dir
529
+ ```
530
+
531
+ To render some templates in a template dir, run krane render with the names of the templates to render:
532
+
533
+ ```
534
+ krane render -f ./path/to/template/dir/this-template.yaml.erb
535
+ ```
536
+
537
+ To render a template in a template dir and output it to a file, run krane render with the name of the template and redirect the output to a file:
538
+
539
+ ```
540
+ krane render -f ./path/to/template/dir/template.yaml.erb > template.yaml
541
+ ```
542
+
543
+ *Options:*
544
+
545
+ - `--filenames / -f [PATHS]`: Accepts a list of directories and/or filenames to specify the set of directories/files that will be deployed.
546
+ - `--stdin`: Read from STDIN. Can be combined with `-f` Example: `cat templates_from_stdin/*.yml | krane render -f path/to/dir path/to/file.yml --stdin`
547
+ - `--bindings=BINDINGS`: Makes additional variables available to your ERB templates. For example, `krane render --bindings=color=blue size=large -f some-template.yaml.erb` will expose `color` and `size` to `some-template.yaml.erb`.
548
+ - `--current-sha`: Expose SHA `current_sha` in ERB bindings
549
+
550
+ You can add additional variables using the `--bindings=BINDINGS` option which can be formated as a string, JSON string or path to a JSON or YAML file. Complex JSON or YAML data will be converted to a Hash for use in templates. To load a file the argument should include the relative
551
+ file path prefixed with an `@` sign. An argument error will be raised if the string argument cannot be parsed, the referenced file does not include a
552
+ valid extension (`.json`, `.yaml` or `.yml`) or the referenced file does not exist.
553
+
554
+ #### Bindings examples
555
+
556
+ ```
557
+ # Comma separated string. Exposes, 'color' and 'size'
558
+ $ krane render --bindings=color=blue size=large
559
+
560
+ # JSON string. Exposes, 'color' and 'size'
561
+ $ krane render --bindings='{"color":"blue","size":"large"}'
562
+
563
+ # Load JSON file from ./config
564
+ $ krane render --bindings='@config/production.json'
565
+
566
+ # Load YAML file from ./config (.yaml or yml supported)
567
+ $ krane render --bindings='@config/production.yaml'
568
+ ```
569
+
570
+ #### Using partials
571
+
572
+ `krane` supports composing templates from so called partials in order to reduce duplication in Kubernetes YAML files. Given a directory `DIR`, partials are searched for in `DIR/partials`and in 'DIR/../partials', in that order. They can be embedded in other ERB templates using the helper method `partial`. For example, let's assume an application needs a number of different CronJob resources, one could place a template called `cron` in one of those directories and then use it in the main deployment.yaml.erb like so:
573
+
574
+ ```yaml
575
+ <%= partial "cron", name: "cleanup", schedule: "0 0 * * *", args: %w(cleanup), cpu: "100m", memory: "100Mi" %>
576
+ <%= partial "cron", name: "send-mail", schedule: "0 0 * * *", args: %w(send-mails), cpu: "200m", memory: "256Mi" %>
577
+ ```
578
+
579
+ Inside a partial, parameters can be accessed as normal variables, or via a hash called `locals`. Thus, the `cron` template could like this:
580
+
581
+ ```yaml
582
+ ---
583
+ apiVersion: batch/v1beta1
584
+ kind: CronJob
585
+ metadata:
586
+ name: cron-<%= name %>
587
+ spec:
588
+ schedule: <%= schedule %>
589
+ successfulJobsHistoryLimit: 3
590
+ failedJobsHistoryLimit: 3
591
+ concurrencyPolicy: Forbid
592
+ jobTemplate:
593
+ spec:
594
+ template:
595
+ spec:
596
+ containers:
597
+ - name: cron-<%= name %>
598
+ image: ...
599
+ args: <%= args %>
600
+ resources:
601
+ requests:
602
+ cpu: "<%= cpu %>"
603
+ memory: <%= memory %>
604
+ restartPolicy: OnFailure
605
+ ```
606
+
607
+ Both `.yaml.erb` and `.yml.erb` file extensions are supported. Templates must refer to the bare filename (e.g. use `partial: 'cron'` to reference `cron.yaml.erb`).
608
+
609
+ ##### Limitations when using partials
610
+
611
+ Partials can be included almost everywhere in ERB templates. Note: when using a partial to insert additional key-value pairs to a map you must use [YAML merge keys](http://yaml.org/type/merge.html). For example, given a partial `p` defining two fields 'a' and 'b',
612
+
613
+ ```yaml
614
+ a: 1
615
+ b: 2
616
+ ```
617
+
618
+ you cannot do this:
619
+
620
+ ```yaml
621
+ x: yz
622
+ <%= partial 'p' %>
623
+ ```
624
+
625
+ hoping to get
626
+
627
+ ```yaml
628
+ x: yz
629
+ a: 1
630
+ b: 2
631
+
632
+ but you can do:
633
+
634
+ ```yaml
635
+ <<: <%= partial 'p' %>
636
+ x: yz
637
+ ```
638
+
639
+ This is a limitation of the current implementation.
640
+
641
+ # Contributing
642
+
643
+ We :heart: contributors! To make it easier for you and us we've written a
644
+ [Contributing Guide](https://github.com/Shopify/krane/blob/master/CONTRIBUTING.md)
645
+
646
+
647
+ You can also reach out to us on our slack channel, #krane, at https://kubernetes.slack.com. All are welcome!
648
+
649
+ ## Code of Conduct
650
+ Everyone is expected to follow our [Code of Conduct](https://github.com/Shopify/krane/blob/master/CODE_OF_CONDUCT.md).
651
+
652
+
653
+ # License
654
+
655
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).