mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-09-10 05:30:26 +00:00
Cloning docs for 0.19.0
This commit is contained in:
27
release-0.19.0/docs/devel/README.md
Normal file
27
release-0.19.0/docs/devel/README.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# Developing Kubernetes
|
||||
|
||||
Docs in this directory relate to developing Kubernetes.
|
||||
|
||||
* **On Collaborative Development** ([collab.md](collab.md)): info on pull requests and code reviews.
|
||||
|
||||
* **Development Guide** ([development.md](development.md)): Setting up your environment tests.
|
||||
|
||||
* **Hunting flaky tests** ([flaky-tests.md](flaky-tests.md)): We have a goal of 99.9% flake free tests.
|
||||
Here's how to run your tests many times.
|
||||
|
||||
* **GitHub Issues** ([issues.md](issues.md)): How incoming issues are reviewed and prioritized.
|
||||
|
||||
* **Logging Conventions** ([logging.md](logging.md)]: Glog levels.
|
||||
|
||||
* **Pull Request Process** ([pull-requests.md](pull-requests.md)): When and why pull requests are closed.
|
||||
|
||||
* **Releasing Kubernetes** ([releasing.md](releasing.md)): How to create a Kubernetes release (as in version)
|
||||
and how the version information gets embedded into the built binaries.
|
||||
|
||||
* **Profiling Kubernetes** ([profiling.md](profiling.md)): How to plug in go pprof profiler to Kubernetes.
|
||||
|
||||
|
||||
[]()
|
||||
|
||||
|
||||
[]()
|
348
release-0.19.0/docs/devel/api_changes.md
Normal file
348
release-0.19.0/docs/devel/api_changes.md
Normal file
@@ -0,0 +1,348 @@
|
||||
# So you want to change the API?
|
||||
|
||||
The Kubernetes API has two major components - the internal structures and
|
||||
the versioned APIs. The versioned APIs are intended to be stable, while the
|
||||
internal structures are implemented to best reflect the needs of the Kubernetes
|
||||
code itself.
|
||||
|
||||
What this means for API changes is that you have to be somewhat thoughtful in
|
||||
how you approach changes, and that you have to touch a number of pieces to make
|
||||
a complete change. This document aims to guide you through the process, though
|
||||
not all API changes will need all of these steps.
|
||||
|
||||
## Operational overview
|
||||
|
||||
It is important to have a high level understanding of the API system used in
|
||||
Kubernetes in order to navigate the rest of this document.
|
||||
|
||||
As mentioned above, the internal representation of an API object is decoupled
|
||||
from any one API version. This provides a lot of freedom to evolve the code,
|
||||
but it requires robust infrastructure to convert between representations. There
|
||||
are multiple steps in processing an API operation - even something as simple as
|
||||
a GET involves a great deal of machinery.
|
||||
|
||||
The conversion process is logically a "star" with the internal form at the
|
||||
center. Every versioned API can be converted to the internal form (and
|
||||
vice-versa), but versioned APIs do not convert to other versioned APIs directly.
|
||||
This sounds like a heavy process, but in reality we do not intend to keep more
|
||||
than a small number of versions alive at once. While all of the Kubernetes code
|
||||
operates on the internal structures, they are always converted to a versioned
|
||||
form before being written to storage (disk or etcd) or being sent over a wire.
|
||||
Clients should consume and operate on the versioned APIs exclusively.
|
||||
|
||||
To demonstrate the general process, here is a (hypothetical) example:
|
||||
|
||||
1. A user POSTs a `Pod` object to `/api/v7beta1/...`
|
||||
2. The JSON is unmarshalled into a `v7beta1.Pod` structure
|
||||
3. Default values are applied to the `v7beta1.Pod`
|
||||
4. The `v7beta1.Pod` is converted to an `api.Pod` structure
|
||||
5. The `api.Pod` is validated, and any errors are returned to the user
|
||||
6. The `api.Pod` is converted to a `v6.Pod` (because v6 is the latest stable
|
||||
version)
|
||||
7. The `v6.Pod` is marshalled into JSON and written to etcd
|
||||
|
||||
Now that we have the `Pod` object stored, a user can GET that object in any
|
||||
supported api version. For example:
|
||||
|
||||
1. A user GETs the `Pod` from `/api/v5/...`
|
||||
2. The JSON is read from etcd and unmarshalled into a `v6.Pod` structure
|
||||
3. Default values are applied to the `v6.Pod`
|
||||
4. The `v6.Pod` is converted to an `api.Pod` structure
|
||||
5. The `api.Pod` is converted to a `v5.Pod` structure
|
||||
6. The `v5.Pod` is marshalled into JSON and sent to the user
|
||||
|
||||
The implication of this process is that API changes must be done carefully and
|
||||
backward-compatibly.
|
||||
|
||||
## On compatibility
|
||||
|
||||
Before talking about how to make API changes, it is worthwhile to clarify what
|
||||
we mean by API compatibility. An API change is considered backward-compatible
|
||||
if it:
|
||||
* adds new functionality that is not required for correct behavior
|
||||
* does not change existing semantics
|
||||
* does not change existing defaults
|
||||
|
||||
Put another way:
|
||||
|
||||
1. Any API call (e.g. a structure POSTed to a REST endpoint) that worked before
|
||||
your change must work the same after your change.
|
||||
2. Any API call that uses your change must not cause problems (e.g. crash or
|
||||
degrade behavior) when issued against servers that do not include your change.
|
||||
3. It must be possible to round-trip your change (convert to different API
|
||||
versions and back) with no loss of information.
|
||||
|
||||
If your change does not meet these criteria, it is not considered strictly
|
||||
compatible. There are times when this might be OK, but mostly we want changes
|
||||
that meet this definition. If you think you need to break compatibility, you
|
||||
should talk to the Kubernetes team first.
|
||||
|
||||
Let's consider some examples. In a hypothetical API (assume we're at version
|
||||
v6), the `Frobber` struct looks something like this:
|
||||
|
||||
```go
|
||||
// API v6.
|
||||
type Frobber struct {
|
||||
Height int `json:"height"`
|
||||
Param string `json:"param"`
|
||||
}
|
||||
```
|
||||
|
||||
You want to add a new `Width` field. It is generally safe to add new fields
|
||||
without changing the API version, so you can simply change it to:
|
||||
|
||||
```go
|
||||
// Still API v6.
|
||||
type Frobber struct {
|
||||
Height int `json:"height"`
|
||||
Width int `json:"width"`
|
||||
Param string `json:"param"`
|
||||
}
|
||||
```
|
||||
|
||||
The onus is on you to define a sane default value for `Width` such that rule #1
|
||||
above is true - API calls and stored objects that used to work must continue to
|
||||
work.
|
||||
|
||||
For your next change you want to allow multiple `Param` values. You can not
|
||||
simply change `Param string` to `Params []string` (without creating a whole new
|
||||
API version) - that fails rules #1 and #2. You can instead do something like:
|
||||
|
||||
```go
|
||||
// Still API v6, but kind of clumsy.
|
||||
type Frobber struct {
|
||||
Height int `json:"height"`
|
||||
Width int `json:"width"`
|
||||
Param string `json:"param"` // the first param
|
||||
ExtraParams []string `json:"params"` // additional params
|
||||
}
|
||||
```
|
||||
|
||||
Now you can satisfy the rules: API calls that provide the old style `Param`
|
||||
will still work, while servers that don't understand `ExtraParams` can ignore
|
||||
it. This is somewhat unsatisfying as an API, but it is strictly compatible.
|
||||
|
||||
Part of the reason for versioning APIs and for using internal structs that are
|
||||
distinct from any one version is to handle growth like this. The internal
|
||||
representation can be implemented as:
|
||||
|
||||
```go
|
||||
// Internal, soon to be v7beta1.
|
||||
type Frobber struct {
|
||||
Height int
|
||||
Width int
|
||||
Params []string
|
||||
}
|
||||
```
|
||||
|
||||
The code that converts to/from versioned APIs can decode this into the somewhat
|
||||
uglier (but compatible!) structures. Eventually, a new API version, let's call
|
||||
it v7beta1, will be forked and it can use the clean internal structure.
|
||||
|
||||
We've seen how to satisfy rules #1 and #2. Rule #3 means that you can not
|
||||
extend one versioned API without also extending the others. For example, an
|
||||
API call might POST an object in API v7beta1 format, which uses the cleaner
|
||||
`Params` field, but the API server might store that object in trusty old v6
|
||||
form (since v7beta1 is "beta"). When the user reads the object back in the
|
||||
v7beta1 API it would be unacceptable to have lost all but `Params[0]`. This
|
||||
means that, even though it is ugly, a compatible change must be made to the v6
|
||||
API.
|
||||
|
||||
As another interesting example, enumerated values provide a unique challenge.
|
||||
Adding a new value to an enumerated set is *not* a compatible change. Clients
|
||||
which assume they know how to handle all possible values of a given field will
|
||||
not be able to handle the new values. However, removing value from an
|
||||
enumerated set *can* be a compatible change, if handled properly (treat the
|
||||
removed value as deprecated but allowed).
|
||||
|
||||
## Changing versioned APIs
|
||||
|
||||
For most changes, you will probably find it easiest to change the versioned
|
||||
APIs first. This forces you to think about how to make your change in a
|
||||
compatible way. Rather than doing each step in every version, it's usually
|
||||
easier to do each versioned API one at a time, or to do all of one version
|
||||
before starting "all the rest".
|
||||
|
||||
### Edit types.go
|
||||
|
||||
The struct definitions for each API are in `pkg/api/<version>/types.go`. Edit
|
||||
those files to reflect the change you want to make. Note that all non-online
|
||||
fields in versioned APIs must have description tags - these are used to generate
|
||||
documentation.
|
||||
|
||||
### Edit defaults.go
|
||||
|
||||
If your change includes new fields for which you will need default values, you
|
||||
need to add cases to `pkg/api/<version>/defaults.go`. Of course, since you
|
||||
have added code, you have to add a test: `pkg/api/<version>/defaults_test.go`.
|
||||
|
||||
Do use pointers to scalars when you need to distinguish between an unset value
|
||||
and an an automatic zero value. For example,
|
||||
`PodSpec.TerminationGracePeriodSeconds` is defined as `*int64` the go type
|
||||
definition. A zero value means 0 seconds, and a nil value asks the system to
|
||||
pick a default.
|
||||
|
||||
Don't forget to run the tests!
|
||||
|
||||
### Edit conversion.go
|
||||
|
||||
Given that you have not yet changed the internal structs, this might feel
|
||||
premature, and that's because it is. You don't yet have anything to convert to
|
||||
or from. We will revisit this in the "internal" section. If you're doing this
|
||||
all in a different order (i.e. you started with the internal structs), then you
|
||||
should jump to that topic below. In the very rare case that you are making an
|
||||
incompatible change you might or might not want to do this now, but you will
|
||||
have to do more later. The files you want are
|
||||
`pkg/api/<version>/conversion.go` and `pkg/api/<version>/conversion_test.go`.
|
||||
|
||||
## Changing the internal structures
|
||||
|
||||
Now it is time to change the internal structs so your versioned changes can be
|
||||
used.
|
||||
|
||||
### Edit types.go
|
||||
|
||||
Similar to the versioned APIs, the definitions for the internal structs are in
|
||||
`pkg/api/types.go`. Edit those files to reflect the change you want to make.
|
||||
Keep in mind that the internal structs must be able to express *all* of the
|
||||
versioned APIs.
|
||||
|
||||
## Edit validation.go
|
||||
|
||||
Most changes made to the internal structs need some form of input validation.
|
||||
Validation is currently done on internal objects in
|
||||
`pkg/api/validation/validation.go`. This validation is the one of the first
|
||||
opportunities we have to make a great user experience - good error messages and
|
||||
thorough validation help ensure that users are giving you what you expect and,
|
||||
when they don't, that they know why and how to fix it. Think hard about the
|
||||
contents of `string` fields, the bounds of `int` fields and the
|
||||
requiredness/optionalness of fields.
|
||||
|
||||
Of course, code needs tests - `pkg/api/validation/validation_test.go`.
|
||||
|
||||
## Edit version conversions
|
||||
|
||||
At this point you have both the versioned API changes and the internal
|
||||
structure changes done. If there are any notable differences - field names,
|
||||
types, structural change in particular - you must add some logic to convert
|
||||
versioned APIs to and from the internal representation. If you see errors from
|
||||
the `serialization_test`, it may indicate the need for explicit conversions.
|
||||
|
||||
Performance of conversions very heavily influence performance of apiserver.
|
||||
Thus, we are auto-generating conversion functions that are much more efficient
|
||||
than the generic ones (which are based on reflections and thus are highly
|
||||
inefficient).
|
||||
|
||||
The conversion code resides with each versioned API. There are two files:
|
||||
- `pkg/api/<version>/conversion.go` containing manually written conversion
|
||||
functions
|
||||
- `pkg/api/<version>/conversion_generated.go` containing auto-generated
|
||||
conversion functions
|
||||
|
||||
Since auto-generated conversion functions are using manually written ones,
|
||||
those manually written should be named with a defined convention, i.e. a function
|
||||
converting type X in pkg a to type Y in pkg b, should be named:
|
||||
`convert_a_X_To_b_Y`.
|
||||
|
||||
Also note that you can (and for efficiency reasons should) use auto-generated
|
||||
conversion functions when writing your conversion functions.
|
||||
|
||||
Once all the necessary manually written conversions are added, you need to
|
||||
regenerate auto-generated ones. To regenerate them:
|
||||
- run
|
||||
```
|
||||
$ hack/update-generated-conversions.sh
|
||||
```
|
||||
|
||||
If running the above script is impossible due to compile errors, the easiest
|
||||
workaround is to comment out the code causing errors and let the script to
|
||||
regenerate it. If the auto-generated conversion methods are not used by the
|
||||
manually-written ones, it's fine to just remove the whole file and let the
|
||||
generator to create it from scratch.
|
||||
|
||||
Unsurprisingly, adding manually written conversion also requires you to add tests to
|
||||
`pkg/api/<version>/conversion_test.go`.
|
||||
|
||||
## Update the fuzzer
|
||||
|
||||
Part of our testing regimen for APIs is to "fuzz" (fill with random values) API
|
||||
objects and then convert them to and from the different API versions. This is
|
||||
a great way of exposing places where you lost information or made bad
|
||||
assumptions. If you have added any fields which need very careful formatting
|
||||
(the test does not run validation) or if you have made assumptions such as
|
||||
"this slice will always have at least 1 element", you may get an error or even
|
||||
a panic from the `serialization_test`. If so, look at the diff it produces (or
|
||||
the backtrace in case of a panic) and figure out what you forgot. Encode that
|
||||
into the fuzzer's custom fuzz functions. Hint: if you added defaults for a field,
|
||||
that field will need to have a custom fuzz function that ensures that the field is
|
||||
fuzzed to a non-empty value.
|
||||
|
||||
The fuzzer can be found in `pkg/api/testing/fuzzer.go`.
|
||||
|
||||
## Update the semantic comparisons
|
||||
|
||||
VERY VERY rarely is this needed, but when it hits, it hurts. In some rare
|
||||
cases we end up with objects (e.g. resource quantities) that have morally
|
||||
equivalent values with different bitwise representations (e.g. value 10 with a
|
||||
base-2 formatter is the same as value 0 with a base-10 formatter). The only way
|
||||
Go knows how to do deep-equality is through field-by-field bitwise comparisons.
|
||||
This is a problem for us.
|
||||
|
||||
The first thing you should do is try not to do that. If you really can't avoid
|
||||
this, I'd like to introduce you to our semantic DeepEqual routine. It supports
|
||||
custom overrides for specific types - you can find that in `pkg/api/helpers.go`.
|
||||
|
||||
There's one other time when you might have to touch this: unexported fields.
|
||||
You see, while Go's `reflect` package is allowed to touch unexported fields, us
|
||||
mere mortals are not - this includes semantic DeepEqual. Fortunately, most of
|
||||
our API objects are "dumb structs" all the way down - all fields are exported
|
||||
(start with a capital letter) and there are no unexported fields. But sometimes
|
||||
you want to include an object in our API that does have unexported fields
|
||||
somewhere in it (for example, `time.Time` has unexported fields). If this hits
|
||||
you, you may have to touch the semantic DeepEqual customization functions.
|
||||
|
||||
## Implement your change
|
||||
|
||||
Now you have the API all changed - go implement whatever it is that you're
|
||||
doing!
|
||||
|
||||
## Write end-to-end tests
|
||||
|
||||
This is, sadly, still sort of painful. Talk to us and we'll try to help you
|
||||
figure out the best way to make sure your cool feature keeps working forever.
|
||||
|
||||
## Examples and docs
|
||||
|
||||
At last, your change is done, all unit tests pass, e2e passes, you're done,
|
||||
right? Actually, no. You just changed the API. If you are touching an
|
||||
existing facet of the API, you have to try *really* hard to make sure that
|
||||
*all* the examples and docs are updated. There's no easy way to do this, due
|
||||
in part to JSON and YAML silently dropping unknown fields. You're clever -
|
||||
you'll figure it out. Put `grep` or `ack` to good use.
|
||||
|
||||
If you added functionality, you should consider documenting it and/or writing
|
||||
an example to illustrate your change.
|
||||
|
||||
Make sure you update the swagger API spec by running:
|
||||
|
||||
```shell
|
||||
$ hack/update-swagger-spec.sh
|
||||
```
|
||||
|
||||
The API spec changes should be in a commit separate from your other changes.
|
||||
|
||||
## Incompatible API changes
|
||||
If your change is going to be backward incompatible or might be a breaking change for API
|
||||
consumers, please send an announcement to `kubernetes-dev@googlegroups.com` before
|
||||
the change gets in. If you are unsure, ask. Also make sure that the change gets documented in
|
||||
`CHANGELOG.md` for the next release.
|
||||
|
||||
## Adding new REST objects
|
||||
|
||||
TODO(smarterclayton): write this.
|
||||
|
||||
|
||||
[]()
|
||||
|
||||
|
||||
[]()
|
13
release-0.19.0/docs/devel/coding-conventions.md
Normal file
13
release-0.19.0/docs/devel/coding-conventions.md
Normal file
@@ -0,0 +1,13 @@
|
||||
Coding style advice for contributors
|
||||
- Bash
|
||||
- https://google-styleguide.googlecode.com/svn/trunk/shell.xml
|
||||
- Go
|
||||
- https://github.com/golang/go/wiki/CodeReviewComments
|
||||
- https://gist.github.com/lavalamp/4bd23295a9f32706a48f
|
||||
|
||||
|
||||
|
||||
[]()
|
||||
|
||||
|
||||
[]()
|
46
release-0.19.0/docs/devel/collab.md
Normal file
46
release-0.19.0/docs/devel/collab.md
Normal file
@@ -0,0 +1,46 @@
|
||||
# On Collaborative Development
|
||||
|
||||
Kubernetes is open source, but many of the people working on it do so as their day job. In order to avoid forcing people to be "at work" effectively 24/7, we want to establish some semi-formal protocols around development. Hopefully these rules make things go more smoothly. If you find that this is not the case, please complain loudly.
|
||||
|
||||
## Patches welcome
|
||||
|
||||
First and foremost: as a potential contributor, your changes and ideas are welcome at any hour of the day or night, weekdays, weekends, and holidays. Please do not ever hesitate to ask a question or send a PR.
|
||||
|
||||
## Code reviews
|
||||
|
||||
All changes must be code reviewed. For non-maintainers this is obvious, since you can't commit anyway. But even for maintainers, we want all changes to get at least one review, preferably (for non-trivial changes obligately) from someone who knows the areas the change touches. For non-trivial changes we may want two reviewers. The primary reviewer will make this decision and nominate a second reviewer, if needed. Except for trivial changes, PRs should not be committed until relevant parties (e.g. owners of the subsystem affected by the PR) have had a reasonable chance to look at PR in their local business hours.
|
||||
|
||||
Most PRs will find reviewers organically. If a maintainer intends to be the primary reviewer of a PR they should set themselves as the assignee on GitHub and say so in a reply to the PR. Only the primary reviewer of a change should actually do the merge, except in rare cases (e.g. they are unavailable in a reasonable timeframe).
|
||||
|
||||
If a PR has gone 2 work days without an owner emerging, please poke the PR thread and ask for a reviewer to be assigned.
|
||||
|
||||
Except for rare cases, such as trivial changes (e.g. typos, comments) or emergencies (e.g. broken builds), maintainers should not merge their own changes.
|
||||
|
||||
Expect reviewers to request that you avoid [common go style mistakes](https://github.com/golang/go/wiki/CodeReviewComments) in your PRs.
|
||||
|
||||
## Assigned reviews
|
||||
|
||||
Maintainers can assign reviews to other maintainers, when appropriate. The assignee becomes the shepherd for that PR and is responsible for merging the PR once they are satisfied with it or else closing it. The assignee might request reviews from non-maintainers.
|
||||
|
||||
## Merge hours
|
||||
|
||||
Maintainers will do merges of appropriately reviewed-and-approved changes during their local "business hours" (typically 7:00 am Monday to 5:00 pm (17:00h) Friday). PRs that arrive over the weekend or on holidays will only be merged if there is a very good reason for it and if the code review requirements have been met. Concretely this means that nobody should merge changes immediately before going to bed for the night.
|
||||
|
||||
There may be discussion an even approvals granted outside of the above hours, but merges will generally be deferred.
|
||||
|
||||
If a PR is considered complex or controversial, the merge of that PR should be delayed to give all interested parties in all timezones the opportunity to provide feedback. Concretely, this means that such PRs should be held for 24
|
||||
hours before merging. Of course "complex" and "controversial" are left to the judgment of the people involved, but we trust that part of being a committer is the judgment required to evaluate such things honestly, and not be
|
||||
motivated by your desire (or your cube-mate's desire) to get their code merged. Also see "Holds" below, any reviewer can issue a "hold" to indicate that the PR is in fact complicated or complex and deserves further review.
|
||||
|
||||
PRs that are incorrectly judged to be merge-able, may be reverted and subject to re-review, if subsequent reviewers believe that they in fact are controversial or complex.
|
||||
|
||||
|
||||
## Holds
|
||||
|
||||
Any maintainer or core contributor who wants to review a PR but does not have time immediately may put a hold on a PR simply by saying so on the PR discussion and offering an ETA measured in single-digit days at most. Any PR that has a hold shall not be merged until the person who requested the hold acks the review, withdraws their hold, or is overruled by a preponderance of maintainers.
|
||||
|
||||
|
||||
[]()
|
||||
|
||||
|
||||
[]()
|
341
release-0.19.0/docs/devel/developer-guides/vagrant.md
Normal file
341
release-0.19.0/docs/devel/developer-guides/vagrant.md
Normal file
@@ -0,0 +1,341 @@
|
||||
## Getting started with Vagrant
|
||||
|
||||
Running kubernetes with Vagrant (and VirtualBox) is an easy way to run/test/develop on your local machine (Linux, Mac OS X).
|
||||
|
||||
### Prerequisites
|
||||
1. Install latest version >= 1.6.2 of vagrant from http://www.vagrantup.com/downloads.html
|
||||
2. Install one of:
|
||||
1. The latest version of Virtual Box from https://www.virtualbox.org/wiki/Downloads
|
||||
2. [VMWare Fusion](https://www.vmware.com/products/fusion/) version 5 or greater as well as the appropriate [Vagrant VMWare Fusion provider](https://www.vagrantup.com/vmware)
|
||||
3. [VMWare Workstation](https://www.vmware.com/products/workstation/) version 9 or greater as well as the [Vagrant VMWare Workstation provider](https://www.vagrantup.com/vmware)
|
||||
4. [Parallels Desktop](https://www.parallels.com/products/desktop/) version 9 or greater as well as the [Vagrant Parallels provider](https://parallels.github.io/vagrant-parallels/)
|
||||
3. Get or build a [binary release](/docs/getting-started-guides/binary_release.md)
|
||||
|
||||
### Setup
|
||||
|
||||
By default, the Vagrant setup will create a single kubernetes-master and 1 kubernetes-minion. Each VM will take 1 GB, so make sure you have at least 2GB to 4GB of free memory (plus appropriate free disk space). To start your local cluster, open a shell and run:
|
||||
|
||||
```sh
|
||||
cd kubernetes
|
||||
|
||||
export KUBERNETES_PROVIDER=vagrant
|
||||
./cluster/kube-up.sh
|
||||
```
|
||||
|
||||
The `KUBERNETES_PROVIDER` environment variable tells all of the various cluster management scripts which variant to use. If you forget to set this, the assumption is you are running on Google Compute Engine.
|
||||
|
||||
If you installed more than one Vagrant provider, Kubernetes will usually pick the appropriate one. However, you can override which one Kubernetes will use by setting the [`VAGRANT_DEFAULT_PROVIDER`](https://docs.vagrantup.com/v2/providers/default.html) environment variable:
|
||||
|
||||
```sh
|
||||
export VAGRANT_DEFAULT_PROVIDER=parallels
|
||||
export KUBERNETES_PROVIDER=vagrant
|
||||
./cluster/kube-up.sh
|
||||
```
|
||||
|
||||
Vagrant will provision each machine in the cluster with all the necessary components to run Kubernetes. The initial setup can take a few minutes to complete on each machine.
|
||||
|
||||
By default, each VM in the cluster is running Fedora, and all of the Kubernetes services are installed into systemd.
|
||||
|
||||
To access the master or any minion:
|
||||
|
||||
```sh
|
||||
vagrant ssh master
|
||||
vagrant ssh minion-1
|
||||
```
|
||||
|
||||
If you are running more than one minion, you can access the others by:
|
||||
|
||||
```sh
|
||||
vagrant ssh minion-2
|
||||
vagrant ssh minion-3
|
||||
```
|
||||
|
||||
To view the service status and/or logs on the kubernetes-master:
|
||||
```sh
|
||||
vagrant ssh master
|
||||
[vagrant@kubernetes-master ~] $ sudo systemctl status kube-apiserver
|
||||
[vagrant@kubernetes-master ~] $ sudo journalctl -r -u kube-apiserver
|
||||
|
||||
[vagrant@kubernetes-master ~] $ sudo systemctl status kube-controller-manager
|
||||
[vagrant@kubernetes-master ~] $ sudo journalctl -r -u kube-controller-manager
|
||||
|
||||
[vagrant@kubernetes-master ~] $ sudo systemctl status etcd
|
||||
[vagrant@kubernetes-master ~] $ sudo systemctl status nginx
|
||||
```
|
||||
|
||||
To view the services on any of the kubernetes-minion(s):
|
||||
```sh
|
||||
vagrant ssh minion-1
|
||||
[vagrant@kubernetes-minion-1] $ sudo systemctl status docker
|
||||
[vagrant@kubernetes-minion-1] $ sudo journalctl -r -u docker
|
||||
[vagrant@kubernetes-minion-1] $ sudo systemctl status kubelet
|
||||
[vagrant@kubernetes-minion-1] $ sudo journalctl -r -u kubelet
|
||||
```
|
||||
|
||||
### Interacting with your Kubernetes cluster with Vagrant.
|
||||
|
||||
With your Kubernetes cluster up, you can manage the nodes in your cluster with the regular Vagrant commands.
|
||||
|
||||
To push updates to new Kubernetes code after making source changes:
|
||||
```sh
|
||||
./cluster/kube-push.sh
|
||||
```
|
||||
|
||||
To stop and then restart the cluster:
|
||||
```sh
|
||||
vagrant halt
|
||||
./cluster/kube-up.sh
|
||||
```
|
||||
|
||||
To destroy the cluster:
|
||||
```sh
|
||||
vagrant destroy
|
||||
```
|
||||
|
||||
Once your Vagrant machines are up and provisioned, the first thing to do is to check that you can use the `kubectl.sh` script.
|
||||
|
||||
You may need to build the binaries first, you can do this with ```make```
|
||||
|
||||
```sh
|
||||
$ ./cluster/kubectl.sh get minions
|
||||
|
||||
NAME LABELS
|
||||
10.245.1.4 <none>
|
||||
10.245.1.5 <none>
|
||||
10.245.1.3 <none>
|
||||
```
|
||||
|
||||
### Interacting with your Kubernetes cluster with the `kube-*` scripts.
|
||||
|
||||
Alternatively to using the vagrant commands, you can also use the `cluster/kube-*.sh` scripts to interact with the vagrant based provider just like any other hosting platform for kubernetes.
|
||||
|
||||
All of these commands assume you have set `KUBERNETES_PROVIDER` appropriately:
|
||||
|
||||
```sh
|
||||
export KUBERNETES_PROVIDER=vagrant
|
||||
```
|
||||
|
||||
Bring up a vagrant cluster
|
||||
|
||||
```sh
|
||||
./cluster/kube-up.sh
|
||||
```
|
||||
|
||||
Destroy the vagrant cluster
|
||||
|
||||
```sh
|
||||
./cluster/kube-down.sh
|
||||
```
|
||||
|
||||
Update the vagrant cluster after you make changes (only works when building your own releases locally):
|
||||
|
||||
```sh
|
||||
./cluster/kube-push.sh
|
||||
```
|
||||
|
||||
Interact with the cluster
|
||||
|
||||
```sh
|
||||
./cluster/kubectl.sh
|
||||
```
|
||||
|
||||
### Authenticating with your master
|
||||
|
||||
When using the vagrant provider in Kubernetes, the `cluster/kubectl.sh` script will cache your credentials in a `~/.kubernetes_vagrant_auth` file so you will not be prompted for them in the future.
|
||||
|
||||
```sh
|
||||
cat ~/.kubernetes_vagrant_auth
|
||||
{ "User": "vagrant",
|
||||
"Password": "vagrant"
|
||||
"CAFile": "/home/k8s_user/.kubernetes.vagrant.ca.crt",
|
||||
"CertFile": "/home/k8s_user/.kubecfg.vagrant.crt",
|
||||
"KeyFile": "/home/k8s_user/.kubecfg.vagrant.key"
|
||||
}
|
||||
```
|
||||
|
||||
You should now be set to use the `cluster/kubectl.sh` script. For example try to list the minions that you have started with:
|
||||
|
||||
```sh
|
||||
./cluster/kubectl.sh get minions
|
||||
```
|
||||
|
||||
### Running containers
|
||||
|
||||
Your cluster is running, you can list the minions in your cluster:
|
||||
|
||||
```sh
|
||||
$ ./cluster/kubectl.sh get minions
|
||||
|
||||
NAME LABELS
|
||||
10.245.2.4 <none>
|
||||
10.245.2.3 <none>
|
||||
10.245.2.2 <none>
|
||||
```
|
||||
|
||||
Now start running some containers!
|
||||
|
||||
You can now use any of the cluster/kube-*.sh commands to interact with your VM machines.
|
||||
Before starting a container there will be no pods, services and replication controllers.
|
||||
|
||||
```
|
||||
$ cluster/kubectl.sh get pods
|
||||
NAME IMAGE(S) HOST LABELS STATUS
|
||||
|
||||
$ cluster/kubectl.sh get services
|
||||
NAME LABELS SELECTOR IP PORT
|
||||
|
||||
$ cluster/kubectl.sh get replicationcontrollers
|
||||
NAME IMAGE(S SELECTOR REPLICAS
|
||||
```
|
||||
|
||||
Start a container running nginx with a replication controller and three replicas
|
||||
|
||||
```
|
||||
$ cluster/kubectl.sh run my-nginx --image=nginx --replicas=3 --port=80
|
||||
```
|
||||
|
||||
When listing the pods, you will see that three containers have been started and are in Waiting state:
|
||||
|
||||
```
|
||||
$ cluster/kubectl.sh get pods
|
||||
NAME IMAGE(S) HOST LABELS STATUS
|
||||
781191ff-3ffe-11e4-9036-0800279696e1 nginx 10.245.2.4/10.245.2.4 name=myNginx Waiting
|
||||
7813c8bd-3ffe-11e4-9036-0800279696e1 nginx 10.245.2.2/10.245.2.2 name=myNginx Waiting
|
||||
78140853-3ffe-11e4-9036-0800279696e1 nginx 10.245.2.3/10.245.2.3 name=myNginx Waiting
|
||||
```
|
||||
|
||||
You need to wait for the provisioning to complete, you can monitor the minions by doing:
|
||||
|
||||
```sh
|
||||
$ sudo salt '*minion-1' cmd.run 'docker images'
|
||||
kubernetes-minion-1:
|
||||
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
|
||||
<none> <none> 96864a7d2df3 26 hours ago 204.4 MB
|
||||
kubernetes/pause latest 6c4579af347b 8 weeks ago 239.8 kB
|
||||
```
|
||||
|
||||
Once the docker image for nginx has been downloaded, the container will start and you can list it:
|
||||
|
||||
```sh
|
||||
$ sudo salt '*minion-1' cmd.run 'docker ps'
|
||||
kubernetes-minion-1:
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
dbe79bf6e25b nginx:latest "nginx" 21 seconds ago Up 19 seconds k8s--mynginx.8c5b8a3a--7813c8bd_-_3ffe_-_11e4_-_9036_-_0800279696e1.etcd--7813c8bd_-_3ffe_-_11e4_-_9036_-_0800279696e1--fcfa837f
|
||||
fa0e29c94501 kubernetes/pause:latest "/pause" 8 minutes ago Up 8 minutes 0.0.0.0:8080->80/tcp k8s--net.a90e7ce4--7813c8bd_-_3ffe_-_11e4_-_9036_-_0800279696e1.etcd--7813c8bd_-_3ffe_-_11e4_-_9036_-_0800279696e1--baf5b21b
|
||||
```
|
||||
|
||||
Going back to listing the pods, services and replicationcontrollers, you now have:
|
||||
|
||||
```
|
||||
$ cluster/kubectl.sh get pods
|
||||
NAME IMAGE(S) HOST LABELS STATUS
|
||||
781191ff-3ffe-11e4-9036-0800279696e1 nginx 10.245.2.4/10.245.2.4 name=myNginx Running
|
||||
7813c8bd-3ffe-11e4-9036-0800279696e1 nginx 10.245.2.2/10.245.2.2 name=myNginx Running
|
||||
78140853-3ffe-11e4-9036-0800279696e1 nginx 10.245.2.3/10.245.2.3 name=myNginx Running
|
||||
|
||||
$ cluster/kubectl.sh get services
|
||||
NAME LABELS SELECTOR IP PORT
|
||||
|
||||
$ cluster/kubectl.sh get replicationcontrollers
|
||||
NAME IMAGE(S SELECTOR REPLICAS
|
||||
myNginx nginx name=my-nginx 3
|
||||
```
|
||||
|
||||
We did not start any services, hence there are none listed. But we see three replicas displayed properly.
|
||||
Check the [guestbook](/examples/guestbook/README.md) application to learn how to create a service.
|
||||
You can already play with scaling the replicas with:
|
||||
|
||||
```sh
|
||||
$ ./cluster/kubectl.sh scale rc my-nginx --replicas=2
|
||||
$ ./cluster/kubectl.sh get pods
|
||||
NAME IMAGE(S) HOST LABELS STATUS
|
||||
7813c8bd-3ffe-11e4-9036-0800279696e1 nginx 10.245.2.2/10.245.2.2 name=myNginx Running
|
||||
78140853-3ffe-11e4-9036-0800279696e1 nginx 10.245.2.3/10.245.2.3 name=myNginx Running
|
||||
```
|
||||
|
||||
Congratulations!
|
||||
|
||||
### Testing
|
||||
|
||||
The following will run all of the end-to-end testing scenarios assuming you set your environment in `cluster/kube-env.sh`:
|
||||
|
||||
```sh
|
||||
NUM_MINIONS=3 hack/e2e-test.sh
|
||||
```
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
#### I keep downloading the same (large) box all the time!
|
||||
|
||||
By default the Vagrantfile will download the box from S3. You can change this (and cache the box locally) by providing a name and an alternate URL when calling `kube-up.sh`
|
||||
|
||||
```sh
|
||||
export KUBERNETES_BOX_NAME=choose_your_own_name_for_your_kuber_box
|
||||
export KUBERNETES_BOX_URL=path_of_your_kuber_box
|
||||
export KUBERNETES_PROVIDER=vagrant
|
||||
./cluster/kube-up.sh
|
||||
```
|
||||
|
||||
#### I just created the cluster, but I am getting authorization errors!
|
||||
|
||||
You probably have an incorrect ~/.kubernetes_vagrant_auth file for the cluster you are attempting to contact.
|
||||
|
||||
```sh
|
||||
rm ~/.kubernetes_vagrant_auth
|
||||
```
|
||||
|
||||
After using kubectl.sh make sure that the correct credentials are set:
|
||||
|
||||
```sh
|
||||
cat ~/.kubernetes_vagrant_auth
|
||||
{
|
||||
"User": "vagrant",
|
||||
"Password": "vagrant"
|
||||
}
|
||||
```
|
||||
|
||||
#### I just created the cluster, but I do not see my container running!
|
||||
|
||||
If this is your first time creating the cluster, the kubelet on each minion schedules a number of docker pull requests to fetch prerequisite images. This can take some time and as a result may delay your initial pod getting provisioned.
|
||||
|
||||
#### I changed Kubernetes code, but it's not running!
|
||||
|
||||
Are you sure there was no build error? After running `$ vagrant provision`, scroll up and ensure that each Salt state was completed successfully on each box in the cluster.
|
||||
It's very likely you see a build error due to an error in your source files!
|
||||
|
||||
#### I have brought Vagrant up but the minions won't validate!
|
||||
|
||||
Are you sure you built a release first? Did you install `net-tools`? For more clues, login to one of the minions (`vagrant ssh minion-1`) and inspect the salt minion log (`sudo cat /var/log/salt/minion`).
|
||||
|
||||
#### I want to change the number of minions!
|
||||
|
||||
You can control the number of minions that are instantiated via the environment variable `NUM_MINIONS` on your host machine. If you plan to work with replicas, we strongly encourage you to work with enough minions to satisfy your largest intended replica size. If you do not plan to work with replicas, you can save some system resources by running with a single minion. You do this, by setting `NUM_MINIONS` to 1 like so:
|
||||
|
||||
```sh
|
||||
export NUM_MINIONS=1
|
||||
```
|
||||
|
||||
#### I want my VMs to have more memory!
|
||||
|
||||
You can control the memory allotted to virtual machines with the `KUBERNETES_MEMORY` environment variable.
|
||||
Just set it to the number of megabytes you would like the machines to have. For example:
|
||||
|
||||
```sh
|
||||
export KUBERNETES_MEMORY=2048
|
||||
```
|
||||
|
||||
If you need more granular control, you can set the amount of memory for the master and minions independently. For example:
|
||||
|
||||
```sh
|
||||
export KUBERNETES_MASTER_MEMORY=1536
|
||||
export KUBERNETES_MINION_MEMORY=2048
|
||||
```
|
||||
|
||||
#### I ran vagrant suspend and nothing works!
|
||||
```vagrant suspend``` seems to mess up the network. It's not supported at this time.
|
||||
|
||||
|
||||
[]()
|
||||
|
||||
|
||||
[]()
|
275
release-0.19.0/docs/devel/development.md
Normal file
275
release-0.19.0/docs/devel/development.md
Normal file
@@ -0,0 +1,275 @@
|
||||
# Development Guide
|
||||
|
||||
# Releases and Official Builds
|
||||
|
||||
Official releases are built in Docker containers. Details are [here](../../build/README.md). You can do simple builds and development with just a local Docker installation. If want to build go locally outside of docker, please continue below.
|
||||
|
||||
## Go development environment
|
||||
|
||||
Kubernetes is written in [Go](http://golang.org) programming language. If you haven't set up Go development environment, please follow [this instruction](http://golang.org/doc/code.html) to install go tool and set up GOPATH. Ensure your version of Go is at least 1.3.
|
||||
|
||||
## Clone kubernetes into GOPATH
|
||||
|
||||
We highly recommend to put kubernetes' code into your GOPATH. For example, the following commands will download kubernetes' code under the current user's GOPATH (Assuming there's only one directory in GOPATH.):
|
||||
|
||||
```
|
||||
$ echo $GOPATH
|
||||
/home/user/goproj
|
||||
$ mkdir -p $GOPATH/src/github.com/GoogleCloudPlatform/
|
||||
$ cd $GOPATH/src/github.com/GoogleCloudPlatform/
|
||||
$ git clone https://github.com/GoogleCloudPlatform/kubernetes.git
|
||||
```
|
||||
|
||||
The commands above will not work if there are more than one directory in ``$GOPATH``.
|
||||
|
||||
If you plan to do development, read about the
|
||||
[Kubernetes Github Flow](https://docs.google.com/presentation/d/1HVxKSnvlc2WJJq8b9KCYtact5ZRrzDzkWgKEfm0QO_o/pub?start=false&loop=false&delayms=3000),
|
||||
and then clone your own fork of Kubernetes as described there.
|
||||
|
||||
## godep and dependency management
|
||||
|
||||
Kubernetes uses [godep](https://github.com/tools/godep) to manage dependencies. It is not strictly required for building Kubernetes but it is required when managing dependencies under the Godeps/ tree, and is required by a number of the build and test scripts. Please make sure that ``godep`` is installed and in your ``$PATH``.
|
||||
|
||||
### Installing godep
|
||||
There are many ways to build and host go binaries. Here is an easy way to get utilities like ```godep``` installed:
|
||||
|
||||
1) Ensure that [mercurial](http://mercurial.selenic.com/wiki/Download) is installed on your system. (some of godep's dependencies use the mercurial
|
||||
source control system). Use ```apt-get install mercurial``` or ```yum install mercurial``` on Linux, or [brew.sh](http://brew.sh) on OS X, or download
|
||||
directly from mercurial.
|
||||
|
||||
2) Create a new GOPATH for your tools and install godep:
|
||||
```
|
||||
export GOPATH=$HOME/go-tools
|
||||
mkdir -p $GOPATH
|
||||
go get github.com/tools/godep
|
||||
```
|
||||
|
||||
3) Add $GOPATH/bin to your path. Typically you'd add this to your ~/.profile:
|
||||
```
|
||||
export GOPATH=$HOME/go-tools
|
||||
export PATH=$PATH:$GOPATH/bin
|
||||
```
|
||||
|
||||
### Using godep
|
||||
Here's a quick walkthrough of one way to use godeps to add or update a Kubernetes dependency into Godeps/_workspace. For more details, please see the instructions in [godep's documentation](https://github.com/tools/godep).
|
||||
|
||||
1) Devote a directory to this endeavor:
|
||||
```
|
||||
export KPATH=$HOME/code/kubernetes
|
||||
mkdir -p $KPATH/src/github.com/GoogleCloudPlatform/kubernetes
|
||||
cd $KPATH/src/github.com/GoogleCloudPlatform/kubernetes
|
||||
git clone https://path/to/your/fork .
|
||||
# Or copy your existing local repo here. IMPORTANT: making a symlink doesn't work.
|
||||
```
|
||||
|
||||
2) Set up your GOPATH.
|
||||
```
|
||||
# Option A: this will let your builds see packages that exist elsewhere on your system.
|
||||
export GOPATH=$KPATH:$GOPATH
|
||||
# Option B: This will *not* let your local builds see packages that exist elsewhere on your system.
|
||||
export GOPATH=$KPATH
|
||||
# Option B is recommended if you're going to mess with the dependencies.
|
||||
```
|
||||
|
||||
3) Populate your new GOPATH.
|
||||
```
|
||||
cd $KPATH/src/github.com/GoogleCloudPlatform/kubernetes
|
||||
godep restore
|
||||
```
|
||||
|
||||
4) Next, you can either add a new dependency or update an existing one.
|
||||
```
|
||||
# To add a new dependency, do:
|
||||
cd $KPATH/src/github.com/GoogleCloudPlatform/kubernetes
|
||||
go get path/to/dependency
|
||||
# Change code in Kubernetes to use the dependency.
|
||||
godep save ./...
|
||||
|
||||
# To update an existing dependency, do:
|
||||
cd $KPATH/src/github.com/GoogleCloudPlatform/kubernetes
|
||||
go get -u path/to/dependency
|
||||
# Change code in Kubernetes accordingly if necessary.
|
||||
godep update path/to/dependency
|
||||
```
|
||||
|
||||
5) Before sending your PR, it's a good idea to sanity check that your Godeps.json file is ok by re-restoring: ```godep restore```
|
||||
|
||||
It is sometimes expedient to manually fix the /Godeps/godeps.json file to minimize the changes.
|
||||
|
||||
Please send dependency updates in separate commits within your PR, for easier reviewing.
|
||||
|
||||
## Hooks
|
||||
|
||||
Before committing any changes, please link/copy these hooks into your .git
|
||||
directory. This will keep you from accidentally committing non-gofmt'd go code.
|
||||
|
||||
```
|
||||
cd kubernetes/.git/hooks/
|
||||
ln -s ../../hooks/pre-commit .
|
||||
```
|
||||
|
||||
## Unit tests
|
||||
|
||||
```
|
||||
cd kubernetes
|
||||
hack/test-go.sh
|
||||
```
|
||||
|
||||
Alternatively, you could also run:
|
||||
|
||||
```
|
||||
cd kubernetes
|
||||
godep go test ./...
|
||||
```
|
||||
|
||||
If you only want to run unit tests in one package, you could run ``godep go test`` under the package directory. For example, the following commands will run all unit tests in package kubelet:
|
||||
|
||||
```
|
||||
$ cd kubernetes # step into kubernetes' directory.
|
||||
$ cd pkg/kubelet
|
||||
$ godep go test
|
||||
# some output from unit tests
|
||||
PASS
|
||||
ok github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet 0.317s
|
||||
```
|
||||
|
||||
## Coverage
|
||||
|
||||
Currently, collecting coverage is only supported for the Go unit tests.
|
||||
|
||||
To run all unit tests and generate an HTML coverage report, run the following:
|
||||
|
||||
```
|
||||
cd kubernetes
|
||||
KUBE_COVER=y hack/test-go.sh
|
||||
```
|
||||
|
||||
At the end of the run, an the HTML report will be generated with the path printed to stdout.
|
||||
|
||||
To run tests and collect coverage in only one package, pass its relative path under the `kubernetes` directory as an argument, for example:
|
||||
```
|
||||
cd kubernetes
|
||||
KUBE_COVER=y hack/test-go.sh pkg/kubectl
|
||||
```
|
||||
|
||||
Multiple arguments can be passed, in which case the coverage results will be combined for all tests run.
|
||||
|
||||
Coverage results for the project can also be viewed on [Coveralls](https://coveralls.io/r/GoogleCloudPlatform/kubernetes), and are continuously updated as commits are merged. Additionally, all pull requests which spawn a Travis build will report unit test coverage results to Coveralls.
|
||||
|
||||
## Integration tests
|
||||
|
||||
You need an [etcd](https://github.com/coreos/etcd/releases/tag/v2.0.0) in your path, please make sure it is installed and in your ``$PATH``.
|
||||
```
|
||||
cd kubernetes
|
||||
hack/test-integration.sh
|
||||
```
|
||||
|
||||
## End-to-End tests
|
||||
|
||||
You can run an end-to-end test which will bring up a master and two minions, perform some tests, and then tear everything down. Make sure you have followed the getting started steps for your chosen cloud platform (which might involve changing the `KUBERNETES_PROVIDER` environment variable to something other than "gce".
|
||||
```
|
||||
cd kubernetes
|
||||
hack/e2e-test.sh
|
||||
```
|
||||
|
||||
Pressing control-C should result in an orderly shutdown but if something goes wrong and you still have some VMs running you can force a cleanup with this command:
|
||||
```
|
||||
go run hack/e2e.go --down
|
||||
```
|
||||
|
||||
### Flag options
|
||||
See the flag definitions in `hack/e2e.go` for more options, such as reusing an existing cluster, here is an overview:
|
||||
|
||||
```sh
|
||||
# Build binaries for testing
|
||||
go run hack/e2e.go --build
|
||||
|
||||
# Create a fresh cluster. Deletes a cluster first, if it exists
|
||||
go run hack/e2e.go --up
|
||||
|
||||
# Create a fresh cluster at a specific release version.
|
||||
go run hack/e2e.go --up --version=0.7.0
|
||||
|
||||
# Test if a cluster is up.
|
||||
go run hack/e2e.go --isup
|
||||
|
||||
# Push code to an existing cluster
|
||||
go run hack/e2e.go --push
|
||||
|
||||
# Push to an existing cluster, or bring up a cluster if it's down.
|
||||
go run hack/e2e.go --pushup
|
||||
|
||||
# Run all tests
|
||||
go run hack/e2e.go --test
|
||||
|
||||
# Run tests matching the regex "Pods.*env"
|
||||
go run hack/e2e.go -v -test --test_args="--ginkgo.focus=Pods.*env"
|
||||
|
||||
# Alternately, if you have the e2e cluster up and no desire to see the event stream, you can run ginkgo-e2e.sh directly:
|
||||
hack/ginkgo-e2e.sh --ginkgo.focus=Pods.*env
|
||||
```
|
||||
|
||||
### Combining flags
|
||||
```sh
|
||||
# Flags can be combined, and their actions will take place in this order:
|
||||
# -build, -push|-up|-pushup, -test|-tests=..., -down
|
||||
# e.g.:
|
||||
go run hack/e2e.go -build -pushup -test -down
|
||||
|
||||
# -v (verbose) can be added if you want streaming output instead of only
|
||||
# seeing the output of failed commands.
|
||||
|
||||
# -ctl can be used to quickly call kubectl against your e2e cluster. Useful for
|
||||
# cleaning up after a failed test or viewing logs. Use -v to avoid suppressing
|
||||
# kubectl output.
|
||||
go run hack/e2e.go -v -ctl='get events'
|
||||
go run hack/e2e.go -v -ctl='delete pod foobar'
|
||||
```
|
||||
|
||||
## Conformance testing
|
||||
End-to-end testing, as described above, is for [development
|
||||
distributions](../../docs/devel/writing-a-getting-started-guide.md). A conformance test is used on
|
||||
a [versioned distro](../../docs/devel/writing-a-getting-started-guide.md).
|
||||
|
||||
The conformance test runs a subset of the e2e-tests against a manually-created cluster. It does not
|
||||
require support for up/push/down and other operations. To run a conformance test, you need to know the
|
||||
IP of the master for your cluster and the authorization arguments to use. The conformance test is
|
||||
intended to run against a cluster at a specific binary release of Kubernetes.
|
||||
See [conformance-test.sh](../../hack/conformance-test.sh).
|
||||
|
||||
## Testing out flaky tests
|
||||
[Instructions here](flaky-tests.md)
|
||||
|
||||
## Keeping your development fork in sync
|
||||
|
||||
One time after cloning your forked repo:
|
||||
|
||||
```
|
||||
git remote add upstream https://github.com/GoogleCloudPlatform/kubernetes.git
|
||||
```
|
||||
|
||||
Then each time you want to sync to upstream:
|
||||
|
||||
```
|
||||
git fetch upstream
|
||||
git rebase upstream/master
|
||||
```
|
||||
|
||||
If you have write access to the main repository, you should modify your git configuration so that
|
||||
you can't accidentally push to upstream:
|
||||
|
||||
```
|
||||
git remote set-url --push upstream no_push
|
||||
```
|
||||
|
||||
## Regenerating the CLI documentation
|
||||
|
||||
```
|
||||
hack/run-gendocs.sh
|
||||
```
|
||||
|
||||
|
||||
[]()
|
||||
|
||||
|
||||
[]()
|
183
release-0.19.0/docs/devel/faster_reviews.md
Normal file
183
release-0.19.0/docs/devel/faster_reviews.md
Normal file
@@ -0,0 +1,183 @@
|
||||
# How to get faster PR reviews
|
||||
|
||||
Most of what is written here is not at all specific to Kubernetes, but it bears
|
||||
being written down in the hope that it will occasionally remind people of "best
|
||||
practices" around code reviews.
|
||||
|
||||
You've just had a brilliant idea on how to make Kubernetes better. Let's call
|
||||
that idea "FeatureX". Feature X is not even that complicated. You have a
|
||||
pretty good idea of how to implement it. You jump in and implement it, fixing a
|
||||
bunch of stuff along the way. You send your PR - this is awesome! And it sits.
|
||||
And sits. A week goes by and nobody reviews it. Finally someone offers a few
|
||||
comments, which you fix up and wait for more review. And you wait. Another
|
||||
week or two goes by. This is horrible.
|
||||
|
||||
What went wrong? One particular problem that comes up frequently is this - your
|
||||
PR is too big to review. You've touched 39 files and have 8657 insertions.
|
||||
When your would-be reviewers pull up the diffs they run away - this PR is going
|
||||
to take 4 hours to review and they don't have 4 hours right now. They'll get to it
|
||||
later, just as soon as they have more free time (ha!).
|
||||
|
||||
Let's talk about how to avoid this.
|
||||
|
||||
## 1. Don't build a cathedral in one PR
|
||||
|
||||
Are you sure FeatureX is something the Kubernetes team wants or will accept, or
|
||||
that it is implemented to fit with other changes in flight? Are you willing to
|
||||
bet a few days or weeks of work on it? If you have any doubt at all about the
|
||||
usefulness of your feature or the design - make a proposal doc or a sketch PR
|
||||
or both. Write or code up just enough to express the idea and the design and
|
||||
why you made those choices, then get feedback on this. Now, when we ask you to
|
||||
change a bunch of facets of the design, you don't have to re-write it all.
|
||||
|
||||
## 2. Smaller diffs are exponentially better
|
||||
|
||||
Small PRs get reviewed faster and are more likely to be correct than big ones.
|
||||
Let's face it - attention wanes over time. If your PR takes 60 minutes to
|
||||
review, I almost guarantee that the reviewer's eye for details is not as keen in
|
||||
the last 30 minutes as it was in the first. This leads to multiple rounds of
|
||||
review when one might have sufficed. In some cases the review is delayed in its
|
||||
entirety by the need for a large contiguous block of time to sit and read your
|
||||
code.
|
||||
|
||||
Whenever possible, break up your PRs into multiple commits. Making a series of
|
||||
discrete commits is a powerful way to express the evolution of an idea or the
|
||||
different ideas that make up a single feature. There's a balance to be struck,
|
||||
obviously. If your commits are too small they become more cumbersome to deal
|
||||
with. Strive to group logically distinct ideas into commits.
|
||||
|
||||
For example, if you found that FeatureX needed some "prefactoring" to fit in,
|
||||
make a commit that JUST does that prefactoring. Then make a new commit for
|
||||
FeatureX. Don't lump unrelated things together just because you didn't think
|
||||
about prefactoring. If you need to, fork a new branch, do the prefactoring
|
||||
there and send a PR for that. If you can explain why you are doing seemingly
|
||||
no-op work ("it makes the FeatureX change easier, I promise") we'll probably be
|
||||
OK with it.
|
||||
|
||||
Obviously, a PR with 25 commits is still very cumbersome to review, so use
|
||||
common sense.
|
||||
|
||||
## 3. Multiple small PRs are often better than multiple commits
|
||||
|
||||
If you can extract whole ideas from your PR and send those as PRs of their own,
|
||||
you can avoid the painful problem of continually rebasing. Kubernetes is a
|
||||
fast-moving codebase - lock in your changes ASAP, and make merges be someone
|
||||
else's problem.
|
||||
|
||||
Obviously, we want every PR to be useful on its own, so you'll have to use
|
||||
common sense in deciding what can be a PR vs what should be a commit in a larger
|
||||
PR. Rule of thumb - if this commit or set of commits is directly related to
|
||||
FeatureX and nothing else, it should probably be part of the FeatureX PR. If
|
||||
you can plausibly imagine someone finding value in this commit outside of
|
||||
FeatureX, try it as a PR.
|
||||
|
||||
Don't worry about flooding us with PRs. We'd rather have 100 small, obvious PRs
|
||||
than 10 unreviewable monoliths.
|
||||
|
||||
## 4. Don't rename, reformat, comment, etc in the same PR
|
||||
|
||||
Often, as you are implementing FeatureX, you find things that are just wrong.
|
||||
Bad comments, poorly named functions, bad structure, weak type-safety. You
|
||||
should absolutely fix those things (or at least file issues, please) - but not
|
||||
in this PR. See the above points - break unrelated changes out into different
|
||||
PRs or commits. Otherwise your diff will have WAY too many changes, and your
|
||||
reviewer won't see the forest because of all the trees.
|
||||
|
||||
## 5. Comments matter
|
||||
|
||||
Read up on GoDoc - follow those general rules. If you're writing code and you
|
||||
think there is any possible chance that someone might not understand why you did
|
||||
something (or that you won't remember what you yourself did), comment it. If
|
||||
you think there's something pretty obvious that we could follow up on, add a
|
||||
TODO. Many code-review comments are about this exact issue.
|
||||
|
||||
## 5. Tests are almost always required
|
||||
|
||||
Nothing is more frustrating than doing a review, only to find that the tests are
|
||||
inadequate or even entirely absent. Very few PRs can touch code and NOT touch
|
||||
tests. If you don't know how to test FeatureX - ask! We'll be happy to help
|
||||
you design things for easy testing or to suggest appropriate test cases.
|
||||
|
||||
## 6. Look for opportunities to generify
|
||||
|
||||
If you find yourself writing something that touches a lot of modules, think hard
|
||||
about the dependencies you are introducing between packages. Can some of what
|
||||
you're doing be made more generic and moved up and out of the FeatureX package?
|
||||
Do you need to use a function or type from an otherwise unrelated package? If
|
||||
so, promote! We have places specifically for hosting more generic code.
|
||||
|
||||
Likewise if FeatureX is similar in form to FeatureW which was checked in last
|
||||
month and it happens to exactly duplicate some tricky stuff from FeatureW,
|
||||
consider prefactoring core logic out and using it in both FeatureW and FeatureX.
|
||||
But do that in a different commit or PR, please.
|
||||
|
||||
## 7. Fix feedback in a new commit
|
||||
|
||||
Your reviewer has finally sent you some feedback on FeatureX. You make a bunch
|
||||
of changes and ... what? You could patch those into your commits with git
|
||||
"squash" or "fixup" logic. But that makes your changes hard to verify. Unless
|
||||
your whole PR is pretty trivial, you should instead put your fixups into a new
|
||||
commit and re-push. Your reviewer can then look at that commit on its own - so
|
||||
much faster to review than starting over.
|
||||
|
||||
We might still ask you to clean up your commits at the very end, for the sake
|
||||
of a more readable history.
|
||||
|
||||
## 8. KISS, YAGNI, MVP, etc
|
||||
|
||||
Sometimes we need to remind each other of core tenets of software design - Keep
|
||||
It Simple, You Aren't Gonna Need It, Minimum Viable Product, and so on. Adding
|
||||
features "because we might need it later" is antithetical to software that
|
||||
ships. Add the things you need NOW and (ideally) leave room for things you
|
||||
might need later - but don't implement them now.
|
||||
|
||||
## 9. Push back
|
||||
|
||||
We understand that it is hard to imagine, but sometimes we make mistakes. It's
|
||||
OK to push back on changes requested during a review. If you have a good reason
|
||||
for doing something a certain way, you are absolutely allowed to debate the
|
||||
merits of a requested change. You might be overruled, but you might also
|
||||
prevail. We're mostly pretty reasonable people. Mostly.
|
||||
|
||||
## 10. I'm still getting stalled - help?!
|
||||
|
||||
So, you've done all that and you still aren't getting any PR love? Here's some
|
||||
things you can do that might help kick a stalled process along:
|
||||
|
||||
* Make sure that your PR has an assigned reviewer (assignee in GitHub). If
|
||||
this is not the case, reply to the PR comment stream asking for one to be
|
||||
assigned.
|
||||
|
||||
* Ping the assignee (@username) on the PR comment stream asking for an
|
||||
estimate of when they can get to it.
|
||||
|
||||
* Ping the assignee by email (many of us have email addresses that are well
|
||||
published or are the same as our GitHub handle @google.com or @redhat.com).
|
||||
|
||||
If you think you have fixed all the issues in a round of review, and you haven't
|
||||
heard back, you should ping the reviewer (assignee) on the comment stream with a
|
||||
"please take another look" (PTAL) or similar comment indicating you are done and
|
||||
you think it is ready for re-review. In fact, this is probably a good habit for
|
||||
all PRs.
|
||||
|
||||
One phenomenon of open-source projects (where anyone can comment on any issue)
|
||||
is the dog-pile - your PR gets so many comments from so many people it becomes
|
||||
hard to follow. In this situation you can ask the primary reviewer
|
||||
(assignee) whether they want you to fork a new PR to clear out all the comments.
|
||||
Remember: you don't HAVE to fix every issue raised by every person who feels
|
||||
like commenting, but you should at least answer reasonable comments with an
|
||||
explanation.
|
||||
|
||||
## Final: Use common sense
|
||||
|
||||
Obviously, none of these points are hard rules. There is no document that can
|
||||
take the place of common sense and good taste. Use your best judgment, but put
|
||||
a bit of thought into how your work can be made easier to review. If you do
|
||||
these things your PRs will flow much more easily.
|
||||
|
||||
|
||||
|
||||
[]()
|
||||
|
||||
|
||||
[]()
|
68
release-0.19.0/docs/devel/flaky-tests.md
Normal file
68
release-0.19.0/docs/devel/flaky-tests.md
Normal file
@@ -0,0 +1,68 @@
|
||||
# Hunting flaky tests in Kubernetes
|
||||
Sometimes unit tests are flaky. This means that due to (usually) race conditions, they will occasionally fail, even though most of the time they pass.
|
||||
|
||||
We have a goal of 99.9% flake free tests. This means that there is only one flake in one thousand runs of a test.
|
||||
|
||||
Running a test 1000 times on your own machine can be tedious and time consuming. Fortunately, there is a better way to achieve this using Kubernetes.
|
||||
|
||||
_Note: these instructions are mildly hacky for now, as we get run once semantics and logging they will get better_
|
||||
|
||||
There is a testing image ```brendanburns/flake``` up on the docker hub. We will use this image to test our fix.
|
||||
|
||||
Create a replication controller with the following config:
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ReplicationController
|
||||
metadata:
|
||||
name: flakecontroller
|
||||
spec:
|
||||
replicas: 24
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
name: flake
|
||||
spec:
|
||||
containers:
|
||||
- name: flake
|
||||
image: brendanburns/flake
|
||||
env:
|
||||
- name: TEST_PACKAGE
|
||||
value: pkg/tools
|
||||
- name: REPO_SPEC
|
||||
value: https://github.com/GoogleCloudPlatform/kubernetes
|
||||
```
|
||||
Note that we omit the labels and the selector fields of the replication controller, because they will be populated from the labels field of the pod template by default.
|
||||
|
||||
```
|
||||
kubectl create -f controller.yaml
|
||||
```
|
||||
|
||||
This will spin up 24 instances of the test. They will run to completion, then exit, and the kubelet will restart them, accumulating more and more runs of the test.
|
||||
You can examine the recent runs of the test by calling ```docker ps -a``` and looking for tasks that exited with non-zero exit codes. Unfortunately, docker ps -a only keeps around the exit status of the last 15-20 containers with the same image, so you have to check them frequently.
|
||||
You can use this script to automate checking for failures, assuming your cluster is running on GCE and has four nodes:
|
||||
|
||||
```sh
|
||||
echo "" > output.txt
|
||||
for i in {1..4}; do
|
||||
echo "Checking kubernetes-minion-${i}"
|
||||
echo "kubernetes-minion-${i}:" >> output.txt
|
||||
gcloud compute ssh "kubernetes-minion-${i}" --command="sudo docker ps -a" >> output.txt
|
||||
done
|
||||
grep "Exited ([^0])" output.txt
|
||||
```
|
||||
|
||||
Eventually you will have sufficient runs for your purposes. At that point you can stop and delete the replication controller by running:
|
||||
|
||||
```sh
|
||||
kubectl stop replicationcontroller flakecontroller
|
||||
```
|
||||
|
||||
If you do a final check for flakes with ```docker ps -a```, ignore tasks that exited -1, since that's what happens when you stop the replication controller.
|
||||
|
||||
Happy flake hunting!
|
||||
|
||||
|
||||
[]()
|
||||
|
||||
|
||||
[]()
|
25
release-0.19.0/docs/devel/issues.md
Normal file
25
release-0.19.0/docs/devel/issues.md
Normal file
@@ -0,0 +1,25 @@
|
||||
GitHub Issues for the Kubernetes Project
|
||||
========================================
|
||||
|
||||
A list quick overview of how we will review and prioritize incoming issues at https://github.com/GoogleCloudPlatform/kubernetes/issues
|
||||
|
||||
Priorities
|
||||
----------
|
||||
|
||||
We will use GitHub issue labels for prioritization. The absence of a priority label means the bug has not been reviewed and prioritized yet.
|
||||
|
||||
Definitions
|
||||
-----------
|
||||
* P0 - something broken for users, build broken, or critical security issue. Someone must drop everything and work on it.
|
||||
* P1 - must fix for earliest possible binary release (every two weeks)
|
||||
* P2 - should be fixed in next major release version
|
||||
* P3 - default priority for lower importance bugs that we still want to track and plan to fix at some point
|
||||
* design - priority/design is for issues that are used to track design discussions
|
||||
* support - priority/support is used for issues tracking user support requests
|
||||
* untriaged - anything without a priority/X label will be considered untriaged
|
||||
|
||||
|
||||
[]()
|
||||
|
||||
|
||||
[]()
|
32
release-0.19.0/docs/devel/logging.md
Normal file
32
release-0.19.0/docs/devel/logging.md
Normal file
@@ -0,0 +1,32 @@
|
||||
Logging Conventions
|
||||
===================
|
||||
|
||||
The following conventions for the glog levels to use. [glog](http://godoc.org/github.com/golang/glog) is globally preferred to [log](http://golang.org/pkg/log/) for better runtime control.
|
||||
|
||||
* glog.Errorf() - Always an error
|
||||
* glog.Warningf() - Something unexpected, but probably not an error
|
||||
* glog.Infof() has multiple levels:
|
||||
* glog.V(0) - Generally useful for this to ALWAYS be visible to an operator
|
||||
* Programmer errors
|
||||
* Logging extra info about a panic
|
||||
* CLI argument handling
|
||||
* glog.V(1) - A reasonable default log level if you don't want verbosity.
|
||||
* Information about config (listening on X, watching Y)
|
||||
* Errors that repeat frequently that relate to conditions that can be corrected (pod detected as unhealthy)
|
||||
* glog.V(2) - Useful steady state information about the service and important log messages that may correlate to significant changes in the system. This is the recommended default log level for most systems.
|
||||
* Logging HTTP requests and their exit code
|
||||
* System state changing (killing pod)
|
||||
* Controller state change events (starting pods)
|
||||
* Scheduler log messages
|
||||
* glog.V(3) - Extended information about changes
|
||||
* More info about system state changes
|
||||
* glog.V(4) - Debug level verbosity (for now)
|
||||
* Logging in particularly thorny parts of code where you may want to come back later and check it
|
||||
|
||||
As per the comments, the practical default level is V(2). Developers and QE environments may wish to run at V(3) or V(4). If you wish to change the log level, you can pass in `-v=X` where X is the desired maximum level to log.
|
||||
|
||||
|
||||
[]()
|
||||
|
||||
|
||||
[]()
|
40
release-0.19.0/docs/devel/profiling.md
Normal file
40
release-0.19.0/docs/devel/profiling.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# Profiling Kubernetes
|
||||
|
||||
This document explain how to plug in profiler and how to profile Kubernetes services.
|
||||
|
||||
## Profiling library
|
||||
|
||||
Go comes with inbuilt 'net/http/pprof' profiling library and profiling web service. The way service works is binding debug/pprof/ subtree on a running webserver to the profiler. Reading from subpages of debug/pprof returns pprof-formatted profiles of the running binary. The output can be processed offline by the tool of choice, or used as an input to handy 'go tool pprof', which can graphically represent the result.
|
||||
|
||||
## Adding profiling to services to APIserver.
|
||||
|
||||
TL;DR: Add lines:
|
||||
```
|
||||
m.mux.HandleFunc("/debug/pprof/", pprof.Index)
|
||||
m.mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
|
||||
m.mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
|
||||
```
|
||||
to the init(c *Config) method in 'pkg/master/master.go' and import 'net/http/pprof' package.
|
||||
|
||||
In most use cases to use profiler service it's enough to do 'import _ net/http/pprof', which automatically registers a handler in the default http.Server. Slight inconvenience is that APIserver uses default server for intra-cluster communication, so plugging profiler to it is not really useful. In 'pkg/master/server/server.go' more servers are created and started as separate goroutines. The one that is usually serving external traffic is secureServer. The handler for this traffic is defined in 'pkg/master/master.go' and stored in Handler variable. It is created from HTTP multiplexer, so the only thing that needs to be done is adding profiler handler functions to this multiplexer. This is exactly what lines after TL;DR do.
|
||||
|
||||
## Connecting to the profiler
|
||||
Even when running profiler I found not really straightforward to use 'go tool pprof' with it. The problem is that at least for dev purposes certificates generated for APIserver are not signed by anyone trusted and because secureServer serves only secure traffic it isn't straightforward to connect to the service. The best workaround I found is by creating an ssh tunnel from the kubernetes_master open unsecured port to some external server, and use this server as a proxy. To save everyone looking for correct ssh flags, it is done by running:
|
||||
```
|
||||
ssh kubernetes_master -L<local_port>:localhost:8080
|
||||
```
|
||||
or analogous one for you Cloud provider. Afterwards you can e.g. run
|
||||
```
|
||||
go tool pprof http://localhost:<local_port>/debug/pprof/profile
|
||||
```
|
||||
to get 30 sec. CPU profile.
|
||||
|
||||
## Contention profiling
|
||||
|
||||
To enable contention profiling you need to add line ```rt.SetBlockProfileRate(1)``` in addition to ```m.mux.HandleFunc(...)``` added before (```rt``` stands for ```runtime``` in ```master.go```). This enables 'debug/pprof/block' subpage, which can be used as an input to ```go tool pprof```.
|
||||
|
||||
|
||||
[]()
|
||||
|
||||
|
||||
[]()
|
22
release-0.19.0/docs/devel/pull-requests.md
Normal file
22
release-0.19.0/docs/devel/pull-requests.md
Normal file
@@ -0,0 +1,22 @@
|
||||
Pull Request Process
|
||||
====================
|
||||
|
||||
An overview of how we will manage old or out-of-date pull requests.
|
||||
|
||||
Process
|
||||
-------
|
||||
|
||||
We will close any pull requests older than two weeks.
|
||||
|
||||
Exceptions can be made for PRs that have active review comments, or that are awaiting other dependent PRs. Closed pull requests are easy to recreate, and little work is lost by closing a pull request that subsequently needs to be reopened.
|
||||
|
||||
We want to limit the total number of PRs in flight to:
|
||||
* Maintain a clean project
|
||||
* Remove old PRs that would be difficult to rebase as the underlying code has changed over time
|
||||
* Encourage code velocity
|
||||
|
||||
|
||||
[]()
|
||||
|
||||
|
||||
[]()
|
113
release-0.19.0/docs/devel/releasing.dot
Normal file
113
release-0.19.0/docs/devel/releasing.dot
Normal file
@@ -0,0 +1,113 @@
|
||||
// Build it with:
|
||||
// $ dot -Tsvg releasing.dot >releasing.svg
|
||||
|
||||
digraph tagged_release {
|
||||
size = "5,5"
|
||||
// Arrows go up.
|
||||
rankdir = BT
|
||||
subgraph left {
|
||||
// Group the left nodes together.
|
||||
ci012abc -> pr101 -> ci345cde -> pr102
|
||||
style = invis
|
||||
}
|
||||
subgraph right {
|
||||
// Group the right nodes together.
|
||||
version_commit -> dev_commit
|
||||
style = invis
|
||||
}
|
||||
{ // Align the version commit and the info about it.
|
||||
rank = same
|
||||
// Align them with pr101
|
||||
pr101
|
||||
version_commit
|
||||
// release_info shows the change in the commit.
|
||||
release_info
|
||||
}
|
||||
{ // Align the dev commit and the info about it.
|
||||
rank = same
|
||||
// Align them with 345cde
|
||||
ci345cde
|
||||
dev_commit
|
||||
dev_info
|
||||
}
|
||||
// Join the nodes from subgraph left.
|
||||
pr99 -> ci012abc
|
||||
pr102 -> pr100
|
||||
// Do the version node.
|
||||
pr99 -> version_commit
|
||||
dev_commit -> pr100
|
||||
tag -> version_commit
|
||||
pr99 [
|
||||
label = "Merge PR #99"
|
||||
shape = box
|
||||
fillcolor = "#ccccff"
|
||||
style = "filled"
|
||||
fontname = "Helvetica Neue, Helvetica, Segoe UI, Arial, freesans, sans-serif"
|
||||
];
|
||||
ci012abc [
|
||||
label = "012abc"
|
||||
shape = circle
|
||||
fillcolor = "#ffffcc"
|
||||
style = "filled"
|
||||
fontname = "Consolas, Liberation Mono, Menlo, Courier, monospace"
|
||||
];
|
||||
pr101 [
|
||||
label = "Merge PR #101"
|
||||
shape = box
|
||||
fillcolor = "#ccccff"
|
||||
style = "filled"
|
||||
fontname = "Helvetica Neue, Helvetica, Segoe UI, Arial, freesans, sans-serif"
|
||||
];
|
||||
ci345cde [
|
||||
label = "345cde"
|
||||
shape = circle
|
||||
fillcolor = "#ffffcc"
|
||||
style = "filled"
|
||||
fontname = "Consolas, Liberation Mono, Menlo, Courier, monospace"
|
||||
];
|
||||
pr102 [
|
||||
label = "Merge PR #102"
|
||||
shape = box
|
||||
fillcolor = "#ccccff"
|
||||
style = "filled"
|
||||
fontname = "Helvetica Neue, Helvetica, Segoe UI, Arial, freesans, sans-serif"
|
||||
];
|
||||
version_commit [
|
||||
label = "678fed"
|
||||
shape = circle
|
||||
fillcolor = "#ccffcc"
|
||||
style = "filled"
|
||||
fontname = "Consolas, Liberation Mono, Menlo, Courier, monospace"
|
||||
];
|
||||
dev_commit [
|
||||
label = "456dcb"
|
||||
shape = circle
|
||||
fillcolor = "#ffffcc"
|
||||
style = "filled"
|
||||
fontname = "Consolas, Liberation Mono, Menlo, Courier, monospace"
|
||||
];
|
||||
pr100 [
|
||||
label = "Merge PR #100"
|
||||
shape = box
|
||||
fillcolor = "#ccccff"
|
||||
style = "filled"
|
||||
fontname = "Helvetica Neue, Helvetica, Segoe UI, Arial, freesans, sans-serif"
|
||||
];
|
||||
release_info [
|
||||
label = "pkg/version/base.go:\ngitVersion = \"v0.5\";"
|
||||
shape = none
|
||||
fontname = "Helvetica Neue, Helvetica, Segoe UI, Arial, freesans, sans-serif"
|
||||
];
|
||||
dev_info [
|
||||
label = "pkg/version/base.go:\ngitVersion = \"v0.5-dev\";"
|
||||
shape = none
|
||||
fontname = "Helvetica Neue, Helvetica, Segoe UI, Arial, freesans, sans-serif"
|
||||
];
|
||||
tag [
|
||||
label = "$ git tag -a v0.5"
|
||||
fillcolor = "#ffcccc"
|
||||
style = "filled"
|
||||
fontname = "Helvetica Neue, Helvetica, Segoe UI, Arial, freesans, sans-serif"
|
||||
];
|
||||
}
|
||||
|
171
release-0.19.0/docs/devel/releasing.md
Normal file
171
release-0.19.0/docs/devel/releasing.md
Normal file
@@ -0,0 +1,171 @@
|
||||
# Releasing Kubernetes
|
||||
|
||||
This document explains how to create a Kubernetes release (as in version) and
|
||||
how the version information gets embedded into the built binaries.
|
||||
|
||||
## Origin of the Sources
|
||||
|
||||
Kubernetes may be built from either a git tree (using `hack/build-go.sh`) or
|
||||
from a tarball (using either `hack/build-go.sh` or `go install`) or directly by
|
||||
the Go native build system (using `go get`).
|
||||
|
||||
When building from git, we want to be able to insert specific information about
|
||||
the build tree at build time. In particular, we want to use the output of `git
|
||||
describe` to generate the version of Kubernetes and the status of the build
|
||||
tree (add a `-dirty` prefix if the tree was modified.)
|
||||
|
||||
When building from a tarball or using the Go build system, we will not have
|
||||
access to the information about the git tree, but we still want to be able to
|
||||
tell whether this build corresponds to an exact release (e.g. v0.3) or is
|
||||
between releases (e.g. at some point in development between v0.3 and v0.4).
|
||||
|
||||
## Version Number Format
|
||||
|
||||
In order to account for these use cases, there are some specific formats that
|
||||
may end up representing the Kubernetes version. Here are a few examples:
|
||||
|
||||
- **v0.5**: This is official version 0.5 and this version will only be used
|
||||
when building from a clean git tree at the v0.5 git tag, or from a tree
|
||||
extracted from the tarball corresponding to that specific release.
|
||||
- **v0.5-15-g0123abcd4567**: This is the `git describe` output and it indicates
|
||||
that we are 15 commits past the v0.5 release and that the SHA1 of the commit
|
||||
where the binaries were built was `0123abcd4567`. It is only possible to have
|
||||
this level of detail in the version information when building from git, not
|
||||
when building from a tarball.
|
||||
- **v0.5-15-g0123abcd4567-dirty** or **v0.5-dirty**: The extra `-dirty` prefix
|
||||
means that the tree had local modifications or untracked files at the time of
|
||||
the build, so there's no guarantee that the source code matches exactly the
|
||||
state of the tree at the `0123abcd4567` commit or at the `v0.5` git tag
|
||||
(resp.)
|
||||
- **v0.5-dev**: This means we are building from a tarball or using `go get` or,
|
||||
if we have a git tree, we are using `go install` directly, so it is not
|
||||
possible to inject the git version into the build information. Additionally,
|
||||
this is not an official release, so the `-dev` prefix indicates that the
|
||||
version we are building is after `v0.5` but before `v0.6`. (There is actually
|
||||
an exception where a commit with `v0.5-dev` is not present on `v0.6`, see
|
||||
later for details.)
|
||||
|
||||
## Injecting Version into Binaries
|
||||
|
||||
In order to cover the different build cases, we start by providing information
|
||||
that can be used when using only Go build tools or when we do not have the git
|
||||
version information available.
|
||||
|
||||
To be able to provide a meaningful version in those cases, we set the contents
|
||||
of variables in a Go source file that will be used when no overrides are
|
||||
present.
|
||||
|
||||
We are using `pkg/version/base.go` as the source of versioning in absence of
|
||||
information from git. Here is a sample of that file's contents:
|
||||
|
||||
```
|
||||
var (
|
||||
gitVersion string = "v0.4-dev" // version from git, output of $(git describe)
|
||||
gitCommit string = "" // sha1 from git, output of $(git rev-parse HEAD)
|
||||
)
|
||||
```
|
||||
|
||||
This means a build with `go install` or `go get` or a build from a tarball will
|
||||
yield binaries that will identify themselves as `v0.4-dev` and will not be able
|
||||
to provide you with a SHA1.
|
||||
|
||||
To add the extra versioning information when building from git, the
|
||||
`hack/build-go.sh` script will gather that information (using `git describe` and
|
||||
`git rev-parse`) and then create a `-ldflags` string to pass to `go install` and
|
||||
tell the Go linker to override the contents of those variables at build time. It
|
||||
can, for instance, tell it to override `gitVersion` and set it to
|
||||
`v0.4-13-g4567bcdef6789-dirty` and set `gitCommit` to `4567bcdef6789...` which
|
||||
is the complete SHA1 of the (dirty) tree used at build time.
|
||||
|
||||
## Handling Official Versions
|
||||
|
||||
Handling official versions from git is easy, as long as there is an annotated
|
||||
git tag pointing to a specific version then `git describe` will return that tag
|
||||
exactly which will match the idea of an official version (e.g. `v0.5`).
|
||||
|
||||
Handling it on tarballs is a bit harder since the exact version string must be
|
||||
present in `pkg/version/base.go` for it to get embedded into the binaries. But
|
||||
simply creating a commit with `v0.5` on its own would mean that the commits
|
||||
coming after it would also get the `v0.5` version when built from tarball or `go
|
||||
get` while in fact they do not match `v0.5` (the one that was tagged) exactly.
|
||||
|
||||
To handle that case, creating a new release should involve creating two adjacent
|
||||
commits where the first of them will set the version to `v0.5` and the second
|
||||
will set it to `v0.5-dev`. In that case, even in the presence of merges, there
|
||||
will be a single commit where the exact `v0.5` version will be used and all
|
||||
others around it will either have `v0.4-dev` or `v0.5-dev`.
|
||||
|
||||
The diagram below illustrates it.
|
||||
|
||||

|
||||
|
||||
After working on `v0.4-dev` and merging PR 99 we decide it is time to release
|
||||
`v0.5`. So we start a new branch, create one commit to update
|
||||
`pkg/version/base.go` to include `gitVersion = "v0.5"` and `git commit` it.
|
||||
|
||||
We test it and make sure everything is working as expected.
|
||||
|
||||
Before sending a PR for it, we create a second commit on that same branch,
|
||||
updating `pkg/version/base.go` to include `gitVersion = "v0.5-dev"`. That will
|
||||
ensure that further builds (from tarball or `go install`) on that tree will
|
||||
always include the `-dev` prefix and will not have a `v0.5` version (since they
|
||||
do not match the official `v0.5` exactly.)
|
||||
|
||||
We then send PR 100 with both commits in it.
|
||||
|
||||
Once the PR is accepted, we can use `git tag -a` to create an annotated tag
|
||||
*pointing to the one commit* that has `v0.5` in `pkg/version/base.go` and push
|
||||
it to GitHub. (Unfortunately GitHub tags/releases are not annotated tags, so
|
||||
this needs to be done from a git client and pushed to GitHub using SSH.)
|
||||
|
||||
## Parallel Commits
|
||||
|
||||
While we are working on releasing `v0.5`, other development takes place and
|
||||
other PRs get merged. For instance, in the example above, PRs 101 and 102 get
|
||||
merged to the master branch before the versioning PR gets merged.
|
||||
|
||||
This is not a problem, it is only slightly inaccurate that checking out the tree
|
||||
at commit `012abc` or commit `345cde` or at the commit of the merges of PR 101
|
||||
or 102 will yield a version of `v0.4-dev` *but* those commits are not present in
|
||||
`v0.5`.
|
||||
|
||||
In that sense, there is a small window in which commits will get a
|
||||
`v0.4-dev` or `v0.4-N-gXXX` label and while they're indeed later than `v0.4`
|
||||
but they are not really before `v0.5` in that `v0.5` does not contain those
|
||||
commits.
|
||||
|
||||
Unfortunately, there is not much we can do about it. On the other hand, other
|
||||
projects seem to live with that and it does not really become a large problem.
|
||||
|
||||
As an example, Docker commit a327d9b91edf has a `v1.1.1-N-gXXX` label but it is
|
||||
not present in Docker `v1.2.0`:
|
||||
|
||||
```
|
||||
$ git describe a327d9b91edf
|
||||
v1.1.1-822-ga327d9b91edf
|
||||
|
||||
$ git log --oneline v1.2.0..a327d9b91edf
|
||||
a327d9b91edf Fix data space reporting from Kb/Mb to KB/MB
|
||||
|
||||
(Non-empty output here means the commit is not present on v1.2.0.)
|
||||
```
|
||||
|
||||
## Release Notes
|
||||
|
||||
No official release should be made final without properly matching release notes.
|
||||
|
||||
There should be made available, per release, a small summary, preamble, of the
|
||||
major changes, both in terms of feature improvements/bug fixes and notes about
|
||||
functional feature changes (if any) regarding the previous released version so
|
||||
that the BOM regarding updating to it gets as obvious and trouble free as possible.
|
||||
|
||||
After this summary, preamble, all the relevant PRs/issues that got in that
|
||||
version should be listed and linked together with a small summary understandable
|
||||
by plain mortals (in a perfect world PR/issue's title would be enough but often
|
||||
it is just too cryptic/geeky/domain-specific that it isn't).
|
||||
|
||||
|
||||
[]()
|
||||
|
||||
|
||||
[]()
|
BIN
release-0.19.0/docs/devel/releasing.png
Normal file
BIN
release-0.19.0/docs/devel/releasing.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 30 KiB |
113
release-0.19.0/docs/devel/releasing.svg
Normal file
113
release-0.19.0/docs/devel/releasing.svg
Normal file
@@ -0,0 +1,113 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Generated by graphviz version 2.36.0 (20140111.2315)
|
||||
-->
|
||||
<!-- Title: tagged_release Pages: 1 -->
|
||||
<svg width="257pt" height="360pt"
|
||||
viewBox="0.00 0.00 257.33 360.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph0" class="graph" transform="scale(0.649819 0.649819) rotate(0) translate(4 550)">
|
||||
<title>tagged_release</title>
|
||||
<polygon fill="white" stroke="none" points="-4,4 -4,-550 392,-550 392,4 -4,4"/>
|
||||
<!-- ci012abc -->
|
||||
<g id="node1" class="node"><title>ci012abc</title>
|
||||
<ellipse fill="#ffffcc" stroke="black" cx="56" cy="-115" rx="42.7926" ry="42.7926"/>
|
||||
<text text-anchor="middle" x="56" y="-111.3" font-family="Consolas, Liberation Mono, Menlo, Courier, monospace" font-size="14.00">012abc</text>
|
||||
</g>
|
||||
<!-- pr101 -->
|
||||
<g id="node2" class="node"><title>pr101</title>
|
||||
<polygon fill="#ccccff" stroke="black" points="112,-255 0,-255 0,-219 112,-219 112,-255"/>
|
||||
<text text-anchor="middle" x="56" y="-233.3" font-family="Helvetica Neue, Helvetica, Segoe UI, Arial, freesans, sans-serif" font-size="14.00">Merge PR #101</text>
|
||||
</g>
|
||||
<!-- ci012abc->pr101 -->
|
||||
<g id="edge1" class="edge"><title>ci012abc->pr101</title>
|
||||
<path fill="none" stroke="black" d="M56,-157.97C56,-174.83 56,-193.784 56,-208.789"/>
|
||||
<polygon fill="black" stroke="black" points="52.5001,-208.93 56,-218.93 59.5001,-208.93 52.5001,-208.93"/>
|
||||
</g>
|
||||
<!-- ci345cde -->
|
||||
<g id="node3" class="node"><title>ci345cde</title>
|
||||
<ellipse fill="#ffffcc" stroke="black" cx="62" cy="-359" rx="42.7926" ry="42.7926"/>
|
||||
<text text-anchor="middle" x="62" y="-355.3" font-family="Consolas, Liberation Mono, Menlo, Courier, monospace" font-size="14.00">345cde</text>
|
||||
</g>
|
||||
<!-- pr101->ci345cde -->
|
||||
<g id="edge2" class="edge"><title>pr101->ci345cde</title>
|
||||
<path fill="none" stroke="black" d="M56.8597,-255.193C57.5237,-268.473 58.4796,-287.592 59.3874,-305.748"/>
|
||||
<polygon fill="black" stroke="black" points="55.904,-306.17 59.8991,-315.982 62.8953,-305.82 55.904,-306.17"/>
|
||||
</g>
|
||||
<!-- pr102 -->
|
||||
<g id="node4" class="node"><title>pr102</title>
|
||||
<polygon fill="#ccccff" stroke="black" points="129,-474 17,-474 17,-438 129,-438 129,-474"/>
|
||||
<text text-anchor="middle" x="73" y="-452.3" font-family="Helvetica Neue, Helvetica, Segoe UI, Arial, freesans, sans-serif" font-size="14.00">Merge PR #102</text>
|
||||
</g>
|
||||
<!-- ci345cde->pr102 -->
|
||||
<g id="edge3" class="edge"><title>ci345cde->pr102</title>
|
||||
<path fill="none" stroke="black" d="M66.8248,-401.668C67.8523,-410.542 68.9117,-419.692 69.8567,-427.853"/>
|
||||
<polygon fill="black" stroke="black" points="66.3936,-428.375 71.0207,-437.906 73.3472,-427.57 66.3936,-428.375"/>
|
||||
</g>
|
||||
<!-- pr100 -->
|
||||
<g id="node10" class="node"><title>pr100</title>
|
||||
<polygon fill="#ccccff" stroke="black" points="174,-546 62,-546 62,-510 174,-510 174,-546"/>
|
||||
<text text-anchor="middle" x="118" y="-524.3" font-family="Helvetica Neue, Helvetica, Segoe UI, Arial, freesans, sans-serif" font-size="14.00">Merge PR #100</text>
|
||||
</g>
|
||||
<!-- pr102->pr100 -->
|
||||
<g id="edge6" class="edge"><title>pr102->pr100</title>
|
||||
<path fill="none" stroke="black" d="M84.1236,-474.303C89.355,-482.441 95.6999,-492.311 101.478,-501.299"/>
|
||||
<polygon fill="black" stroke="black" points="98.6526,-503.377 107.004,-509.896 104.541,-499.591 98.6526,-503.377"/>
|
||||
</g>
|
||||
<!-- version_commit -->
|
||||
<g id="node5" class="node"><title>version_commit</title>
|
||||
<ellipse fill="#ccffcc" stroke="black" cx="173" cy="-237" rx="42.7926" ry="42.7926"/>
|
||||
<text text-anchor="middle" x="173" y="-233.3" font-family="Consolas, Liberation Mono, Menlo, Courier, monospace" font-size="14.00">678fed</text>
|
||||
</g>
|
||||
<!-- dev_commit -->
|
||||
<g id="node6" class="node"><title>dev_commit</title>
|
||||
<ellipse fill="#ffffcc" stroke="black" cx="169" cy="-359" rx="42.7926" ry="42.7926"/>
|
||||
<text text-anchor="middle" x="169" y="-355.3" font-family="Consolas, Liberation Mono, Menlo, Courier, monospace" font-size="14.00">456dcb</text>
|
||||
</g>
|
||||
<!-- version_commit->dev_commit -->
|
||||
<g id="edge4" class="edge"><title>version_commit->dev_commit</title>
|
||||
<path fill="none" stroke="black" d="M171.601,-279.97C171.322,-288.326 171.027,-297.195 170.739,-305.844"/>
|
||||
<polygon fill="black" stroke="black" points="167.24,-305.74 170.405,-315.851 174.236,-305.973 167.24,-305.74"/>
|
||||
</g>
|
||||
<!-- dev_commit->pr100 -->
|
||||
<g id="edge8" class="edge"><title>dev_commit->pr100</title>
|
||||
<path fill="none" stroke="black" d="M158.36,-400.568C152.438,-422.433 144.719,-449.815 137,-474 134.253,-482.606 131.013,-491.906 127.994,-500.278"/>
|
||||
<polygon fill="black" stroke="black" points="124.616,-499.325 124.47,-509.919 131.191,-501.729 124.616,-499.325"/>
|
||||
</g>
|
||||
<!-- release_info -->
|
||||
<g id="node7" class="node"><title>release_info</title>
|
||||
<text text-anchor="middle" x="304" y="-240.8" font-family="Helvetica Neue, Helvetica, Segoe UI, Arial, freesans, sans-serif" font-size="14.00">pkg/version/base.go:</text>
|
||||
<text text-anchor="middle" x="304" y="-225.8" font-family="Helvetica Neue, Helvetica, Segoe UI, Arial, freesans, sans-serif" font-size="14.00">gitVersion = "v0.5";</text>
|
||||
</g>
|
||||
<!-- dev_info -->
|
||||
<g id="node8" class="node"><title>dev_info</title>
|
||||
<text text-anchor="middle" x="309" y="-362.8" font-family="Helvetica Neue, Helvetica, Segoe UI, Arial, freesans, sans-serif" font-size="14.00">pkg/version/base.go:</text>
|
||||
<text text-anchor="middle" x="309" y="-347.8" font-family="Helvetica Neue, Helvetica, Segoe UI, Arial, freesans, sans-serif" font-size="14.00">gitVersion = "v0.5-dev";</text>
|
||||
</g>
|
||||
<!-- pr99 -->
|
||||
<g id="node9" class="node"><title>pr99</title>
|
||||
<polygon fill="#ccccff" stroke="black" points="143,-36 39,-36 39,-0 143,-0 143,-36"/>
|
||||
<text text-anchor="middle" x="91" y="-14.3" font-family="Helvetica Neue, Helvetica, Segoe UI, Arial, freesans, sans-serif" font-size="14.00">Merge PR #99</text>
|
||||
</g>
|
||||
<!-- pr99->ci012abc -->
|
||||
<g id="edge5" class="edge"><title>pr99->ci012abc</title>
|
||||
<path fill="none" stroke="black" d="M84.5805,-36.4245C81.5586,-44.6267 77.7879,-54.8615 73.9865,-65.1795"/>
|
||||
<polygon fill="black" stroke="black" points="70.6804,-64.0292 70.5075,-74.6226 77.2488,-66.4492 70.6804,-64.0292"/>
|
||||
</g>
|
||||
<!-- pr99->version_commit -->
|
||||
<g id="edge7" class="edge"><title>pr99->version_commit</title>
|
||||
<path fill="none" stroke="black" d="M97.4344,-36.0276C109.585,-68.1826 136.317,-138.924 154.498,-187.038"/>
|
||||
<polygon fill="black" stroke="black" points="151.318,-188.523 158.127,-196.64 157.866,-186.048 151.318,-188.523"/>
|
||||
</g>
|
||||
<!-- tag -->
|
||||
<g id="node11" class="node"><title>tag</title>
|
||||
<ellipse fill="#ffcccc" stroke="black" cx="226" cy="-115" rx="71.4873" ry="18"/>
|
||||
<text text-anchor="middle" x="226" y="-111.3" font-family="Helvetica Neue, Helvetica, Segoe UI, Arial, freesans, sans-serif" font-size="14.00">$ git tag -a v0.5</text>
|
||||
</g>
|
||||
<!-- tag->version_commit -->
|
||||
<g id="edge9" class="edge"><title>tag->version_commit</title>
|
||||
<path fill="none" stroke="black" d="M218.519,-132.939C212.168,-147.318 202.736,-168.673 194.103,-188.22"/>
|
||||
<polygon fill="black" stroke="black" points="190.784,-187.071 189.946,-197.632 197.188,-189.899 190.784,-187.071"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 7.1 KiB |
105
release-0.19.0/docs/devel/writing-a-getting-started-guide.md
Normal file
105
release-0.19.0/docs/devel/writing-a-getting-started-guide.md
Normal file
@@ -0,0 +1,105 @@
|
||||
# Writing a Getting Started Guide
|
||||
This page gives some advice for anyone planning to write or update a Getting Started Guide for Kubernetes.
|
||||
It also gives some guidelines which reviewers should follow when reviewing a pull request for a
|
||||
guide.
|
||||
|
||||
A Getting Started Guide is instructions on how to create a Kubernetes cluster on top of a particular
|
||||
type(s) of infrastructure. Infrastructure includes: the IaaS provider for VMs;
|
||||
the node OS; inter-node networking; and node Configuration Management system.
|
||||
A guide refers to scripts, Configuration Management files, and/or binary assets such as RPMs. We call
|
||||
the combination of all these things needed to run on a particular type of infrastructure a
|
||||
**distro**.
|
||||
|
||||
[The Matrix](../../docs/getting-started-guides/README.md) lists the distros. If there is already a guide
|
||||
which is similar to the one you have planned, consider improving that one.
|
||||
|
||||
|
||||
Distros fall into two categories:
|
||||
- **versioned distros** are tested to work with a particular binary release of Kubernetes. These
|
||||
come in a wide variety, reflecting a wide range of ideas and preferences in how to run a cluster.
|
||||
- **development distros** are tested work with the latest Kubernetes source code. But, there are
|
||||
relatively few of these and the bar is much higher for creating one.
|
||||
|
||||
There are different guidelines for each.
|
||||
|
||||
## Versioned Distro Guidelines
|
||||
These guidelines say *what* to do. See the Rationale section for *why*.
|
||||
- Send us a PR.
|
||||
- Put the instructions in `docs/getting-started-guides/...`. Scripts go there too. This helps devs easily
|
||||
search for uses of flags by guides.
|
||||
- We may ask that you host binary assets or large amounts of code in our `contrib` directory or on your
|
||||
own repo.
|
||||
- Setup a cluster and run the [conformance test](../../docs/devel/conformance-test.md) against it, and report the
|
||||
results in your PR.
|
||||
- Add or update a row in [The Matrix](../../docs/getting-started-guides/README.md).
|
||||
- State the binary version of kubernetes that you tested clearly in your Guide doc and in The Matrix.
|
||||
- Even if you are just updating the binary version used, please still do a conformance test.
|
||||
- If it worked before and now fails, you can ask on IRC,
|
||||
check the release notes since your last tested version, or look at git -logs for files in other distros
|
||||
that are updated to the new version.
|
||||
- Versioned distros should typically not modify or add code in `cluster/`. That is just scripts for developer
|
||||
distros.
|
||||
- If a versioned distro has not been updated for many binary releases, it may be dropped from the Matrix.
|
||||
|
||||
If you have a cluster partially working, but doing all the above steps seems like too much work,
|
||||
we still want to hear from you. We suggest you write a blog post or a Gist, and we will link to it on our wiki page.
|
||||
Just file an issue or chat us on IRC and one of the committers will link to it from the wiki.
|
||||
|
||||
## Development Distro Guidelines
|
||||
These guidelines say *what* to do. See the Rationale section for *why*.
|
||||
- the main reason to add a new development distro is to support a new IaaS provider (VM and
|
||||
network management). This means implementing a new `pkg/cloudprovider/$IAAS_NAME`.
|
||||
- Development distros should use Saltstack for Configuration Management.
|
||||
- development distros need to support automated cluster creation, deletion, upgrading, etc.
|
||||
This mean writing scripts in `cluster/$IAAS_NAME`.
|
||||
- all commits to the tip of this repo need to not break any of the development distros
|
||||
- the author of the change is responsible for making changes necessary on all the cloud-providers if the
|
||||
change affects any of them, and reverting the change if it breaks any of the CIs.
|
||||
- a development distro needs to have an organization which owns it. This organization needs to:
|
||||
- Setting up and maintaining Continuous Integration that runs e2e frequently (multiple times per day) against the
|
||||
Distro at head, and which notifies all devs of breakage.
|
||||
- being reasonably available for questions and assisting with
|
||||
refactoring and feature additions that affect code for their IaaS.
|
||||
|
||||
## Rationale
|
||||
- We want want people to create Kubernetes clusters with whatever IaaS, Node OS,
|
||||
configuration management tools, and so on, which they are familiar with. The
|
||||
guidelines for **versioned distros** are designed for flexibility.
|
||||
- We want developers to be able to work without understanding all the permutations of
|
||||
IaaS, NodeOS, and configuration management. The guidelines for **developer distros** are designed
|
||||
for consistency.
|
||||
- We want users to have a uniform experience with Kubernetes whenever they follow instructions anywhere
|
||||
in our Github repository. So, we ask that versioned distros pass a **conformance test** to make sure
|
||||
really work.
|
||||
- We ask versioned distros to **clearly state a version**. People pulling from Github may
|
||||
expect any instructions there to work at Head, so stuff that has not been tested at Head needs
|
||||
to be called out. We are still changing things really fast, and, while the REST API is versioned,
|
||||
it is not practical at this point to version or limit changes that affect distros. We still change
|
||||
flags at the Kubernetes/Infrastructure interface.
|
||||
- We want to **limit the number of development distros** for several reasons. Developers should
|
||||
only have to change a limited number of places to add a new feature. Also, since we will
|
||||
gate commits on passing CI for all distros, and since end-to-end tests are typically somewhat
|
||||
flaky, it would be highly likely for there to be false positives and CI backlogs with many CI pipelines.
|
||||
- We do not require versioned distros to do **CI** for several reasons. It is a steep
|
||||
learning curve to understand our our automated testing scripts. And it is considerable effort
|
||||
to fully automate setup and teardown of a cluster, which is needed for CI. And, not everyone
|
||||
has the time and money to run CI. We do not want to
|
||||
discourage people from writing and sharing guides because of this.
|
||||
- Versioned distro authors are free to run their own CI and let us know if there is breakage, but we
|
||||
will not include them as commit hooks -- there cannot be so many commit checks that it is impossible
|
||||
to pass them all.
|
||||
- We prefer a single Configuration Management tool for development distros. If there were more
|
||||
than one, the core developers would have to learn multiple tools and update config in multiple
|
||||
places. **Saltstack** happens to be the one we picked when we started the project. We
|
||||
welcome versioned distros that use any tool; there are already examples of
|
||||
CoreOS Fleet, Ansible, and others.
|
||||
- You can still run code from head or your own branch
|
||||
if you use another Configuration Management tool -- you just have to do some manual steps
|
||||
during testing and deployment.
|
||||
|
||||
|
||||
|
||||
[]()
|
||||
|
||||
|
||||
[]()
|
Reference in New Issue
Block a user