diff --git a/docs/book/.gitignore b/docs/book/.gitignore new file mode 100644 index 00000000..3c3629e6 --- /dev/null +++ b/docs/book/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/docs/book/CONTRIBUTING.md b/docs/book/CONTRIBUTING.md new file mode 100644 index 00000000..7c7d70a9 --- /dev/null +++ b/docs/book/CONTRIBUTING.md @@ -0,0 +1,73 @@ +# Contributing + +## Process + +### Fixing Issues + +1. Open an Issue +1. Create a PR +1. Email PR to sig-cli@googlegroups.com with subject `Kubectl Book: Fix Issue in ` +1. Optional: Come to sig-cli meeting to discuss + +### Adding New Content + +1. Open an Issue with proposed content +1. Email sig-cli@googlegroups.com with subject `Kubectl Book: Proposed Content ` +1. Optional: Come to sig-cli meeting to discuss + +## Editing + +### Running Locally + +- Install [GitBook Toolchain](https://toolchain.gitbook.com/setup.html) +- From `docs/book` run `npm install` to install node_modules locally (don't run install, it updates the shrinkwrap.json) +- From `docs/book` run `gitbook serve` +- Go to `http://localhost:4000` in a browser + +### Adding a Section + +- Update `SUMMARY.md` with a new section formatted as `## Section Name` + +### Adding a Chapter + +- Update `SUMMARY.md` under section with chapter formatted as `* [Name of Chapter](pages/section_chapter.md)` +- Add file `pages/section_chapter.md` + +### Adding Examples to a Chapter + +```bash +{% method %} +Text Explaining Example +{% sample lang="yaml" %} +Formatted code +{% endmethod %} +``` + +### Adding Notes to a Chapter + +```bash +{% panel style="info", title="Title of Note" %} +Note text +{% endpanel %} +``` + +Notes may have the following styles: + +- success +- info +- warning +- danger + +### Building and Publishing a release + +- Run `gitbook build` +- Push fies in `_book` to a server + +### Adding GitBook plugins + +- Update `book.json` with the plugin +- Run `npm install ` + +### Cool plugins + +See https://github.com/swapagarwal/awesome-gitbook-plugins for more plugins. \ No newline at end of file diff --git a/docs/book/Dockerfile b/docs/book/Dockerfile new file mode 100644 index 00000000..62d7586d --- /dev/null +++ b/docs/book/Dockerfile @@ -0,0 +1,27 @@ +# Copyright 2019 The Kubernetes Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +FROM python:3.7 + +EXPOSE 4000 +RUN curl -sL https://deb.nodesource.com/setup_11.x | bash + +RUN apt-get update && apt-get install -y nodejs npm && apt-get clean; +RUN npm install gitbook-cli -g + +WORKDIR /opt/book/ +COPY . /opt/book/ +RUN npm install + +CMD ["gitbook", "serve"] diff --git a/docs/book/README.md b/docs/book/README.md new file mode 100644 index 00000000..102fc021 --- /dev/null +++ b/docs/book/README.md @@ -0,0 +1,81 @@ +{% panel style="success", title="Feedback and Contributing" %} +**Provide feedback on new kubectl docs at the [survey](https://www.surveymonkey.com/r/JH35X82)** + +See [CONTRIBUTING](https://github.com/kubernetes/kubectl/blob/master/docs/book/CONTRIBUTING.md) for +instructions on filing/fixing issues and adding new content. +{% endpanel %} + +{% panel style="info", title="TL;DR" %} +- Kubectl is the Kubernetes cli +- Kubectl provides a swiss army knife of functionality for working with Kubernetes clusters +- Kubectl may be used to deploy and manage applications on Kubernetes +- Kubectl may be used for scripting and building higher-level frameworks +{% endpanel %} + +# Kubectl + +Kubectl is the Kubernetes cli version of a swiss army knife, and can do many things. + +While this Book is focused on using Kubectl to declaratively manage Applications in Kubernetes, it +also covers other Kubectl functions. + +## Command Families + +Most Kubectl commands typically fall into one of a few categories: + +| Type | Used For | Description | +|----------------------------------------|----------------------------|----------------------------------------------------| +| Declarative Resource Management | Deployment and Operations (e.g. GitOps) | Declaratively manage Kubernetes Workloads using Resource Config | +| Imperative Resource Management | Development Only | Run commands to manage Kubernetes Workloads using Command Line arguments and flags | +| Printing Workload State | Debugging | Print information about Workloads | +| Interacting with Containers | Debugging | Exec, Attach, Cp, Logs | +| Cluster Management | Cluster Ops | Drain and Cordon Nodes | + +## Declarative Application Management + +The preferred approach for managing Resources is through +declarative files called Resource Config used with the Kubectl *Apply* command. +This command reads a local (or remote) file structure and modifies cluster state to +reflect the declared intent. + +{% panel style="info", title="Apply" %} +Apply is the preferred mechanism for managing Resources in a Kubernetes cluster. +{% endpanel %} + +## Printing state about Workloads + +Users will need to view Workload state. + +- Printing summarize state and information about Resources +- Printing complete state and information about Resources +- Printing specific fields from Resources +- Query Resources matching labels + +## Debugging Workloads + +Kubectl supports debugging by providing commands for: + +- Printing Container logs +- Printing cluster events +- Exec or attaching to a Container +- Copying files from Containers in the cluster to a user's filesystem + +## Cluster Management + +On occasion, users may need to perform operations to the Nodes of cluster. Kubectl supports +commands to drain Workloads from a Node so that it can be decommission or debugged. + +## Porcelain + +Users may find using Resource Config overly verbose for *Development* and prefer to work with +the cluster *imperatively* with a shell-like workflow. Kubectl offers porcelain commands for +generating and modifying Resources. + +- Generating + creating Resources such as Deployments, StatefulSets, Services, ConfigMaps, etc +- Setting fields on Resources +- Editing (live) Resources in a text editor + +{% panel style="danger", title="Porcelain For Dev Only" %} +Porcelain commands are time saving for experimenting with workloads in a dev cluster, but shouldn't +be used for production. +{% endpanel %} diff --git a/docs/book/SUMMARY.md b/docs/book/SUMMARY.md new file mode 100644 index 00000000..3445ed3d --- /dev/null +++ b/docs/book/SUMMARY.md @@ -0,0 +1,71 @@ +# Resource Management With Kubectl + +## Background Information + +* [Getting Started with Kubectl](pages/kubectl_book/getting_started.md) +* [Resources + Controllers Overview](pages/kubectl_book/resources_and_controllers.md) + +## App Management + +* [Introduction](pages/app_management/introduction.md) +* [Apply](pages/app_management/apply.md) +* [Secrets and ConfigMaps](pages/app_management/secrets_and_configmaps.md) +* [Container Images](pages/app_management/container_images.md) +* [Namespaces and Names](pages/app_management/namespaces_and_names.md) +* [Labels and Annotations](pages/app_management/labels_and_annotations.md) +* [Field Merge Semantics](pages/app_management/field_merge_semantics.md) + +## Resource Printing + +* [Summaries](pages/resource_printing/summaries.md) +* [Raw](pages/resource_printing/raw.md) +* [Fields](pages/resource_printing/fields.md) +* [Describe](pages/resource_printing/describe.md) +* [Queries and Options](pages/resource_printing/queries_and_options.md) +* [Watch](pages/resource_printing/watch.md) +* [Cluster Information](pages/resource_printing/cluster_information.md) + +## Container Debugging + +* [Container Logs](pages/container_debugging/container_logs.md) +* [Copying Container Files](pages/container_debugging/copying_container_files.md) +* [Executing a Command in a Container](pages/container_debugging/executing_a_command_in_a_container.md) +* [Port Forward to Pods](pages/container_debugging/port_forward_to_pods.md) +* [Proxying Traffic to Services](pages/container_debugging/proxying_traffic_to_services.md) + +## App Customization + +* [Introduction](pages/app_customization/introduction.md) +* [Bases and Variations](pages/app_customization/bases_and_variants.md) +* [Customizing Pod Templates](pages/app_customization/customizing_pod_templates.md) +* [Customizing Arbitrary Fields](pages/app_customization/customizing_arbitrary_fields.md) +* [Config Reflection](pages/app_customization/config_reflection.md) + +## App Structure + +* [Introduction](pages/app_composition_and_deployment/structure_introduction.md) +* [Directory Layout](pages/app_composition_and_deployment/structure_directories.md) +* [Branches Layout](pages/app_composition_and_deployment/structure_branches.md) +* [Repository Layout](pages/app_composition_and_deployment/structure_repositories.md) +* [Shared Base Layout](pages/app_composition_and_deployment/structure_multi_tier_apps.md) + +## App Deployment + +* [Diffing Local and Remote State](pages/app_composition_and_deployment/diffing_local_and_remote_resources.md) +* [Accessing Multiple Clusters](pages/app_composition_and_deployment/accessing_multiple_clusters.md) +* [Publishing Config](pages/app_composition_and_deployment/publishing_bases.md) + +## Reference + +* [kustomization.yaml](pages/reference/kustomize.md) + +## Examples + +* [kustomization.yaml](pages/examples/kustomize.md) + +## Miscellaneous Imperative Commands + +* [Introduction](pages/imperative_porcelain/introduction.md) +* [Creating Resources](pages/imperative_porcelain/creating_resources.md) +* [Setting Fields](pages/imperative_porcelain/setting_fields.md) +* [Editing Workloads](pages/imperative_porcelain/editing_workloads.md) \ No newline at end of file diff --git a/docs/book/book.json b/docs/book/book.json new file mode 100644 index 00000000..27d5806e --- /dev/null +++ b/docs/book/book.json @@ -0,0 +1,31 @@ +{ + "plugins": ["mermaid-gb3","sequence-diagrams","theme-api", "panel", "copy-code-button", "insert-logo", "ga", "custom-favicon"], + "pluginsConfig": { + "favicon": "favicon.ico", + "ga": { + "token": "UA-136142416-1" + }, + "mermaid-gb3": { + "width": "100%" + }, + "insert-logo": { + "url": "data:image/gif;base64,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" + }, + "theme-api": { + "split": false + }, + "sequence-diagrams": { + "theme": "hand" + }, + "toc": { + "addClass": true, + "className": "toc" + }, + "selector": ".markdown-section h1, .markdown-section h2, .markdown-section h3, .markdown-section h4", + "position": "before-first", + "showByDefault": true + }, + "gitbook": ">= 3.0.0", + "author": "Phillip Wittrock", + "title": "The Kubectl Book" +} diff --git a/docs/book/examples/nginx/nginx.yaml b/docs/book/examples/nginx/nginx.yaml new file mode 100644 index 00000000..49fc755f --- /dev/null +++ b/docs/book/examples/nginx/nginx.yaml @@ -0,0 +1,34 @@ +kind: Service +apiVersion: v1 +metadata: + name: nginx +spec: + selector: + app: nginx + ports: + - protocol: TCP + port: 80 + targetPort: 9376 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment + labels: + app: nginx +spec: + replicas: 3 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.7.9 + ports: + - containerPort: 80 + diff --git a/docs/book/favicon.ico b/docs/book/favicon.ico new file mode 100644 index 00000000..9eb514b6 Binary files /dev/null and b/docs/book/favicon.ico differ diff --git a/docs/book/firebase.json b/docs/book/firebase.json new file mode 100644 index 00000000..7a0acb9b --- /dev/null +++ b/docs/book/firebase.json @@ -0,0 +1,16 @@ +{ + "hosting": { + "public": "_book", + "ignore": [ + "firebase.json", + "**/.*", + "**/node_modules/**" + ], + "rewrites": [ + { + "source": "**", + "destination": "/index.html" + } + ] + } +} diff --git a/docs/book/npm-shrinkwrap.json b/docs/book/npm-shrinkwrap.json new file mode 100644 index 00000000..2832a424 --- /dev/null +++ b/docs/book/npm-shrinkwrap.json @@ -0,0 +1,6075 @@ +{ + "name": "book", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "abab": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/abab/-/abab-1.0.4.tgz", + "integrity": "sha1-X6rZwsB/YN12dw9xzwJbYqY8/U4=", + "optional": true + }, + "acorn": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-2.7.0.tgz", + "integrity": "sha1-q259nYhqrKiwhbwzEreaGYQz8Oc=" + }, + "acorn-globals": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-1.0.9.tgz", + "integrity": "sha1-VbtemGkVB7dFedBRNBMhfDgMVM8=", + "optional": true, + "requires": { + "acorn": "^2.1.0" + } + }, + "ajv": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", + "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-red": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-red/-/ansi-red-0.1.1.tgz", + "integrity": "sha1-jGOPnRCAgAo1PJwoyKgcpHBdlGw=", + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "ansi-wrap": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", + "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=" + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + }, + "async": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async/-/async-1.0.0.tgz", + "integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k=" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "autolinker": { + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/autolinker/-/autolinker-0.15.3.tgz", + "integrity": "sha1-NCQX2PLzRhsUzwkIjV7fh5HcmDI=" + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + }, + "aws4": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "bash-color": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/bash-color/-/bash-color-0.0.4.tgz", + "integrity": "sha1-6b6M4zVAytpIgXaMWb1jhlc26RM=" + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "optional": true, + "requires": { + "file-uri-to-path": "1.0.0" + } + }, + "bl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.0.3.tgz", + "integrity": "sha1-/FQhoo/UImA2w7OJGmaiW8ZNIm4=", + "requires": { + "readable-stream": "~2.0.5" + }, + "dependencies": { + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" + }, + "readable-stream": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", + "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "string_decoder": "~0.10.x", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + } + } + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" + }, + "boom": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/boom/-/boom-7.3.0.tgz", + "integrity": "sha512-Swpoyi2t5+GhOEGw8rEsKvTxFLIDiiKoUc2gsoV6Lyr43LHBIzch3k2MvYUs8RTROrIkVJ3Al0TkaOGjnb+B6A==", + "requires": { + "hoek": "6.x.x" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "cheerio": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.20.0.tgz", + "integrity": "sha1-XHEPK6uVZTJyhCugHG6mGzVF7DU=", + "requires": { + "css-select": "~1.2.0", + "dom-serializer": "~0.1.0", + "entities": "~1.1.1", + "htmlparser2": "~3.8.1", + "jsdom": "^7.0.2", + "lodash": "^4.1.0" + } + }, + "coffee-script": { + "version": "1.12.7", + "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.12.7.tgz", + "integrity": "sha512-fLeEhqwymYat/MpTPUjSKHVYYl0ec2mOyALEMLmzr5i1isuG+6jfI2j2d5oBO3VIzgUXgBVIcOT9uH1TFxBckw==" + }, + "colors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=" + }, + "combined-stream": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", + "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", + "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "cryptiles": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-4.1.3.tgz", + "integrity": "sha512-gT9nyTMSUC1JnziQpPbxKGBbUg8VL7Zn2NB4E1cJYvuXdElHrwxrV9bmltZGDzet45zSDGyYceueke1TjynGzw==", + "requires": { + "boom": "7.x.x" + } + }, + "css-select": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", + "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", + "requires": { + "boolbase": "~1.0.0", + "css-what": "2.1", + "domutils": "1.5.1", + "nth-check": "~1.0.1" + } + }, + "css-what": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", + "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==" + }, + "cssom": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.6.tgz", + "integrity": "sha512-DtUeseGk9/GBW0hl0vVPpU22iHL6YB5BUX7ml1hB+GMpo0NX5G4voX3kdWiMSEguFtcW3Vh3djqNF4aIe6ne0A==" + }, + "cssstyle": { + "version": "0.2.37", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-0.2.37.tgz", + "integrity": "sha1-VBCXI0yyUTyDzu06zdwn/yeYfVQ=", + "optional": true, + "requires": { + "cssom": "0.3.x" + } + }, + "cycle": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", + "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI=" + }, + "d3": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/d3/-/d3-3.5.17.tgz", + "integrity": "sha1-vEZ0gAQ3iyGjYMn8fPUjF5B2L7g=" + }, + "dagre-d3-renderer": { + "version": "0.4.26", + "resolved": "https://registry.npmjs.org/dagre-d3-renderer/-/dagre-d3-renderer-0.4.26.tgz", + "integrity": "sha512-vOWj1uA4/APTrfDyfHaH/xpfXhPh9rszW+HOaEwPCeA6Afl06Lobfh7OpESuVMQW2QGuY4UQ7pte/p0WhdDs7w==", + "requires": { + "d3": "3.5.17", + "dagre-layout": "^0.8.0", + "graphlib": "^2.1.1", + "lodash": "^4.17.4" + } + }, + "dagre-layout": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/dagre-layout/-/dagre-layout-0.8.8.tgz", + "integrity": "sha512-ZNV15T9za7X+fV8Z07IZquUKugCxm5owoiPPxfEx6OJRD331nkiIaF3vSt0JEY5FkrY0KfRQxcpQ3SpXB7pLPQ==", + "requires": { + "graphlibrary": "^2.2.0", + "lodash": "^4.17.5" + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "optional": true + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "dnode": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/dnode/-/dnode-1.2.2.tgz", + "integrity": "sha1-SsPP4m4pKzs5uCWK59lO3FgTLvo=", + "requires": { + "dnode-protocol": "~0.2.2", + "jsonify": "~0.0.0", + "weak": "^1.0.0" + } + }, + "dnode-protocol": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/dnode-protocol/-/dnode-protocol-0.2.2.tgz", + "integrity": "sha1-URUdFvw7X4SBXuC5SXoQYdDRlJ0=", + "requires": { + "jsonify": "~0.0.0", + "traverse": "~0.6.3" + } + }, + "dom-serializer": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", + "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", + "requires": { + "domelementtype": "^1.3.0", + "entities": "^1.1.1" + } + }, + "domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" + }, + "domhandler": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz", + "integrity": "sha1-LeWaCCLVAn+r/28DLCsloqir5zg=", + "requires": { + "domelementtype": "1" + } + }, + "domutils": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" + }, + "es6-promise": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.6.tgz", + "integrity": "sha512-aRVgGdnmW2OiySVPUC9e6m+plolMAJKjZnQlCwNSuK5yQ0JN61DZSO1X1Ufd1foqWRAlig0rhduTCHe7sVtK5Q==" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "escodegen": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.11.1.tgz", + "integrity": "sha512-JwiqFD9KdGVVpeuRa68yU3zZnBEOcPs0nKW7wZzXky8Z7tffdYUHbe11bPCV5jYlK6DVdKLWLm0f5I/QlL0Kmw==", + "optional": true, + "requires": { + "esprima": "^3.1.3", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + } + }, + "esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", + "optional": true + }, + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "optional": true + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "optional": true + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "extract-zip": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.7.tgz", + "integrity": "sha1-qEC0uK9kAyZMjbV/Txp0Mz74H+k=", + "requires": { + "concat-stream": "1.6.2", + "debug": "2.6.9", + "mkdirp": "0.5.1", + "yauzl": "2.4.1" + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + }, + "eyes": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", + "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=" + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "optional": true + }, + "faye-websocket": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.4.4.tgz", + "integrity": "sha1-wUxbO/FNdBf/v9mQwKdJXNnzN7w=" + }, + "fd-slicer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz", + "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=", + "requires": { + "pend": "~1.2.0" + } + }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "optional": true + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "fs-extra": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", + "integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=", + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "generate-function": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", + "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", + "requires": { + "is-property": "^1.0.2" + } + }, + "generate-object-property": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", + "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", + "requires": { + "is-property": "^1.0.0" + } + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "gitbook-cli": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/gitbook-cli/-/gitbook-cli-2.3.2.tgz", + "integrity": "sha512-eyGtkY7jKHhmgpfuvgAP5fZcUob/FBz4Ld0aLRdEmiTrS1RklimN9epzPp75dd4MWpGhYvSbiwxnpyLiv1wh6A==", + "requires": { + "bash-color": "0.0.4", + "commander": "2.11.0", + "fs-extra": "3.0.1", + "lodash": "4.17.4", + "npm": "5.1.0", + "npmi": "1.0.1", + "optimist": "0.6.1", + "q": "1.5.0", + "semver": "5.3.0", + "tmp": "0.0.31", + "user-home": "2.0.0" + }, + "dependencies": { + "fs-extra": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-3.0.1.tgz", + "integrity": "sha1-N5TzeMWLNC6n27sjCVEJxLO2IpE=", + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^3.0.0", + "universalify": "^0.1.0" + } + }, + "jsonfile": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-3.0.1.tgz", + "integrity": "sha1-pezG9l9T9mLEQVx2daAzHQmS7GY=", + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" + }, + "q": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.0.tgz", + "integrity": "sha1-3QG6ydBtMObyGa7LglPunr3DCPE=" + } + } + }, + "gitbook-plugin-copy-code-button": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/gitbook-plugin-copy-code-button/-/gitbook-plugin-copy-code-button-0.0.2.tgz", + "integrity": "sha1-Q0UzIAtc9ZbChMFOHYu1d3IIRHU=" + }, + "gitbook-plugin-custom-favicon": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/gitbook-plugin-custom-favicon/-/gitbook-plugin-custom-favicon-0.0.4.tgz", + "integrity": "sha1-y3NynUdYy3xsVk6O+wNdH24Irs8=" + }, + "gitbook-plugin-ga": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gitbook-plugin-ga/-/gitbook-plugin-ga-1.0.1.tgz", + "integrity": "sha1-yF17jAFkDEuz3DsjGrn+dKpuUhs=" + }, + "gitbook-plugin-insert-logo": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/gitbook-plugin-insert-logo/-/gitbook-plugin-insert-logo-0.1.5.tgz", + "integrity": "sha1-2q6N2kGiNtVPE5MeVwsmcpVXiFo=" + }, + "gitbook-plugin-mermaid": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/gitbook-plugin-mermaid/-/gitbook-plugin-mermaid-0.0.9.tgz", + "integrity": "sha1-l3EKopRojUoex1+whZGb1rpS6/k=", + "requires": { + "phantom": "^0.8.3", + "phantomjs": "~1.9.18", + "q": "1.1.2" + }, + "dependencies": { + "assert-plus": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", + "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=" + }, + "async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz", + "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", + "requires": { + "lodash": "^4.17.11" + } + }, + "aws-sign2": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", + "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=" + }, + "caseless": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz", + "integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c=" + }, + "concat-stream": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.0.tgz", + "integrity": "sha1-U/fUPFHF5D+ByP3QMyHGMb5o1hE=", + "requires": { + "inherits": "~2.0.1", + "readable-stream": "~2.0.0", + "typedarray": "~0.0.5" + } + }, + "debug": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz", + "integrity": "sha1-BuHqgILCyxTjmAbiLi9vdX+Srzk=" + }, + "extract-zip": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.5.0.tgz", + "integrity": "sha1-ksz22B73Cp+kwXRxFMzvbYaIpsQ=", + "requires": { + "concat-stream": "1.5.0", + "debug": "0.7.4", + "mkdirp": "0.5.0", + "yauzl": "2.4.1" + } + }, + "form-data": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-1.0.1.tgz", + "integrity": "sha1-rjFduaSQf6BlUCMEpm13M0de43w=", + "requires": { + "async": "^2.0.1", + "combined-stream": "^1.0.5", + "mime-types": "^2.1.11" + } + }, + "fs-extra": { + "version": "0.26.7", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.26.7.tgz", + "integrity": "sha1-muH92UiXeY7at20JGM9C0MMYT6k=", + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0", + "path-is-absolute": "^1.0.0", + "rimraf": "^2.2.8" + } + }, + "har-validator": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", + "integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=", + "requires": { + "chalk": "^1.1.1", + "commander": "^2.9.0", + "is-my-json-valid": "^2.12.4", + "pinkie-promise": "^2.0.0" + } + }, + "http-signature": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", + "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", + "requires": { + "assert-plus": "^0.2.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + }, + "mkdirp": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz", + "integrity": "sha1-HXMHam35hs2TROFecfzAWkyavxI=", + "requires": { + "minimist": "0.0.8" + } + }, + "node-uuid": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz", + "integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc=" + }, + "oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" + }, + "phantom": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/phantom/-/phantom-0.8.4.tgz", + "integrity": "sha1-zNtT2IqSN/01UZEnfFjZdwWqr/0=", + "requires": { + "dnode": ">=1.2.2", + "shoe": "~0.0.15", + "traverse": "~0.6.3", + "win-spawn": "~2.0.0" + } + }, + "phantomjs": { + "version": "1.9.20", + "resolved": "https://registry.npmjs.org/phantomjs/-/phantomjs-1.9.20.tgz", + "integrity": "sha1-RCSsog4U0lXAsIia9va4lz2hDg0=", + "requires": { + "extract-zip": "~1.5.0", + "fs-extra": "~0.26.4", + "hasha": "^2.2.0", + "kew": "~0.7.0", + "progress": "~1.1.8", + "request": "~2.67.0", + "request-progress": "~2.0.1", + "which": "~1.2.2" + } + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" + }, + "q": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/q/-/q-1.1.2.tgz", + "integrity": "sha1-Y1fikSBnAdmfGXq4TlforRlvKok=" + }, + "qs": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-5.2.1.tgz", + "integrity": "sha1-gB/uAw4LlFDWOFrcSKTMVbRK7fw=" + }, + "readable-stream": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", + "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "string_decoder": "~0.10.x", + "util-deprecate": "~1.0.1" + } + }, + "request": { + "version": "2.67.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.67.0.tgz", + "integrity": "sha1-ivdHgOK/EeoK6aqWXBHxGv0nJ0I=", + "requires": { + "aws-sign2": "~0.6.0", + "bl": "~1.0.0", + "caseless": "~0.11.0", + "combined-stream": "~1.0.5", + "extend": "~3.0.0", + "forever-agent": "~0.6.1", + "form-data": "~1.0.0-rc3", + "har-validator": "~2.0.2", + "hawk": "~3.1.0", + "http-signature": "~1.1.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.7", + "node-uuid": "~1.4.7", + "oauth-sign": "~0.8.0", + "qs": "~5.2.0", + "stringstream": "~0.0.4", + "tough-cookie": "~2.2.0", + "tunnel-agent": "~0.4.1" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + }, + "tough-cookie": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.2.tgz", + "integrity": "sha1-yDoYMPTl7wuT7yo0iOck+N4Basc=" + }, + "tunnel-agent": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", + "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=" + }, + "which": { + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", + "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=", + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "gitbook-plugin-mermaid-gb3": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/gitbook-plugin-mermaid-gb3/-/gitbook-plugin-mermaid-gb3-2.1.0.tgz", + "integrity": "sha512-xCvOWNqkrVrWcBMDGT0ANWlut4GKVzzHh834zy8Ti4Bv7kvGtqA72ykuxBRcJUS+eSVDJNkaQ5D1wF6CNZH9rw==", + "requires": { + "mermaid": "^7.0.7" + } + }, + "gitbook-plugin-page-toc": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/gitbook-plugin-page-toc/-/gitbook-plugin-page-toc-1.1.1.tgz", + "integrity": "sha512-0ii4d4gxaLsZuWvSFyz2eLQvpjB3Sjg8pTBW8P6mT0j1jw3ifS5Jx8HvQLYrOPyolktUqmd0AebrKCur667zfw==" + }, + "gitbook-plugin-panel": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/gitbook-plugin-panel/-/gitbook-plugin-panel-0.0.1.tgz", + "integrity": "sha1-y2hnL+milXMblt7nS0nK6TtCbZs=" + }, + "gitbook-plugin-search": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/gitbook-plugin-search/-/gitbook-plugin-search-2.2.1.tgz", + "integrity": "sha1-bSW1p3aZD6mP39+jfeMx944PaxM=" + }, + "gitbook-plugin-sequence-diagrams": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/gitbook-plugin-sequence-diagrams/-/gitbook-plugin-sequence-diagrams-1.1.0.tgz", + "integrity": "sha1-heZolyEgwYpiXwfugloSWjrevfo=", + "requires": { + "phantom": "^2.0.0", + "q": "^1.4.1" + } + }, + "gitbook-plugin-theme-api": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/gitbook-plugin-theme-api/-/gitbook-plugin-theme-api-1.1.2.tgz", + "integrity": "sha1-jBRaS61JoSE8AlApC5vZtyrqiPw=", + "requires": { + "cheerio": "0.20.0", + "gitbook-plugin-search": ">=2.0.0", + "lodash": "4.12.0", + "q": "1.4.1", + "q-plus": "0.0.8" + }, + "dependencies": { + "lodash": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.12.0.tgz", + "integrity": "sha1-K9bcRqBA9Z5obJcu0h2T3FkFMlg=" + }, + "q": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz", + "integrity": "sha1-VXBbzZPF82c1MMLCy8DCs63cKG4=" + } + } + }, + "gitbook-plugin-toc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/gitbook-plugin-toc/-/gitbook-plugin-toc-0.0.2.tgz", + "integrity": "sha512-ONjfdYpRIeso2UwzFK1B+OgvKvHXgLzhSlM9hTao43V4bRcqMo9EhcqX6WRuoh6pVBlYBj9QPAZMZTFFHAc7Kw==", + "requires": { + "markdown-toc": "^0.11.0" + } + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "graceful-fs": { + "version": "4.1.15", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", + "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==" + }, + "graphlib": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.7.tgz", + "integrity": "sha512-TyI9jIy2J4j0qgPmOOrHTCtpPqJGN/aurBwc6ZT+bRii+di1I+Wv3obRhVrmBEXet+qkMaEX67dXrwsd3QQM6w==", + "requires": { + "lodash": "^4.17.5" + } + }, + "graphlibrary": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/graphlibrary/-/graphlibrary-2.2.0.tgz", + "integrity": "sha512-XTcvT55L8u4MBZrM37zXoUxsgxs/7sow7YSygd9CIwfWTVO8RVu7AYXhhCiTuFEf+APKgx6Jk4SuQbYR0vYKmQ==", + "requires": { + "lodash": "^4.17.5" + } + }, + "gray-matter": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-2.1.1.tgz", + "integrity": "sha1-MELZrewqHe1qdwep7SOA+KF6Qw4=", + "requires": { + "ansi-red": "^0.1.1", + "coffee-script": "^1.12.4", + "extend-shallow": "^2.0.1", + "js-yaml": "^3.8.1", + "toml": "^2.3.2" + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + }, + "har-validator": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "requires": { + "ajv": "^6.5.5", + "har-schema": "^2.0.0" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "hasha": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-2.2.0.tgz", + "integrity": "sha1-eNfL/B5tZjA/55g3NlmEUXsvbuE=", + "requires": { + "is-stream": "^1.0.1", + "pinkie-promise": "^2.0.0" + } + }, + "hawk": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", + "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", + "requires": { + "boom": "2.x.x", + "cryptiles": "2.x.x", + "hoek": "2.x.x", + "sntp": "1.x.x" + }, + "dependencies": { + "boom": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", + "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", + "requires": { + "hoek": "2.x.x" + } + }, + "cryptiles": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", + "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", + "requires": { + "boom": "2.x.x" + } + }, + "hoek": { + "version": "2.16.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", + "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=" + } + } + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" + }, + "hoek": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-6.1.2.tgz", + "integrity": "sha512-6qhh/wahGYZHFSFw12tBbJw5fsAhhwrrG/y3Cs0YMTv2WzMnL0oLPnQJjv1QJvEfylRSOFuP+xCu+tdx0tD16Q==" + }, + "htmlparser2": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", + "integrity": "sha1-mWwosZFRaovoZQGn15dX5ccMEGg=", + "requires": { + "domelementtype": "1", + "domhandler": "2.3", + "domutils": "1.5", + "entities": "1.0", + "readable-stream": "1.1" + }, + "dependencies": { + "entities": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", + "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=" + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + } + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" + }, + "is-my-ip-valid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz", + "integrity": "sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ==" + }, + "is-my-json-valid": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.19.0.tgz", + "integrity": "sha512-mG0f/unGX1HZ5ep4uhRaPOS8EkAY8/j6mDRMJrutq4CqhoJWYp7qAlonIPy3TV7p3ju4TK9fo/PbnoksWmsp5Q==", + "requires": { + "generate-function": "^2.0.0", + "generate-object-property": "^1.1.0", + "is-my-ip-valid": "^1.0.0", + "jsonpointer": "^4.0.0", + "xtend": "^4.0.0" + } + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "requires": { + "isobject": "^3.0.1" + } + }, + "is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=" + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "js-yaml": { + "version": "3.12.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.2.tgz", + "integrity": "sha512-QHn/Lh/7HhZ/Twc7vJYQTkjuCa0kaCcDcjK5Zlk2rvnUpy7DxMJ23+Jc2dcyvltwQVg1nygAVlB2oRDFHoRS5Q==", + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "dependencies": { + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + } + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + }, + "jsdom": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-7.2.2.tgz", + "integrity": "sha1-QLQCdwwr2iNGkJa+6Rq2deOx/G4=", + "optional": true, + "requires": { + "abab": "^1.0.0", + "acorn": "^2.4.0", + "acorn-globals": "^1.0.4", + "cssom": ">= 0.3.0 < 0.4.0", + "cssstyle": ">= 0.2.29 < 0.3.0", + "escodegen": "^1.6.1", + "nwmatcher": ">= 1.3.7 < 2.0.0", + "parse5": "^1.5.1", + "request": "^2.55.0", + "sax": "^1.1.4", + "symbol-tree": ">= 3.1.0 < 4.0.0", + "tough-cookie": "^2.2.0", + "webidl-conversions": "^2.0.0", + "whatwg-url-compat": "~0.6.5", + "xml-name-validator": ">= 2.0.1 < 3.0.0" + } + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" + }, + "jsonpointer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", + "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=" + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "kew": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/kew/-/kew-0.7.0.tgz", + "integrity": "sha1-edk9LTM2PW/dKXCzNdkUGtWR15s=" + }, + "klaw": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", + "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", + "requires": { + "graceful-fs": "^4.1.9" + } + }, + "lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=" + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "optional": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "linerstream": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/linerstream/-/linerstream-0.1.4.tgz", + "integrity": "sha1-Xee/afqisPnYXoMyCZtw5BmoRdU=" + }, + "lodash": { + "version": "4.17.5", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz", + "integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==" + }, + "markdown-link": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/markdown-link/-/markdown-link-0.1.1.tgz", + "integrity": "sha1-MsXGUZmmRXMWMi0eQinRNAfIx88=" + }, + "markdown-toc": { + "version": "0.11.9", + "resolved": "https://registry.npmjs.org/markdown-toc/-/markdown-toc-0.11.9.tgz", + "integrity": "sha1-lh80wbLDHSghiO7v1PkHyMB6bUw=", + "requires": { + "concat-stream": "^1.5.1", + "gray-matter": "^2.0.2", + "lazy-cache": "^1.0.2", + "markdown-link": "^0.1.1", + "minimist": "^1.2.0", + "mixin-deep": "^1.1.3", + "object.pick": "^1.1.1", + "remarkable": "^1.6.1", + "repeat-string": "^1.5.2" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + } + } + }, + "mermaid": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-7.1.2.tgz", + "integrity": "sha512-bDLu3fQuf3/R0fNkNzB0GTaF7+6SxnZpfTs9DVQF1ougsuP23MBzvEIGfL0ML8zeyg7+J2D+0AaoLVhskW5ulw==", + "requires": { + "d3": "3.5.17", + "dagre-d3-renderer": "^0.4.25", + "dagre-layout": "^0.8.0", + "he": "^1.1.1", + "lodash": "^4.17.4", + "moment": "^2.20.1" + } + }, + "mime-db": { + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.38.0.tgz", + "integrity": "sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg==" + }, + "mime-types": { + "version": "2.1.22", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.22.tgz", + "integrity": "sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog==", + "requires": { + "mime-db": "~1.38.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=" + }, + "mixin-deep": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", + "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + } + } + }, + "moment": { + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", + "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "nan": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.13.1.tgz", + "integrity": "sha512-I6YB/YEuDeUZMmhscXKxGgZlFnhsn5y0hgOZBadkzfTRrZBtJDZeg6eQf7PYMIEclwmorTKK8GztsyOUSVBREA==", + "optional": true + }, + "node-uuid": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.3.3.tgz", + "integrity": "sha1-09tNe1aBDZ5AMjQnZigq8HORcps=" + }, + "npm": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm/-/npm-5.1.0.tgz", + "integrity": "sha512-pt5ClxEmY/dLpb60SmGQQBKi3nB6Ljx1FXmpoCUdAULlGqGVn2uCyXxPCWFbcuHGthT7qGiaGa1wOfs/UjGYMw==", + "requires": { + "JSONStream": "~1.3.1", + "abbrev": "~1.1.0", + "ansi-regex": "~3.0.0", + "ansicolors": "~0.3.2", + "ansistyles": "~0.1.3", + "aproba": "~1.1.2", + "archy": "~1.0.0", + "bluebird": "~3.5.0", + "cacache": "~9.2.9", + "call-limit": "~1.1.0", + "chownr": "~1.0.1", + "cmd-shim": "~2.0.2", + "columnify": "~1.5.4", + "config-chain": "~1.1.11", + "debuglog": "*", + "detect-indent": "~5.0.0", + "dezalgo": "~1.0.3", + "editor": "~1.0.0", + "fs-vacuum": "~1.2.10", + "fs-write-stream-atomic": "~1.0.10", + "fstream": "~1.0.11", + "fstream-npm": "~1.2.1", + "glob": "~7.1.2", + "graceful-fs": "~4.1.11", + "has-unicode": "~2.0.1", + "hosted-git-info": "~2.5.0", + "iferr": "~0.1.5", + "imurmurhash": "*", + "inflight": "~1.0.6", + "inherits": "~2.0.3", + "ini": "~1.3.4", + "init-package-json": "~1.10.1", + "lazy-property": "~1.0.0", + "lockfile": "~1.0.3", + "lodash._baseindexof": "*", + "lodash._baseuniq": "~4.6.0", + "lodash._bindcallback": "*", + "lodash._cacheindexof": "*", + "lodash._createcache": "*", + "lodash._getnative": "*", + "lodash.clonedeep": "~4.5.0", + "lodash.restparam": "*", + "lodash.union": "~4.6.0", + "lodash.uniq": "~4.5.0", + "lodash.without": "~4.4.0", + "lru-cache": "~4.1.1", + "mississippi": "~1.3.0", + "mkdirp": "~0.5.1", + "move-concurrently": "~1.0.1", + "node-gyp": "~3.6.2", + "nopt": "~4.0.1", + "normalize-package-data": "~2.4.0", + "npm-cache-filename": "~1.0.2", + "npm-install-checks": "~3.0.0", + "npm-package-arg": "~5.1.2", + "npm-registry-client": "~8.4.0", + "npm-user-validate": "~1.0.0", + "npmlog": "~4.1.2", + "once": "~1.4.0", + "opener": "~1.4.3", + "osenv": "~0.1.4", + "pacote": "~2.7.38", + "path-is-inside": "~1.0.2", + "promise-inflight": "~1.0.1", + "read": "~1.0.7", + "read-cmd-shim": "~1.0.1", + "read-installed": "~4.0.3", + "read-package-json": "~2.0.9", + "read-package-tree": "~5.1.6", + "readable-stream": "~2.3.2", + "readdir-scoped-modules": "*", + "request": "~2.81.0", + "retry": "~0.10.1", + "rimraf": "~2.6.1", + "safe-buffer": "~5.1.1", + "semver": "~5.3.0", + "sha": "~2.0.1", + "slide": "~1.1.6", + "sorted-object": "~2.0.1", + "sorted-union-stream": "~2.1.3", + "ssri": "~4.1.6", + "strip-ansi": "~4.0.0", + "tar": "~2.2.1", + "text-table": "~0.2.0", + "uid-number": "0.0.6", + "umask": "~1.1.0", + "unique-filename": "~1.1.0", + "unpipe": "~1.0.0", + "update-notifier": "~2.2.0", + "uuid": "~3.1.0", + "validate-npm-package-license": "*", + "validate-npm-package-name": "~3.0.0", + "which": "~1.2.14", + "worker-farm": "~1.3.1", + "wrappy": "~1.0.2", + "write-file-atomic": "~2.1.0" + }, + "dependencies": { + "JSONStream": { + "version": "1.3.1", + "bundled": true, + "requires": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + }, + "dependencies": { + "jsonparse": { + "version": "1.3.1", + "bundled": true + }, + "through": { + "version": "2.3.8", + "bundled": true + } + } + }, + "abbrev": { + "version": "1.1.0", + "bundled": true + }, + "ansi-regex": { + "version": "3.0.0", + "bundled": true + }, + "ansicolors": { + "version": "0.3.2", + "bundled": true + }, + "ansistyles": { + "version": "0.1.3", + "bundled": true + }, + "aproba": { + "version": "1.1.2", + "bundled": true + }, + "archy": { + "version": "1.0.0", + "bundled": true + }, + "bluebird": { + "version": "3.5.0", + "bundled": true + }, + "cacache": { + "version": "9.2.9", + "bundled": true, + "requires": { + "bluebird": "^3.5.0", + "chownr": "^1.0.1", + "glob": "^7.1.2", + "graceful-fs": "^4.1.11", + "lru-cache": "^4.1.1", + "mississippi": "^1.3.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.1", + "ssri": "^4.1.6", + "unique-filename": "^1.1.0", + "y18n": "^3.2.1" + }, + "dependencies": { + "lru-cache": { + "version": "4.1.1", + "bundled": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + }, + "dependencies": { + "pseudomap": { + "version": "1.0.2", + "bundled": true + }, + "yallist": { + "version": "2.1.2", + "bundled": true + } + } + }, + "y18n": { + "version": "3.2.1", + "bundled": true + } + } + }, + "call-limit": { + "version": "1.1.0", + "bundled": true + }, + "chownr": { + "version": "1.0.1", + "bundled": true + }, + "cmd-shim": { + "version": "2.0.2", + "bundled": true, + "requires": { + "graceful-fs": "^4.1.2", + "mkdirp": "~0.5.0" + } + }, + "columnify": { + "version": "1.5.4", + "bundled": true, + "requires": { + "strip-ansi": "^3.0.0", + "wcwidth": "^1.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "requires": { + "ansi-regex": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "bundled": true + } + } + }, + "wcwidth": { + "version": "1.0.1", + "bundled": true, + "requires": { + "defaults": "^1.0.3" + }, + "dependencies": { + "defaults": { + "version": "1.0.3", + "bundled": true, + "requires": { + "clone": "^1.0.2" + }, + "dependencies": { + "clone": { + "version": "1.0.2", + "bundled": true + } + } + } + } + } + } + }, + "config-chain": { + "version": "1.1.11", + "bundled": true, + "requires": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + }, + "dependencies": { + "proto-list": { + "version": "1.2.4", + "bundled": true + } + } + }, + "debuglog": { + "version": "1.0.1", + "bundled": true + }, + "detect-indent": { + "version": "5.0.0", + "bundled": true + }, + "dezalgo": { + "version": "1.0.3", + "bundled": true, + "requires": { + "asap": "^2.0.0", + "wrappy": "1" + }, + "dependencies": { + "asap": { + "version": "2.0.5", + "bundled": true + } + } + }, + "editor": { + "version": "1.0.0", + "bundled": true + }, + "fs-vacuum": { + "version": "1.2.10", + "bundled": true, + "requires": { + "graceful-fs": "^4.1.2", + "path-is-inside": "^1.0.1", + "rimraf": "^2.5.2" + } + }, + "fs-write-stream-atomic": { + "version": "1.0.10", + "bundled": true, + "requires": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + } + }, + "fstream": { + "version": "1.0.11", + "bundled": true, + "requires": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + } + }, + "fstream-npm": { + "version": "1.2.1", + "bundled": true, + "requires": { + "fstream-ignore": "^1.0.0", + "inherits": "2" + }, + "dependencies": { + "fstream-ignore": { + "version": "1.0.5", + "bundled": true, + "requires": { + "fstream": "^1.0.0", + "inherits": "2", + "minimatch": "^3.0.0" + }, + "dependencies": { + "minimatch": { + "version": "3.0.4", + "bundled": true, + "requires": { + "brace-expansion": "^1.1.7" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.8", + "bundled": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + }, + "dependencies": { + "balanced-match": { + "version": "1.0.0", + "bundled": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true + } + } + } + } + } + } + } + } + }, + "glob": { + "version": "7.1.2", + "bundled": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "dependencies": { + "fs.realpath": { + "version": "1.0.0", + "bundled": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "requires": { + "brace-expansion": "^1.1.7" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.8", + "bundled": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + }, + "dependencies": { + "balanced-match": { + "version": "1.0.0", + "bundled": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true + } + } + } + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true + } + } + }, + "graceful-fs": { + "version": "4.1.11", + "bundled": true + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true + }, + "hosted-git-info": { + "version": "2.5.0", + "bundled": true + }, + "iferr": { + "version": "0.1.5", + "bundled": true + }, + "imurmurhash": { + "version": "0.1.4", + "bundled": true + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true + }, + "ini": { + "version": "1.3.4", + "bundled": true + }, + "init-package-json": { + "version": "1.10.1", + "bundled": true, + "requires": { + "glob": "^7.1.1", + "npm-package-arg": "^4.0.0 || ^5.0.0", + "promzard": "^0.3.0", + "read": "~1.0.1", + "read-package-json": "1 || 2", + "semver": "2.x || 3.x || 4 || 5", + "validate-npm-package-license": "^3.0.1", + "validate-npm-package-name": "^3.0.0" + }, + "dependencies": { + "promzard": { + "version": "0.3.0", + "bundled": true, + "requires": { + "read": "1" + } + } + } + }, + "lazy-property": { + "version": "1.0.0", + "bundled": true + }, + "lockfile": { + "version": "1.0.3", + "bundled": true + }, + "lodash._baseindexof": { + "version": "3.1.0", + "bundled": true + }, + "lodash._baseuniq": { + "version": "4.6.0", + "bundled": true, + "requires": { + "lodash._createset": "~4.0.0", + "lodash._root": "~3.0.0" + }, + "dependencies": { + "lodash._createset": { + "version": "4.0.3", + "bundled": true + }, + "lodash._root": { + "version": "3.0.1", + "bundled": true + } + } + }, + "lodash._bindcallback": { + "version": "3.0.1", + "bundled": true + }, + "lodash._cacheindexof": { + "version": "3.0.2", + "bundled": true + }, + "lodash._createcache": { + "version": "3.1.2", + "bundled": true, + "requires": { + "lodash._getnative": "^3.0.0" + } + }, + "lodash._getnative": { + "version": "3.9.1", + "bundled": true + }, + "lodash.clonedeep": { + "version": "4.5.0", + "bundled": true + }, + "lodash.restparam": { + "version": "3.6.1", + "bundled": true + }, + "lodash.union": { + "version": "4.6.0", + "bundled": true + }, + "lodash.uniq": { + "version": "4.5.0", + "bundled": true + }, + "lodash.without": { + "version": "4.4.0", + "bundled": true + }, + "lru-cache": { + "version": "4.1.1", + "bundled": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + }, + "dependencies": { + "pseudomap": { + "version": "1.0.2", + "bundled": true + }, + "yallist": { + "version": "2.1.2", + "bundled": true + } + } + }, + "mississippi": { + "version": "1.3.0", + "bundled": true, + "requires": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^1.0.0", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + }, + "dependencies": { + "concat-stream": { + "version": "1.6.0", + "bundled": true, + "requires": { + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + }, + "dependencies": { + "typedarray": { + "version": "0.0.6", + "bundled": true + } + } + }, + "duplexify": { + "version": "3.5.0", + "bundled": true, + "requires": { + "end-of-stream": "1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + }, + "dependencies": { + "end-of-stream": { + "version": "1.0.0", + "bundled": true, + "requires": { + "once": "~1.3.0" + }, + "dependencies": { + "once": { + "version": "1.3.3", + "bundled": true, + "requires": { + "wrappy": "1" + } + } + } + }, + "stream-shift": { + "version": "1.0.0", + "bundled": true + } + } + }, + "end-of-stream": { + "version": "1.4.0", + "bundled": true, + "requires": { + "once": "^1.4.0" + } + }, + "flush-write-stream": { + "version": "1.0.2", + "bundled": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.4" + } + }, + "from2": { + "version": "2.3.0", + "bundled": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "parallel-transform": { + "version": "1.1.0", + "bundled": true, + "requires": { + "cyclist": "~0.2.2", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + }, + "dependencies": { + "cyclist": { + "version": "0.2.2", + "bundled": true + } + } + }, + "pump": { + "version": "1.0.2", + "bundled": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.3.5", + "bundled": true, + "requires": { + "duplexify": "^3.1.2", + "inherits": "^2.0.1", + "pump": "^1.0.0" + } + }, + "stream-each": { + "version": "1.2.0", + "bundled": true, + "requires": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + }, + "dependencies": { + "stream-shift": { + "version": "1.0.0", + "bundled": true + } + } + }, + "through2": { + "version": "2.0.3", + "bundled": true, + "requires": { + "readable-stream": "^2.1.5", + "xtend": "~4.0.1" + }, + "dependencies": { + "xtend": { + "version": "4.0.1", + "bundled": true + } + } + } + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "bundled": true + } + } + }, + "move-concurrently": { + "version": "1.0.1", + "bundled": true, + "requires": { + "aproba": "^1.1.1", + "copy-concurrently": "^1.0.0", + "fs-write-stream-atomic": "^1.0.8", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.3" + }, + "dependencies": { + "copy-concurrently": { + "version": "1.0.3", + "bundled": true, + "requires": { + "aproba": "^1.1.1", + "fs-write-stream-atomic": "^1.0.8", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.0" + } + }, + "run-queue": { + "version": "1.0.3", + "bundled": true, + "requires": { + "aproba": "^1.1.1" + } + } + } + }, + "node-gyp": { + "version": "3.6.2", + "bundled": true, + "requires": { + "fstream": "^1.0.0", + "glob": "^7.0.3", + "graceful-fs": "^4.1.2", + "minimatch": "^3.0.2", + "mkdirp": "^0.5.0", + "nopt": "2 || 3", + "npmlog": "0 || 1 || 2 || 3 || 4", + "osenv": "0", + "request": "2", + "rimraf": "2", + "semver": "~5.3.0", + "tar": "^2.0.0", + "which": "1" + }, + "dependencies": { + "minimatch": { + "version": "3.0.4", + "bundled": true, + "requires": { + "brace-expansion": "^1.1.7" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.8", + "bundled": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + }, + "dependencies": { + "balanced-match": { + "version": "1.0.0", + "bundled": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true + } + } + } + } + }, + "nopt": { + "version": "3.0.6", + "bundled": true, + "requires": { + "abbrev": "1" + } + } + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "normalize-package-data": { + "version": "2.4.0", + "bundled": true, + "requires": { + "hosted-git-info": "^2.1.4", + "is-builtin-module": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "is-builtin-module": { + "version": "1.0.0", + "bundled": true, + "requires": { + "builtin-modules": "^1.0.0" + }, + "dependencies": { + "builtin-modules": { + "version": "1.1.1", + "bundled": true + } + } + } + } + }, + "npm-cache-filename": { + "version": "1.0.2", + "bundled": true + }, + "npm-install-checks": { + "version": "3.0.0", + "bundled": true, + "requires": { + "semver": "^2.3.0 || 3.x || 4 || 5" + } + }, + "npm-package-arg": { + "version": "5.1.2", + "bundled": true, + "requires": { + "hosted-git-info": "^2.4.2", + "osenv": "^0.1.4", + "semver": "^5.1.0", + "validate-npm-package-name": "^3.0.0" + } + }, + "npm-registry-client": { + "version": "8.4.0", + "bundled": true, + "requires": { + "concat-stream": "^1.5.2", + "graceful-fs": "^4.1.6", + "normalize-package-data": "~1.0.1 || ^2.0.0", + "npm-package-arg": "^3.0.0 || ^4.0.0 || ^5.0.0", + "npmlog": "2 || ^3.1.0 || ^4.0.0", + "once": "^1.3.3", + "request": "^2.74.0", + "retry": "^0.10.0", + "semver": "2 >=2.2.1 || 3.x || 4 || 5", + "slide": "^1.1.3", + "ssri": "^4.1.2" + }, + "dependencies": { + "concat-stream": { + "version": "1.6.0", + "bundled": true, + "requires": { + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + }, + "dependencies": { + "typedarray": { + "version": "0.0.6", + "bundled": true + } + } + } + } + }, + "npm-user-validate": { + "version": "1.0.0", + "bundled": true + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + }, + "dependencies": { + "are-we-there-yet": { + "version": "1.1.4", + "bundled": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + }, + "dependencies": { + "delegates": { + "version": "1.0.0", + "bundled": true + } + } + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + }, + "dependencies": { + "object-assign": { + "version": "4.1.1", + "bundled": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "dependencies": { + "code-point-at": { + "version": "1.1.0", + "bundled": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "requires": { + "number-is-nan": "^1.0.0" + }, + "dependencies": { + "number-is-nan": { + "version": "1.0.1", + "bundled": true + } + } + } + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "requires": { + "ansi-regex": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "bundled": true + } + } + }, + "wide-align": { + "version": "1.1.2", + "bundled": true, + "requires": { + "string-width": "^1.0.2" + } + } + } + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true + } + } + }, + "once": { + "version": "1.4.0", + "bundled": true, + "requires": { + "wrappy": "1" + } + }, + "opener": { + "version": "1.4.3", + "bundled": true + }, + "osenv": { + "version": "0.1.4", + "bundled": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + }, + "dependencies": { + "os-homedir": { + "version": "1.0.2", + "bundled": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true + } + } + }, + "pacote": { + "version": "2.7.38", + "bundled": true, + "requires": { + "bluebird": "^3.5.0", + "cacache": "^9.2.9", + "glob": "^7.1.2", + "lru-cache": "^4.1.1", + "make-fetch-happen": "^2.4.13", + "minimatch": "^3.0.4", + "mississippi": "^1.2.0", + "normalize-package-data": "^2.4.0", + "npm-package-arg": "^5.1.2", + "npm-pick-manifest": "^1.0.4", + "osenv": "^0.1.4", + "promise-inflight": "^1.0.1", + "promise-retry": "^1.1.1", + "protoduck": "^4.0.0", + "safe-buffer": "^5.1.1", + "semver": "^5.3.0", + "ssri": "^4.1.6", + "tar-fs": "^1.15.3", + "tar-stream": "^1.5.4", + "unique-filename": "^1.1.0", + "which": "^1.2.12" + }, + "dependencies": { + "make-fetch-happen": { + "version": "2.4.13", + "bundled": true, + "requires": { + "agentkeepalive": "^3.3.0", + "cacache": "^9.2.9", + "http-cache-semantics": "^3.7.3", + "http-proxy-agent": "^2.0.0", + "https-proxy-agent": "^2.0.0", + "lru-cache": "^4.1.1", + "mississippi": "^1.2.0", + "node-fetch-npm": "^2.0.1", + "promise-retry": "^1.1.1", + "socks-proxy-agent": "^3.0.0", + "ssri": "^4.1.6" + }, + "dependencies": { + "agentkeepalive": { + "version": "3.3.0", + "bundled": true, + "requires": { + "humanize-ms": "^1.2.1" + }, + "dependencies": { + "humanize-ms": { + "version": "1.2.1", + "bundled": true, + "requires": { + "ms": "^2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "bundled": true + } + } + } + } + }, + "http-cache-semantics": { + "version": "3.7.3", + "bundled": true + }, + "http-proxy-agent": { + "version": "2.0.0", + "bundled": true, + "requires": { + "agent-base": "4", + "debug": "2" + }, + "dependencies": { + "agent-base": { + "version": "4.1.0", + "bundled": true, + "requires": { + "es6-promisify": "^5.0.0" + }, + "dependencies": { + "es6-promisify": { + "version": "5.0.0", + "bundled": true, + "requires": { + "es6-promise": "^4.0.3" + }, + "dependencies": { + "es6-promise": { + "version": "4.1.1", + "bundled": true + } + } + } + } + }, + "debug": { + "version": "2.6.8", + "bundled": true, + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "bundled": true + } + } + } + } + }, + "https-proxy-agent": { + "version": "2.0.0", + "bundled": true, + "requires": { + "agent-base": "^4.1.0", + "debug": "^2.4.1" + }, + "dependencies": { + "agent-base": { + "version": "4.1.0", + "bundled": true, + "requires": { + "es6-promisify": "^5.0.0" + }, + "dependencies": { + "es6-promisify": { + "version": "5.0.0", + "bundled": true, + "requires": { + "es6-promise": "^4.0.3" + }, + "dependencies": { + "es6-promise": { + "version": "4.1.1", + "bundled": true + } + } + } + } + }, + "debug": { + "version": "2.6.8", + "bundled": true, + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "bundled": true + } + } + } + } + }, + "node-fetch-npm": { + "version": "2.0.1", + "bundled": true, + "requires": { + "encoding": "^0.1.11", + "json-parse-helpfulerror": "^1.0.3", + "safe-buffer": "^5.0.1" + }, + "dependencies": { + "encoding": { + "version": "0.1.12", + "bundled": true, + "requires": { + "iconv-lite": "~0.4.13" + }, + "dependencies": { + "iconv-lite": { + "version": "0.4.18", + "bundled": true + } + } + }, + "json-parse-helpfulerror": { + "version": "1.0.3", + "bundled": true, + "requires": { + "jju": "^1.1.0" + }, + "dependencies": { + "jju": { + "version": "1.3.0", + "bundled": true + } + } + } + } + }, + "socks-proxy-agent": { + "version": "3.0.0", + "bundled": true, + "requires": { + "agent-base": "^4.0.1", + "socks": "^1.1.10" + }, + "dependencies": { + "agent-base": { + "version": "4.1.0", + "bundled": true, + "requires": { + "es6-promisify": "^5.0.0" + }, + "dependencies": { + "es6-promisify": { + "version": "5.0.0", + "bundled": true, + "requires": { + "es6-promise": "^4.0.3" + }, + "dependencies": { + "es6-promise": { + "version": "4.1.1", + "bundled": true + } + } + } + } + }, + "socks": { + "version": "1.1.10", + "bundled": true, + "requires": { + "ip": "^1.1.4", + "smart-buffer": "^1.0.13" + }, + "dependencies": { + "ip": { + "version": "1.1.5", + "bundled": true + }, + "smart-buffer": { + "version": "1.1.15", + "bundled": true + } + } + } + } + } + } + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "requires": { + "brace-expansion": "^1.1.7" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.8", + "bundled": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + }, + "dependencies": { + "balanced-match": { + "version": "1.0.0", + "bundled": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true + } + } + } + } + }, + "npm-pick-manifest": { + "version": "1.0.4", + "bundled": true, + "requires": { + "npm-package-arg": "^5.1.2", + "semver": "^5.3.0" + } + }, + "promise-retry": { + "version": "1.1.1", + "bundled": true, + "requires": { + "err-code": "^1.0.0", + "retry": "^0.10.0" + }, + "dependencies": { + "err-code": { + "version": "1.1.2", + "bundled": true + } + } + }, + "protoduck": { + "version": "4.0.0", + "bundled": true, + "requires": { + "genfun": "^4.0.1" + }, + "dependencies": { + "genfun": { + "version": "4.0.1", + "bundled": true + } + } + }, + "tar-fs": { + "version": "1.15.3", + "bundled": true, + "requires": { + "chownr": "^1.0.1", + "mkdirp": "^0.5.1", + "pump": "^1.0.0", + "tar-stream": "^1.1.2" + }, + "dependencies": { + "pump": { + "version": "1.0.2", + "bundled": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + }, + "dependencies": { + "end-of-stream": { + "version": "1.4.0", + "bundled": true, + "requires": { + "once": "^1.4.0" + } + } + } + } + } + }, + "tar-stream": { + "version": "1.5.4", + "bundled": true, + "requires": { + "bl": "^1.0.0", + "end-of-stream": "^1.0.0", + "readable-stream": "^2.0.0", + "xtend": "^4.0.0" + }, + "dependencies": { + "bl": { + "version": "1.2.1", + "bundled": true, + "requires": { + "readable-stream": "^2.0.5" + } + }, + "end-of-stream": { + "version": "1.4.0", + "bundled": true, + "requires": { + "once": "^1.4.0" + } + }, + "xtend": { + "version": "4.0.1", + "bundled": true + } + } + } + } + }, + "path-is-inside": { + "version": "1.0.2", + "bundled": true + }, + "promise-inflight": { + "version": "1.0.1", + "bundled": true + }, + "read": { + "version": "1.0.7", + "bundled": true, + "requires": { + "mute-stream": "~0.0.4" + }, + "dependencies": { + "mute-stream": { + "version": "0.0.7", + "bundled": true + } + } + }, + "read-cmd-shim": { + "version": "1.0.1", + "bundled": true, + "requires": { + "graceful-fs": "^4.1.2" + } + }, + "read-installed": { + "version": "4.0.3", + "bundled": true, + "requires": { + "debuglog": "^1.0.1", + "graceful-fs": "^4.1.2", + "read-package-json": "^2.0.0", + "readdir-scoped-modules": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "slide": "~1.1.3", + "util-extend": "^1.0.1" + }, + "dependencies": { + "util-extend": { + "version": "1.0.3", + "bundled": true + } + } + }, + "read-package-json": { + "version": "2.0.9", + "bundled": true, + "requires": { + "glob": "^7.1.1", + "graceful-fs": "^4.1.2", + "json-parse-helpfulerror": "^1.0.2", + "normalize-package-data": "^2.0.0" + }, + "dependencies": { + "json-parse-helpfulerror": { + "version": "1.0.3", + "bundled": true, + "requires": { + "jju": "^1.1.0" + }, + "dependencies": { + "jju": { + "version": "1.3.0", + "bundled": true + } + } + } + } + }, + "read-package-tree": { + "version": "5.1.6", + "bundled": true, + "requires": { + "debuglog": "^1.0.1", + "dezalgo": "^1.0.0", + "once": "^1.3.0", + "read-package-json": "^2.0.0", + "readdir-scoped-modules": "^1.0.0" + } + }, + "readable-stream": { + "version": "2.3.2", + "bundled": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "safe-buffer": "~5.1.0", + "string_decoder": "~1.0.0", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "core-util-is": { + "version": "1.0.2", + "bundled": true + }, + "isarray": { + "version": "1.0.0", + "bundled": true + }, + "process-nextick-args": { + "version": "1.0.7", + "bundled": true + }, + "string_decoder": { + "version": "1.0.3", + "bundled": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true + } + } + }, + "readdir-scoped-modules": { + "version": "1.0.2", + "bundled": true, + "requires": { + "debuglog": "^1.0.1", + "dezalgo": "^1.0.0", + "graceful-fs": "^4.1.2", + "once": "^1.3.0" + } + }, + "request": { + "version": "2.81.0", + "bundled": true, + "requires": { + "aws-sign2": "~0.6.0", + "aws4": "^1.2.1", + "caseless": "~0.12.0", + "combined-stream": "~1.0.5", + "extend": "~3.0.0", + "forever-agent": "~0.6.1", + "form-data": "~2.1.1", + "har-validator": "~4.2.1", + "hawk": "~3.1.3", + "http-signature": "~1.1.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.7", + "oauth-sign": "~0.8.1", + "performance-now": "^0.2.0", + "qs": "~6.4.0", + "safe-buffer": "^5.0.1", + "stringstream": "~0.0.4", + "tough-cookie": "~2.3.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.0.0" + }, + "dependencies": { + "aws-sign2": { + "version": "0.6.0", + "bundled": true + }, + "aws4": { + "version": "1.6.0", + "bundled": true + }, + "caseless": { + "version": "0.12.0", + "bundled": true + }, + "combined-stream": { + "version": "1.0.5", + "bundled": true, + "requires": { + "delayed-stream": "~1.0.0" + }, + "dependencies": { + "delayed-stream": { + "version": "1.0.0", + "bundled": true + } + } + }, + "extend": { + "version": "3.0.1", + "bundled": true + }, + "forever-agent": { + "version": "0.6.1", + "bundled": true + }, + "form-data": { + "version": "2.1.4", + "bundled": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.5", + "mime-types": "^2.1.12" + }, + "dependencies": { + "asynckit": { + "version": "0.4.0", + "bundled": true + } + } + }, + "har-validator": { + "version": "4.2.1", + "bundled": true, + "requires": { + "ajv": "^4.9.1", + "har-schema": "^1.0.5" + }, + "dependencies": { + "ajv": { + "version": "4.11.8", + "bundled": true, + "requires": { + "co": "^4.6.0", + "json-stable-stringify": "^1.0.1" + }, + "dependencies": { + "co": { + "version": "4.6.0", + "bundled": true + }, + "json-stable-stringify": { + "version": "1.0.1", + "bundled": true, + "requires": { + "jsonify": "~0.0.0" + }, + "dependencies": { + "jsonify": { + "version": "0.0.0", + "bundled": true + } + } + } + } + }, + "har-schema": { + "version": "1.0.5", + "bundled": true + } + } + }, + "hawk": { + "version": "3.1.3", + "bundled": true, + "requires": { + "boom": "2.x.x", + "cryptiles": "2.x.x", + "hoek": "2.x.x", + "sntp": "1.x.x" + }, + "dependencies": { + "boom": { + "version": "2.10.1", + "bundled": true, + "requires": { + "hoek": "2.x.x" + } + }, + "cryptiles": { + "version": "2.0.5", + "bundled": true, + "requires": { + "boom": "2.x.x" + } + }, + "hoek": { + "version": "2.16.3", + "bundled": true + }, + "sntp": { + "version": "1.0.9", + "bundled": true, + "requires": { + "hoek": "2.x.x" + } + } + } + }, + "http-signature": { + "version": "1.1.1", + "bundled": true, + "requires": { + "assert-plus": "^0.2.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "dependencies": { + "assert-plus": { + "version": "0.2.0", + "bundled": true + }, + "jsprim": { + "version": "1.4.0", + "bundled": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.0.2", + "json-schema": "0.2.3", + "verror": "1.3.6" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true + }, + "extsprintf": { + "version": "1.0.2", + "bundled": true + }, + "json-schema": { + "version": "0.2.3", + "bundled": true + }, + "verror": { + "version": "1.3.6", + "bundled": true, + "requires": { + "extsprintf": "1.0.2" + } + } + } + }, + "sshpk": { + "version": "1.13.1", + "bundled": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "tweetnacl": "~0.14.0" + }, + "dependencies": { + "asn1": { + "version": "0.2.3", + "bundled": true + }, + "assert-plus": { + "version": "1.0.0", + "bundled": true + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "bundled": true, + "optional": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "dashdash": { + "version": "1.14.1", + "bundled": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "ecc-jsbn": { + "version": "0.1.1", + "bundled": true, + "optional": true, + "requires": { + "jsbn": "~0.1.0" + } + }, + "getpass": { + "version": "0.1.7", + "bundled": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "jsbn": { + "version": "0.1.1", + "bundled": true, + "optional": true + }, + "tweetnacl": { + "version": "0.14.5", + "bundled": true, + "optional": true + } + } + } + } + }, + "is-typedarray": { + "version": "1.0.0", + "bundled": true + }, + "isstream": { + "version": "0.1.2", + "bundled": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "bundled": true + }, + "mime-types": { + "version": "2.1.15", + "bundled": true, + "requires": { + "mime-db": "~1.27.0" + }, + "dependencies": { + "mime-db": { + "version": "1.27.0", + "bundled": true + } + } + }, + "oauth-sign": { + "version": "0.8.2", + "bundled": true + }, + "performance-now": { + "version": "0.2.0", + "bundled": true + }, + "qs": { + "version": "6.4.0", + "bundled": true + }, + "stringstream": { + "version": "0.0.5", + "bundled": true + }, + "tough-cookie": { + "version": "2.3.2", + "bundled": true, + "requires": { + "punycode": "^1.4.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "bundled": true + } + } + }, + "tunnel-agent": { + "version": "0.6.0", + "bundled": true, + "requires": { + "safe-buffer": "^5.0.1" + } + } + } + }, + "retry": { + "version": "0.10.1", + "bundled": true + }, + "rimraf": { + "version": "2.6.1", + "bundled": true, + "requires": { + "glob": "^7.0.5" + } + }, + "safe-buffer": { + "version": "5.1.1", + "bundled": true + }, + "semver": { + "version": "5.3.0", + "bundled": true + }, + "sha": { + "version": "2.0.1", + "bundled": true, + "requires": { + "graceful-fs": "^4.1.2", + "readable-stream": "^2.0.2" + } + }, + "slide": { + "version": "1.1.6", + "bundled": true + }, + "sorted-object": { + "version": "2.0.1", + "bundled": true + }, + "sorted-union-stream": { + "version": "2.1.3", + "bundled": true, + "requires": { + "from2": "^1.3.0", + "stream-iterate": "^1.1.0" + }, + "dependencies": { + "from2": { + "version": "1.3.0", + "bundled": true, + "requires": { + "inherits": "~2.0.1", + "readable-stream": "~1.1.10" + }, + "dependencies": { + "readable-stream": { + "version": "1.1.14", + "bundled": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + }, + "dependencies": { + "core-util-is": { + "version": "1.0.2", + "bundled": true + }, + "isarray": { + "version": "0.0.1", + "bundled": true + }, + "string_decoder": { + "version": "0.10.31", + "bundled": true + } + } + } + } + }, + "stream-iterate": { + "version": "1.2.0", + "bundled": true, + "requires": { + "readable-stream": "^2.1.5", + "stream-shift": "^1.0.0" + }, + "dependencies": { + "stream-shift": { + "version": "1.0.0", + "bundled": true + } + } + } + } + }, + "ssri": { + "version": "4.1.6", + "bundled": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "bundled": true, + "requires": { + "ansi-regex": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "bundled": true + } + } + }, + "tar": { + "version": "2.2.1", + "bundled": true, + "requires": { + "block-stream": "*", + "fstream": "^1.0.2", + "inherits": "2" + }, + "dependencies": { + "block-stream": { + "version": "0.0.9", + "bundled": true, + "requires": { + "inherits": "~2.0.0" + } + } + } + }, + "text-table": { + "version": "0.2.0", + "bundled": true + }, + "uid-number": { + "version": "0.0.6", + "bundled": true + }, + "umask": { + "version": "1.1.0", + "bundled": true + }, + "unique-filename": { + "version": "1.1.0", + "bundled": true, + "requires": { + "unique-slug": "^2.0.0" + }, + "dependencies": { + "unique-slug": { + "version": "2.0.0", + "bundled": true, + "requires": { + "imurmurhash": "^0.1.4" + } + } + } + }, + "unpipe": { + "version": "1.0.0", + "bundled": true + }, + "update-notifier": { + "version": "2.2.0", + "bundled": true, + "requires": { + "boxen": "^1.0.0", + "chalk": "^1.0.0", + "configstore": "^3.0.0", + "import-lazy": "^2.1.0", + "is-npm": "^1.0.0", + "latest-version": "^3.0.0", + "semver-diff": "^2.0.0", + "xdg-basedir": "^3.0.0" + }, + "dependencies": { + "boxen": { + "version": "1.1.0", + "bundled": true, + "requires": { + "ansi-align": "^2.0.0", + "camelcase": "^4.0.0", + "chalk": "^1.1.1", + "cli-boxes": "^1.0.0", + "string-width": "^2.0.0", + "term-size": "^0.1.0", + "widest-line": "^1.0.0" + }, + "dependencies": { + "ansi-align": { + "version": "2.0.0", + "bundled": true, + "requires": { + "string-width": "^2.0.0" + } + }, + "camelcase": { + "version": "4.1.0", + "bundled": true + }, + "cli-boxes": { + "version": "1.0.0", + "bundled": true + }, + "string-width": { + "version": "2.1.0", + "bundled": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "2.0.0", + "bundled": true + }, + "strip-ansi": { + "version": "4.0.0", + "bundled": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "term-size": { + "version": "0.1.1", + "bundled": true, + "requires": { + "execa": "^0.4.0" + }, + "dependencies": { + "execa": { + "version": "0.4.0", + "bundled": true, + "requires": { + "cross-spawn-async": "^2.1.1", + "is-stream": "^1.1.0", + "npm-run-path": "^1.0.0", + "object-assign": "^4.0.1", + "path-key": "^1.0.0", + "strip-eof": "^1.0.0" + }, + "dependencies": { + "cross-spawn-async": { + "version": "2.2.5", + "bundled": true, + "requires": { + "lru-cache": "^4.0.0", + "which": "^1.2.8" + } + }, + "is-stream": { + "version": "1.1.0", + "bundled": true + }, + "npm-run-path": { + "version": "1.0.0", + "bundled": true, + "requires": { + "path-key": "^1.0.0" + } + }, + "object-assign": { + "version": "4.1.1", + "bundled": true + }, + "path-key": { + "version": "1.0.0", + "bundled": true + }, + "strip-eof": { + "version": "1.0.0", + "bundled": true + } + } + } + } + }, + "widest-line": { + "version": "1.0.0", + "bundled": true, + "requires": { + "string-width": "^1.0.1" + }, + "dependencies": { + "string-width": { + "version": "1.0.2", + "bundled": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "dependencies": { + "code-point-at": { + "version": "1.1.0", + "bundled": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "requires": { + "number-is-nan": "^1.0.0" + }, + "dependencies": { + "number-is-nan": { + "version": "1.0.1", + "bundled": true + } + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "requires": { + "ansi-regex": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "bundled": true + } + } + } + } + } + } + } + } + }, + "chalk": { + "version": "1.1.3", + "bundled": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "bundled": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "bundled": true + }, + "has-ansi": { + "version": "2.0.0", + "bundled": true, + "requires": { + "ansi-regex": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "bundled": true + } + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "requires": { + "ansi-regex": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "bundled": true + } + } + }, + "supports-color": { + "version": "2.0.0", + "bundled": true + } + } + }, + "configstore": { + "version": "3.1.0", + "bundled": true, + "requires": { + "dot-prop": "^4.1.0", + "graceful-fs": "^4.1.2", + "make-dir": "^1.0.0", + "unique-string": "^1.0.0", + "write-file-atomic": "^2.0.0", + "xdg-basedir": "^3.0.0" + }, + "dependencies": { + "dot-prop": { + "version": "4.1.1", + "bundled": true, + "requires": { + "is-obj": "^1.0.0" + }, + "dependencies": { + "is-obj": { + "version": "1.0.1", + "bundled": true + } + } + }, + "make-dir": { + "version": "1.0.0", + "bundled": true, + "requires": { + "pify": "^2.3.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "bundled": true + } + } + }, + "unique-string": { + "version": "1.0.0", + "bundled": true, + "requires": { + "crypto-random-string": "^1.0.0" + }, + "dependencies": { + "crypto-random-string": { + "version": "1.0.0", + "bundled": true + } + } + } + } + }, + "import-lazy": { + "version": "2.1.0", + "bundled": true + }, + "is-npm": { + "version": "1.0.0", + "bundled": true + }, + "latest-version": { + "version": "3.1.0", + "bundled": true, + "requires": { + "package-json": "^4.0.0" + }, + "dependencies": { + "package-json": { + "version": "4.0.1", + "bundled": true, + "requires": { + "got": "^6.7.1", + "registry-auth-token": "^3.0.1", + "registry-url": "^3.0.3", + "semver": "^5.1.0" + }, + "dependencies": { + "got": { + "version": "6.7.1", + "bundled": true, + "requires": { + "create-error-class": "^3.0.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "is-redirect": "^1.0.0", + "is-retry-allowed": "^1.0.0", + "is-stream": "^1.0.0", + "lowercase-keys": "^1.0.0", + "safe-buffer": "^5.0.1", + "timed-out": "^4.0.0", + "unzip-response": "^2.0.1", + "url-parse-lax": "^1.0.0" + }, + "dependencies": { + "create-error-class": { + "version": "3.0.2", + "bundled": true, + "requires": { + "capture-stack-trace": "^1.0.0" + }, + "dependencies": { + "capture-stack-trace": { + "version": "1.0.0", + "bundled": true + } + } + }, + "duplexer3": { + "version": "0.1.4", + "bundled": true + }, + "get-stream": { + "version": "3.0.0", + "bundled": true + }, + "is-redirect": { + "version": "1.0.0", + "bundled": true + }, + "is-retry-allowed": { + "version": "1.1.0", + "bundled": true + }, + "is-stream": { + "version": "1.1.0", + "bundled": true + }, + "lowercase-keys": { + "version": "1.0.0", + "bundled": true + }, + "timed-out": { + "version": "4.0.1", + "bundled": true + }, + "unzip-response": { + "version": "2.0.1", + "bundled": true + }, + "url-parse-lax": { + "version": "1.0.0", + "bundled": true, + "requires": { + "prepend-http": "^1.0.1" + }, + "dependencies": { + "prepend-http": { + "version": "1.0.4", + "bundled": true + } + } + } + } + }, + "registry-auth-token": { + "version": "3.3.1", + "bundled": true, + "requires": { + "rc": "^1.1.6", + "safe-buffer": "^5.0.1" + }, + "dependencies": { + "rc": { + "version": "1.2.1", + "bundled": true, + "requires": { + "deep-extend": "~0.4.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "deep-extend": { + "version": "0.4.2", + "bundled": true + }, + "minimist": { + "version": "1.2.0", + "bundled": true + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true + } + } + } + } + }, + "registry-url": { + "version": "3.1.0", + "bundled": true, + "requires": { + "rc": "^1.0.1" + }, + "dependencies": { + "rc": { + "version": "1.2.1", + "bundled": true, + "requires": { + "deep-extend": "~0.4.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "deep-extend": { + "version": "0.4.2", + "bundled": true + }, + "minimist": { + "version": "1.2.0", + "bundled": true + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true + } + } + } + } + } + } + } + } + }, + "semver-diff": { + "version": "2.1.0", + "bundled": true, + "requires": { + "semver": "^5.0.3" + } + }, + "xdg-basedir": { + "version": "3.0.0", + "bundled": true + } + } + }, + "uuid": { + "version": "3.1.0", + "bundled": true + }, + "validate-npm-package-license": { + "version": "3.0.1", + "bundled": true, + "requires": { + "spdx-correct": "~1.0.0", + "spdx-expression-parse": "~1.0.0" + }, + "dependencies": { + "spdx-correct": { + "version": "1.0.2", + "bundled": true, + "requires": { + "spdx-license-ids": "^1.0.2" + }, + "dependencies": { + "spdx-license-ids": { + "version": "1.2.2", + "bundled": true + } + } + }, + "spdx-expression-parse": { + "version": "1.0.4", + "bundled": true + } + } + }, + "validate-npm-package-name": { + "version": "3.0.0", + "bundled": true, + "requires": { + "builtins": "^1.0.3" + }, + "dependencies": { + "builtins": { + "version": "1.0.3", + "bundled": true + } + } + }, + "which": { + "version": "1.2.14", + "bundled": true, + "requires": { + "isexe": "^2.0.0" + }, + "dependencies": { + "isexe": { + "version": "2.0.0", + "bundled": true + } + } + }, + "worker-farm": { + "version": "1.3.1", + "bundled": true, + "requires": { + "errno": ">=0.1.1 <0.2.0-0", + "xtend": ">=4.0.0 <4.1.0-0" + }, + "dependencies": { + "errno": { + "version": "0.1.4", + "bundled": true, + "requires": { + "prr": "~0.0.0" + }, + "dependencies": { + "prr": { + "version": "0.0.0", + "bundled": true + } + } + }, + "xtend": { + "version": "4.0.1", + "bundled": true + } + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true + }, + "write-file-atomic": { + "version": "2.1.0", + "bundled": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "slide": "^1.1.5" + } + } + } + }, + "npmi": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npmi/-/npmi-1.0.1.tgz", + "integrity": "sha1-FddpJzVHVF5oCdzwzhiu1IsCkOI=", + "requires": { + "npm": "^2.1.12", + "semver": "^4.1.0" + }, + "dependencies": { + "npm": { + "version": "2.15.12", + "resolved": "https://registry.npmjs.org/npm/-/npm-2.15.12.tgz", + "integrity": "sha1-33w+1aJ3w/nUtdgZsFMR0QogCuY=", + "requires": { + "abbrev": "~1.0.9", + "ansi": "~0.3.1", + "ansi-regex": "*", + "ansicolors": "~0.3.2", + "ansistyles": "~0.1.3", + "archy": "~1.0.0", + "async-some": "~1.0.2", + "block-stream": "0.0.9", + "char-spinner": "~1.0.1", + "chmodr": "~1.0.2", + "chownr": "~1.0.1", + "cmd-shim": "~2.0.2", + "columnify": "~1.5.4", + "config-chain": "~1.1.10", + "dezalgo": "~1.0.3", + "editor": "~1.0.0", + "fs-vacuum": "~1.2.9", + "fs-write-stream-atomic": "~1.0.8", + "fstream": "~1.0.10", + "fstream-npm": "~1.1.1", + "github-url-from-git": "~1.4.0", + "github-url-from-username-repo": "~1.0.2", + "glob": "~7.0.6", + "graceful-fs": "~4.1.6", + "hosted-git-info": "~2.1.5", + "imurmurhash": "*", + "inflight": "~1.0.4", + "inherits": "~2.0.3", + "ini": "~1.3.4", + "init-package-json": "~1.9.4", + "lockfile": "~1.0.1", + "lru-cache": "~4.0.1", + "minimatch": "~3.0.3", + "mkdirp": "~0.5.1", + "node-gyp": "~3.6.0", + "nopt": "~3.0.6", + "normalize-git-url": "~3.0.2", + "normalize-package-data": "~2.3.5", + "npm-cache-filename": "~1.0.2", + "npm-install-checks": "~1.0.7", + "npm-package-arg": "~4.1.0", + "npm-registry-client": "~7.2.1", + "npm-user-validate": "~0.1.5", + "npmlog": "~2.0.4", + "once": "~1.4.0", + "opener": "~1.4.1", + "osenv": "~0.1.3", + "path-is-inside": "~1.0.0", + "read": "~1.0.7", + "read-installed": "~4.0.3", + "read-package-json": "~2.0.4", + "readable-stream": "~2.1.5", + "realize-package-specifier": "~3.0.1", + "request": "~2.74.0", + "retry": "~0.10.0", + "rimraf": "~2.5.4", + "semver": "~5.1.0", + "sha": "~2.0.1", + "slide": "~1.1.6", + "sorted-object": "~2.0.0", + "spdx-license-ids": "~1.2.2", + "strip-ansi": "~3.0.1", + "tar": "~2.2.1", + "text-table": "~0.2.0", + "uid-number": "0.0.6", + "umask": "~1.1.0", + "validate-npm-package-license": "~3.0.1", + "validate-npm-package-name": "~2.2.2", + "which": "~1.2.11", + "wrappy": "~1.0.2", + "write-file-atomic": "~1.1.4" + }, + "dependencies": { + "abbrev": { + "version": "1.0.9", + "bundled": true + }, + "ansi": { + "version": "0.3.1", + "bundled": true + }, + "ansi-regex": { + "version": "2.0.0", + "bundled": true + }, + "ansicolors": { + "version": "0.3.2", + "bundled": true + }, + "ansistyles": { + "version": "0.1.3", + "bundled": true + }, + "archy": { + "version": "1.0.0", + "bundled": true + }, + "async-some": { + "version": "1.0.2", + "bundled": true, + "requires": { + "dezalgo": "^1.0.2" + } + }, + "block-stream": { + "version": "0.0.9", + "bundled": true, + "requires": { + "inherits": "~2.0.0" + } + }, + "char-spinner": { + "version": "1.0.1", + "bundled": true + }, + "chmodr": { + "version": "1.0.2", + "bundled": true + }, + "chownr": { + "version": "1.0.1", + "bundled": true + }, + "cmd-shim": { + "version": "2.0.2", + "bundled": true, + "requires": { + "graceful-fs": "^4.1.2", + "mkdirp": "~0.5.0" + } + }, + "columnify": { + "version": "1.5.4", + "bundled": true, + "requires": { + "strip-ansi": "^3.0.0", + "wcwidth": "^1.0.0" + }, + "dependencies": { + "wcwidth": { + "version": "1.0.0", + "bundled": true, + "requires": { + "defaults": "^1.0.0" + }, + "dependencies": { + "defaults": { + "version": "1.0.3", + "bundled": true, + "requires": { + "clone": "^1.0.2" + }, + "dependencies": { + "clone": { + "version": "1.0.2", + "bundled": true + } + } + } + } + } + } + }, + "config-chain": { + "version": "1.1.10", + "bundled": true, + "requires": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + }, + "dependencies": { + "proto-list": { + "version": "1.2.4", + "bundled": true + } + } + }, + "dezalgo": { + "version": "1.0.3", + "bundled": true, + "requires": { + "asap": "^2.0.0", + "wrappy": "1" + }, + "dependencies": { + "asap": { + "version": "2.0.3", + "bundled": true + } + } + }, + "editor": { + "version": "1.0.0", + "bundled": true + }, + "fs-vacuum": { + "version": "1.2.9", + "bundled": true, + "requires": { + "graceful-fs": "^4.1.2", + "path-is-inside": "^1.0.1", + "rimraf": "^2.5.2" + } + }, + "fs-write-stream-atomic": { + "version": "1.0.8", + "bundled": true, + "requires": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + }, + "dependencies": { + "iferr": { + "version": "0.1.5", + "bundled": true + } + } + }, + "fstream": { + "version": "1.0.10", + "bundled": true, + "requires": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + } + }, + "fstream-npm": { + "version": "1.1.1", + "bundled": true, + "requires": { + "fstream-ignore": "^1.0.0", + "inherits": "2" + }, + "dependencies": { + "fstream-ignore": { + "version": "1.0.5", + "bundled": true, + "requires": { + "fstream": "^1.0.0", + "inherits": "2", + "minimatch": "^3.0.0" + } + } + } + }, + "github-url-from-git": { + "version": "1.4.0", + "bundled": true + }, + "github-url-from-username-repo": { + "version": "1.0.2", + "bundled": true + }, + "glob": { + "version": "7.0.6", + "bundled": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.2", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "dependencies": { + "fs.realpath": { + "version": "1.0.0", + "bundled": true + }, + "path-is-absolute": { + "version": "1.0.0", + "bundled": true + } + } + }, + "graceful-fs": { + "version": "4.1.6", + "bundled": true + }, + "hosted-git-info": { + "version": "2.1.5", + "bundled": true + }, + "imurmurhash": { + "version": "0.1.4", + "bundled": true + }, + "inflight": { + "version": "1.0.5", + "bundled": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true + }, + "ini": { + "version": "1.3.4", + "bundled": true + }, + "init-package-json": { + "version": "1.9.4", + "bundled": true, + "requires": { + "glob": "^6.0.0", + "npm-package-arg": "^4.0.0", + "promzard": "^0.3.0", + "read": "~1.0.1", + "read-package-json": "1 || 2", + "semver": "2.x || 3.x || 4 || 5", + "validate-npm-package-license": "^3.0.1", + "validate-npm-package-name": "^2.0.1" + }, + "dependencies": { + "glob": { + "version": "6.0.4", + "bundled": true, + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "dependencies": { + "path-is-absolute": { + "version": "1.0.0", + "bundled": true + } + } + }, + "promzard": { + "version": "0.3.0", + "bundled": true, + "requires": { + "read": "1" + } + } + } + }, + "lockfile": { + "version": "1.0.1", + "bundled": true + }, + "lru-cache": { + "version": "4.0.1", + "bundled": true, + "requires": { + "pseudomap": "^1.0.1", + "yallist": "^2.0.0" + }, + "dependencies": { + "pseudomap": { + "version": "1.0.2", + "bundled": true + }, + "yallist": { + "version": "2.0.0", + "bundled": true + } + } + }, + "minimatch": { + "version": "3.0.3", + "bundled": true, + "requires": { + "brace-expansion": "^1.0.0" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.6", + "bundled": true, + "requires": { + "balanced-match": "^0.4.1", + "concat-map": "0.0.1" + }, + "dependencies": { + "balanced-match": { + "version": "0.4.2", + "bundled": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true + } + } + } + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "bundled": true + } + } + }, + "node-gyp": { + "version": "3.6.0", + "bundled": true, + "requires": { + "fstream": "^1.0.0", + "glob": "^7.0.3", + "graceful-fs": "^4.1.2", + "minimatch": "^3.0.2", + "mkdirp": "^0.5.0", + "nopt": "2 || 3", + "npmlog": "0 || 1 || 2 || 3 || 4", + "osenv": "0", + "request": "2", + "rimraf": "2", + "semver": "~5.3.0", + "tar": "^2.0.0", + "which": "1" + }, + "dependencies": { + "semver": { + "version": "5.3.0", + "bundled": true + } + } + }, + "nopt": { + "version": "3.0.6", + "bundled": true, + "requires": { + "abbrev": "1" + } + }, + "normalize-git-url": { + "version": "3.0.2", + "bundled": true + }, + "normalize-package-data": { + "version": "2.3.5", + "bundled": true, + "requires": { + "hosted-git-info": "^2.1.4", + "is-builtin-module": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "is-builtin-module": { + "version": "1.0.0", + "bundled": true, + "requires": { + "builtin-modules": "^1.0.0" + }, + "dependencies": { + "builtin-modules": { + "version": "1.1.0", + "bundled": true + } + } + } + } + }, + "npm-cache-filename": { + "version": "1.0.2", + "bundled": true + }, + "npm-install-checks": { + "version": "1.0.7", + "bundled": true, + "requires": { + "npmlog": "0.1 || 1 || 2", + "semver": "^2.3.0 || 3.x || 4 || 5" + } + }, + "npm-package-arg": { + "version": "4.1.0", + "bundled": true, + "requires": { + "hosted-git-info": "^2.1.4", + "semver": "4 || 5" + } + }, + "npm-registry-client": { + "version": "7.2.1", + "bundled": true, + "requires": { + "concat-stream": "^1.5.2", + "graceful-fs": "^4.1.6", + "normalize-package-data": "~1.0.1 || ^2.0.0", + "npm-package-arg": "^3.0.0 || ^4.0.0", + "npmlog": "~2.0.0 || ~3.1.0", + "once": "^1.3.3", + "request": "^2.74.0", + "retry": "^0.10.0", + "semver": "2 >=2.2.1 || 3.x || 4 || 5", + "slide": "^1.1.3" + }, + "dependencies": { + "concat-stream": { + "version": "1.5.2", + "bundled": true, + "requires": { + "inherits": "~2.0.1", + "readable-stream": "~2.0.0", + "typedarray": "~0.0.5" + }, + "dependencies": { + "readable-stream": { + "version": "2.0.6", + "bundled": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "string_decoder": "~0.10.x", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "core-util-is": { + "version": "1.0.2", + "bundled": true + }, + "isarray": { + "version": "1.0.0", + "bundled": true + }, + "process-nextick-args": { + "version": "1.0.7", + "bundled": true + }, + "string_decoder": { + "version": "0.10.31", + "bundled": true + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true + } + } + }, + "typedarray": { + "version": "0.0.6", + "bundled": true + } + } + }, + "retry": { + "version": "0.10.0", + "bundled": true + } + } + }, + "npm-user-validate": { + "version": "0.1.5", + "bundled": true + }, + "npmlog": { + "version": "2.0.4", + "bundled": true, + "requires": { + "ansi": "~0.3.1", + "are-we-there-yet": "~1.1.2", + "gauge": "~1.2.5" + }, + "dependencies": { + "are-we-there-yet": { + "version": "1.1.2", + "bundled": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.0 || ^1.1.13" + }, + "dependencies": { + "delegates": { + "version": "1.0.0", + "bundled": true + } + } + }, + "gauge": { + "version": "1.2.7", + "bundled": true, + "requires": { + "ansi": "^0.3.0", + "has-unicode": "^2.0.0", + "lodash.pad": "^4.1.0", + "lodash.padend": "^4.1.0", + "lodash.padstart": "^4.1.0" + }, + "dependencies": { + "has-unicode": { + "version": "2.0.0", + "bundled": true + }, + "lodash._baseslice": { + "version": "4.0.0", + "bundled": true + }, + "lodash._basetostring": { + "version": "4.12.0", + "bundled": true + }, + "lodash.pad": { + "version": "4.4.0", + "bundled": true, + "requires": { + "lodash._baseslice": "~4.0.0", + "lodash._basetostring": "~4.12.0", + "lodash.tostring": "^4.0.0" + } + }, + "lodash.padend": { + "version": "4.5.0", + "bundled": true, + "requires": { + "lodash._baseslice": "~4.0.0", + "lodash._basetostring": "~4.12.0", + "lodash.tostring": "^4.0.0" + } + }, + "lodash.padstart": { + "version": "4.5.0", + "bundled": true, + "requires": { + "lodash._baseslice": "~4.0.0", + "lodash._basetostring": "~4.12.0", + "lodash.tostring": "^4.0.0" + } + }, + "lodash.tostring": { + "version": "4.1.4", + "bundled": true + } + } + } + } + }, + "once": { + "version": "1.4.0", + "bundled": true, + "requires": { + "wrappy": "1" + } + }, + "opener": { + "version": "1.4.1", + "bundled": true + }, + "osenv": { + "version": "0.1.3", + "bundled": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + }, + "dependencies": { + "os-homedir": { + "version": "1.0.0", + "bundled": true + }, + "os-tmpdir": { + "version": "1.0.1", + "bundled": true + } + } + }, + "path-is-inside": { + "version": "1.0.1", + "bundled": true + }, + "read": { + "version": "1.0.7", + "bundled": true, + "requires": { + "mute-stream": "~0.0.4" + }, + "dependencies": { + "mute-stream": { + "version": "0.0.5", + "bundled": true + } + } + }, + "read-installed": { + "version": "4.0.3", + "bundled": true, + "requires": { + "debuglog": "^1.0.1", + "graceful-fs": "^4.1.2", + "read-package-json": "^2.0.0", + "readdir-scoped-modules": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "slide": "~1.1.3", + "util-extend": "^1.0.1" + }, + "dependencies": { + "debuglog": { + "version": "1.0.1", + "bundled": true + }, + "readdir-scoped-modules": { + "version": "1.0.2", + "bundled": true, + "requires": { + "debuglog": "^1.0.1", + "dezalgo": "^1.0.0", + "graceful-fs": "^4.1.2", + "once": "^1.3.0" + } + }, + "util-extend": { + "version": "1.0.1", + "bundled": true + } + } + }, + "read-package-json": { + "version": "2.0.4", + "bundled": true, + "requires": { + "glob": "^6.0.0", + "graceful-fs": "^4.1.2", + "json-parse-helpfulerror": "^1.0.2", + "normalize-package-data": "^2.0.0" + }, + "dependencies": { + "glob": { + "version": "6.0.4", + "bundled": true, + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "dependencies": { + "path-is-absolute": { + "version": "1.0.0", + "bundled": true + } + } + }, + "json-parse-helpfulerror": { + "version": "1.0.3", + "bundled": true, + "requires": { + "jju": "^1.1.0" + }, + "dependencies": { + "jju": { + "version": "1.3.0", + "bundled": true + } + } + } + } + }, + "readable-stream": { + "version": "2.1.5", + "bundled": true, + "requires": { + "buffer-shims": "^1.0.0", + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "string_decoder": "~0.10.x", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "buffer-shims": { + "version": "1.0.0", + "bundled": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true + }, + "isarray": { + "version": "1.0.0", + "bundled": true + }, + "process-nextick-args": { + "version": "1.0.7", + "bundled": true + }, + "string_decoder": { + "version": "0.10.31", + "bundled": true + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true + } + } + }, + "realize-package-specifier": { + "version": "3.0.1", + "bundled": true, + "requires": { + "dezalgo": "^1.0.1", + "npm-package-arg": "^4.0.0" + } + }, + "request": { + "version": "2.74.0", + "bundled": true, + "requires": { + "aws-sign2": "~0.6.0", + "aws4": "^1.2.1", + "bl": "~1.1.2", + "caseless": "~0.11.0", + "combined-stream": "~1.0.5", + "extend": "~3.0.0", + "forever-agent": "~0.6.1", + "form-data": "~1.0.0-rc4", + "har-validator": "~2.0.6", + "hawk": "~3.1.3", + "http-signature": "~1.1.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.7", + "node-uuid": "~1.4.7", + "oauth-sign": "~0.8.1", + "qs": "~6.2.0", + "stringstream": "~0.0.4", + "tough-cookie": "~2.3.0", + "tunnel-agent": "~0.4.1" + }, + "dependencies": { + "aws-sign2": { + "version": "0.6.0", + "bundled": true + }, + "aws4": { + "version": "1.4.1", + "bundled": true + }, + "bl": { + "version": "1.1.2", + "bundled": true, + "requires": { + "readable-stream": "~2.0.5" + }, + "dependencies": { + "readable-stream": { + "version": "2.0.6", + "bundled": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "string_decoder": "~0.10.x", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "core-util-is": { + "version": "1.0.2", + "bundled": true + }, + "isarray": { + "version": "1.0.0", + "bundled": true + }, + "process-nextick-args": { + "version": "1.0.7", + "bundled": true + }, + "string_decoder": { + "version": "0.10.31", + "bundled": true + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true + } + } + } + } + }, + "caseless": { + "version": "0.11.0", + "bundled": true + }, + "combined-stream": { + "version": "1.0.5", + "bundled": true, + "requires": { + "delayed-stream": "~1.0.0" + }, + "dependencies": { + "delayed-stream": { + "version": "1.0.0", + "bundled": true + } + } + }, + "extend": { + "version": "3.0.0", + "bundled": true + }, + "forever-agent": { + "version": "0.6.1", + "bundled": true + }, + "form-data": { + "version": "1.0.0-rc4", + "bundled": true, + "requires": { + "async": "^1.5.2", + "combined-stream": "^1.0.5", + "mime-types": "^2.1.10" + }, + "dependencies": { + "async": { + "version": "1.5.2", + "bundled": true + } + } + }, + "har-validator": { + "version": "2.0.6", + "bundled": true, + "requires": { + "chalk": "^1.1.1", + "commander": "^2.9.0", + "is-my-json-valid": "^2.12.4", + "pinkie-promise": "^2.0.0" + }, + "dependencies": { + "chalk": { + "version": "1.1.3", + "bundled": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "bundled": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "bundled": true + }, + "has-ansi": { + "version": "2.0.0", + "bundled": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "bundled": true + } + } + }, + "commander": { + "version": "2.9.0", + "bundled": true, + "requires": { + "graceful-readlink": ">= 1.0.0" + }, + "dependencies": { + "graceful-readlink": { + "version": "1.0.1", + "bundled": true + } + } + }, + "is-my-json-valid": { + "version": "2.13.1", + "bundled": true, + "requires": { + "generate-function": "^2.0.0", + "generate-object-property": "^1.1.0", + "jsonpointer": "2.0.0", + "xtend": "^4.0.0" + }, + "dependencies": { + "generate-function": { + "version": "2.0.0", + "bundled": true + }, + "generate-object-property": { + "version": "1.2.0", + "bundled": true, + "requires": { + "is-property": "^1.0.0" + }, + "dependencies": { + "is-property": { + "version": "1.0.2", + "bundled": true + } + } + }, + "jsonpointer": { + "version": "2.0.0", + "bundled": true + }, + "xtend": { + "version": "4.0.1", + "bundled": true + } + } + }, + "pinkie-promise": { + "version": "2.0.1", + "bundled": true, + "requires": { + "pinkie": "^2.0.0" + }, + "dependencies": { + "pinkie": { + "version": "2.0.4", + "bundled": true + } + } + } + } + }, + "hawk": { + "version": "3.1.3", + "bundled": true, + "requires": { + "boom": "2.x.x", + "cryptiles": "2.x.x", + "hoek": "2.x.x", + "sntp": "1.x.x" + }, + "dependencies": { + "boom": { + "version": "2.10.1", + "bundled": true, + "requires": { + "hoek": "2.x.x" + } + }, + "cryptiles": { + "version": "2.0.5", + "bundled": true, + "requires": { + "boom": "2.x.x" + } + }, + "hoek": { + "version": "2.16.3", + "bundled": true + }, + "sntp": { + "version": "1.0.9", + "bundled": true, + "requires": { + "hoek": "2.x.x" + } + } + } + }, + "http-signature": { + "version": "1.1.1", + "bundled": true, + "requires": { + "assert-plus": "^0.2.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "dependencies": { + "assert-plus": { + "version": "0.2.0", + "bundled": true + }, + "jsprim": { + "version": "1.3.0", + "bundled": true, + "requires": { + "extsprintf": "1.0.2", + "json-schema": "0.2.2", + "verror": "1.3.6" + }, + "dependencies": { + "extsprintf": { + "version": "1.0.2", + "bundled": true + }, + "json-schema": { + "version": "0.2.2", + "bundled": true + }, + "verror": { + "version": "1.3.6", + "bundled": true, + "requires": { + "extsprintf": "1.0.2" + } + } + } + }, + "sshpk": { + "version": "1.9.2", + "bundled": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jodid25519": "^1.0.0", + "jsbn": "~0.1.0", + "tweetnacl": "~0.13.0" + }, + "dependencies": { + "asn1": { + "version": "0.2.3", + "bundled": true + }, + "assert-plus": { + "version": "1.0.0", + "bundled": true + }, + "dashdash": { + "version": "1.14.0", + "bundled": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "ecc-jsbn": { + "version": "0.1.1", + "bundled": true, + "optional": true, + "requires": { + "jsbn": "~0.1.0" + } + }, + "getpass": { + "version": "0.1.6", + "bundled": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "jodid25519": { + "version": "1.0.2", + "bundled": true, + "optional": true, + "requires": { + "jsbn": "~0.1.0" + } + }, + "jsbn": { + "version": "0.1.0", + "bundled": true, + "optional": true + }, + "tweetnacl": { + "version": "0.13.3", + "bundled": true, + "optional": true + } + } + } + } + }, + "is-typedarray": { + "version": "1.0.0", + "bundled": true + }, + "isstream": { + "version": "0.1.2", + "bundled": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "bundled": true + }, + "mime-types": { + "version": "2.1.11", + "bundled": true, + "requires": { + "mime-db": "~1.23.0" + }, + "dependencies": { + "mime-db": { + "version": "1.23.0", + "bundled": true + } + } + }, + "node-uuid": { + "version": "1.4.7", + "bundled": true + }, + "oauth-sign": { + "version": "0.8.2", + "bundled": true + }, + "qs": { + "version": "6.2.1", + "bundled": true + }, + "stringstream": { + "version": "0.0.5", + "bundled": true + }, + "tough-cookie": { + "version": "2.3.1", + "bundled": true + }, + "tunnel-agent": { + "version": "0.4.3", + "bundled": true + } + } + }, + "retry": { + "version": "0.10.0", + "bundled": true + }, + "rimraf": { + "version": "2.5.4", + "bundled": true, + "requires": { + "glob": "^7.0.5" + } + }, + "semver": { + "version": "5.1.0", + "bundled": true + }, + "sha": { + "version": "2.0.1", + "bundled": true, + "requires": { + "graceful-fs": "^4.1.2", + "readable-stream": "^2.0.2" + }, + "dependencies": { + "readable-stream": { + "version": "2.0.2", + "bundled": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "process-nextick-args": "~1.0.0", + "string_decoder": "~0.10.x", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "core-util-is": { + "version": "1.0.1", + "bundled": true + }, + "isarray": { + "version": "0.0.1", + "bundled": true + }, + "process-nextick-args": { + "version": "1.0.3", + "bundled": true + }, + "string_decoder": { + "version": "0.10.31", + "bundled": true + }, + "util-deprecate": { + "version": "1.0.1", + "bundled": true + } + } + } + } + }, + "slide": { + "version": "1.1.6", + "bundled": true + }, + "sorted-object": { + "version": "2.0.0", + "bundled": true + }, + "spdx-license-ids": { + "version": "1.2.2", + "bundled": true + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "tar": { + "version": "2.2.1", + "bundled": true, + "requires": { + "block-stream": "*", + "fstream": "^1.0.2", + "inherits": "2" + } + }, + "text-table": { + "version": "0.2.0", + "bundled": true + }, + "uid-number": { + "version": "0.0.6", + "bundled": true + }, + "umask": { + "version": "1.1.0", + "bundled": true + }, + "validate-npm-package-license": { + "version": "3.0.1", + "bundled": true, + "requires": { + "spdx-correct": "~1.0.0", + "spdx-expression-parse": "~1.0.0" + }, + "dependencies": { + "spdx-correct": { + "version": "1.0.2", + "bundled": true, + "requires": { + "spdx-license-ids": "^1.0.2" + } + }, + "spdx-expression-parse": { + "version": "1.0.2", + "bundled": true, + "requires": { + "spdx-exceptions": "^1.0.4", + "spdx-license-ids": "^1.0.0" + }, + "dependencies": { + "spdx-exceptions": { + "version": "1.0.4", + "bundled": true + } + } + } + } + }, + "validate-npm-package-name": { + "version": "2.2.2", + "bundled": true, + "requires": { + "builtins": "0.0.7" + }, + "dependencies": { + "builtins": { + "version": "0.0.7", + "bundled": true + } + } + }, + "which": { + "version": "1.2.11", + "bundled": true, + "requires": { + "isexe": "^1.1.1" + }, + "dependencies": { + "isexe": { + "version": "1.1.2", + "bundled": true + } + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true + }, + "write-file-atomic": { + "version": "1.1.4", + "bundled": true, + "requires": { + "graceful-fs": "^4.1.2", + "imurmurhash": "^0.1.4", + "slide": "^1.1.5" + } + } + } + }, + "semver": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", + "integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto=" + } + } + }, + "nth-check": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "requires": { + "boolbase": "~1.0.0" + } + }, + "nwmatcher": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/nwmatcher/-/nwmatcher-1.4.4.tgz", + "integrity": "sha512-3iuY4N5dhgMpCUrOVnuAdGrgxVqV2cJpM+XNccjR2DKOB1RUP0aA+wGXEiNziG/UKboFyGBIoKOaNlJxx8bciQ==", + "optional": true + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "requires": { + "isobject": "^3.0.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "requires": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + }, + "dependencies": { + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" + } + } + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "optional": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.4", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "wordwrap": "~1.0.0" + } + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + }, + "parse5": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-1.5.1.tgz", + "integrity": "sha1-m387DeMr543CQBsXVzzK8Pb1nZQ=", + "optional": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=" + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "phantom": { + "version": "2.1.21", + "resolved": "https://registry.npmjs.org/phantom/-/phantom-2.1.21.tgz", + "integrity": "sha1-drd5D/Ys8J++kiroRLn7dFzouyg=", + "requires": { + "linerstream": "^0.1.4", + "phantomjs-prebuilt": "^2.1.4", + "winston": "^2.2.0" + } + }, + "phantomjs-prebuilt": { + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.16.tgz", + "integrity": "sha1-79ISpKOWbTZHaE6ouniFSb4q7+8=", + "requires": { + "es6-promise": "^4.0.3", + "extract-zip": "^1.6.5", + "fs-extra": "^1.0.0", + "hasha": "^2.2.0", + "kew": "^0.7.0", + "progress": "^1.1.8", + "request": "^2.81.0", + "request-progress": "^2.0.1", + "which": "^1.2.10" + } + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "requires": { + "pinkie": "^2.0.0" + } + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" + }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" + }, + "progress": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", + "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=" + }, + "psl": { + "version": "1.1.31", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz", + "integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw==" + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=" + }, + "q-plus": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/q-plus/-/q-plus-0.0.8.tgz", + "integrity": "sha1-TMZssZvRRbQ+nhtUAjYUI3e2Hqs=", + "requires": { + "q": "^1.1.2" + } + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "remarkable": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/remarkable/-/remarkable-1.7.1.tgz", + "integrity": "sha1-qspJchALZqZCpjoQIcpLrBvjv/Y=", + "requires": { + "argparse": "~0.1.15", + "autolinker": "~0.15.0" + }, + "dependencies": { + "argparse": { + "version": "0.1.16", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-0.1.16.tgz", + "integrity": "sha1-z9AeD7uj1srtBJ+9dY1A9lGW9Xw=", + "requires": { + "underscore": "~1.7.0", + "underscore.string": "~2.4.0" + } + }, + "underscore.string": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.4.0.tgz", + "integrity": "sha1-jN2PusTi0uoefi6Al8QvRCKA+Fs=" + } + } + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" + }, + "request": { + "version": "2.88.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + } + }, + "request-progress": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-2.0.1.tgz", + "integrity": "sha1-XTa7V5YcZzqlt4jbyBQf3yO0Tgg=", + "requires": { + "throttleit": "^1.0.0" + } + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "optional": true + }, + "semver": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=" + }, + "shoe": { + "version": "0.0.15", + "resolved": "https://registry.npmjs.org/shoe/-/shoe-0.0.15.tgz", + "integrity": "sha1-uu2PGn8I9TC2bwkUKH/KplsSRDo=", + "requires": { + "sockjs": "0.3.7", + "sockjs-client": "*" + }, + "dependencies": { + "sockjs-client": { + "version": "0.0.0-unreleasable", + "bundled": true + } + } + }, + "sntp": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", + "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", + "requires": { + "hoek": "2.x.x" + }, + "dependencies": { + "hoek": { + "version": "2.16.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", + "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=" + } + } + }, + "sockjs": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.7.tgz", + "integrity": "sha1-KVDgWG2KnTBElYqDGt5o2xl3Scs=", + "requires": { + "faye-websocket": "0.4.4", + "node-uuid": "1.3.3" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "stringstream": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.6.tgz", + "integrity": "sha512-87GEBAkegbBcweToUrdzf3eLhWNg06FJTebl4BVJz/JgWy8CvEr9dRtX5qWphiynMSQlxxi+QqN0z5T32SLlhA==" + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + }, + "symbol-tree": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz", + "integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY=", + "optional": true + }, + "throttleit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", + "integrity": "sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw=" + }, + "tmp": { + "version": "0.0.31", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.31.tgz", + "integrity": "sha1-jzirlDjhcxXl29izZX6L+yd65Kc=", + "requires": { + "os-tmpdir": "~1.0.1" + } + }, + "toml": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/toml/-/toml-2.3.6.tgz", + "integrity": "sha512-gVweAectJU3ebq//Ferr2JUY4WKSDe5N+z0FvjDncLGyHmIDoxgY/2Ie4qfEIDm4IS7OA6Rmdm7pdEEdMcV/xQ==" + }, + "tough-cookie": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "requires": { + "psl": "^1.1.24", + "punycode": "^1.4.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + } + } + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", + "optional": true + }, + "traverse": { + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz", + "integrity": "sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc=" + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "underscore": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz", + "integrity": "sha1-a7rwh3UA02vjTsqlhODbn+8DUgk=" + }, + "underscore.string": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.5.tgz", + "integrity": "sha512-g+dpmgn+XBneLmXXo+sGlW5xQEt4ErkS3mgeN2GFbremYeMBSJKr9Wf2KJplQVaiPY/f7FN6atosWYNm9ovrYg==", + "requires": { + "sprintf-js": "^1.0.3", + "util-deprecate": "^1.0.2" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "requires": { + "punycode": "^2.1.0" + } + }, + "user-home": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz", + "integrity": "sha1-nHC/2Babwdy/SGBODwS4tJzenp8=", + "requires": { + "os-homedir": "^1.0.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "weak": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/weak/-/weak-1.0.1.tgz", + "integrity": "sha1-q5mqswcGlZqgIAy4z1RbucszuZ4=", + "optional": true, + "requires": { + "bindings": "^1.2.1", + "nan": "^2.0.5" + } + }, + "webidl-conversions": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-2.0.1.tgz", + "integrity": "sha1-O/glj30xjHRDw28uFpQCoaZwNQY=", + "optional": true + }, + "whatwg-url-compat": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/whatwg-url-compat/-/whatwg-url-compat-0.6.5.tgz", + "integrity": "sha1-AImBEa9om7CXVBzVpFymyHmERb8=", + "optional": true, + "requires": { + "tr46": "~0.0.1" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "requires": { + "isexe": "^2.0.0" + } + }, + "win-spawn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/win-spawn/-/win-spawn-2.0.0.tgz", + "integrity": "sha1-OXopEw7JjQqgvIa6pGITk+/9Cwc=" + }, + "winston": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/winston/-/winston-2.4.4.tgz", + "integrity": "sha512-NBo2Pepn4hK4V01UfcWcDlmiVTs7VTB1h7bgnB0rgP146bYhMxX0ypCz3lBOfNxCO4Zuek7yeT+y/zM1OfMw4Q==", + "requires": { + "async": "~1.0.0", + "colors": "1.0.x", + "cycle": "1.0.x", + "eyes": "0.1.x", + "isstream": "0.1.x", + "stack-trace": "0.0.x" + } + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "optional": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "xml-name-validator": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-2.0.1.tgz", + "integrity": "sha1-TYuPHszTQZqjYgYb7O9RXh5VljU=", + "optional": true + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" + }, + "yauzl": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz", + "integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=", + "requires": { + "fd-slicer": "~1.0.1" + } + } + } +} diff --git a/docs/book/package.json b/docs/book/package.json new file mode 100644 index 00000000..0504a44d --- /dev/null +++ b/docs/book/package.json @@ -0,0 +1,31 @@ +{ + "name": "book", + "private": true, + "version": "1.0.0", + "description": "**Note:** Impatient readers head straight to [Quick Start](quick_start.md).", + "main": "index.js", + "dependencies": { + "cryptiles": "^4.1.2", + "gitbook-cli": "^2.3.2", + "gitbook-plugin-copy-code-button": "0.0.2", + "gitbook-plugin-custom-favicon": "0.0.4", + "gitbook-plugin-ga": "^1.0.1", + "gitbook-plugin-insert-logo": "^0.1.5", + "gitbook-plugin-mermaid": "0.0.9", + "gitbook-plugin-mermaid-gb3": "^2.1.0", + "gitbook-plugin-page-toc": "^1.1.0", + "gitbook-plugin-panel": "^0.0.1", + "gitbook-plugin-sequence-diagrams": "^1.1.0", + "gitbook-plugin-theme-api": "^1.1.2", + "gitbook-plugin-toc": "0.0.2", + "lodash": "4.17.11", + "phantomjs-prebuilt": "^2.1.16", + "underscore.string": "^3.3.5" + }, + "devDependencies": {}, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "Apache-2.0" +} diff --git a/docs/book/pages/app_composition_and_deployment/accessing_multiple_clusters.md b/docs/book/pages/app_composition_and_deployment/accessing_multiple_clusters.md new file mode 100644 index 00000000..0055b5f0 --- /dev/null +++ b/docs/book/pages/app_composition_and_deployment/accessing_multiple_clusters.md @@ -0,0 +1,142 @@ +{% panel style="success", title="Providing Feedback" %} +**Provide feedback at the [survey](https://www.surveymonkey.com/r/JH35X82)** +{% endpanel %} + +{% panel style="info", title="TL;DR" %} +- Target a cluster for a rollout with the `--context` flag +- Target a cluster for a rollout with the `--kubeconfig` flag +{% endpanel %} + +# Multi-Cluster Targeting + +## Motivation + +It is common for users to need to deploy **different Variants of an Application to different clusters**. +This can be done by configuring the different Variants using different `kustomization.yaml`'s, +and targeting each variant using the `--context` or `--kubeconfig` flag. + +**Note:** The examples shown in this chapter store the Resource Config in a directory +matching the name of the cluster (i.e. as it is referred to be context). + + +## Targeting a Cluster via Context + +The kubeconfig file allows multiple contexts to be specified, each with a different cluster + auth. + +### List Contexts + +{% method %} + +List the contexts in the kubeconfig file + +{% sample lang="yaml" %} +```sh +kubectl config get-contexts +``` + +```sh +CURRENT NAME CLUSTER AUTHINFO NAMESPACE + us-central1-c us-central1-c us-central1-c +* us-east1-c us-east1-c us-east1-c + us-west2-c us-west2-c us-west2-c +``` + +{% endmethod %} + +### Print a Context + +{% method %} + +Print information about the current context + +{% sample lang="yaml" %} +```sh +kubectl config --kubeconfig=config-demo view --minify +``` + +```yaml +apiVersion: v1 +clusters: +- cluster: + certificate-authority: fake-ca-file + server: https://1.2.3.4 + name: development +contexts: +- context: + cluster: development + namespace: frontend + user: developer + name: dev-frontend +current-context: dev-frontend +kind: Config +preferences: {} +users: +- name: developer + user: + client-certificate: fake-cert-file + client-key: fake-key-file +``` + +{% endmethod %} + +### Specify a Context Flag + +{% method %} + +Specify the kubeconfig context as part of the command. + +**Note:** In this example the `kustomization.yaml` exists in a directory whose name matches +the name of the context. + +{% sample lang="yaml" %} + +```sh +export CLUSTER=us-west2-c; kubectl apply -k ${CLUSTER} --context=${CLUSTER} +``` + +{% endmethod %} + +### Switch to use a Context + +{% method %} + +Switch the current context before running the command. + +**Note:** In this example the `kustomization.yaml` exists in a directory whose name matches +the name of the context. + +{% sample lang="yaml" %} + +```sh +# change the context to us-west2-c +kubectl config use-context us-west2-c +# deploy Resources from the ./us-west2-c/kustomization.yaml +kubectl apply -k ./us-west2-c +``` + +{% endmethod %} + +## Targeting a Cluster via Kubeconfig + +{% method %} + +Alternatively, different kubeconfig files may be used for different clusters. The +kubeconfig may be specified with the `--kubeconfig` flag. + +**Note:** In this example the `kustomization.yaml` exists in a directory whose name matches +the name of the directory containing the kubeconfig. + +{% sample lang="yaml" %} + +```sh +kubectl apply -k ./us-west2-c --kubeconfig /path/to/us-west2-c/config +``` + +{% endmethod %} + +{% panel style="info", title="More Info" %} +For more information on configuring kubeconfig and contexts, see the +[Configure Access to Multiple Clusters](https://kubernetes.io/docs/tasks/access-application-cluster/configure-access-multiple-clusters/) +k8s.io document. +{% endpanel %} + diff --git a/docs/book/pages/app_composition_and_deployment/diffing_local_and_remote_resources.md b/docs/book/pages/app_composition_and_deployment/diffing_local_and_remote_resources.md new file mode 100644 index 00000000..1484f3a6 --- /dev/null +++ b/docs/book/pages/app_composition_and_deployment/diffing_local_and_remote_resources.md @@ -0,0 +1,44 @@ +{% panel style="success", title="Providing Feedback" %} +**Provide feedback at the [survey](https://www.surveymonkey.com/r/JH35X82)** +{% endpanel %} + +{% panel style="info", title="TL;DR" %} +- View diff of changes before they are Applied to the cluster +{% endpanel %} + +# Diffing Local and Cluster State + +## Motivation + +The ability to view what changes will be made before applying them to a cluster can be useful. + +{% method %} +## Generating a Diff + +Use the `diff` program in a user's path to display a diff of the changes that will be +made by Apply. + +{% sample lang="yaml" %} + +```sh +kubectl diff -k ./dir/ +``` + +{% endmethod %} + +{% method %} +## Setting the Diff Program + +The `KUBECTL_EXTERNAL_DIFF` environment variable can be used to select your own diff command. +By default, the "diff" command available in your path will be run with "-u" (unified) and "-N" +(treat new files as empty) options. + + +{% sample lang="yaml" %} + +```sh +export KUBECTL_EXTERNAL_DIFF=meld; kubectl diff -k ./dir/ +``` + +{% endmethod %} + diff --git a/docs/book/pages/app_composition_and_deployment/publishing_bases.md b/docs/book/pages/app_composition_and_deployment/publishing_bases.md new file mode 100644 index 00000000..91419e66 --- /dev/null +++ b/docs/book/pages/app_composition_and_deployment/publishing_bases.md @@ -0,0 +1,96 @@ +{% panel style="success", title="Providing Feedback" %} +**Provide feedback at the [survey](https://www.surveymonkey.com/r/JH35X82)** +{% endpanel %} + +{% panel style="warning", title="Experimental" %} +**Content in this chapter is experimental and will evolve based on user feedback.** + +Leave feedback on the conventions by creating an issue in the [kubectl](https://github.com/kubernetes/kubectl/issues) +GitHub repository. + +Also provide feedback on new kubectl docs at the [survey](https://www.surveymonkey.com/r/JH35X82) +{% endpanel %} + +{% panel style="info", title="TL;DR" %} +- Publish a White Box Application as a Base for other users to Kustomize +{% endpanel %} + +# Publishing Bases + +## Motivation + +Users may want to run a common White Box Application without writing the Resource Config +for the Application from scratch. Instead they may want to consume ready-made Resource +Config published specifically for the White Box Application, and add customizations for +their specific needs. + +- Run a White Box Application (e.g. Cassandra, MongoDB) instance from ready-made Resource Config +- Publish Resource Config to run an Application + +## Publishing a White Box Base + +{% method %} +White Box Applications may be published to a URL and consumed as Bases in an `kustomization.yaml`. It +can then be consumed in the following manner. + +**Use Case:** Run a White Box Application published to GitHub. + +{% sample lang="yaml" %} +**Input:** The kustomization.yaml file + +```yaml +# kustomization.yaml +bases: +# GitHub URL +- github.com/kubernetes-sigs/kustomize/examples/multibases/dev/?ref=v1.0.6 +``` + +**Applied:** The Resource that is Applied to the cluster + +```yaml +# Resource comes from the Remote Base +apiVersion: v1 +kind: Pod +metadata: + labels: + app: myapp + name: dev-myapp-pod +spec: + containers: + - image: nginx:1.7.9 + name: nginx +``` +{% endmethod %} + +## Customizing White Box Bases + +The White Box Application may be customized using the same techniques described in +[Bases and Variations](../app_customization/bases_and_variants.md). + +## Versioning White Box Bases + +White Box Bases may be versioned using the well known versioning techniques provided by Git. + +**Tag:** + +Bases may be versioned by applying a tag to the repo and modifying the url to point to the tag: +`github.com/kubernetes-sigs/kustomize/examples/multibases?ref=v1.0.6` + +**Branch:** + +Bases may be versioned by creating a branch and modifying the url to point to the branch: +`github.com/Liujingfang1/kustomize/examples/helloWorld?ref=repoUrl2` + +**Commit:** + +If the White Box Base has not been explicitly versioned by the maintainer, users may pin the +base to a specific commit: +`github.com/Liujingfang1/kustomize/examples/helloWorld?ref=7050a45134e9848fca214ad7e7007e96e5042c03` + +## Forking a White Box Base + +Uses may fork a White Box Base hosted on GitHub by forking the GitHub repo. This allows the user +complete control over changes to the Base. Users should periodically pull changes from the +upstream repo back into the fork to get bug fixes and optimizations. + + diff --git a/docs/book/pages/app_composition_and_deployment/structure_branches.md b/docs/book/pages/app_composition_and_deployment/structure_branches.md new file mode 100644 index 00000000..f0e9fd85 --- /dev/null +++ b/docs/book/pages/app_composition_and_deployment/structure_branches.md @@ -0,0 +1,275 @@ +{% panel style="success", title="Providing Feedback" %} +**Provide feedback at the [survey](https://www.surveymonkey.com/r/JH35X82)** +{% endpanel %} + +{% panel style="warning", title="Experimental" %} +**Content in this chapter is experimental and will evolve based on user feedback.** + +Leave feedback on the conventions by creating an issue in the [kubectl](https://github.com/kubernetes/kubectl/issues) +GitHub repository. + +Also provide feedback on new kubectl docs at the [survey](https://www.surveymonkey.com/r/JH35X82) +{% endpanel %} + +{% panel style="info", title="TL;DR" %} +Decouple changes to Config to be deployed to separate Environments. +{% endpanel %} + +# Branch Structure Based Layout + +## Motivation + +**Why use branches?** Decouple changes that are rolled out with releases (e.g. new flags) from changes that are +rolled out in response to production events (e.g. resource tuning). + +## Branch Structure + +The convention shown here should be changed and adapted as needed. + +| Branch Type Name | Deployed to a Cluster | Purpose | Example Config Change | Example Branch Name | +|----------------------------------------|----|-----------|--------|----| +| Base | **No**. Merged into other Branches only. | Changes that should be rolled out as part of a release. | Add *pubsub topic* flag | `master`, `release-1.14`, `i1026` | +| Deploy | **Yes**. - Manually or Continuously. | Base + Changes required to respond to "production" events (or dev, staging, etc). | Increase *memory resources* - e.g. for crashing Containers | `deploy-test`, `deploy-staging`, `deploy-prod` | + +Use with techniques described in [Directories](structure_directories.md) and [Branches](structure_branches.md) + +## Workflow Example + +### Diagram + +#### Scenario + +1. Live Prod App version is *v1* +1. *v2* changes committed to Base Branch Config +1. *v2* rolled out to Staging + - Deployed by continuous deployment +1. Live Prod App requires change to *v1* (unrelated to *v2*) + - Change memory resources in Prod +1. Prod Branch Config Updated at *v1* + - Deployed immediately by continuous deployment +1. *v2* changes rolled out separately + - Tag on Base Branch merged into Prod Branch + - Prod Branch continuously deployed + +{% sequence width=1000 %} + +participant Base Branch as BB +participant Staging Branch as SB +participant Staging Clusters as SC +participant Prod Branch as PB +participant Prod Clusters as PC + +Note over SC: At v1 release +Note over PC: At v1 release +Note left of BB: Bob: App Dev +Note over BB: Bob Adds Flag +Note over BB: Bob Tags v2 +Note over SB: Bob Releases v2 +BB-->SB: Merge v2 +SB-->SC: Deploy +Note over SC: At v2 release +Note over BB,PC: Prod Outage +Note left of PB: Alice: App SRE +Note over PB: Alice fixes Config +PB-->PC: Alice's changes (only) +Note over PC: At v1* release +Note over BB,PC: Prod Outage resolved +Note over PB: Alice Releases v2 +BB-->PB: Merge v2 +PB-->PC: Deploy v2 +Note over PC: At v2 release + +{% endsequence %} + +### Description + +**Note:** Starting version of Application is *v1* + +1. Developer Bob introduces new app flag for release with *v2* + - e.g. PubSub topic name +1. Bob updates the Base Config with the new flag + - Add staging topic for Staging (e.g. `staging-topic`) + - Add prod topic for Prod (e.g. `prod-topic`) + - Flag should be rolled out with *v2* release +1. *v2* is cut + - Base tagged with *v2* tag +1. *v2* rolled out to Staging + - Merge *v2* Tag -> Staging Branch + - Deploy Staging Branch to Staging Clusters +1. SRE Alice identifies issue in Prod (at *v1*) + - Fix is to increase memory of containers +1. Alice updates the Prod branch Config by increasing memory resources + - Changes go directly into Prod Branch without going into Base +1. *v1* changes rolled out to Prod (*v1++*) + - Include Alice's changes, but not Bob's +1. *v2* rolled out to Prod + - Merge *v2* Tag -> Prod Branch + - Deploy Prod Branch to Prod Clusters + +{% method %} + +Techniques: + +- Add new required flags and environment variables to the Resource Config in the Base branch at the + time they are added to the code. + - Will be rolled out when the code is rolled out. +- Adjust flags and configuration to the Resource Config in the Deploy branch in the deploy directory. + - Will be rolled out immediately independent of versions. +- Merge code from the Base branch to the Deploy branches to perform a Rollout. + +## Directory and Branch Layout + +Structure: + +- Base branch (e.g. `master`, `app-version`, etc) for Config changes tied to releases. + - Looks like [Directories](structure_directories.md) +- Separate Deploy branches for separate Environments (e.g. `deploy-`). + - A new **Directory in each branch with will contain overlay customizations** - e.g. `deploy-`. + +{% sample lang="yaml" %} + +**Base Branch:** `master` + +```bash +tree +. +├── bases +│   ├── ... +├── prod +│   ├── bases +│   │   ├── ... +│   ├── us-central +│   │   ├── kustomization.yaml +│   │   └── backend +│   │   └── deployment-patch.yaml +│   ├── us-east +│   │   └── kustomization.yaml +│   └── us-west +│   └── kustomization.yaml +├── staging +│   ├── bases +│   │   ├── ... +│   └── us-west +│   └── kustomization.yaml +└── test + ├── bases + │   ├── ... + └── us-west + └── kustomization.yaml +``` + +**Deploy Branches:** + +Prod Branch: `deploy-prod` + +```bash +tree +. +├── bases # From Base Branch +│   └── ... +└── deploy-prod # Prod deploy folder +│   ├── us-central +│   │   ├── kustomization.yaml # Uses bases: ["../../prod/us-central"] +│   ├── us-east +│   │   └── kustomization.yaml # Uses bases: ["../../prod/us-east"] +│ └── us-west +│ └── kustomization.yaml # Uses bases: ["../../prod/us-west"] +├── prod # From Base Branch +│   └── ... +├── staging # From Base Branch +│   └── ... +└── test # From Base Branch + └── ... +``` + +Staging Branch: `deploy-staging` + +```bash +tree +. +├── bases # From Base Branch +│   ├── ... +├── deploy-staging # Staging deploy folder +│ └── us-west +│ └── kustomization.yaml # Uses bases: ["../../staging/us-west"] +├── prod # From Base Branch +│   └── ... +├── staging # From Base Branch +│   └── ... +└── test # From Base Branch + └── ... +``` + +Test Branch: `deploy-test` + +```bash +tree +. +├── bases # From Base Branch +│   ├── ... +├──deploy-test # Test deploy folder +│ └── us-west +│ └── kustomization.yaml # Uses bases: ["../../test/us-west"] +├── prod # From Base Branch +│   └── ... +├── staging # From Base Branch +│   └── ... +└── test # From Base Branch + └── ... +``` + +{% endmethod %} + +## Rollback Workflow Example + +Summary of rollback workflow with Branches: + +1. Live Prod App version is *v1* +1. Changes are introduced to Base Branch Config + - To be released with version *v2* +1. Release *v2* is cut to be rolled out + - Tag Base *v2* and build artifacts (e.g. images) +1. Changes are introduced into the Base Branch Confiug + - To be released with version *v3* +1. *v2* is pushed to Prod (eventually) + - *v2* Tag merged into Prod Branch +1. *v2* has issues in Prod and must be rolled back + - *v2* changes are rolled back in new commit to Prod Branch +1. Base Branch is unaffected + - Fix introduced in *v3* + +**Note:** New changes committed to the Base for "v3" did not make the rollback from +"v2" -> "v1" more challenging, as they had not been merged into the Prod Branch. + +### Diagram + +{% sequence width=1000 %} + +participant Base Branch as BB +participant Staging Branch as SB +participant Staging Clusters as SC +participant Prod Branch as PB +participant Prod Clusters as PC + +Note over SC: At v1 release +Note over PC: At v1 release +Note left of BB: Bob: App Dev +Note over BB: Bob Adds Flag (for v2) +Note over BB: Bob Tags v2 +Note over SB: Bob Releases v2 +BB-->SB: Merge v2 +SB-->SC: Deploy +Note over SC: At v2 release +Note over SB: Bob Adds another Flag (for v3) +Note over PB: Bob Releases v2 +BB-->PB: Merge v2 +PB-->PC: Deploy v2 +Note over PC: At v2 release +Note over BB,PC: Unrelated Prod Outage +Note left of PB: Alice: App SRE +Note over PB: Alice rolls back v2 merge commit +PB-->PC: Deploy v1 +Note over PC: At v1 release +Note over BB,PC: Prod Outage resolved + +{% endsequence %} diff --git a/docs/book/pages/app_composition_and_deployment/structure_directories.md b/docs/book/pages/app_composition_and_deployment/structure_directories.md new file mode 100644 index 00000000..faba6f2b --- /dev/null +++ b/docs/book/pages/app_composition_and_deployment/structure_directories.md @@ -0,0 +1,203 @@ +{% panel style="success", title="Providing Feedback" %} +**Provide feedback at the [survey](https://www.surveymonkey.com/r/JH35X82)** +{% endpanel %} + +{% panel style="warning", title="Experimental" %} +**Content in this chapter is experimental and will evolve based on user feedback.** + +Leave feedback on the conventions by creating an issue in the [kubectl](https://github.com/kubernetes/kubectl/issues) +GitHub repository. + +Also provide feedback on new kubectl docs at the [survey](https://www.surveymonkey.com/r/JH35X82) +{% endpanel %} + +{% panel style="info", title="TL;DR" %} +- Use **directory hierarchy to structure Resource Config** + - Separate directories for separate Environment and Cluster [Config Variants](../app_customization/bases_and_variants.md) +{% endpanel %} + +# Directory Structure Based Layout + +## Motivation + +{% panel style="success", title="Which is right for my organization?" %} +While this chapter is focused on conventions when using Directories, Branches and +Repositories should be used with Directories as needed. +{% endpanel %} + +{% panel style="info", title="Config Repo or Mono Repo?" %} +The techniques and conventions in this Chapter work regardless of whether or not the Resource Config +exists in the same Repository as the source code that is being deployed. +{% endpanel %} + +## Directory Structure + +| Dir Type | Deployed to a Cluster | Contains | Example Names | +|----------------|----------------------------------|----------|---------------| +| Base | **No** - Used as base | Shared Config. | `base/` | +| Env | **No** - Contains other dirs | Base and Cluster dirs. | `test/`, `staging/`, `prod/` | +| Cluster | **Yes** - Manually or Continuously | Deployable Config. | `us-west1`, `us-east1`, `us-central1` | + + +### Bases + +A Kustomize Base (e.g. `bases:`) provides shared Config that is customized by some consuming `kustomization.yaml`. + +The directory structure outlined in this chapter organizes Bases into a hierarchy as: +`app-bases/environment-bases/cluster` + +## Workflow Example + +- Changes made to *env/cluster/* roll out to **only that specific env-cluster** +- Changes made to *env>/bases/* roll out to **all clusters for that env** +- Changes made to *bases/* roll out to **all clusters in all envs** + +## Diagram + +```mermaid +graph TD; + B("bases/ ")---|base|P("prod/bases/ "); + B("bases/ ")---|base|S("staging/bases/ "); + B("bases/ ")---|base|T("test/bases/ "); + P("prod/bases/ ")---|base|PUW("prod/us-west/ "); + P("prod/bases/ ")---|base|PUE("prod/us-east/ "); + P("prod/bases/ ")---|base|PUC("prod/us-central/ "); + S("staging/bases/ ")---|base|SUW("staging/us-west/ "); + T("test/bases/ ")---|base|TUW("test/us-west/ "); +``` + +### Scenario + +1. Alice modifies prod/us-west1 with change A + - Change gets pushed to prod us-west1 cluster by continuous deployment +1. Alice modifies prod/bases with change B + - Change gets pushed to all prod clusters by continuous deployment +1. Alice modifies bases with change C + - Change gets pushed to all clusters by continuous deployment + +{% sequence width=1000 %} + +participant Config in Git as B +participant Test Cluster as TC +participant Staging Cluster as SC +participant US West Prod Cluster as WC +participant US East Prod Cluster as EC + +Note over B: Alice modifies prod/us-west1 with change A +B-->WC: A deployed + +Note over B: Alice modifies prod/bases with change B +B-->EC: B deployed +B-->WC: B deployed + +Note over B: Alice modifies bases/ with change C +B-->EC: C deployed +B-->TC: C deployed +B-->WC: C deployed +B-->SC: C deployed + +{% endsequence %} + +{% method %} + +Techniques: + +- Each Layer adds a [namePrefix](../app_management/namespaces_and_names.md#setting-a-name-prefix-or-suffix-for-all-resources) and [commonLabels](../app_management/labels_and_annotations.md#setting-labels-for-all-resources). +- Each Layer adds labels and annotations. +- Each deployable target sets a [namespace](../app_management/namespaces_and_names.md#setting-the-namespace-for-all-resources). +- Override [Pod Environment Variables and Arguments](../app_customization/customizing_pod_templates.md) using `configMapGenerator`s with `behavior: merge`. +- Perform Last-mile customizations with [patches / overlays](../app_customization/customizing_arbitrary_fields.md) + +Structure: + +- Put reusable bases under `*/bases/` + - `/bases/` + - `//bases/` +- Put deployable targets under `///` + +{% sample lang="yaml" %} + +```bash +tree +. +├── bases # Used as a Base only +│   ├── kustomization.yaml +│   ├── backend +│   │   ├── deployment.yaml +│   │   └── service.yaml +│   ├── frontend +│   │   ├── deployment.yaml +│   │   ├── ingress.yaml +│   │   └── service.yaml +│   └── storage +│   ├── service.yaml +│   └── statefulset.yaml +├── prod # Production +│   ├── bases +│   │   ├── kustomization.yaml # Uses bases: ["../../bases"] +│   │   ├── backend +│   │   │   └── deployment-patch.yaml # Production Env specific backend overrides +│   │   ├── frontend +│   │   │   └── deployment-patch.yaml # Production Env specific frontend overrides +│   │   └── storage +│   │   └── statefulset-patch.yaml # Production Env specific storage overrides +│   ├── us-central +│   │   ├── kustomization.yaml # Uses bases: ["../bases"] +│   │   └── backend +│   │   └── deployment-patch.yaml # us-central cluster specific backend overrides +│   ├── us-east +│   │   └── kustomization.yaml # Uses bases: ["../bases"] +│   └── us-west +│   └── kustomization.yaml # Uses bases: ["../bases"] +├── staging # Staging +│   ├── bases +│   │   ├── kustomization.yaml # Uses bases: ["../../bases"] +│   └── us-west +│   └── kustomization.yaml # Uses bases: ["../bases"] +└── test # Test + ├── bases + │   ├── kustomization.yaml # Uses bases: ["../../bases"] + └── us-west + └── kustomization.yaml # Uses bases: ["../bases"] +``` + +{% endmethod %} + +{% panel style="warning", title="Applying Environment + Cluster" %} +Though the directory structure contains the cluster in the path, this won't be used by +Apply to determine the cluster context. To Apply a specific cluster, add that cluster to the +kubectl config`, and specify the corresponding context when running Apply. + +For more information see [Multi-Cluster](accessing_multiple_clusters.md). +{% endpanel %} + +{% panel style="success", title="Code Owners" %} +Some git hosting services provide the concept of *Code Owners* for providing a finer grain permissions model. +*Code Owners* may be used to provide separate permissions for separate environments - e.g. dev, test, prod. +{% endpanel %} + +## Rollback Diagram + +{% sequence width=1000 %} + +participant Config in Git as B +participant Test Cluster as TC +participant Staging Cluster as SC +participant US West Prod Cluster as WC +participant US East Prod Cluster as EC + +Note over B: Bob modifies bases/ with change B +B-->EC: B deployed +B-->SC: B deployed +B-->WC: B deployed +Note over B,EC: Prod Outage caused by B +B-->TC: B deployed +Note over B: Bob rolls back bases/ git commits to A +B-->WC: A deployed +B-->TC: A deployed +B-->EC: A deployed +Note over B,EC: Prod Outage resolved +B-->SC: A deployed + + +{% endsequence %} \ No newline at end of file diff --git a/docs/book/pages/app_composition_and_deployment/structure_introduction.md b/docs/book/pages/app_composition_and_deployment/structure_introduction.md new file mode 100644 index 00000000..1676b28d --- /dev/null +++ b/docs/book/pages/app_composition_and_deployment/structure_introduction.md @@ -0,0 +1,43 @@ +{% panel style="success", title="Providing Feedback" %} +**Provide feedback at the [survey](https://www.surveymonkey.com/r/JH35X82)** +{% endpanel %} + +{% panel style="info", title="TL;DR" %} +- Resource Config is stored in one or more git repositories +- Directory hierarchy, git branches and git repositories may be used for loose coupling +{% endpanel %} + + +# Resource Config Structure + +The chapters in this section cover how to structure Resource Config using git. + +Users may start with a pure Directory Hierarchy approach, and later include Branches +and / or Repositories as part of the structure. + +## Background + +Terms: + +- *Bases:* provide **common or shared Resource Config to be factored out** that can be + imported into multiple projects. +- *Overlays and Customizations:* tailor **common or shared Resource Config to be modified** to + a specific application, environment or purpose. + +| Technique | Decouple Changes | Used For | Workflow | +|---------------------------------------------|-----------------------------|----------------------------------------------------|----------| +| [Directories](structure_directories.md) | NA | Foundational structure. | Changes are immediately propagated globally. | +| [Branches](structure_branches.md) | *Across Environments* | Promoting changes across Environments. | Changes are promoted across linear stages. | +| [Repositories](structure_repositories.md) | *Across Teams* | Fetching changes across config shared across Teams. | Changes are pulled by consumers (like upgrades). | + +Concepts: + +- Resource Config may be initially structured using only Directory Hierarchy for organization. + - Use Bases with Overlays / Customizations for factoring across Directories +- Different Deployment environments for the same app may be loosely coupled + - Use separate **Branches for separate environments**. + - Use Bases with Overlays / Customization for factoring across Branches +- Different Teams owning sharing Config may be loosely coupled + - Use separate **Repositories for separate teams**. + - Use Bases with Overlays / Customization for factoring across Repositories + diff --git a/docs/book/pages/app_composition_and_deployment/structure_multi_tier_apps.md b/docs/book/pages/app_composition_and_deployment/structure_multi_tier_apps.md new file mode 100644 index 00000000..744b35fa --- /dev/null +++ b/docs/book/pages/app_composition_and_deployment/structure_multi_tier_apps.md @@ -0,0 +1,354 @@ +{% panel style="success", title="Providing Feedback" %} +**Provide feedback at the [survey](https://www.surveymonkey.com/r/JH35X82)** +{% endpanel %} + +{% panel style="warning", title="Experimental" %} +**Content in this chapter is experimental and will evolve based on user feedback.** + +Leave feedback on the conventions by creating an issue in the [kubectl](https://github.com/kubernetes/kubectl/issues) +GitHub repository. + +Also provide feedback on new kubectl docs at the [survey](https://www.surveymonkey.com/r/JH35X82) +{% endpanel %} + +{% panel style="info", title="TL;DR" %} +- The same Base may be used multiple times for different Applications within the same project. +{% endpanel %} + +# Composition with Shared Bases + +## Motivation + +Users may want to reuse the **same base multiple times within the same Apply Project**. Examples: + +- Define a very generic base (e.g. "Java Application") used by multiple Applications within a Project. +- Define multiple Environments (e.g. Staging, Canary, Prod) within a Project. + +## Composition With A Shared Base + +```mermaid +graph TD; + B("B ")---|base|A1("A1 "); + B("B ")---|base|A2("A2 "); + A1("A1 ")---|base|C("A "); + A2("A2 ")---|base|C("A "); +``` + + +{% method %} +It is possible to reuse the same base multiple times within the same project by using a 3-tier +structure to compose multiple Variants of the base. + +1. Generic Base in a `kustomization.yaml`. +1. Variants of the Generic Base in multiple `kustomization.yaml`'s. +1. Compose Variants as Bases to a single `kustomization.yaml`. + +Each layer may add customizations and resources to the preceding layers. + +Generic Base Layer: **../base/java** + +- define the java app base Deployment +- define the java app base Service + +Variant Layers: **../app1/ + ../app2/** + +- inherit the generic base +- set a namePrefix +- set labels and selectors +- overlay an image on the base +- set the image tag + +Composition Layer: **kustomization.yaml** + +- compose the 2 apps as bases +- set the namespace for Resources in the project +- set a namePrefix for Resources in the project + +{% sample lang="yaml" %} +**Generic Base Layer:** + +```yaml +# base/java/kustomization.yaml +resources: +- deployment.yaml +- service.yaml +``` + +```yaml +# base/java/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: java + name: java +spec: + selector: + matchLabels: + app: java + template: + metadata: + labels: + app: java + spec: + containers: + - image: java + name: java + ports: + - containerPort: 8010 + livenessProbe: + httpGet: + path: /health + port: 8010 + initialDelaySeconds: 30 + timeoutSeconds: 1 + readinessProbe: + httpGet: + path: /ready + port: 8010 + initialDelaySeconds: 30 + timeoutSeconds: 1 +``` + +```yaml +# base/java/service.yaml +kind: Service +apiVersion: v1 +metadata: + name: java +spec: + selector: + app: app + ports: + - protocol: TCP + port: 8080 + targetPort: 8080 +``` + +**Variant Layers 1 and 2:** + +```yaml +# app1/kustomization.yaml +namePrefix: 1- +commonLabels: + app: app1 +bases: +- ../base/java +patchesStrategicMerge: +- overlay.yaml +images: + - name: myapp1 + newTag: v2 +``` + +```yaml +# app1/overlay.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: java +spec: + template: + spec: + containers: + - image: myapp1 + name: java +``` + +```yaml +# ../app2/kustomization.yaml +namePrefix: 2- +commonLabels: + app: app2 +bases: +- ../base/java +patchesStrategicMerge: +- overlay.yaml +images: + - name: myapp2 + newTag: v1 +``` + +```yaml +# app2/overlay.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: java +spec: + template: + spec: + containers: + - image: myapp2 + name: java +``` + +**Composition Layer:** + +```yaml +# kustomization.yaml +namePrefix: app- +namespace: app +bases: +- app1 +- app2 +``` + +{% endmethod %} + +{% method %} +**Result**: + +- 2 Deployments are created +- Each Deployment has a different images +- Each Deployment has different labels / selectors +- Each Deployment has a different name +- 2 Services are created +- Each Service has different selectors, matching the corresponding Deployment +- All Resource names share the same prefix +- All Resources share the same namespace + +**Summary** + +- Most of the complexity lives in the shared common base +- Cross Team or Cross Org conventions can be canonized in the common base +- Variations of the Base are much simpler and can modify pieces bespoke to the Variation - e.g. images, args, etc +- Variations may be Composed to form a Project where project-wide conventions are applied + +**Benefits** + +- Reduced maintenance through propagating updates to Base downstream +- Reduced complexity in Variations through separation of concerns + +{% sample lang="yaml" %} +**Applied:** + +```yaml +apiVersion: v1 +kind: Service +metadata: + # name has both app1 and project kustomization.yaml namePrefixes + name: app-1-java + # namespace updated by namespace in project kustomization.yaml + namespace: app + # labels updated by commonLabels in app1 kustomization.yaml + labels: + app: app1 +spec: + ports: + - port: 8080 + protocol: TCP + targetPort: 8080 + # selector updated by commonLabels in app1 kustomization.yaml + selector: + app: app1 +--- +apiVersion: v1 +kind: Service +metadata: + # name has both app2 and project kustomization.yaml namePrefixes + name: app-2-java + # namespace updated by namespace in project kustomization.yaml + namespace: app + # labels updated by commonLabels in app2 kustomization.yaml + labels: + app: app2 +spec: + ports: + - port: 8080 + protocol: TCP + targetPort: 8080 + # selector updated by commonLabels in app2 kustomization.yaml + selector: + app: app2 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + # namespace updated by namespace in project kustomization.yaml + namespace: app + # name has both app1 and project kustomization.yaml namePrefixes + name: app-1-java + # labels updated by commonLabels in app1 kustomization.yaml + labels: + app: app1 +spec: + # selector updated by commonLabels in app1 kustomization.yaml + selector: + matchLabels: + app: app1 + template: + metadata: + # labels updated by commonLabels in app1 kustomization.yaml + labels: + app: app1 + spec: + containers: + # Image is updated by Overlay + # ImageTag is updated by images in app1 kustomization.yaml + - image: myapp1:v2 + name: java + # ports and probes inherited from the base + ports: + - containerPort: 8010 + livenessProbe: + httpGet: + path: /health + port: 8010 + initialDelaySeconds: 30 + timeoutSeconds: 1 + readinessProbe: + httpGet: + path: /ready + port: 8010 + initialDelaySeconds: 30 + timeoutSeconds: 1 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + # namespace updated by namespace in project kustomization.yaml + namespace: app + # name has both app2 and project kustomization.yaml namePrefixes + name: app-2-java + # labels updated by commonLabels in app2 kustomization.yaml + labels: + app: app2 +spec: + # selector updated by commonLabels in app2 kustomization.yaml + selector: + matchLabels: + app: app2 + template: + metadata: + # labels updated by commonLabels in app2 kustomization.yaml + labels: + app: app2 + spec: + containers: + # Image is updated by Overlay + # ImageTag is updated by images in app2 kustomization.yaml + - image: myapp2:v1 + name: java + # ports and probes inherited from the base + ports: + - containerPort: 8010 + livenessProbe: + httpGet: + path: /health + port: 8010 + initialDelaySeconds: 30 + timeoutSeconds: 1 + readinessProbe: + httpGet: + path: /ready + port: 8010 + initialDelaySeconds: 30 + timeoutSeconds: 1 +``` +{% endmethod %} + +{% panel style="info", title="Use Cases" %} +- Defining Generic Per-Application Archetype Bases +- Composing multiple Projects pushed together into a meta-Project +{% endpanel %} diff --git a/docs/book/pages/app_composition_and_deployment/structure_repositories.md b/docs/book/pages/app_composition_and_deployment/structure_repositories.md new file mode 100644 index 00000000..046da598 --- /dev/null +++ b/docs/book/pages/app_composition_and_deployment/structure_repositories.md @@ -0,0 +1,121 @@ +{% panel style="success", title="Providing Feedback" %} +**Provide feedback at the [survey](https://www.surveymonkey.com/r/JH35X82)** +{% endpanel %} + +{% panel style="warning", title="Experimental" %} +**Content in this chapter is experimental and will evolve based on user feedback.** + +Leave feedback on the conventions by creating an issue in the [kubectl](https://github.com/kubernetes/kubectl/issues) +GitHub repository. + +Also provide feedback on new kubectl docs at the [survey](https://www.surveymonkey.com/r/JH35X82) +{% endpanel %} + + +{% panel style="info", title="TL;DR" %} +Decouple changes to Config owned by separate Teams. +{% endpanel %} + +# Repository Structure Based Layout + +## Motivation + +- **Isolation between teams** managing separate Environments + - Permissions +- **Fine grain control** over + - PRs + - Issues + - Projects + - Automation + +## Directory Structure + +### Resource Config + +| Repo Type | Deployed to a Cluster | Contains | Example Names | +|-----------------|------------------------------------|----------|---------------| +| Base | **No** - Used as Base | Config shared with other teams. | `platform` | +| App | **Yes** - Manually or Continuously | Deployable Config. | `guest-book` | + +Use with techniques described in [Directories](structure_directories.md) and [Branches](structure_branches.md) + +## Workflow Example + +1. Alice on the Java Platform team updates the Java Base used by other teams +1. Alice creates a Git Tag for the new release +1. Bob on the GuestBook App team switches to the new Java Base by updating the reference + +## Diagram + +### Scenario + +1. Alice modifies java Base Repo and tags it v2 + - Change doesn't get pushed anywhere yet +1. Bob modifies GuestBook App Repo to use v2 of the java Base + - Change gets pushed by continuous deployment + +{% sequence width=1000 %} + +participant Base Repo as BR +participant App Repo as AR +participant Cluster as C + +Note left of BR: Alice: Platform Dev +Note over BR: Alice modifies java Base +Note over BR: Alice tags java Base v2 +Note left of AR: Bob: App Dev +Note over AR: Uses java Base v1 +BR-->AR: Bob updates to reference Base v2 +Note over AR: Uses java Base v2 +AR-->C: java Base v2 changes deployed + +{% endsequence %} + + +{% method %} + +{% sample lang="yaml" %} + +Structure: + +- Platform teams create Base Repositories for shared Config +- App teams create App Repositories for their Apps + - Remotely reference the Base Repository + +**Base Repository:** Platform Team + +```bash +tree +. +├── bases # Used as a Base only +│   ├── kustomization.yaml +│   └── ... +├── java # Java Bases +│   ├── kustomization.yaml # Uses bases: ["../bases"] +│   └── ... +└── python # Python Bases +``` + +**App Repository:** GuestBook Team + +```bash +tree +. +├── bases # References Base Repositories +│   └── ... +├── prod +│   └── ... +├── staging +│   └── ... +└── test + └── ... +``` + +{% endmethod %} + +{% panel style="info", title="Remote URLs vs Vendoring" %} +- Repositories owned and controlled by the same organization may be referenced to by their URL +- Repositories owned or controlled by separate organizations should be vendored and referenced + by path to the vendor directory. +{% endpanel %} + diff --git a/docs/book/pages/app_customization/bases_and_variants.md b/docs/book/pages/app_customization/bases_and_variants.md new file mode 100644 index 00000000..c638449c --- /dev/null +++ b/docs/book/pages/app_customization/bases_and_variants.md @@ -0,0 +1,181 @@ +{% panel style="success", title="Providing Feedback" %} +**Provide feedback at the [survey](https://www.surveymonkey.com/r/C855WZW)** +{% endpanel %} + +{% panel style="info", title="TL;DR" %} +- Reuse Resource Config as Bases to `kustomization.yaml`'s. +- Customize Base for different Environments. +- Reuse a Base across multiple Projects. +{% endpanel %} + + + +# Bases and Variations + +## Motivation + +It is common for users to deploy several **Variants of the same Resource Config**, or for different projects +to **reuse the same Resource Config**. The Resource Config produced by a `kustomization.yaml` can be +reused across multiple project using the `kustomization.yaml` as a *Base*. + +Examples: + +- a project may be deployed to **dev, test, staging, canary and production environments**, + but with variants between the environments. +- a project may be deployed to **different clusters** that are tuned differently or running + different versions of the project. + +{% panel style="info", title="Reference" %} + - [bases](../reference/kustomize.md#bases) + {% endpanel %} + +## Bases + +Bases are shared Resource Config in a `kustomization.yaml` to be used and customized by another `kustomization.yaml`. + +Examples of Bases: + +- Common Java Base + - Used in multiple Apps (e.g. Guest Book, Calendar, Auth) +- Common Guest Book App Base + - Used in multiple Environments (e.g. Test, Staging, Prod) +- Common Prod Guest Book App Base + - Used in multiple clusters (e.g. us-west, us-east, us-canary) + +## Referring to a Base + +A project can add a Base by adding a path (relative to the `kustomization.yaml`) to **`base` that +points to a directory** containing another `kustomization.yaml` file. This will automatically +add and kustomize all of the Resources from the base project to the current project. + +Bases can be: + +- Relative paths from the `kustomization.yaml` - e.g. `../base` +- Urls - e.g. `github.com/kubernetes-sigs/kustomize/examples/multibases?ref=v1.0.6` + +### Diagrams + +Single Base inheritted by single Application + +```mermaid +graph TD; + B[B]-->A[A]; +``` + +Shared Bases inheritted by different Applications + +```mermaid +graph TD; + B1[B1]-->A1[A1]; + B2[B2]-->A1[A1]; + B2[B2]-->A2[A2]; + B3[B3]-->A2[A2]; +``` + + +{% method %} +**Example:** Add a `kustomization.yaml` as a Base. + +{% sample lang="yaml" %} +**Input:** The kustomization.yaml file + +```yaml +# kustomization.yaml +bases: +- ../base +``` + +**Base: kustomization.yaml and Resource Config** + +```yaml +# ../base/kustomization.yaml +configMapGenerator: +- name: my-java-server-env-vars + literals: + - JAVA_HOME=/opt/java/jdk + - JAVA_TOOL_OPTIONS=-agentlib:hprof +resources: +- deployment.yaml +``` + +```yaml +# ../base/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: nginx + name: nginx-deployment +spec: + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - image: nginx + name: nginx + volumeMounts: + - mountPath: /etc/config + name: config-volume + volumes: + - configMap: + name: my-java-server-env-vars + name: config-volume +``` + +**Applied:** The Resource that is Applied to the cluster + +```yaml +# Unmodified Generated Base Resource +apiVersion: v1 +kind: ConfigMap +metadata: + name: my-java-server-env-vars-k44mhd6h5f +data: + JAVA_HOME: /opt/java/jdk + JAVA_TOOL_OPTIONS: -agentlib:hprof +--- +# Unmodified Config Resource +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: nginx + name: nginx-deployment +spec: + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - image: nginx + name: nginx + volumeMounts: + - mountPath: /etc/config + name: config-volume + volumes: + - configMap: + name: my-java-server-env-vars-k44mhd6h5f + name: config-volume +``` +{% endmethod %} + +{% panel style="info", title="Bases in Bases" %} +Bases themselves may also be Variants and have their own Bases. See [Advanced Composition](../app_composition_and_deployment/structure_multi_tier_apps.md) +for more information. +{% endpanel %} + +```mermaid +graph TD; + B1[B1]-->B2[B2]; + B2[B2]-->A[A]; +``` + diff --git a/docs/book/pages/app_customization/config_reflection.md b/docs/book/pages/app_customization/config_reflection.md new file mode 100644 index 00000000..1bba32ad --- /dev/null +++ b/docs/book/pages/app_customization/config_reflection.md @@ -0,0 +1,149 @@ +{% panel style="success", title="Providing Feedback" %} +**Provide feedback at the [survey](https://www.surveymonkey.com/r/C855WZW)** +{% endpanel %} + +{% panel style="info", title="TL;DR" %} +- Inject the values of other Resource Config fields into Pod Env Vars and Command Args with `vars`. +{% endpanel %} + +# Config Reflection + +## Motivation + +Applications running in Pods may need to know about Application context or configuration. +For example, a **Pod may take the name of Service defined in the Project as a command argument**. +Instead of hard coding the value of the Service directly into the PodSpec, users can **reference +the Service value using a `vars` entry**. If the value is updated or transformed by the +`kustomization.yaml` file (e.g. by setting a `namePrefix`), the value will be propagated +to where it is referenced in the PodSpec. + +{% panel style="info", title="Reference" %} + - [vars](../reference/kustomize.md#var) + {% endpanel %} + +## Vars + +The `vars` section contains variable references to Resource Config fields within the project. They require +the following to be defined: + +- Resource Kind +- Resource Version +- Resource name +- Field path + +{% method %} + +**Example:** Set the Pod command argument to the value of a Service name. + +Apply will resolve `$(BACKEND_SERVICE_NAME)` to a value using the object reference +specified in `vars`. + +{% sample lang="yaml" %} +**Input:** The kustomization.yaml, deployment.yaml and service.yaml files + +```yaml +# kustomization.yaml +namePrefix: "test-" +vars: + # Name of the variable so it can be referenced +- name: BACKEND_SERVICE_NAME + # GVK of the object with the field + objref: + kind: Service + name: backend-service + apiVersion: v1 + # Path to the field + fieldref: + fieldpath: metadata.name +resources: +- deployment.yaml +- service.yaml +``` + +```yaml +# service.yaml +kind: Service +apiVersion: v1 +metadata: + # Value of the variable. This will be customized with + # a namePrefix, and change the Variable value. + name: backend-service +spec: + selector: + app: backend + ports: + - protocol: TCP + port: 80 + targetPort: 9376 +``` + +```yaml +# deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: curl-deployment + labels: + app: curl +spec: + selector: + matchLabels: + app: curl + template: + metadata: + labels: + app: curl + spec: + containers: + - name: curl + image: ubuntu + # Reference the Service name field value as a variable + command: ["curl", "$(BACKEND_SERVICE_NAME)"] +``` + +**Applied:** The Resources that are Applied to the cluster + +```yaml +apiVersion: v1 +kind: Service +metadata: + name: test-backend-service +spec: + ports: + - port: 80 + protocol: TCP + targetPort: 9376 + selector: + app: backend +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: test-curl-deployment + labels: + app: curl +spec: + selector: + matchLabels: + app: curl + template: + metadata: + labels: + app: curl + spec: + containers: + - command: + - curl + # $(BACKEND_SERVICE_NAME) has been resolved to + # test-backend-service + - test-backend-service + image: ubuntu + name: curl +``` +{% endmethod %} + +{% panel style="warning", title="Referencing Variables" %} +Variables are intended only to inject Resource Config into Pods. They are +**not** intended as a general templating mechanism. Overriding values should be done with +patches instead of variables. See [Bases and Variations](bases_and_variants.md). +{% endpanel %} diff --git a/docs/book/pages/app_customization/customizing_arbitrary_fields.md b/docs/book/pages/app_customization/customizing_arbitrary_fields.md new file mode 100644 index 00000000..00fc15dc --- /dev/null +++ b/docs/book/pages/app_customization/customizing_arbitrary_fields.md @@ -0,0 +1,235 @@ +{% panel style="success", title="Providing Feedback" %} +**Provide feedback at the [survey](https://www.surveymonkey.com/r/C855WZW)** +{% endpanel %} + +{% panel style="info", title="TL;DR" %} +- Customize arbitrary fields from arbitrary Resources in a Base. +{% endpanel %} + +# Customizing Resource Fields + +## Motivation + +It is often necessary for users to want to **modify arbitrary fields** from a Base, such +as resource reservations for Pods, replicas on Deployments, etc. Overlays and patches can +be used by Variants to specify fields values which will override the Base field values. + +{% panel style="info", title="Reference" %} +- [patchesjson6902](../reference/kustomize.md#patchesjson6902) +- [patchesStrategicMerge](../reference/kustomize.md#patchesstrategicmerge) +{% endpanel %} + +## Customizing Arbitrary Fields with Overlays + +{% method %} +Arbitrary **fields may be added, changed, or deleted** by supplying *Overlays* against the +Resources provided by the Base. **Overlays are sparse Resource definitions** that +allow arbitrary customizations to be performed without requiring a base to expose +the customization as a template. + +Overlays require the *Group, Version, Kind* and *Name* of the Resource to be specified, as +well as any fields that should be set on the base Resource. Overlays are applied using +*StrategicMergePatch*. + +**Use Case:** Different Environments (test, dev, staging, canary, prod) require fields such as +replicas or resources to be overridden. + +{% sample lang="yaml" %} +**Input:** The kustomization.yaml file and overlay + +```yaml +# kustomization.yaml +bases: +- ../base +patchesStrategicMerge: +- overlay.yaml +``` + +```yaml +# overlay.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment +spec: + # override replicas + replicas: 3 + template: + spec: + containers: + - name: nginx + # override resources + resources: + limits: + cpu: "1" + requests: + cpu: "0.5" +``` + +**Base:** + +```yaml +# ../base/kustomization.yaml +resources: +- deployment.yaml +``` + +```yaml +# ../base/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: nginx + name: nginx-deployment +spec: + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - image: nginx + name: nginx + resources: + limits: + cpu: "0.2" + requests: + cpu: "0.1" +``` + +**Applied:** The Resource that is Applied to the cluster + +```yaml +# Overlayed Base Resource +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: nginx + name: nginx-deployment +spec: + # replicas field has been added + replicas: 3 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - image: nginx + name: nginx + # resources have been overridden + resources: + limits: + cpu: "1" + requests: + cpu: "0.5" +``` + +{% endmethod %} + +{% panel style="info", title="Merge Semantics for Overlays" %} +Overlays use the same [merge semantics](../app_management/field_merge_semantics.md) as Applying Resource Config to cluster. One difference +is that there is no *Last Applied Resource Config* when merging overlays, so fields may only be deleted +if they are explicitly set to nil. +{% endpanel %} + +## Customizing Arbitrary Fields with JsonPatch + +{% method %} +Arbitrary fields may be added, changed, or deleted by supplying *JSON Patches* against the +Resources provided by the base. + +**Use Case:** Different Environments (test, dev, staging, canary, prod) require fields such as +replicas or resources to be overridden. + +JSON Patches are [RFC 6902](https://tools.ietf.org/html/rfc6902) patches that are applied +to resources. Patches require the *Group, Version, Kind* and *Name* of the Resource to be +specified in addition to the Patch. Patches offer a number of powerful imperative operations +for modifying the base Resources. + +{% sample lang="yaml" %} +**Input:** The kustomization.yaml file + +```yaml +# kustomization.yaml +bases: +- ../base +patchesJson6902: +- target: + group: apps + version: v1 + kind: Deployment + name: nginx-deployment + path: patch.yaml +``` + +```yaml +# patch.yaml +- op: add + path: /spec/replicas + value: 3 +``` + +```yaml +# ../base/kustomization.yaml +resources: +- deployment.yaml +``` + +```yaml +# ../base/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: nginx + name: nginx-deployment +spec: + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - image: nginx + name: nginx +``` + +**Applied:** The Resource that is Applied to the cluster + +```yaml +# Patched Base Resource +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: nginx + name: nginx-deployment +spec: + # replicas field has been added + replicas: 3 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - image: nginx + name: nginx +``` + +{% endmethod %} diff --git a/docs/book/pages/app_customization/customizing_metadata.md b/docs/book/pages/app_customization/customizing_metadata.md new file mode 100644 index 00000000..edb9ffc2 --- /dev/null +++ b/docs/book/pages/app_customization/customizing_metadata.md @@ -0,0 +1,281 @@ +{% panel style="success", title="Providing Feedback" %} +**Provide feedback at the [survey](https://www.surveymonkey.com/r/C855WZW)** +{% endpanel %} + +{% panel style="info", title="TL;DR" %} +- Customize Base Resource Namespaces +- Customize Base Resource Names with Prefixes or Suffixes +- Customize Base Resource Labels or Annotations +{% endpanel %} + +# Customizing Resource Metadata + +## Motivation + +It is common for users to customize the metadata of their Applications - including +the **names, namespaces, labels and annotations**. + +Examples: + +- Overriding the Namespace +- Overriding the Names of Resources by supplying a Prefix or Suffix +- Overriding Labels and Annotations +- Running **multiple instances of the same White-Box Base** using the above techniques + + {% panel style="info", title="Reference" %} + - [namespace](../reference/kustomize.md#namespace) + - [namePrefix](../reference/kustomize.md#nameprefix) + - [nameSuffix](../reference/kustomize.md#namesuffix) + {% endpanel %} + +## Customizing Resource Namespaces + +{% method %} +**Use Case:** +- Change the Namespace for Resources from Base. + +Customize the Namespace of all Resources in the Base by adding `namespace`. + +{% sample lang="yaml" %} +**Input:** The kustomization.yaml file + +```yaml +# kustomization.yaml +bases: +- ../base +namespace: test +``` + +**Base:** + +```yaml +# ../base/kustomization.yaml +resources: +- deployment.yaml +``` + +```yaml +# ../base/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: nginx + name: nginx-deployment + namespace: default +spec: + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - image: nginx + name: nginx +``` + +**Applied:** The Resource that is Applied to the cluster + +```yaml +# Modified Base Resource +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: nginx + name: nginx-deployment + # Namepace has been changed to test + namespace: test +spec: + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - image: nginx + name: nginx +``` + +{% endmethod %} + +## Customizing Resource Name Prefixes and Suffixes + +{% method %} +**Use Case:** +- Run multiple instances of the same Base. +- Create naming conventions for different Environments (test, dev, staging, canary, prod). + +Customize the Name of all Resources in the Base by adding `namePrefix` or `nameSuffix` in Variants. + +{% sample lang="yaml" %} +**Input:** The kustomization.yaml file + +```yaml +# kustomization.yaml +bases: +- ../base +namePrefix: test- +``` + +**Base:** + +```yaml +# ../base/kustomization.yaml +resources: +- deployment.yaml +``` + +```yaml +# ../base/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: nginx + name: nginx-deployment +spec: + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - image: nginx + name: nginx +``` + +**Applied:** The Resource that is Applied to the cluster + +```yaml +# Modified Base Resource +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: nginx + # Name has been prefixed with the environment + name: test-nginx-deployment +spec: + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - image: nginx + name: nginx +``` + +{% endmethod %} + +See [Namespaces and Names](../app_management/namespaces_and_names.md). + +{% panel style="success", title="Chaining Name Prefixes" %} +Name Prefix's and Suffix's in Bases will be concatenated with Name Prefix's +and Suffix's specified in Variants - e.g. if a Base has a Name Prefix of `app-name-` +and the Variant has a Name Prefix of `test-` the Applied Resources will have +a Name Prefix of `test-app-name-`. +{% endpanel %} + +## Customizing Resource Labels and Annotations + +{% method %} +**Use Case:** +- Create Label or Annotation conventions for different Environments (test, dev, staging, canary, prod). + +Customize the Labels and Annotations of all Resources in the Base by adding a +`commonLabels` or `commonAnnotations` in the variants. + +{% sample lang="yaml" %} +**Input:** The kustomization.yaml file + +```yaml +# kustomization.yaml +bases: +- ../base +commonLabels: + app: test-nginx + environment: test +commonAnnotations: + oncallPager: 800-555-1212 +``` + +**Base:** + +```yaml +# ../base/kustomization.yaml +resources: +- deployment.yaml +``` + +```yaml +# ../base/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: nginx + base: label + name: nginx-deployment +spec: + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - image: nginx + name: nginx +``` + +**Applied:** The Resource that is Applied to the cluster + +```yaml +# Modified Base Resource +apiVersion: apps/v1 +kind: Deployment +metadata: + # labels have been overridden + labels: + app: test-nginx + environment: test + base: label + # annotations have been overridden + annotations: + oncallPager: 800-555-1212 + name: nginx-deployment +spec: + selector: + matchLabels: + app: test-nginx + environment: test + base: label + template: + metadata: + labels: + app: test-nginx + environment: test + base: label + spec: + containers: + - image: nginx + name: nginx +``` + +{% endmethod %} \ No newline at end of file diff --git a/docs/book/pages/app_customization/customizing_pod_templates.md b/docs/book/pages/app_customization/customizing_pod_templates.md new file mode 100644 index 00000000..4b463755 --- /dev/null +++ b/docs/book/pages/app_customization/customizing_pod_templates.md @@ -0,0 +1,357 @@ +{% panel style="success", title="Providing Feedback" %} +**Provide feedback at the [survey](https://www.surveymonkey.com/r/C855WZW)** +{% endpanel %} + +{% panel style="info", title="TL;DR" %} +- Override Base Pod and PodTemplate Image **Names** and **Tags** +- Override Base Pod and PodTemplate Environment Variables and Arguments +{% endpanel %} + +# Customizing Pods + +## Motivation + +It is common for users to customize their Applications for specific environments. +Simple customizations to Pod Templates may be through **Images, Environment Variables and +Command Line Arguments**. + +Common examples include: + +- Running **different versions of an Image** for dev, test, canary, production +- Configuring **different Pod Environment Variables and Arguments** for dev, test, canary, production + +{% panel style="info", title="Reference" %} +- [images](../reference/kustomize.md#images) +- [configMapGenerator](../reference/kustomize.md#configmapgenerator) +- [secretGenerator](../reference/kustomize.md#secretgenerator) +{% endpanel %} + +## Customizing Images + +{% method %} +**Use Case:** Different Environments (test, dev, staging, canary, prod) use images with different tags. + +Override the name or tag for an `image` field from a [Pod Template](https://kubernetes.io/docs/concepts/workloads/pods/pod-overview/#pod-templates) +in a base by specifying the `images` field in the `kustomization.yaml`. + +| Field | Description | Example Field | Example Result | +|-----------|--------------------------------------------------------------------------|----------| --- | +| `name` | Match images with this image name| `name: nginx`| | +| `newTag` | Override the image **tag** or **digest** for images whose image name matches `name` | `newTag: new` | `nginx:old` -> `nginx:new` | +| `newName` | Override the image **name** for images whose image name matches `name` | `newImage: nginx-special` | `nginx:old` -> `nginx-special:old` | + +{% sample lang="yaml" %} +**Input:** The `kustomization.yaml` file + +```yaml +# kustomization.yaml +bases: +- ../base +images: + - name: nginx-pod + newTag: 1.15 + newName: nginx-pod-2 +``` + +**Base:** Resources to be modified by the `kustomization.yaml` + +```yaml +# ../base/kustomization.yaml +resources: +- deployment.yaml +``` + +```yaml +# ../base/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment + labels: + app: nginx +spec: + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx-pod +``` + +**Applied:** The Resource that is Applied to the cluster + +```yaml +# Modified Base Resource +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: nginx + name: nginx-deployment +spec: + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + # The image image tag has been changed for the container + - name: nginx + image: nginx-pod-2:1.15 +``` +{% endmethod %} + + +{% panel style="info", title="Replacing Images" %} +`newImage` allows an image name to be replaced with another arbitrary image name. e.g. you could +call your image `webserver` or `database` and replace it with `nginx` or `mysql`. + +For more information on customizing images, see [Container Images](../app_management/container_images.md). +{% endpanel %} + +## Customizing Pod Environment Variables + +{% method %} + +**Use Case:** Different Environments (test, dev, staging, canary, prod) are configured with +different Environment Variables. + +Override Pod Environment Variables. + +- Base uses ConfigMap data in Pods as Environment Variables +- Each Variant overrides or extends ConfigMap data + +{% sample lang="yaml" %} +**Input:** The kustomization.yaml file + +```yaml +# kustomization.yaml +bases: +- ../base +configMapGenerator: +- name: special-config + behavior: merge + literals: + - special.how=very # override the base value + - special.type=charm # add a value to the base +``` + +**Base: kustomization.yaml and Resources** + +```yaml +# ../base/kustomization.yaml +resources: +- deployment.yaml +configMapGenerator: +- name: special-config + behavior: merge + literals: + - special.how=some # this value is overridden + - special.other=that # this value is added +``` + +```yaml +# ../base/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment + labels: + app: nginx +spec: + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx + envFrom: + - configMapRef: + name: special-config +``` + +**Applied:** The Resources that are Applied to the cluster + +```yaml +# Generated Variant Resource +apiVersion: v1 +kind: ConfigMap +metadata: + name: special-config-82tc88cmcg +data: + special.how: very + special.type: charm + special.other: that +--- +# Unmodified Base Resource +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: nginx + name: nginx-deployment +spec: + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx + envFrom: + # Container env will have the overridden ConfigMap values + - configMapRef: + name: special-config-82tc88cmcg +``` +{% endmethod %} + +See [ConfigMaps and Secrets](../app_management/secrets_and_configmaps.md). + + +## Customizing Pod Command Arguments + +{% method %} +**Use Case:** Different Environments (test, dev, staging, canary, prod) provide different Commandline +Arguments to a Pod. + +Override Pod Command Arguments. + +- Base uses ConfigMap data in Pods as Command Arguments +- Each Variant defines different ConfigMap data + +{% sample lang="yaml" %} +**Input:** The kustomization.yaml file + +```yaml +# kustomization.yaml +bases: +- ../base +configMapGenerator: +- name: special-config + behavior: merge + literals: + - SPECIAL_LEVEL=very + - SPECIAL_TYPE=charm +``` + +```yaml +# ../base/kustomization.yaml +resources: +- deployment.yaml + +configMapGenerator: +- name: special-config + literals: + - SPECIAL_LEVEL=override.me + - SPECIAL_TYPE=override.me +``` + +```yaml +# ../base/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment + labels: + app: nginx +spec: + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: test-container + image: k8s.gcr.io/busybox + command: [ "/bin/sh" ] + # Use the ConfigMap Environment Variables in the Command + args: ["-c", "echo $(SPECIAL_LEVEL_KEY) $(SPECIAL_TYPE_KEY)" ] + env: + - name: SPECIAL_LEVEL_KEY + valueFrom: + configMapKeyRef: + name: special-config + key: SPECIAL_LEVEL + - name: SPECIAL_TYPE_KEY + valueFrom: + configMapKeyRef: + name: special-config + key: SPECIAL_TYPE +``` + +**Applied:** The Resources that are Applied to the cluster + +```yaml +# Generated Variant Resource +apiVersion: v1 +kind: ConfigMap +metadata: + name: special-config-82tc88cmcg +data: + SPECIAL_LEVEL: very + SPECIAL_TYPE: charm +--- +# Unmodified Base Resource +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: nginx + name: nginx-deployment +spec: + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - image: k8s.gcr.io/busybox + name: test-container + command: + - /bin/sh + args: + - -c + # Container args will have the overridden ConfigMap values + - echo $(SPECIAL_LEVEL_KEY) $(SPECIAL_TYPE_KEY) + env: + - name: SPECIAL_LEVEL_KEY + valueFrom: + configMapKeyRef: + key: SPECIAL_LEVEL + name: special-config-82tc88cmcg + - name: SPECIAL_TYPE_KEY + valueFrom: + configMapKeyRef: + key: SPECIAL_TYPE + name: special-config-82tc88cmcg +``` + +{% endmethod %} + +{% panel style="info", title="More Info" %} +See [Secrets and ConfigMaps](../app_management/secrets_and_configmaps.md) for more information on ConfigMap and Secret generation. +{% endpanel %} + diff --git a/docs/book/pages/app_customization/introduction.md b/docs/book/pages/app_customization/introduction.md new file mode 100644 index 00000000..12082df0 --- /dev/null +++ b/docs/book/pages/app_customization/introduction.md @@ -0,0 +1,16 @@ +{% panel style="success", title="Providing Feedback" %} +**Provide feedback at the [survey](https://www.surveymonkey.com/r/C855WZW)** +{% endpanel %} + +# Introduction + +This section of the book covers how to build Projects and Applications with Config +shared across teams. Apply kustomizations allow the authoring of Resource Config to +be a collaboration across teams. + +Kustomizations facilitate: + +- Developing Variations of Resource Config for multiple Environments with different configurations +- Developing Variations of Resource Config for multiple Clusters with different configurations +- Developing and Publishing Ready-Made Resource Config for users to extend and customize +- Composing Resource Config from multiple sources diff --git a/docs/book/pages/app_management/apply.md b/docs/book/pages/app_management/apply.md new file mode 100644 index 00000000..36fcbb3d --- /dev/null +++ b/docs/book/pages/app_management/apply.md @@ -0,0 +1,152 @@ +{% panel style="success", title="Providing Feedback" %} +**Provide feedback at the [survey](https://www.surveymonkey.com/r/CLQBQHR)** +{% endpanel %} + +{% panel style="info", title="TL;DR" %} +- Apply Creates and Updates Resources in a cluster through running `kubectl apply` on Resource Config. +- Apply manages complexity such as ordering of operations and merging user defined and cluster defined state. +{% endpanel %} + +# Apply + +## Motivation + +Apply is a command that will update a Kubernetes cluster to match state defined locally in files. + +```bash +kubectl apply +``` + +- Fully declarative - don't need to specify create or update - just manage files +- Merges user owned state (e.g. Service `selector`) with state owned by the cluster (e.g. Service `clusterIp`) + +## Definitions + +- **Resources**: *Objects* in a cluster - e.g. Deployments, Services, etc. +- **Resource Config**: *Files* declaring the desired state for Resources - e.g. deployment.yaml. + Resources are created and updated using Apply with these files. + +*kubectl apply* Creates and Updates Resources through local or remote files. This may be through +either raw Resource Config or *kustomization.yaml*. + +## Usage + +{% method %} + +Though Apply can be run directly against Resource Config files or directories using `-f`, it is recommended +to run Apply against a `kustomization.yaml` using `-k`. The `kustomization.yaml` allows users to define +configuration that cuts across many Resources (e.g. namespace). + +{% sample lang="yaml" %} + +```yaml +# kustomization.yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +# list of Resource Config to be Applied +resources: +- deployment.yaml + +# namespace to deploy all Resources to +namespace: default + +# labels added to all Resources +commonLabels: + app: example + env: test +``` + +```yaml +# deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx + labels: + component: nginx + tier: frontend +spec: + selector: + matchLabels: + component: nginx + tier: frontend + template: + metadata: + labels: + component: nginx + tier: frontend + spec: + containers: + - name: nginx + image: nginx:1.15.4 +``` + +{% endmethod %} + +{% method %} +Users run Apply on directories containing `kustomization.yaml` files using `-k` or on raw +ResourceConfig files using `-f`. + +{% sample lang="yaml" %} +```bash +# Apply the Resource Config +kubectl apply -k . + +# View the Resources +kubectl get -k . +``` +{% endmethod %} + +{% panel style="info", title="Multi-Resource Configs" %} +A single Resource Config file may declare multiple Resources separated by `\n---\n`. +{% endpanel %} + +## CRUD Operations + +### Creating Resources + +Any Resources that do not exist and are declared in Resource Config when Apply is run will be Created. + +### Updating Resources + +Any Resources that already exist and are declared in Resource Config when Apply is run may be Updated. + +**Added Fields** + +Any fields that have been added to the Resource Config will be set on the Resource. + +**Updated Fields** + +Any fields that contain different values for the fields specified locally in the Resource Config from what is +in the Resource will be updated by merging the Resource Config into the live Resource. See [merging](field_merge_semantics.md) +for more details. + +**Deleted Fields** + +Fields that were in the Resource Config the last time Apply was run, will be deleted from the Resource, and +return to their default values. + +**Unmanaged Fields** + +Fields that were not specified in the Resource Config but are set on the Resource will be left unmodified. + +### Deleting Resources + +Declarative deletion of Resources does not yet exist in a usable form, but is under development. + +{% panel style="info", title="Continuously Applying The Hard Way" %} +In some cases, it may be useful to automatically Apply changes when ever the Resource Config is changed. + +This example uses the unix `watch` command to periodically invoke Apply against a target. +`watch -n 60 kubectl apply -k https://github.com/myorg/myrepo` + +{% endpanel %} + +## Resource Creation Ordering + +Certain Resource Types may be dependent on other Resource Types being created first. e.g. Namespaced +Resources on the Namespaces, RoleBindings on Roles, CustomResources on the CRDs, etc. + +When used with a `kustomization.yaml`, Apply sorts the Resources by Resource type to ensure Resources +with these dependencies are created in the correct order. diff --git a/docs/book/pages/app_management/container_images.md b/docs/book/pages/app_management/container_images.md new file mode 100644 index 00000000..13437210 --- /dev/null +++ b/docs/book/pages/app_management/container_images.md @@ -0,0 +1,202 @@ +{% panel style="success", title="Providing Feedback" %} +**Provide feedback at the [survey](https://www.surveymonkey.com/r/CLQBQHR)** +{% endpanel %} + +{% panel style="info", title="TL;DR" %} +- Override or set the Name and Tag for Container Images +{% endpanel %} + +# Container Images + +## Motivation + +It may be useful to define the tags or digests of container images which are used across many Workloads. + +Container image tags and digests are used to refer to a specific version or instance of a container +image - e.g. for the `nginx` container image you might use the tag `1.15.9` or `1.14.2`. + +- Update the container image name or tag for multiple Workloads at once +- Increase visibility of the versions of container images being used within + the project +- Set the image tag from external sources - such as environment variables +- Copy or Fork an existing Project and change the Image Tag for a container +- Change the registry used for an image + +See [Bases and Variations](../app_customization/bases_and_variants.md) for more details on Copying Projects. + +{% panel style="info", title="Reference" %} +- [images](../reference/kustomize.md#images) +{% endpanel %} + +## images + +It is possible to set image tags for container images through +the `kustomization.yaml` using the `images` field. When `images` are +specified, Apply will override the images whose image name matches `name` with a new +tag. + + +| Field | Description | Example Field | Example Result | +|-----------|--------------------------------------------------------------------------|----------| --- | +| `name` | Match images with this image name| `name: nginx`| | +| `newTag` | Override the image **tag** or **digest** for images whose image name matches `name` | `newTag: new` | `nginx:old` -> `nginx:new` | +| `newName` | Override the image **name** for images whose image name matches `name` | `newImage: nginx-special` | `nginx:old` -> `nginx-special:old` | + +{% method %} + +**Example:** Use `images` in the `kustomization.yaml` to update the container +images in `deployment.yaml` + +Apply will set the `nginx` image to have the tag `1.8.0` - e.g. `nginx:1.8.0` and +change the image name to `nginx-special`. +This will set the name and tag for *all* images matching the *name*. + +{% sample lang="yaml" %} +**Input:** The kustomization.yaml and deployment.yaml files + +```yaml +# kustomization.yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +images: + - name: nginx # match images with this name + newTag: 1.8.0 # override the tag + newName: nginx-special # override the name +resources: +- deployment.yaml +``` + +```yaml +# deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment + labels: + app: nginx +spec: + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx +``` + +**Applied:** The Resource that is Applied to the cluster + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: nginx + name: nginx-deployment +spec: + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + # The image has been changed + - image: nginx-special:1.8.0 + name: nginx +``` +{% endmethod %} + + +## Setting a Name + +{% method %} +The name for an image may be set by specifying `newName` and the name of the old container image. +{% sample lang="yaml" %} +```yaml +# kustomization.yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +images: + - name: mycontainerregistry/myimage + newName: differentregistry/myimage +``` +{% endmethod %} + +## Setting a Tag + +{% method %} +The tag for an image may be set by specifying `newTag` and the name of the container image. +{% sample lang="yaml" %} +```yaml +# kustomization.yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +images: + - name: mycontainerregistry/myimage + newTag: v1 +``` +{% endmethod %} + +## Setting a Digest + +{% method %} +The digest for an image may be set by specifying `digest` and the name of the container image. +{% sample lang="yaml" %} +```yaml +# kustomization.yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +images: + - name: alpine + digest: sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3 +``` +{% endmethod %} + + +## Setting a Tag from the latest commit SHA + +{% method %} +A common CI/CD pattern is to tag container images with the git commit SHA of source code. e.g. if +the image name is `foo` and an image was built for the source code at commit `1bb359ccce344ca5d263cd257958ea035c978fd3` +then the container image would be `foo:1bb359ccce344ca5d263cd257958ea035c978fd3`. + +A simple way to push an image that was just built without manually updating the image tags is to +download the [kustomize standalone](https://github.com/kubernetes-sigs/kustomize/) tool and run +`kustomize edit set imagetag` command to update the tags for you. + +**Example:** Set the latest git commit SHA as the image tag for `foo` images. + +{% sample lang="yaml" %} +```bash +kustomize edit set imagetag foo:$(git log -n 1 --pretty=format:"%H") +kubectl apply -f . +``` +{% endmethod %} + +## Setting a Tag from an Environment Variable + +{% method %} +It is also possible to set a Tag from an environment variable using the same technique for setting from a commit SHA. + +**Example:** Set the tag for the `foo` image to the value in the environment variable `FOO_IMAGE_TAG`. + +{% sample lang="yaml" %} +```bash +kustomize edit set image foo:$FOO_IMAGE_TAG +kubectl apply -f . +``` +{% endmethod %} + +{% panel style="info", title="Committing Image Tag Updates" %} +The `kustomization.yaml` changes *may* be committed back to git so that they +can be audited. When committing the image tag updates that have already +been pushed by a CI/CD system, be careful not to trigger new builds + +deployments for these changes. +{% endpanel %} diff --git a/docs/book/pages/app_management/field_merge_semantics.md b/docs/book/pages/app_management/field_merge_semantics.md new file mode 100644 index 00000000..5b7737af --- /dev/null +++ b/docs/book/pages/app_management/field_merge_semantics.md @@ -0,0 +1,481 @@ +{% panel style="success", title="Providing Feedback" %} +**Provide feedback at the [survey](https://www.surveymonkey.com/r/CLQBQHR)** +{% endpanel %} + +{% panel style="info", title="TL;DR" %} +- Fields set and deleted from Resource Config are merged into Resources by Apply + - If a Resource already exists, Apply updates the Resources by merging the local Resource Config into the remote Resources + - Fields removed from the Resource Config will be deleted from the remote Resource +{% endpanel %} + +# Merging Fields + +{% panel style="warning", title="Advanced Section" %} +This chapter contains advanced material that readers may want to skip and come back to later. +{% endpanel %} + +## When are fields merged? + +This page describes how Resource Config is merged with Resources or other Resource Config. This +may occur when: + +- Applying Resource Config updates to the live Resources in the cluster +- Defining Patches in the `kustomization.yaml` which are overlayed on `resources` and [bases](../app_customization/bases_and_variants.md) + +### Applying Resource Config Updates + +Rather than replacing the Resource with the new Resource Config, **Apply will merge the new Resource Config +into the live Resource**. This retains values which may be set by the control plane - such as `replicas` values +set by auto scalers + +### Defining Patches + +`patches` are sparse Resource Config which **contain a subset of fields that override values +defined in other Resource Config** with the same Group/Version/Kind/Namespace/Name. +This is used to alter values defined on Resource Config without having to fork it. + +## Motivation (Apply) + +This page describes the semantics for merging Resource Config. + +Ownership of Resource fields are shared between declarative Resource Config authored by human +users, and values set by Controllers running in the cluster. Some fields, such as the `status` +and `clusterIp` fields, are owned exclusively by Controllers. Fields, such as the `name` +and `namespace` fields, are owned exclusively by the human user managing the Resource. + +Other fields, such as `replicas`, may be owned by either human users, the apiserver or +Controllers. For example, `replicas` may be explicitly set by a user, implicitly set +to a default value by the apiserver, or continuously adjusted by a Controller such as +and HorizontalPodAutoscaler. + +{% method %} +### Last Applied Resource Config + +When Apply creates or updates a Resource, it writes the Resource Config it Applied to an annotation on the +Resource. This allows it to compare the last Resource Config it Applied to the current Resource +Config and identify fields that have been deleted. +{% sample lang="yaml" %} + +```yaml +# deployment.yaml (Resource Config) +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment +spec: + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.7.9 +``` + +```yaml +# Original Resource +Doesn't Exist +``` + +```yaml +# Applied Resource +kind: Deployment +metadata: + annotations: + # ... + # This is the deployment.yaml Resource Config written as an annotation on the object + # It was written by kubectl apply when the object was created + kubectl.kubernetes.io/last-applied-configuration: | + {"apiVersion":"apps/v1","kind":"Deployment", + "metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"}, + "spec":{"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}}, + "spec":{"containers":[{"image":"nginx:1.7.9","name":"nginx"}]}}}} + # ... +spec: + # ... +status: + # ... + +``` + +{% endmethod %} + +## Merging Resources + +Following are the merge semantics for Resources: + +{% method %} +**Adding Fields:** + +- Fields present in the Resource Config that are missing from the Resource will be added to the + Resource. +- Fields will be added to the Last Applied Resource Config +{% sample lang="yaml" %} + +```yaml +# deployment.yaml (Resource Config) +apiVersion: apps/v1 +kind: Deployment +metadata: + # ... + name: nginx-deployment +spec: + # ... + minReadySeconds: 3 +``` + +```yaml +# Original Resource +kind: Deployment +metadata: + # ... + name: nginx-deployment +spec: + # ... +status: + # ... +``` + +```yaml +# Applied Resource +kind: Deployment +metadata: + # ... + name: nginx-deployment +spec: + # ... + minReadySeconds: 3 +status: + # ... +``` +{% endmethod %} + +{% method %} +**Updating Fields** + +- Fields present in the Resource Config that are also present in the Resource will be merged recursively + until a primitive field is updated, or a field is added / deleted. +- Fields will be updated in the Last Applied Resource Config +{% sample lang="yaml" %} + +```yaml +# deployment.yaml (Resource Config) +apiVersion: apps/v1 +kind: Deployment +metadata: + # ... + name: nginx-deployment +spec: + # ... + replicas: 2 +``` + +```yaml +# Original Resource +kind: Deployment +metadata: + # ... + name: nginx-deployment +spec: + # ... + # could be defaulted or set by Resource Config + replicas: 1 +status: + # ... +``` + +```yaml +# Applied Resource +kind: Deployment +metadata: + # ... + name: nginx-deployment +spec: + # ... + # updated + replicas: 2 +status: + # ... +``` +{% endmethod %} + +{% method %} +**Deleting Fields** + +- Fields present in the **Last Applied Resource Config** that have been removed from the Resource Config + will be deleted from the Resource. +- Fields set to *null* in the Resource Config that are present in the Resource Config will be deleted from the + Resource. +- Fields will be removed from the Last Applied Resource Config + +{% sample lang="yaml" %} + +```yaml +# deployment.yaml (Resource Config) +apiVersion: apps/v1 +kind: Deployment +metadata: + # ... + name: nginx-deployment +spec: + # ... +``` + +```yaml +# Original Resource +kind: Deployment +metadata: + # ... + name: nginx-deployment + # Containers replicas and minReadySeconds + kubectl.kubernetes.io/last-applied-configuration: | + {"apiVersion":"apps/v1","kind":"Deployment", "spec":{"replicas": "2", "minReadySeconds": "3", ...}, "metadata": {...}} +spec: + # ... + minReadySeconds: 3 + replicas: 2 +status: + # ... +``` + +```yaml +# Applied Resource +kind: Deployment +metadata: + # ... + name: nginx-deployment + kubectl.kubernetes.io/last-applied-configuration: | + {"apiVersion":"apps/v1","kind":"Deployment", "spec":{...}, "metadata": {...}} +spec: + # ... + # deleted and then defaulted, but not in Last Applied + replicas: 1 + # minReadySeconds deleted +status: + # ... +``` +{% endmethod %} + +{% panel style="danger", title="Removing Fields from Resource Config" %} +Simply removing a field from the Resource Config will *not* transfer the ownership to the cluster. +Instead it will delete the field from the Resource. If a field is set in the Resource Config and +the user wants to give up ownership (e.g. removing `replicas` from the Resource Config and using +and autoscaler), the user must first remove it from the last Applied Resource Config stored by the +cluster. + +This can be performed using `kubectl apply edit-last-applied` to delete the `replicas` field from +the **Last Applied Resource Config**, and then deleting it from the **Resource Config.** +{% endpanel %} + +## Field Merge Semantics + +### Merging Primitives + +Primitive fields are merged by replacing the current value with the new value. + +**Field Creation:** Add the primitive field + +**Field Update:** Change the primitive field value + +**Field Deletion:** Delete the primitive field + +| Field in Resource Config | Field in Resource | Field in Last Applied | Action | +|---------------------------|-------------------|-----------------------|-----------------------------------------| +| Yes | Yes | - | Set live to the Resource Config value. | +| Yes | No | - | Set live to the Resource Config value. | +| No | - | Yes | Remove from Resource. | +| No | - | No | Do nothing. | + + +### Merging Objects + +Objects fields are updated by merging the sub-fields recursively (by field name) until a primitive field is found or +the field is added / deleted. + +**Field Creation:** Add the object field + +**Field Update:** Recursively compare object sub-field values and merge them + +**Field Deletion:** Delete the object field + +**Merge Table:** For each field merge Resource Config and Resource values with the same name + +| Field in Resource Config | Field in Resource | Field in Last Applied | Action | +|---------------------------|-------------------|-----------------------|-------------------------------------------| +| Yes | Yes | - | Recursively merge the Resource Config and Resource values. | +| Yes | No | - | Set live to the Resource Config value. | +| No | - | Yes | Remove field from Resource. | +| No | - | No | Do nothing. | + +### Merging Maps + +Map fields are updated by merging the elements (by key) until a primitive field is found or the value is +added / deleted. + +**Field Creation:** Add the map field + +**Field Update:** Recursively compare map values by key and merge them + +**Field Deletion:** Delete the map field + +**Merge Table:** For each map element merge Resource Config and Resource values with the same key + +| Key in Resource Config | Key in Resource | Key in Last Applied | Action | +|---------------------------|-------------------|-----------------------|-------------------------------------------| +| Yes | Yes | - | Recursively merge the Resource Config and Resource values. | +| Yes | No | - | Set live to the Resource Config value. | +| No | - | Yes | Remove map element from Resource. | +| No | - | No | Do nothing. | + +### Merging Lists of Primitives + +Lists of primitives will be merged if they have a `patch strategy: merge` on the field otherwise they will +be replaced. [Finalizer list example](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.12/#objectmeta-v1-meta) + +**Merge Strategy:** + +- Merged primitive lists behave like ordered sets +- Replace primitive lists are replaced when merged + +**Ordering:** Uses the ordering specified in the Resource Config. Elements not specified in the Resource Config +do not have ordering guarantees with respect to the elements in the Resource Config. + +**Merge Table:** For each list element merge Resource Config and Resource element with the same value + +| Element in Resource Config | Element in Resource | Element in Last Applied | Action | +|---------------------------|-------------------|-----------------------|-----------------------------------------| +| Yes | Yes | - | Do nothing | +| Yes | No | - | Add to list. | +| No | - | Yes | Remove from list. | +| No | - | No | Do nothing. | + +{% method %} + +This merge strategy uses the patch merge key to identify container elements in a list and merge them. +The `patch merge key` is defined in the [Kubernetes API](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.12/#podspec-v1-core) +on the field. + +{% sample lang="yaml" %} + +```yaml +# Last Applied +args: ["a", "b"] +``` + +```yaml +# Resource Config (Local) +args: ["a", "c"] +``` + +```yaml +# Resource (Live) +args: ["a", "b", "d"] +``` + +```yaml +# Applied Resource +args: ["a", "c", "d"] +``` + +{% endmethod %} + +### Merging Lists of Objects + +**Merge Strategy:** Lists of primitives may be merged or replaced. Lists are merged if the list has a `patch strategy` of *merge* +and a `patch merge key` on the list field. [Container list example](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.12/#podspec-v1-core). + +**Merge Key:** The `patch merge key` is used to identify same elements in a list. Unlike map elements (keyed by key) and object fields +(keyed by field name), lists don't have a built-in merge identity for elements (index does not define identity). +Instead an object field is used as a synthetic *key/value* for merging elements. This fields is the +`patch merge key`. List elements with the same patch merge key will be merged when lists are merged. + +**Ordering:** Uses the ordering specified in the Resource Config. Elements not specified in the Resource Config +do not have ordering guarantees. + +**Merge Table:** For each list element merge Resource Config and Resource element where the elements have the same +value for the `patch merge key` + +| Element in Resource Config | Element in Resource | Element in Last Applied | Action | +|---------------------------|-------------------|-----------------------|-----------------------------------------| +| Yes | - | - | Recursively merge the Resource Config and Resource values. | +| Yes | No | - | Add to list. | +| No | - | Yes | Remove from list. | +| No | - | No | Do nothing. | + +{% method %} + +This merge strategy uses the patch merge key to identify container elements in a list and merge them. +The `patch merge key` is defined in the [Kubernetes API](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.12/#podspec-v1-core) +on the field. + +{% sample lang="yaml" %} + +```yaml +# Last Applied Resource Config +containers: +- name: nginx # key: nginx + image: nginx:1.10 +- name: nginx-helper-a # key: nginx-helper-a; will be deleted in result + image: helper:1.3 +- name: nginx-helper-b # key: nginx-helper-b; will be retained + image: helper:1.3 +``` + +```yaml +# Resource Config (Local) +containers: +- name: nginx + image: nginx:1.10 +- name: nginx-helper-b + image: helper:1.3 +- name: nginx-helper-c # key: nginx-helper-c; will be added in result + image: helper:1.3 +``` + +```yaml +# Resource (Live) +containers: +- name: nginx + image: nginx:1.10 +- name: nginx-helper-a + image: helper:1.3 +- name: nginx-helper-b + image: helper:1.3 + args: ["run"] # Field will be retained +- name: nginx-helper-d # key: nginx-helper-d; will be retained + image: helper:1.3 +``` + +```yaml +# Applied Resource +containers: +- name: nginx + image: nginx:1.10 + # Element nginx-helper-a was Deleted +- name: nginx-helper-b + image: helper:1.3 + # Field was Ignored + args: ["run"] + # Element was Added +- name: nginx-helper-c + image: helper:1.3 + # Element was Ignored +- name: nginx-helper-d + image: helper:1.3 +``` +{% endmethod %} + +{% panel style="info", title="Edit and Set" %} +While `kubectl edit` and `kubectl set` ignore the Last Applied Resource Config, Apply will +change any values in the Resource Config set by either `kubectl edit` or `kubectl set`. +To ignore values set by `kubectl edit` or `kubectl set`: + +- Use `kubectl apply edit-last-applied` to remove the value from the Last Applied (if it is present) +- Remove the field from the Resource Config + +This is the same technique for retaining values set by cluster components such as autoscalers. +{% endpanel %} diff --git a/docs/book/pages/app_management/introduction.md b/docs/book/pages/app_management/introduction.md new file mode 100644 index 00000000..f52df55b --- /dev/null +++ b/docs/book/pages/app_management/introduction.md @@ -0,0 +1,48 @@ +{% panel style="success", title="Providing Feedback" %} +**Provide feedback at the [survey](https://www.surveymonkey.com/r/CLQBQHR)** +{% endpanel %} + +{% panel style="info", title="TL;DR" %} +- Apply manages Applications through files defining Kubernetes Resources (i.e. Resource Config) +- Kustomize is used to author Resource Config +{% endpanel %} + + +# Declarative Application Management + +This section covers how to declaratively manage Workloads and Applications. + +Workloads in a cluster may be configured through files called *Resource Config*. These files are +typically checked into source control, and allow cluster state changes to be reviewed before they +are audited and applied. + +There are 2 components to Application Management. + +## Client Component + +The client component consists of authoring Resource Config which defines the desired state +of an Application. This may be done as a collection of raw Resource Config files, or by +composing and overlaying Resource Config authored by separate teams +(using the `-k` flag with a `kustomization.yaml`). + +Kustomize offers low-level tooling for simplifying the authoring of Resource Config. It provides: + +- **Generating Resource Config** from other canonical sources - e.g. ConfigMaps, Secrets +- **Reusing and Composing one or more collections of Resource Config** +- **Customizing Resource Config** +- **Setting cross-cutting fields** - e.g. namespace, labels, annotations, name-prefixes, etc + +**Example:** One user may define a Base for an application, while another user may customize +a specific instance of the Base. + +## Server Component + +The server component consists of a human applying the authored Resource Config to the cluster +to create or update Resources. Once Applied, the Kubernetes cluster will set additional desired +state on the Resource - e.g. *defaulting unspecified fields, filling in IP addresses, autoscaling +replica count, etc.* + +Note that the process of Application Management is a collaborative one between users and the +Kubernetes system itself - where each may contribute to defining the desired state. + +**Example**: An Autoscaler Controller in the cluster may set the scale field on a Deployment managed by a user. diff --git a/docs/book/pages/app_management/labels_and_annotations.md b/docs/book/pages/app_management/labels_and_annotations.md new file mode 100644 index 00000000..e055bf25 --- /dev/null +++ b/docs/book/pages/app_management/labels_and_annotations.md @@ -0,0 +1,197 @@ +{% panel style="success", title="Providing Feedback" %} +**Provide feedback at the [survey](https://www.surveymonkey.com/r/CLQBQHR)** +{% endpanel %} + +{% panel style="info", title="TL;DR" %} +- Set Labels for all Resources declared within a Project with `commonLables` +- Set Annotations for all Resources declared within a Project with `commonAnnotations` +{% endpanel %} + +# Setting Labels and Annotations + +## Motivation + +Users may want to define a common set of labels or annotations for all the Resource in a project. + +- Identify the Resources within a project by querying their labels. +- Set metadata for all Resources within a project (e.g. environment=test). +- Copy or Fork an existing Project and add or change labels and annotations. + +See [Bases and Variations](../app_customization/bases_and_variants.md) for more details on Copying Projects. + +{% panel style="info", title="Reference" %} +- [commonLabels](../reference/kustomize.md#commonlabels) +- [commonAnnotations](../reference/kustomize.md#commonannotations) +{% endpanel %} + + +## Setting Labels for all Resources + +{% method %} +**Example:** Add the labels declared in `commonLabels` to all Resources in the project. + +**Important:** Once set, commonLabels should not be changed so as not to change the Selectors for Services +or Workloads. + +{% sample lang="yaml" %} +**Input:** The kustomization.yaml and deployment.yaml files + +```yaml +# kustomization.yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +commonLabels: + app: foo + environment: test +resources: +- deployment.yaml +``` + +```yaml +# deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment + labels: + app: nginx + bar: baz +spec: + selector: + matchLabels: + app: nginx + bar: baz + template: + metadata: + labels: + app: nginx + bar: baz + spec: + containers: + - name: nginx + image: nginx +``` + +**Applied:** The Resource that is Applied to the cluster + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: foo # Label was changed + environment: test # Label was added + bar: baz # Label was ignored + name: nginx-deployment +spec: + selector: + matchLabels: + app: foo # Selector was changed + environment: test # Selector was added + bar: baz # Selector was ignored + template: + metadata: + labels: + app: foo # Label was changed + environment: test # Label was added + bar: baz # Label was ignored + spec: + containers: + - image: nginx + name: nginx +``` +{% endmethod %} + +{% panel style="warning", title="Propagating Labels to Selectors" %} +In addition to updating the labels for each Resource, any selectors will also be updated to target the +labels. e.g. the selectors for Services in the project will be updated to include the commonLabels +*in addition* to the other labels. + +**Note:** Once set, commonLabels should not be changed so as not to change the Selectors for Services +or Workloads. +{% endpanel %} + +{% panel style="success", title="Common Labels" %} +The k8s.io documentation defines a set of [Common Labeling Conventions](https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/) +that may be applied to Applications. + +**Note:** commonLabels should only be set for **immutable** labels, since they will be applied to Selectors. + +Labeling Workload Resources makes it simpler to query Pods - e.g. for the purpose of getting their logs. +{% endpanel %} + + +## Setting Annotations for all Resources + +{% method %} +**Example:** Add the annotations declared in `commonAnnotations` to all Resources in the project. + +{% sample lang="yaml" %} +**Input:** The kustomization.yaml and deployment.yaml files + +```yaml +# kustomization.yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +commonAnnotations: + oncallPager: 800-555-1212 +resources: +- deployment.yaml +``` + +```yaml +# deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment + labels: + app: nginx +spec: + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx +``` + +**Applied:** The Resource that is Applied to the cluster + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + # Annotation added to the Deployment + annotations: + oncallPager: 800-555-1212 + labels: + app: nginx + name: nginx-deployment +spec: + selector: + matchLabels: + app: nginx + template: + metadata: + # Annotation also added to PodTemplate + annotations: + oncallPager: 800-555-1212 + labels: + app: nginx + spec: + containers: + - image: nginx + name: nginx +``` +{% endmethod %} + +{% panel style="info", title="Propagating Annotations" %} +In addition to updating the annotations for each Resource, any fields that contain ObjectMeta +(e.g. PodTemplate) will also have the annotations added. +{% endpanel %} diff --git a/docs/book/pages/app_management/namespaces_and_names.md b/docs/book/pages/app_management/namespaces_and_names.md new file mode 100644 index 00000000..b5791c89 --- /dev/null +++ b/docs/book/pages/app_management/namespaces_and_names.md @@ -0,0 +1,280 @@ +{% panel style="success", title="Providing Feedback" %} +**Provide feedback at the [survey](https://www.surveymonkey.com/r/CLQBQHR)** +{% endpanel %} + +{% panel style="info", title="TL;DR" %} +- Set the Namespace for all Resources within a Project with `namespace` +- Prefix the Names of all Resources within a Project with `namePrefix` +- Suffix the Names of all Resources within a Project with `nameSuffix` +{% endpanel %} + +# Setting Namespaces and Names + +## Motivation + +It may be useful to enforce consistency across the namespace and names of all Resources within +a Project. + +- Ensure all Resources are in the correct Namespace +- Ensure all Resources share a common naming convention +- Copy or Fork an existing Project and change the Namespace / Names + +See [Bases and Variations](../app_customization/bases_and_variants.md) for more details on Copying Projects. + + +{% panel style="info", title="Reference" %} +- [namespace](../reference/kustomize.md#namespace) +- [namePrefix](../reference/kustomize.md#nameprefix) +- [nameSuffix](../reference/kustomize.md#namesuffix) +{% endpanel %} + + +## Setting the Namespace for all Resources + +Reference: + +The Namespace for all namespaced Resources declared in the Resource Config may be set with `namespace`. +This sets the namespace for both generated Resources (e.g. ConfigMaps and Secrets) and non-generated +Resources. + +{% method %} +**Example:** Set the `namespace` specified in the `kustomization.yaml` on the namespaced Resources. + +{% sample lang="yaml" %} +**Input:** The kustomization.yaml and deployment.yaml files + +```yaml +# kustomization.yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +namespace: my-namespace +resources: +- deployment.yaml +``` + +```yaml +# deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment + labels: + app: nginx +spec: + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx +``` + +**Applied:** The Resource that is Applied to the cluster + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: nginx + name: nginx-deployment + # The namespace has been added + namespace: my-namespace +spec: + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - image: nginx + name: nginx +``` + +{% endmethod %} + +{% panel style="info", title="Overriding Namespaces" %} +Setting the namespace will override the namespace on Resources if it is already set. +{% endpanel %} + +## Setting a Name prefix or suffix for all Resources + +A name prefix or suffix can be set for all resources using `namePrefix` or +`nameSuffix`. + +{% method %} +**Example:** Prefix the names of all Resources. + +{% sample lang="yaml" %} +**Input:** The kustomization.yaml and deployment.yaml files + +```yaml +# kustomization.yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +namePrefix: foo- +resources: +- deployment.yaml +``` + +```yaml +# deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment + labels: + app: nginx +spec: + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx +``` + +**Applied:** The Resource that is Applied to the cluster + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: nginx + # The name has been prefixed with "foo-" + name: foo-nginx-deployment +spec: + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - image: nginx + name: nginx +``` +{% endmethod %} + +{% panel style="info", title="Propagation of the Name to Object References" %} +Resources such as Deployments and StatefulSets may reference other Resources such as +ConfigMaps and Secrets in the Pod Spec. + +This sets a name prefix or suffix for both generated Resources (e.g. ConfigMaps +and Secrets) and non-generated Resources. + +The namePrefix or nameSuffix that is applied is propagated to references to updated resources - +e.g. references to Secrets and ConfigMaps are updated with the namePrefix and nameSuffix. +{% endpanel %} + +{% method %} +**Example:** Prefix the names of all Resources. + +This will update the ConfigMap reference in the Deployment to have the `foo` prefix. + +{% sample lang="yaml" %} +**Input:** The kustomization.yaml and deployment.yaml files + +```yaml +# kustomization.yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +namePrefix: foo- +configMapGenerator: +- name: props + literals: + - BAR=baz +resources: +- deployment.yaml +``` + +```yaml +# deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment + labels: + app: nginx +spec: + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx + env: + - name: BAR + valueFrom: + configMapKeyRef: + name: props + key: BAR +``` + +**Applied:** The Resource that is Applied to the cluster + + ```yaml +apiVersion: v1 +data: + BAR: baz +kind: ConfigMap +metadata: + creationTimestamp: null + name: foo-props-44kfh86dgg +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: nginx + name: foo-nginx-deployment +spec: + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - env: + - name: BAR + valueFrom: + configMapKeyRef: + key: BAR + name: foo-props-44kfh86dgg + image: nginx + name: nginx +``` +{% endmethod %} + +{% panel style="info", title="References" %} +Apply will propagate the `namePrefix` to any place Resources within the project are referenced by other Resources +including: + +- Service references from StatefulSets +- ConfigMap references from PodSpecs +- Secret references from PodSpecs +{% endpanel %} \ No newline at end of file diff --git a/docs/book/pages/app_management/secrets_and_configmaps.md b/docs/book/pages/app_management/secrets_and_configmaps.md new file mode 100644 index 00000000..ff86eefc --- /dev/null +++ b/docs/book/pages/app_management/secrets_and_configmaps.md @@ -0,0 +1,380 @@ +{% panel style="success", title="Providing Feedback" %} +**Provide feedback at the [survey](https://www.surveymonkey.com/r/CLQBQHR)** +{% endpanel %} + +{% panel style="info", title="TL;DR" %} +- Generate Secrets from files and literals with `secretGenerator` +- Generate ConfigMaps from files and literals with `configMapGenerator` +- Rolling out changes to Secrets and ConfigMaps +{% endpanel %} + +# Secrets and ConfigMaps + +{% panel style="info", title="Reference" %} +- [secretGenerators](../reference/kustomize.md#secretgenerator) +- [configMapGenerators](../reference/kustomize.md#configmapgenerator) +- [generatorOptions](../reference/kustomize.md#generatoroptions) +{% endpanel %} + +## Motivation + +The source of truth for Secret and ConfigMap Resources typically resides +somewhere else, such as a `.properties` file. Apply offers native support +for generating both Secrets and ConfigMaps from other sources such as files and +literals. + +Additionally, Secrets and ConfigMaps require rollouts to be performed +differently than for most other Resources in order for the changes to be +rolled out to Pods consuming them. + +## Generators + +Secret and ConfigMap Resources can be generated by adding `secretGenerator` +or `configMapGenerator` entries to the `kustomization.yaml` file. + +**The generated Resources name's will have suffixes that change when their data +changes. See [Rollouts](#rollouts) for more on this.** + +### ConfigMaps From Files + +{% method %} +ConfigMap Resources may be generated from files - such as a java `.properties` file. To generate a ConfigMap +Resource for a file, add an entry to `configMapGenerator` with the filename. + +**Example:** Generate a ConfigMap with a data item containing the contents of a file. + +The ConfigMaps will have data values populated from the file contents. The contents of each file will +appear as a single data item in the ConfigMap keyed by the filename. + +{% sample lang="yaml" %} +**Input:** The kustomization.yaml file + +```yaml +# kustomization.yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +configMapGenerator: +- name: my-application-properties + files: + - application.properties +``` + +```yaml +# application.properties +FOO=Bar +``` + +**Applied:** The Resource that is Applied to the cluster + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + # The name has had a suffix applied + name: my-application-properties-c79528k426 +# The data has been populated from each file's contents +data: + application.properties: | + FOO=Bar +``` +{% endmethod %} + +### ConfigMaps From Literals + +ConfigMap Resources may be generated from literal key-value pairs - such as `JAVA_HOME=/opt/java/jdk`. +To generate a ConfigMap Resource from literal key-value pairs, add an entry to `configMapGenerator` with a +list of `literals`. + +{% panel style="info", title="Literal Syntax" %} +- The key/value are separated by a `=` sign (left side is the key) +- The value of each literal will appear as a data item in the ConfigMap keyed by its key. +{% endpanel %} + +{% method %} +**Example:** Create a ConfigMap with 2 data items generated from literals. + +{% sample lang="yaml" %} +**Input:** The kustomization.yaml file + +```yaml +# kustomization.yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +configMapGenerator: +- name: my-java-server-env-vars + literals: + - JAVA_HOME=/opt/java/jdk + - JAVA_TOOL_OPTIONS=-agentlib:hprof +``` + +**Applied:** The Resource that is Applied to the cluster + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + # The name has had a suffix applied + name: my-java-server-env-vars-k44mhd6h5f +# The data has been populated from each literal pair +data: + JAVA_HOME: /opt/java/jdk + JAVA_TOOL_OPTIONS: -agentlib:hprof +``` +{% endmethod %} + +### ConfigMaps From Environment Files + +ConfigMap Resources may be generated from key-value pairs much the same as using the literals option +but taking the key-value pairs from an environment file. These generally end in `.env`. +To generate a ConfigMap Resource from an environment file, add an entry to `configMapGenerator` with a +single `env` entry, e.g. `env: config.env`. + +{% panel style="info", title="Environment File Syntax" %} +- The key/value pairs inside of the environment file are separated by a `=` sign (left side is the key) +- The value of each line will appear as a data item in the ConfigMap keyed by its key. +{% endpanel %} + +{% method %} +**Example:** Create a ConfigMap with 3 data items generated from an environment file. + +{% sample lang="yaml" %} +**Input:** The kustomization.yaml file + +```yaml +# kustomization.yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +configMapGenerator: +- name: tracing-options + env: tracing.env +``` + +```bash +# tracing.env +ENABLE_TRACING=true +SAMPLER_TYPE=probabilistic +SAMPLER_PARAMETERS=0.1 +``` + +**Applied:** The Resource that is Applied to the cluster + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + # The name has had a suffix applied + name: tracing-options-6bh8gkdf7k +# The data has been populated from each literal pair +data: + ENABLE_TRACING: "true" + SAMPLER_TYPE: "probabilistic" + SAMPLER_PARAMETERS: "0.1" +``` +{% endmethod %} + +{% panel style="success", title="Overriding Base ConfigMap Values" %} +ConfigMaps Values from Bases may be overridden by adding another generator for the ConfigMap +in the Variant and specifying the `behavior` field. `behavior` may be +one of `create` (default value), `replace` (replace the base ConfigMap), +or `merge` (add or update the values the ConfigMap). See [Bases and Variantions](../app_customization/bases_and_variants.md) +for more on using Bases. e.g. `behavior: "merge"` +{% endpanel %} + +### Secrets from Files + +Secret Resources may be generated much like ConfigMaps can. This includes generating them +from literals, files or environment files. + +{% panel style="info", title="Secret Syntax" %} +Secret type is set using the `type` field. +{% endpanel %} + +{% method %} +**Example:** Generate a `kubernetes.io/tls` Secret from local files + +{% sample lang="yaml" %} +**Input:** The kustomization.yaml file + +```yaml +# kustomization.yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +secretGenerator: +- name: app-tls + files: + - "secret/tls.cert" + - "secret/tls.key" + type: "kubernetes.io/tls" +``` + +**Applied:** The Resource that is Applied to the cluster + +```yaml +apiVersion: v1 +kind: Secret +metadata: + # The name has had a suffix applied + name: app-tls-4tc9tcbd8k +type: kubernetes.io/tls +# The data has been populated from each command's output +data: + tls.crt: LS0tLS1CRUd...tCg== + tls.key: LS0tLS1CRUd...0tLQo= +``` +{% endmethod %} + +### Generator Options + +{% method %} +It is also possible to specify cross-cutting options for generated objects +using `generatorOptions`. + +{% sample lang="yaml" %} + +```yaml +# kustomization.yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +generatorOptions: + # labels to add to all generated resources + labels: + kustomize.generated.resources: somevalue + # annotations to add to all generated resources + annotations: + kustomize.generated.resource: somevalue + # disableNameSuffixHash is true disables the default behavior of adding a + # suffix to the names of generated resources that is a hash of + # the resource contents. + disableNameSuffixHash: true +``` + +{% endmethod %} + +### Propagating the Name Suffix + +{% method %} +Workloads that reference the ConfigMap or Secret will need to know the name of the generated Resource +including the suffix, however Apply takes care of this automatically for users. Apply will identify +references to generated ConfigMaps and Secrets, and update them. + +The generated ConfigMap name will be `my-java-server-env-vars` with a suffix unique to its contents. +Changes to the contents will change the name suffix, resulting in the creation of a new ConfigMap, +and transform Workloads to point to this one. + +The PodTemplate volume references the ConfigMap by the name specified in the generator (excluding the suffix). +Apply will update the name to include the suffix applied to the ConfigMap name. + +{% sample lang="yaml" %} +**Input:** The kustomization.yaml and deployment.yaml files + +```yaml +# kustomization.yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +configMapGenerator: +- name: my-java-server-env-vars + literals: + - JAVA_HOME=/opt/java/jdk + - JAVA_TOOL_OPTIONS=-agentlib:hprof +resources: +- deployment.yaml +``` + +```yaml +# deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: test-deployment + labels: + app: test +spec: + selector: + matchLabels: + app: test + template: + metadata: + labels: + app: test + spec: + containers: + - name: container + image: k8s.gcr.io/busybox + command: [ "/bin/sh", "-c", "ls /etc/config/" ] + volumeMounts: + - name: config-volume + mountPath: /etc/config + volumes: + - name: config-volume + configMap: + name: my-java-server-env-vars +``` + +**Applied:** The Resources that are Applied to the cluster. + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + # The name has been updated to include the suffix + name: my-java-server-env-vars-k44mhd6h5f +data: + JAVA_HOME: /opt/java/jdk + JAVA_TOOL_OPTIONS: -agentlib:hprof +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: test + name: test-deployment +spec: + selector: + matchLabels: + app: test + template: + metadata: + labels: + app: test + spec: + containers: + - command: + - /bin/sh + - -c + - ls /etc/config/ + image: k8s.gcr.io/busybox + name: container + volumeMounts: + - mountPath: /etc/config + name: config-volume + volumes: + - configMap: + # The name has been updated to include the + # suffix matching the ConfigMap + name: my-java-server-env-vars-k44mhd6h5f + name: config-volume +``` +{% endmethod %} + +## Rollouts + +ConfigMap values are consumed by Pods as: environment variables, command line arguments and files. + +This is important because Updating a ConfigMap will: + +- immediately update the files mounted by *all* Pods consuming them +- not update the environment variables or command line arguments until the Pod is restarted + +Typically users want to perform a rolling update of the ConfigMap changes to Pods as soon as +the ConfigMap changes are pushed. + +Apply facilitates rolling updates for ConfigMaps by creating a new ConfigMap +for each change to the data. Workloads (e.g. Deployments, StatefulSets, etc) are updated to point to a new +ConfigMap instead of the old one. This allows the change to be gradually rolled the same way +other Pod Template changes are rolled out. + +Each generated Resources name has a suffix appended by hashing the contents. This approach ensures a new +ConfigMap is generated each time the contents is modified. + +**Note:** Because the Resource names will contain a suffix, when looking for them with `kubectl get`, +their names will not match exactly what is specified in the kustomization.yaml file. diff --git a/docs/book/pages/container_debugging/container_logs.md b/docs/book/pages/container_debugging/container_logs.md new file mode 100644 index 00000000..35c185a0 --- /dev/null +++ b/docs/book/pages/container_debugging/container_logs.md @@ -0,0 +1,165 @@ +{% panel style="success", title="Providing Feedback" %} +**Provide feedback at the [survey](https://www.surveymonkey.com/r/JH35X82)** +{% endpanel %} + +{% panel style="info", title="TL;DR" %} +- Print the Logs of a Container in a cluster +{% endpanel %} + +# Summarizing Resources + +## Motivation + +Debugging Workloads by printing out the Logs of containers in a cluster. + +{% method %} +## Print Logs for a Container in a Pod + +Print the logs for a Pod running a single Container +{% sample lang="yaml" %} + +```bash +kubectl logs echo-c6bc8ccff-nnj52 +``` + +```bash +hello +hello +``` + +{% endmethod %} + + +{% panel style="success", title="Crash Looping Containers" %} +If a container is crash looping and you want to print its logs after it +exits, use the `-p` flag to look at the **logs from containers that have +exited**. e.g. `kubectl logs -p -c ruby web-1` +{% endpanel %} + +--- + +{% method %} +## Print Logs for all Pods for a Workload + +Print the logs for all Pods for a Workload +{% sample lang="yaml" %} + +```bash +# Print logs from all containers matching label +kubectl logs -l app=nginx +``` + +{% endmethod %} + +{% panel style="success", title="Workloads Logs" %} +Print all logs from **all containers for a Workload** by passing the +Workload label selector to the `-l` flag. e.g. if your Workload +label selector is `app=nginx` usie `-l "app=nginx"` to print logs +for all the Pods from that Workload. +{% endpanel %} + +--- + +{% method %} +## Follow Logs for a Container + +Stream logs from a container. + +{% sample lang="yaml" %} + +```bash +# Follow logs from container +kubectl logs nginx-78f5d695bd-czm8z -f +``` + +{% endmethod %} + +--- + +{% method %} +## Printing Logs for a Container that has exited + +Print the logs for the previously running container. This is useful for printing containers that have +crashed or are crash looping. +{% sample lang="yaml" %} + +```bash +# Print logs from exited container +kubectl logs nginx-78f5d695bd-czm8z -p +``` + +{% endmethod %} + +--- + +{% method %} +## Selecting a Container in a Pod + +Print the logs from a specific container within a Pod. This is necessary for Pods running multiple +containers. +{% sample lang="yaml" %} + +```bash +# Print logs from the nginx container in the nginx-78f5d695bd-czm8z Pod +kubectl logs nginx-78f5d695bd-czm8z -c nginx +``` + +{% endmethod %} + +--- + +{% method %} +## Printing Logs After a Time + +Print the logs that occurred after an absolute time. +{% sample lang="yaml" %} + +```bash +# Print logs since a date +kubectl logs nginx-78f5d695bd-czm8z --since-time=2018-11-01T15:00:00Z +``` + +{% endmethod %} + +--- + +{% method %} +## Printing Logs Since a Time + +Print the logs that are newer than a duration. + +Examples: + +- 0s: 0 seconds +- 1m: 1 minute +- 2h: 2 hours + +{% sample lang="yaml" %} + +```bash +# Print logs for the past hour +kubectl logs nginx-78f5d695bd-czm8z --since=1h +``` + +{% endmethod %} + +--- + +{% method %} +## Include Timestamps + +Include timestamps in the log lines + +{% sample lang="yaml" %} + +```bash +# Print logs with timestamps +kubectl logs -l app=echo --timestamps +``` + +```bash +2018-11-16T05:26:31.38898405Z hello +2018-11-16T05:27:13.363932497Z hello +``` + +{% endmethod %} \ No newline at end of file diff --git a/docs/book/pages/container_debugging/copying_container_files.md b/docs/book/pages/container_debugging/copying_container_files.md new file mode 100644 index 00000000..edfb20cf --- /dev/null +++ b/docs/book/pages/container_debugging/copying_container_files.md @@ -0,0 +1,80 @@ +{% panel style="success", title="Providing Feedback" %} +**Provide feedback at the [survey](https://www.surveymonkey.com/r/JH35X82)** +{% endpanel %} + +{% panel style="info", title="TL;DR" %} +- Copy files to and from Containers in a cluster +{% endpanel %} + +# Copying Container Files + +## Motivation + +- Copying files from Containers in a cluster to a local filesystem +- Copying files from a local filesystem to Containers in a cluster + +{% panel style="warning", title="Install Tar" %} +Copy requires that *tar* be installed in the container image. +{% endpanel %} + +{% method %} +## Local to Remote + +Copy a local file to a remote Pod in a cluster. + +- Local file format is `` +- Remote file format is `:` + +{% sample lang="yaml" %} + +```bash +kubectl cp /tmp/foo_dir :/tmp/bar_dir +``` + +{% endmethod %} + +{% method %} +## Remote to Local + +Copy a remote file from a Pod to a local file. + +- Local file format is `` +- Remote file format is `:` + +{% sample lang="yaml" %} + +```bash +kubectl cp /tmp/foo :/tmp/bar +``` + +{% endmethod %} + +{% method %} +## Specify the Container + +Specify the Container within a Pod running multiple containers. + +- `-c ` + +{% sample lang="yaml" %} + +```bash +kubectl cp /tmp/foo :/tmp/bar -c +``` + +{% endmethod %} + +{% method %} +## Namespaces + +Set the Pod namespace by prefixing the Pod name with `/` . + +- `/:` + +{% sample lang="yaml" %} + +```bash +kubectl cp /tmp/foo /:/tmp/bar +``` + +{% endmethod %} diff --git a/docs/book/pages/container_debugging/executing_a_command_in_a_container.md b/docs/book/pages/container_debugging/executing_a_command_in_a_container.md new file mode 100644 index 00000000..ad02d49a --- /dev/null +++ b/docs/book/pages/container_debugging/executing_a_command_in_a_container.md @@ -0,0 +1,54 @@ +{% panel style="success", title="Providing Feedback" %} +**Provide feedback at the [survey](https://www.surveymonkey.com/r/JH35X82)** +{% endpanel %} + +{% panel style="info", title="TL;DR" %} +- Execute a Command in a Container +- Get a Shell in a Container +{% endpanel %} + +# Executing Commands + +## Motivation + +Debugging Workloads by running commands within the Container. Commands may be a Shell with +a tty. + +{% method %} +## Exec Command + +Run a command in a Container in the cluster by specifying the **Pod name**. + +{% sample lang="yaml" %} + +```bash +kubectl exec nginx-78f5d695bd-czm8z ls +``` + +```bash +bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var +``` + +{% endmethod %} + +{% method %} +## Exec Shell + +To get a Shell in a Container, use the `-t -i` options to get a tty and attach STDIN. + +{% sample lang="yaml" %} + +```bash +kubectl exec -t -i nginx-78f5d695bd-czm8z bash +``` + +```bash +root@nginx-78f5d695bd-czm8z:/# ls +bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var +``` + +{% endmethod %} + +{% panel style="info", title="Specifying the Container" %} +For Pods running multiple Containers, the Container should be specified with `-c `. +{% endpanel %} diff --git a/docs/book/pages/container_debugging/port_forward_to_pods.md b/docs/book/pages/container_debugging/port_forward_to_pods.md new file mode 100644 index 00000000..d983cf74 --- /dev/null +++ b/docs/book/pages/container_debugging/port_forward_to_pods.md @@ -0,0 +1,68 @@ +{% panel style="success", title="Providing Feedback" %} +**Provide feedback at the [survey](https://www.surveymonkey.com/r/JH35X82)** +{% endpanel %} + +{% panel style="info", title="TL;DR" %} +- Port Forward local connections to Pods running in a cluster +{% endpanel %} + +# Port Forward + +## Motivation + +Connect to ports of Pods running a cluster by port forwarding local ports. + +{% method %} +## Forward Multiple Ports + +Listen on ports 5000 and 6000 locally, forwarding data to/from ports 5000 and 6000 in the pod +{% sample lang="yaml" %} + +```bash +kubectl port-forward pod/mypod 5000 6000 +``` + +{% endmethod %} + +--- + +{% method %} +## Pod in a Workload + +Listen on ports 5000 and 6000 locally, forwarding data to/from ports 5000 and 6000 in a pod selected by the +deployment +{% sample lang="yaml" %} + +```bash +kubectl port-forward deployment/mydeployment 5000 6000 +``` + +{% endmethod %} + +--- + +{% method %} +## Different Local and Remote Ports + +Listen on port 8888 locally, forwarding to 5000 in the pod +{% sample lang="yaml" %} + +```bash +kubectl port-forward pod/mypod 8888:5000 +``` + +{% endmethod %} + +--- + +{% method %} +## Random Local Port + +Listen on a random port locally, forwarding to 5000 in the pod +{% sample lang="yaml" %} + +```bash +kubectl port-forward pod/mypod :5000 +``` + +{% endmethod %} diff --git a/docs/book/pages/container_debugging/proxying_traffic_to_services.md b/docs/book/pages/container_debugging/proxying_traffic_to_services.md new file mode 100644 index 00000000..cf1cdb7b --- /dev/null +++ b/docs/book/pages/container_debugging/proxying_traffic_to_services.md @@ -0,0 +1,77 @@ +{% panel style="success", title="Providing Feedback" %} +**Provide feedback at the [survey](https://www.surveymonkey.com/r/JH35X82)** +{% endpanel %} + +{% panel style="info", title="TL;DR" %} +- Proxy local connections to Services running in the cluster +{% endpanel %} + +# Connecting to Services + +## Motivation + +Not all Services running a Kubernetes cluster are exposed externally. However Services +only exposed internally to a cluster with a *clusterIp* are accessible through an +apiserver proxy. + +Users may use Proxy to **connect to Kubernetes Services in a cluster that are not +externally exposed**. + + +**Note:** Services running a type LoadBalancer or type NodePort may be exposed externally and +accessed without the need for a Proxy. + +{% method %} +## Connecting to an internal Service + +Connect to a internal Service using the Proxy command, and the Service Proxy url. + +To visit the nginx service go to the Proxy URL at +`http://127.0.0.1:8001/api/v1/namespaces/default/services/nginx/proxy/` + +{% sample lang="yaml" %} + +```bash +kubectl proxy + +Starting to serve on 127.0.0.1:8001 +``` + +```bash +curl http://127.0.0.1:8001/api/v1/namespaces/default/services/nginx/proxy/ +``` + +{% endmethod %} + +{% panel style="info", title="Literal Syntax" %} +To connect to a Service through a proxy the user must build the Proxy URL. The Proxy URL format is: + +`http:///api/v1/namespaces//services/[https:][:]/proxy` + +- The apiserver-address should be the URL printed by the Proxy command +- The Port is optional if you haven’t specified a name for your port +- The Protocol is optional if you are using `http` + +{% endpanel %} + +## Builtin Cluster Services + +A common usecase is to connect to Services running as part of the cluster itself. A user can print out these +Services and their Proxy Urls with `kubectl cluster-info`. + +```bash +kubectl cluster-info + +Kubernetes master is running at https://104.197.5.247 +GLBCDefaultBackend is running at https://104.197.5.247/api/v1/namespaces/kube-system/services/default-http-backend:http/proxy +Heapster is running at https://104.197.5.247/api/v1/namespaces/kube-system/services/heapster/proxy +KubeDNS is running at https://104.197.5.247/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy +Metrics-server is running at https://104.197.5.247/api/v1/namespaces/kube-system/services/https:metrics-server:/proxy +``` + +{% panel style="info", title="More Info" %} +For more information on connecting to a cluster, see +[Accessing Clusters](https://kubernetes.io/docs/tasks/access-application-cluster/access-cluster/). +{% endpanel %} + + diff --git a/docs/book/pages/examples/kustomize.md b/docs/book/pages/examples/kustomize.md new file mode 100644 index 00000000..a8e0cc10 --- /dev/null +++ b/docs/book/pages/examples/kustomize.md @@ -0,0 +1,317 @@ +{% panel style="success", title="Providing Feedback" %} +**Provide feedback at the [survey](https://www.surveymonkey.com/r/JH35X82)** +{% endpanel %} + +{% panel style="info", title="TL;DR" %} +- Examples for `kustomization.yaml` +{% endpanel %} + +# Kustomization.yaml Examples + + {% method %} +This file declares the customization provided by the kustomize program. + +Since customization is, by definition, _custom_, there are no default +values that should be copied from this file or that are recommended. + +In practice, fields with no value should simply be omitted from kustomization.yaml +to reduce the content visible in configuration reviews. + +Example copied from the [kustomize repo](https://github.com/kubernetes-sigs/kustomize/blob/master/docs/kustomization.yaml) + + {% sample lang="yaml" %} +```yaml +# ---------------------------------------------------- +# apiVersion and kind of Kustomization +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +# Adds namespace to all resources. +namespace: my-namespace + +# Value of this field is prepended to the +# names of all resources, e.g. a deployment named +# "wordpress" becomes "alices-wordpress". +namePrefix: alices- + +# Value of this field is appended to the +# names of all resources, e.g. a deployment named +# "wordpress" becomes "wordpress-v2". +# The suffix is appended before content hash +# if resource type is ConfigMap or Secret. +nameSuffix: -v2 + +# Labels to add to all resources and selectors. +commonLabels: + someName: someValue + owner: alice + app: bingo + +# Annotations (non-identifying metadata) +# to add to all resources. Like labels, +# these are key value pairs. +commonAnnotations: + oncallPager: 800-555-1212 + +# Each entry in this list must resolve to an existing +# resource definition in YAML. These are the resource +# files that kustomize reads, modifies and emits as a +# YAML string, with resources separated by document +# markers ("---"). +resources: +- some-service.yaml +- sub-dir/some-deployment.yaml + +# Each entry in this list results in the creation of +# one ConfigMap resource (it's a generator of n maps). +# The example below creates two ConfigMaps. One with the +# names and contents of the given files, the other with +# key/value as data. +# Each configMapGenerator item accepts a parameter of +# behavior: [create|replace|merge]. This allows an overlay to modify or +# replace an existing configMap from the parent. +configMapGenerator: +- name: my-java-server-props + files: + - application.properties + - more.properties +- name: my-java-server-env-vars + literals: + - JAVA_HOME=/opt/java/jdk + - JAVA_TOOL_OPTIONS=-agentlib:hprof + +# Each entry in this list results in the creation of +# one Secret resource (it's a generator of n secrets). +secretGenerator: +- name: app-tls + files: + - secret/tls.cert + - secret/tls.key + type: "kubernetes.io/tls" +- name: app-tls-namespaced + # you can define a namespace to generate secret in, defaults to: "default" + namespace: apps + files: + - tls.crt=catsecret/tls.cert + - tls.key=secret/tls.key + type: "kubernetes.io/tls" +- name: env_file_secret + # env is a path to a file to read lines of key=val + # you can only specify one env file per secret. + env: env.txt + type: Opaque + +# generatorOptions modify behavior of all ConfigMap and Secret generators +generatorOptions: + # labels to add to all generated resources + labels: + kustomize.generated.resources: somevalue + # annotations to add to all generated resources + annotations: + kustomize.generated.resource: somevalue + # disableNameSuffixHash is true disables the default behavior of adding a + # suffix to the names of generated resources that is a hash of + # the resource contents. + disableNameSuffixHash: true + +# Each entry in this list should resolve to a directory +# containing a kustomization file, else the +# customization fails. +# +# The entry could be a relative path pointing to a local directory +# or a url pointing to a directory in a remote repo. +# The url should follow hashicorp/go-getter URL format +# https://github.com/hashicorp/go-getter#url-format +# +# The presence of this field means this file (the file +# you a reading) is an _overlay_ that further +# customizes information coming from these _bases_. +# +# Typical use case: a dev, staging and production +# environment that are mostly identical but differing +# crucial ways (image tags, a few server arguments, +# etc. that differ from the common base). +bases: +- ../../base +- github.com/kubernetes-sigs/kustomize/examples/multibases?ref=v1.0.6 +- github.com/Liujingfang1/mysql +- github.com/Liujingfang1/kustomize/examples/helloWorld?ref=test-branch + +# Each entry in this list should resolve to +# a partial or complete resource definition file. +# +# The names in these (possibly partial) resource files +# must match names already loaded via the `resources` +# field or via `resources` loaded transitively via the +# `bases` entries. These entries are used to _patch_ +# (modify) the known resources. +# +# Small patches that do one thing are best, e.g. modify +# a memory request/limit, change an env var in a +# ConfigMap, etc. Small patches are easy to review and +# easy to mix together in overlays. +patchesStrategicMerge: +- service_port_8888.yaml +- deployment_increase_replicas.yaml +- deployment_increase_memory.yaml + +# Each entry in this list should resolve to +# a kubernetes object and a JSON patch that will be applied +# to the object. +# The JSON patch is documented at https://tools.ietf.org/html/rfc6902 +# +# target field points to a kubernetes object within the same kustomization +# by the object's group, version, kind, name and namespace. +# path field is a relative file path of a JSON patch file. +# The content in this patch file can be either in JSON format as +# +# [ +# {"op": "add", "path": "/some/new/path", "value": "value"}, +# {"op": "replace", "path": "/some/existing/path", "value": "new value"} +# ] +# +# or in YAML format as +# +# - op: add +# path: /some/new/path +# value: value +# - op:replace +# path: /some/existing/path +# value: new value +# +patchesJson6902: +- target: + version: v1 + kind: Deployment + name: my-deployment + path: add_init_container.yaml +- target: + version: v1 + kind: Service + name: my-service + path: add_service_annotation.yaml + +# Each entry in this list should be a relative path to +# a file for custom resource definition(CRD) in openAPI definition. +# +# The presence of this field is to allow kustomize be +# aware of CRDs and apply proper +# transformation for any objects in those types. +# +# Typical use case: A CRD object refers to a ConfigMap object. +# In kustomization, the ConfigMap object name may change by adding namePrefix, nameSuffix, or hashing +# The name reference for this ConfigMap object in CRD object need to be +# updated with namePrefix, nameSuffix, or hashing in the same way. +# +# The annotations can be put into openAPI definitions are: +# "x-kubernetes-annotation": "" +# "x-kubernetes-label-selector": "" +# "x-kubernetes-identity": "" +# "x-kubernetes-object-ref-api-version": "v1", +# "x-kubernetes-object-ref-kind": "Secret", +# "x-kubernetes-object-ref-name-key": "name", +crds: +- crds/typeA.json +- crds/typeB.json + +# Vars are used to capture text from one resource's field +# and insert that text elsewhere. +# +# For example, suppose someone specifies the name of a k8s Service +# object in a container's command line, and the name of a +# k8s Secret object in a container's environment variable, +# so that the following would work: +# +# containers: +# - image: myimage +# command: ["start", "--host", "$(MY_SERVICE_NAME)"] +# env: +# - name: SECRET_TOKEN +# value: $(SOME_SECRET_NAME) +# +# +# To do so, add an entry to `vars:` as follows: +# +vars: + - name: SOME_SECRET_NAME + objref: + kind: Secret + name: my-secret + apiVersion: v1 + - name: MY_SERVICE_NAME + objref: + kind: Service + name: my-service + apiVersion: v1 + fieldref: + fieldpath: metadata.name + - name: ANOTHER_DEPLOYMENTS_POD_RESTART_POLICY + objref: + kind: Deployment + name: my-deployment + apiVersion: apps/v1 + fieldref: + fieldpath: spec.template.spec.restartPolicy +# +# A var is a tuple of variable name, object reference and field +# reference within that object. That's where the text is found. +# +# The field reference is optional; it defaults to `metadata.name`, +# a normal default, since kustomize is used to generate or +# modify the names of resources. +# +# At time of writing, only string type fields are supported. +# No ints, bools, arrays etc. It's not possible to, say, +# extract the name of the image in container number 2 of +# some pod template. +# +# A variable reference, i.e. the string '$(FOO)', can only +# be placed in particular fields of particular objects as +# specified by kustomize's configuration data. +# +# The default config data for vars is at +# https://github.com/kubernetes-sigs/kustomize/blob/master/pkg/transformers/config/defaultconfig/varreference.go +# Long story short, the default targets are all +# container command args and env value fields. +# +# Vars should _not_ be used for inserting names in places +# where kustomize is already handling that job. E.g., +# a Deployment may reference a ConfigMap by name, and +# if kustomize changes the name of a ConfigMap, it knows +# to change the name reference in the Deployment. + + +# Images modify the name, tags and/or digest for images without creating patches. +# E.g. Given this kubernetes Deployment fragment: +# +# containers: +# - name: mypostgresdb +# image: postgres:8 +# - name: nginxapp +# image: nginx:1.7.9 +# - name: myapp +# image: my-demo-app:latest +# - name: alpine-app +# image: alpine:3.7 +# +# one can change the `image` in the following ways: +# +# - `postgres:8` to `my-registry/my-postgres:v1`, +# - nginx tag `1.7.9` to `1.8.0`, +# - image name `my-demo-app` to `my-app`, +# - alpine's tag `3.7` to a digest value +# +# all with the following *kustomization*: +images: + - name: postgres + newName: my-registry/my-postgres + newTag: v1 + - name: nginx + newTag: 1.8.0 + - name: my-demo-app + newName: my-app + - name: alpine + digest: sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3 +``` + + {% endmethod %} \ No newline at end of file diff --git a/docs/book/pages/imperative_porcelain/creating_resources.md b/docs/book/pages/imperative_porcelain/creating_resources.md new file mode 100644 index 00000000..36bf7d59 --- /dev/null +++ b/docs/book/pages/imperative_porcelain/creating_resources.md @@ -0,0 +1,172 @@ +{% panel style="success", title="Providing Feedback" %} +**Provide feedback at the [survey](https://www.surveymonkey.com/r/JH35X82)** +{% endpanel %} + +{% panel style="info", title="TL;DR" %} +- Imperatively Create a Resources +{% endpanel %} + +# Creating Resources + +## Motivation + +Create Resources directly from the command line for the purposes of development or debugging. +Not for production Application Management. + +{% method %} +## Deployment + +A Deployment can be created with the `create deployment` command. + +{% sample lang="yaml" %} + +```bash +kubectl create deployment my-dep --image=busybox +``` + +{% endmethod %} + +{% panel style="success", title="Running and Attaching" %} +It is possible to run a container and immediately attach to it using the `-i -t` flags. e.g. +`kubectl run -t -i my-dep --image ubuntu -- bash` +{% endpanel %} + +{% method %} +## ConfigMap + +Create a configmap based on a file, directory, or specified literal value. + +A single configmap may package one or more key/value pairs. + +When creating a configmap based on a file, the key will default to the basename of the file, and the value will default +to the file content. If the basename is an invalid key, you may specify an alternate key. + +When creating a configmap based on a directory, each file whose basename is a valid key in the directory will be +packaged into the configmap. Any directory entries except regular files are ignored (e.g. subdirectories, symlinks, +devices, pipes, etc). + +{% sample lang="yaml" %} + +```bash +# Create a new configmap named my-config based on folder bar +kubectl create configmap my-config --from-file=path/to/bar +``` + +```bash +# Create a new configmap named my-config with specified keys instead of file basenames on disk +kubectl create configmap my-config --from-file=key1=/path/to/bar/file1.txt --from-file=key2=/path/to/bar/file2.txt + ``` + +```bash +# Create a new configmap named my-config with key1=config1 and key2=config2 +kubectl create configmap my-config --from-literal=key1=config1 --from-literal=key2=config2 +``` + +```bash +# Create a new configmap named my-config from an env file +kubectl create configmap my-config --from-env-file=path/to/bar.env +``` + +{% endmethod %} + +{% method %} +## Secret + +Create a new secret named my-secret with keys for each file in folder bar + +{% sample lang="yaml" %} + +```bash +kubectl create secret generic my-secret --from-file=path/to/bar +``` + +{% endmethod %} + +{% panel style="success", title="Bootstrapping Config" %} +Imperative commands can be used to bootstrap config by using `--dry-run -o yaml`. +`kubectl create secret generic my-secret --from-file=path/to/bar --dry-run -o yaml` +{% endpanel %} + +{% method %} +## Namespace + +Create a new namespace named my-namespace + +{% sample lang="yaml" %} + +```bash +kubectl create namespace my-namespace +``` + +{% endmethod %} + +## Auth Resources + +{% method %} +### ClusterRole + +Create a ClusterRole named "foo" with API Group specified. + +{% sample lang="yaml" %} + +```bash +kubectl create clusterrole foo --verb=get,list,watch --resource=rs.extensions +``` + +{% endmethod %} + +{% method %} +### ClusterRoleBinding + +Create a role binding to give a user cluster admin permissions. + +{% sample lang="yaml" %} + +```bash +kubectl create clusterrolebinding --clusterrole=cluster-admin --user= +``` + +{% endmethod %} + +{% panel style="info", title="Required Admin Permissions" %} +The cluster-admin role maybe required for creating new RBAC bindings. +{% endpanel %} + +{% method %} +### Role + +Create a Role named "foo" with API Group specified. + +{% sample lang="yaml" %} + +```bash +kubectl create role foo --verb=get,list,watch --resource=rs.extensions +``` + +{% endmethod %} + +{% method %} +### RoleBinding + +Create a RoleBinding for user1, user2, and group1 using the admin ClusterRole. + +{% sample lang="yaml" %} + +```bash +kubectl create rolebinding admin --clusterrole=admin --user=user1 --user=user2 --group=group1 +``` + +{% endmethod %} + +{% method %} +### ServiceAccount + +Create a new service account named my-service-account + +{% sample lang="yaml" %} + +```bash +kubectl create serviceaccount my-service-account +``` + +{% endmethod %} diff --git a/docs/book/pages/imperative_porcelain/editing_workloads.md b/docs/book/pages/imperative_porcelain/editing_workloads.md new file mode 100644 index 00000000..ba0b3abd --- /dev/null +++ b/docs/book/pages/imperative_porcelain/editing_workloads.md @@ -0,0 +1,44 @@ +{% panel style="success", title="Providing Feedback" %} +**Provide feedback at the [survey](https://www.surveymonkey.com/r/JH35X82)** +{% endpanel %} + +{% panel style="info", title="TL;DR" %} +- Edit a live Resource in an editor +{% endpanel %} + +# Editing Resources + +## Motivation + +Directly modify a Resource in the cluster by opening its Config in an editor. + +{% method %} +## Edit + +Edit allows a user to directly edit a Resource in a cluster rather than +editing it through a local file. + +{% sample lang="yaml" %} + +```yaml +# Edit the service named 'docker-registry': +kubectl edit svc/docker-registry +``` + +```yaml +# Use an alternative editor +KUBE_EDITOR="nano" kubectl edit svc/docker-registry +``` + +```yaml +# Edit the job 'myjob' in JSON using the v1 API format: +kubectl edit job.v1.batch/myjob -o json +``` + +```yaml +# Edit the deployment 'mydeployment' in YAML and save the modified config in its annotation: +kubectl edit deployment/mydeployment -o yaml --save-config +``` + +{% endmethod %} + diff --git a/docs/book/pages/imperative_porcelain/introduction.md b/docs/book/pages/imperative_porcelain/introduction.md new file mode 100644 index 00000000..3c1964f4 --- /dev/null +++ b/docs/book/pages/imperative_porcelain/introduction.md @@ -0,0 +1,15 @@ +{% panel style="success", title="Providing Feedback" %} +**Provide feedback at the [survey](https://www.surveymonkey.com/r/JH35X82)** +{% endpanel %} + +# Introduction + +While Declarative Management of Applications is the recommended pattern for production +use cases, imperative porcelain commands may be helpful for development or debugging +issues. These commands are particularly helpful for learning about Kubernetes when coming +from an imperative system. + +**Note:** Some imperative commands can by run with `--dry-run -o yaml` to display the declarative +form. + +This section describes imperative commands that will generate or patch Resource Config. diff --git a/docs/book/pages/imperative_porcelain/setting_fields.md b/docs/book/pages/imperative_porcelain/setting_fields.md new file mode 100644 index 00000000..c091d0bc --- /dev/null +++ b/docs/book/pages/imperative_porcelain/setting_fields.md @@ -0,0 +1,172 @@ +{% panel style="success", title="Providing Feedback" %} +**Provide feedback at the [survey](https://www.surveymonkey.com/r/JH35X82)** +{% endpanel %} + +{% panel style="info", title="TL;DR" %} +- Imperatively Set fields on Resources +{% endpanel %} + +# Creating Resources + +## Motivation + +Set fields on Resources directly from the command line for the purposes of development or debugging. +Not for production Application Management. + +{% method %} +## Scale + +The Replicas field on a Resource can be set using the `kubectl scale` command. + + +{% sample lang="yaml" %} + +```bash +# Scale a replicaset named 'foo' to 3. +kubectl scale --replicas=3 rs/foo +``` + +```sh +# Scale a resource identified by type and name specified in "foo.yaml" to 3. +kubectl scale --replicas=3 -f foo.yaml +``` + +```sh +# If the deployment named mysql's current size is 2, scale mysql to 3. +kubectl scale --current-replicas=2 --replicas=3 deployment/mysql +``` + +```sh +# Scale multiple replication controllers. +kubectl scale --replicas=5 rc/foo rc/bar rc/baz +``` + +```sh +# Scale statefulset named 'web' to 3. +kubectl scale --replicas=3 statefulset/web +``` + +{% endmethod %} + +{% panel style="info", title="Conditional Scale Update" %} +It is possible to conditionally update the replicas if and only if the +replicas haven't changed from their last known value using the `--current-replicas` flag. +e.g. `kubectl scale --current-replicas=2 --replicas=3 deployment/mysql` +{% endpanel %} + + +{% method %} +## Labels + +Labels can be set using the `kubectl label` command. Multiple Resources can +be updated in a single command using the `-l` flag. + +{% sample lang="yaml" %} + +```sh +# Update pod 'foo' with the label 'unhealthy' and the value 'true'. +kubectl label pods foo unhealthy=true +``` + +```sh +# Update pod 'foo' with the label 'status' and the value 'unhealthy', overwriting any existing value. +kubectl label --overwrite pods foo status=unhealthy +``` + +```sh +# Update all pods in the namespace +kubectl label pods --all status=unhealthy +``` + +```sh +# Update a pod identified by the type and name in "pod.json" +kubectl label -f pod.json status=unhealthy +``` + +```sh +# Update pod 'foo' only if the resource is unchanged from version 1. +kubectl label pods foo status=unhealthy --resource-version=1 +``` + +```sh +# Update pod 'foo' by removing a label named 'bar' if it exists. +# Does not require the --overwrite flag. +kubectl label pods foo bar- +``` + +{% endmethod %} + +{% method %} +## Annotations + +Annotations can be set using the `kubectl annotate` command. + +{% sample lang="yaml" %} + +```sh +# Update pod 'foo' with the annotation 'description' and the value 'my frontend'. +# If the same annotation is set multiple times, only the last value will be applied +kubectl annotate pods foo description='my frontend' +``` + +```sh +# Update a pod identified by type and name in "pod.json" +kubectl annotate -f pod.json description='my frontend' +``` + +```sh +# Update pod 'foo' with the annotation 'description' and the value 'my frontend running nginx', overwriting any +existing value. +kubectl annotate --overwrite pods foo description='my frontend running nginx' +``` + +```sh +# Update all pods in the namespace +kubectl annotate pods --all description='my frontend running nginx' +``` + +```sh +# Update pod 'foo' only if the resource is unchanged from version 1. +kubectl annotate pods foo description='my frontend running nginx' --resource-version=1 +``` + +```sh +# Update pod 'foo' by removing an annotation named 'description' if it exists. +# Does not require the --overwrite flag. +kubectl annotate pods foo description- +``` + +{% endmethod %} + +{% method %} +## Patches + +Arbitrary fields can be set using the `kubectl patch` command. + +{% sample lang="yaml" %} + +```sh +# Partially update a node using a strategic merge patch. Specify the patch as JSON. +kubectl patch node k8s-node-1 -p '{"spec":{"unschedulable":true}}' +``` + +```sh +# Partially update a node using a strategic merge patch. Specify the patch as YAML. +kubectl patch node k8s-node-1 -p $'spec:\n unschedulable: true' +``` + +```sh +# Partially update a node identified by the type and name specified in "node.json" using strategic merge patch. +kubectl patch -f node.json -p '{"spec":{"unschedulable":true}}' +``` + +```sh +# Update a container's image; spec.containers[*].name is required because it's a merge key. +kubectl patch pod valid-pod -p '{"spec":{"containers":[{"name":"kubernetes-serve-hostname","image":"new image"}]}}' +``` + +```sh +# Update a container's image using a json patch with positional arrays. +kubectl patch pod valid-pod --type='json' -p='[{"op": "replace", "path": "/spec/containers/0/image", "value":"newimage"}]' +``` +{% endmethod %} diff --git a/docs/book/pages/kubectl_book/getting_started.md b/docs/book/pages/kubectl_book/getting_started.md new file mode 100644 index 00000000..0e2e71e2 --- /dev/null +++ b/docs/book/pages/kubectl_book/getting_started.md @@ -0,0 +1,207 @@ +{% panel style="success", title="Providing Feedback" %} +**Provide feedback at the [survey](https://www.surveymonkey.com/r/JH35X82)** +{% endpanel %} + +{% panel style="info", title="TL;DR" %} +- Creating Resources +- Printing Resources +- Debugging Containers +{% endpanel %} + +# Getting Started With Kubectl + +**Note**: If you are already familiar with Kubectl, you can skip this section. + +This section provides a brief overview of the most basic Kubectl commands, which are +described in more detail in later chapters. + +For more background on the Kubernetes APIs themselves, see the docs at [k8s.io](k8s.io). + +## Listing Kubernetes Resources + +{% method %} + +List the Kubernetes *Deployment* Resources that are in the kube-system namespace. + +**Note:** Deployments are Resources which manage Pod replicas (Pods run Containers) + +{% sample lang="yaml" %} +```bash +kubectl get deployments --namespace kube-system +``` + +```bash +NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE +event-exporter-v0.2.3 1 1 1 1 14d +fluentd-gcp-scaler 1 1 1 1 14d +heapster-v1.6.0-beta.1 1 1 1 1 14d +kube-dns 2 2 2 2 14d +kube-dns-autoscaler 1 1 1 1 14d +l7-default-backend 1 1 1 1 14d +metrics-server-v0.3.1 1 1 1 1 14d +``` + +{% endmethod %} + +{% method %} + +Print detailed information about the kube-dns Deployment in the kube-system namespace. + +{% sample lang="yaml" %} +```bash +kubectl describe deployment kube-dns --namespace kube-system +``` + +```bash +Name: kube-dns +Namespace: kube-system +CreationTimestamp: Wed, 06 Mar 2019 17:36:05 -0800 +Labels: addonmanager.kubernetes.io/mode=Reconcile + k8s-app=kube-dns + kubernetes.io/cluster-service=true +Annotations: deployment.kubernetes.io/revision: 2 +... +``` +{% endmethod %} + +## Creating a Resource from Config + +{% method %} + +Create or Update Kubernetes Resources from Remote Config. + +{% sample lang="yaml" %} +```bash +kubectl apply -f https://raw.githubusercontent.com/kubernetes/kubectl/master/docs/book/examples/nginx/nginx.yaml +``` + +```bash +service/nginx created +deployment.apps/nginx-deployment created +``` +{% endmethod %} + +{% method %} + +Create or Update Kubernetes Resources from Local Config. + +{% sample lang="yaml" %} +```bash +kubectl apply -f ./examples/nginx/nginx.yaml +``` + +```bash +service/nginx created +deployment.apps/nginx-deployment created +``` +{% endmethod %} + +{% method %} + +Print the Resources that were Applied. + +{% sample lang="yaml" %} +```bash +kubectl get -f ./examples/nginx/nginx.yaml --show-labels +``` + +```bash +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE LABELS +service/nginx ClusterIP 10.59.245.201 80/TCP 11m + +NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE LABELS +deployment.apps/nginx-deployment 3 3 3 3 11m app=nginx +``` +{% endmethod %} + +## Generating a Config from a Command + +{% method %} + +Generate Config for a Deployment Resource. This could be Applied to a cluster by writing the output +to a file, and then running `kubectl apply -f ` + +**Note:** The generated Config has extra boilerplate that users shouldn't include but exists +due to the serialization process of go objects. + +{% sample lang="yaml" %} +```bash +kubectl create deployment nginx --dry-run -o yaml --image nginx +``` + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + creationTimestamp: null # delete this + labels: + app: nginx + name: nginx +spec: + replicas: 1 + selector: + matchLabels: + app: nginx + strategy: {} # delete this + template: + metadata: + creationTimestamp: null # delete this + labels: + app: nginx + spec: + containers: + - image: nginx + name: nginx + resources: {} # delete this +status: {} # delete this +``` +{% endmethod %} + +## Viewing Pods Associated with Resources + +{% method %} + +View the Pods created by the Deployment using the Pod labels. + +{% sample lang="yaml" %} +```bash +kubectl get pods -l app=nginx +``` + +```bash +NAME READY STATUS RESTARTS AGE +nginx-deployment-5c689d88bb-b2xfk 1/1 Running 0 10m +nginx-deployment-5c689d88bb-rx569 1/1 Running 0 10m +nginx-deployment-5c689d88bb-s7xcv 1/1 Running 0 10m +``` +{% endmethod %} + +## Debugging Containers + +{% method %} + +Get the logs from all Pods managed by the Deployment. + +{% sample lang="yaml" %} + +```bash +kubectl logs -l app=nginx +``` + +{% endmethod %} + +{% method %} + +Get a shell into a specific Pod's Container + +{% sample lang="yaml" %} + +```bash +kubectl exec -i -t nginx-deployment-5c689d88bb-s7xcv bash +``` + +```bash +root@nginx-deployment-5c689d88bb-s7xcv:/# +``` + +{% endmethod %} diff --git a/docs/book/pages/kubectl_book/resources_and_controllers.md b/docs/book/pages/kubectl_book/resources_and_controllers.md new file mode 100644 index 00000000..1b243b9c --- /dev/null +++ b/docs/book/pages/kubectl_book/resources_and_controllers.md @@ -0,0 +1,228 @@ +{% panel style="success", title="Providing Feedback" %} +**Provide feedback at the [survey](https://www.surveymonkey.com/r/JH35X82)** +{% endpanel %} + +{% panel style="info", title="TL;DR" %} +- A Kubernetes API has 2 parts - a Resource Type and a Controller +- Resources are objects declared as json or yaml and written to a cluster +- Controllers asynchronously actuate Resources after they are stored +{% endpanel %} + +# Kubernetes Resources and Controllers Overview + +This section provides background on the Kubernetes Resource model. This information +is also available at the [kubernetes.io](https://kubernetes.io/docs/home/) docs site. + +For more information on Kubernetes Resources see: [kubernetes.io Concepts](https://kubernetes.io/docs/concepts/). + +## Resources + +Instances of Kubernetes objects (e.g. Deployment, Services, Namespaces, etc) +are called **Resources**. + +Resources which run containers are referred to as **Workloads**. + +Examples of Workloads: + +- [Deployments](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/) +- [StatefulSets](https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/) +- [Jobs](https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/) +- [CronJobs](https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/) +- [DaemonSets](https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/) + + +**Users work with Resource APIs by declaring them in files which are then Applied to a Kubernetes +cluster. These declarative files are called Resource Config.** + +Resource Config is *Applied* (declarative Create/Update/Delete) to a Kubernetes cluster using +tools such as Kubectl, and then actuated by a *Controller*. + +Resources are uniquely identified: + +- **apiVersion** (API Type Group and Version) +- **kind** (API Type Name) +- **metadata.namespace** (Instance namespace) +- **metadata.name** (Instance name) + +{% panel style="warning", title="Default Namespace" %} +If namespace is omitted from the Resource Config, the *default* namespace is used. Users +should almost always explicitly specify the namespace for their Application using a +`kustomization.yaml`. +{% endpanel %} + +{% method %} + +### Resources Structure + +Resources have the following components. + +**TypeMeta:** Resource Type **apiVersion** and **kind**. + +**ObjectMeta:** Resource **name** and **namespace** + other metadata (labels, annotations, etc). + +**Spec:** the desired state of the Resource - intended state the user provides to the cluster. + +**Status:** the observed state of the object - recorded state the cluster provides to the user. + +Resource Config written by the user omits the Status field. + +**Example Deployment Resource Config** +{% sample lang="yaml" %} + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment + labels: + app: nginx +spec: + replicas: 3 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.15.4 +``` +{% endmethod %} + +{% panel style="info", title="Spec and Status" %} +Resources such as ConfigMaps and Secrets do not have a Status, +and as a result their Spec is implicit (i.e. they don't have a spec field). +{% endpanel %} + +## Controllers + +Controllers actuate Kubernetes APIs. They observe the state of the system and look for +changes either to desired state of Resources (create, update, delete) or the system +(Pod or Node dies). + +Controllers then make changes to the cluster to fulfill the intent specified by the user +(e.g. in Resource Config) or automation (e.g. changes from Autoscalers). + +**Example:** After a user creates a Deployment, the Deployment Controller will see +that the Deployment exists and verify that the corresponding ReplicaSet it expects +to find exists. The Controller will see that the ReplicaSet does not exist and will +create one. + +{% panel style="warning", title="Asynchronous Actuation" %} +Because Controllers run asynchronously, issues such as a bad +Container Image or unschedulable Pods will not be present in the CRUD response. +Tooling must facilitate processes for watching the state of the system until changes are +completely actuated by Controllers. Once the changes have been fully actuated such +that the desired state matches the observed state, the Resource is considered *Settled*. +{% endpanel %} + +### Controller Structure + +**Reconcile** + +Controllers actuate Resources by reading the Resource they are Reconciling + related Resources, +such as those that they create and delete. + +**Controllers *do not* Reconcile events, rather they Reconcile the expected +cluster state to the observed cluster state at the time Reconcile is run.** + +1. Deployment Controller creates/deletes ReplicaSets +1. ReplicaSet Controller creates/delete Pods +1. Scheduler (Controller) writes Nodes to Pods +1. Node (Controller) runs Containers specifid in Pods on the Node + +**Watch** + +Controllers actuate Resources *after* they are written by Watching Resource Types, and then +triggering Reconciles from Events. After a Resource is created/updated/deleted, Controllers +Watching the Resource Type will receive a notification that the Resource has been changed, +and they will read the state of the system to see what has changed (instead of relying on +the Event for this information). + +- Deployment Controller watches Deployments + ReplicaSets (+ Pods) +- ReplicaSet Controller watches ReplicaSets + Pods +- Scheduler (Controller) watches Pods +- Node (Controller) watches Pods (+ Secrets + ConfigMaps) + +{% panel style="info", title="Level vs Edge Based Reconciliation" %} +Because Controllers don't respond to individual Events, but instead Reconcile the state +of the system at the time that Reconcile is run, **changes from several different events may be observed +and Reconciled together.** This is referred to as a *Level Based* system, whereas a system that +responds to each event individually would be referred to as an *Edge Based* system. +{% endpanel %} + +## Overview of Kubernetes Resource APIs + +### Pods + +Containers are run in [*Pods*](https://kubernetes.io/docs/concepts/workloads/pods/pod-overview/) which are +scheduled to run on *Nodes* (i.e. worker machines) in a cluster. + +Pods run a *single replica* of an Application and provide: + +- Compute Resources (cpu, memory, disk) +- Environment Variables +- Readiness and Health Checking +- Network (IP address shared by containers in the Pod) +- Mounting Shared Configuration and Secrets +- Mounting Storage Volumes +- Initialization + +{% panel style="warning", title="Multi Container Pods" %} +Multiple replicas of an Application should be created using a Workload API to manage +creation and deletion of Pod replicas using a PodTemplate. + +In some cases a Pod may contain multiple Containers forming a single instance of an Application. These +containers may coordinate with one another through shared network (IP) and storage. +{% endpanel %} + +### Workloads + +Pods are typically managed by higher level abstractions that handle concerns such as +replication, identity, persistent storage, custom scheduling, rolling updates, etc. + +The most common out-of-the-box Workload APIs (manage Pods) are: + +- [Deployments](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/) (Stateless Applications) + - replication + rollouts +- [StatefulSets](https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/) (Stateful Applications) + - replication + rollouts + persistent storage + identity +- [Jobs](https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/) (Batch Work) + - run to completion +- [CronJobs](https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/) (Scheduled Batch Work) + - scheduled run to completion +- [DaemonSets](https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/) (Per-Machine) + - per-Node scheduling + +{% panel style="success", title="API Abstraction Layers" %} +High-level Workload APIs may manage lower-level Workload APIs instead of directly managing Pods +(e.g. Deployments manage ReplicaSets). +{% endpanel %} + +### Service Discovery and Load Balancing + +Service discovery and Load Balancing may be managed by a *Service* object. Services provide a single +virtual IP address and dns name load balanced to a collection of Pods matching Labels. + +{% panel style="info", title="Internal vs External Services" %} +- [Services Resources](https://kubernetes.io/docs/concepts/services-networking/service/) + (L4) may expose Pods internally within a cluster or externally through an HA proxy. +- [Ingress Resources](https://kubernetes.io/docs/concepts/services-networking/ingress/) (L7) + may expose URI endpoints and route them to Services. +{% endpanel %} + +### Configuration and Secrets + +Shared Configuration and Secret data may be provided by ConfigMaps and Secrets. This allows +Environment Variables, Command Line Arguments and Files to be loosely injected into +the Pods and Containers that consume them. + +{% panel style="info", title="ConfigMaps vs Secrets" %} +- [ConfigMaps](https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/) + are for providing non-sensitive data to Pods. +- [Secrets](https://kubernetes.io/docs/concepts/configuration/secret/) + are for providing sensitive data to Pods. +{% endpanel %} diff --git a/docs/book/pages/reference/kustomize.md b/docs/book/pages/reference/kustomize.md new file mode 100644 index 00000000..d07de97c --- /dev/null +++ b/docs/book/pages/reference/kustomize.md @@ -0,0 +1,806 @@ +{% panel style="success", title="Providing Feedback" %} +**Provide feedback at the [survey](https://www.surveymonkey.com/r/JH35X82)** +{% endpanel %} + +{% panel style="info", title="TL;DR" %} +- Reference for `kustomization.yaml` +{% endpanel %} + +# Kustomization.yaml Reference + +#### Terms: + +- **Generators**: Provide Resource Config to Kustomize - e.g. `resources`, `bases`, `secretGenerators`. +- **Transformers**: Modify Resource Config by adding, updating or deleting fields - e.g. `namespace`, `commonLabels`, `images`. +- **Meta**: Configure behavior of Generators and Transformers - e.g. generatorOptions, crds, configurations. + +## Table of Contents + +| Name | Type | Descriptions | Guides | +| :----------------------------------------------- | :--------------- | -------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | +| [bases](#bases) | Generator | Add Resource Configs from another `kustomization.yaml` | [Bases and Variants](../app_customization/bases_and_variants.md) | +| [commonAnnotations](#commonannotations) | Transformer | Set annotations on all Resources and Selectors. | [Labels and Annotations](../app_management/labels_and_annotations.md#setting-annotations-for-all-resources) | +| [commonLabels](#commonlabels) | Transformer | Set labels on all Resources and Selectors. | [Labels and Annotations](../app_management/labels_and_annotations.md#setting-labels-for-all-resources) | +| [configMapGenerator](#configmapgenerator) | Generator | Generate ConfigMap Resources. | [Secrets and ConfigMaps](../app_management/secrets_and_configmaps.md#configmaps-from-files) | +| [configurations](#configurations) | Meta | Extend functionality of builtin Transformers to work with additional types (e.g. CRDs).| | +| [generatorOptions](#generatoroptions) | Meta | Configure how ConfigMaps and Secrets are generated. | | +| [images](#images) | Transformer | Override image names and tags. | [Container Images](../app_management/container_images.md) | +| [namespace](#namespace) | Transformer | Override namespaces on all Resources. | [Namespaces and Names](../app_management/namespaces_and_names.md##setting-a-namespace-for-all-resources) | +| [namePrefix](#nameprefix) | Transformer | Add a prefix to the names of all Resources and References. | [Namespaces and Names](../app_management/namespaces_and_names.md#setting-a-name-prefix-or-suffix-for-all-resources) | +| [nameSuffix](#namesuffix) | Transformer | Add a suffix to the name of all Resources and References. | [Namespaces and Names](../app_management/namespaces_and_names.md#setting-a-name-prefix-or-suffix-for-all-resources) | +| [patchesJson6902](#patchesjson6902) | Transformer | Patch Resource Config using json patch. | [Customizing Resource Fields](../app_customization/customizing_arbitrary_fields.md#customizing-arbitrary-fields-with-jsonpatch) | +| [patchesStrategicMerge](#patchesstrategicmerge) | Transformer | Patch Resource Config using an overlay. | [Customizing Resource Fields](../app_customization/customizing_arbitrary_fields.md#customizing-arbitrary-fields-with-overlays) | +| [resources](#resources) | Generator | Add Raw Resource Configs. | [Apply](../app_management/apply.md#usage) | +| [secretGenerator](#secretgenerator) | Generator | Generate Secret Resources. | [Secrets and ConfigMaps](../app_management/secrets_and_configmaps.md#secrets-from-files) | +| [vars](#vars) | Transformer | Substitute Resource Config field values into Pod Arguments. | [Config Reflection](../app_customization/config_reflection.md) | + +See this [example kustomization.yaml](../examples/kustomize.md) + +## Resource Generators + +Resource Generators provide Resource Configs to Kustomize from sources such as files, urls, or +`kustomization.yaml` fields. + +### bases + +{% method %} + +`bases` contains a list of paths to **directories or git repositories** containing `kustomization.yaml`s. + +`bases` produce Resource Config by running Kustomize against the target. The provided Resource Config +will then have Transformers from the current `kustomization.yaml` applied. + +`bases` are conceptually similar to a base image referenced by `FROM` in a Dockerfile. + +| Name | Type | Desc | +| :------------ | :-------- | :---------------------------------- | +| **base** | []string | List of paths must point to directories or git repositories containing `kustomization.yaml`s. | + + +{% sample lang="yaml" %} + +```yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +bases: +- path/to/dir/with/kust/ +- https://github.com/org/repo/dir/ +``` + +{% endmethod %} + +### configMapGenerator + +{% method %} + +`configMapGenerator` contains a list of ConfigMaps to generate. + +By default, generated ConfigMaps will have a hash appended to the name. The ConfigMap hash is +appended after a `nameSuffix`, if one is specified. Changes to ConfigMap data will cause a ConfigMap +with a new name to be generated, triggering a rolling update to Workloads referencing the ConfigMap. + +Resources such as PodTemplates should reference ConfigMaps by the `name` ConfigMapGenerator field, +and Kustomize will update the reference to match the generated name, +as well as `namePrefix`'s and `nameSuffix`'s. + +**Note:** Hash suffix generation can be disabled for a subset of ConfigMaps by creating a separate +`kustomization.yaml` and generating these ConfigMaps there. This `kustomization.yaml` must set +`generatorOptions.disableNameSuffixHash=true`, and be used as a `base`. See +[generatorOptions](#generatoroptions) for more details. + + +| Name | Type | Desc | +| :--------------------- | :------------------------ | :---------------------------------- | +| **configMapGenerator** | []ConfigMapGeneratorArgs | List of ConfigMaps to generate. | + +##### ConfigMapGeneratorArgs + +| Name | Type | Desc | +| :------------ | :-------- | :---------------------------------- | +| **behavior** | string | Merge behavior when the ConfigMap generator is defined in a base. May be one of `create`, `replace`, `merge. | +| **env** | string | Single file to generate ConfigMap data entries from. Should be a path to a local *env* file, e.g. `path/to/file.env`, where each line of the file is a `key=value` pair. *Each line* will appear as an entry in the ConfigMap data field. | +| **files** | []string | List of files to generate ConfigMap data entries from. Each item should be a path to a local file, e.g. `path/to/file.config`, and the filename will appear as an entry in the ConfigMap data field with its contents as a value. | +| **literals** | []string | List of literal ConfigMap data entries. Each item should be a key and literal value, e.g. `somekey=somevalue`, and the key/value will appear as an entry in the ConfigMap data field.| +| **name** | string | Name for the ConfigMap. Modified by the `namePrefix` and `nameSuffix` fields. | +| **namespace** | string | Namespace for the ConfigMap. Overridden by kustomize-wide `namespace` field.| + + +{% sample lang="yaml" %} + +```yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +configMapGenerator: +# generate a ConfigMap named my-java-server-props- where each file +# in the list appears as a data entry (keyed by base filename). +- name: my-java-server-props + files: + - application.properties + - more.properties +# generate a ConfigMap named my-java-server-env-vars- where each literal +# in the list appears as a data entry (keyed by literal key). +- name: my-java-server-env-vars + literals: + - JAVA_HOME=/opt/java/jdk + - JAVA_TOOL_OPTIONS=-agentlib:hprof +# generate a ConfigMap named my-system-env- where each key/value pair in the +# env.txt appears as a data entry (separated by \n). +- name: my-system-env + env: env.txt +``` + +{% endmethod %} + +### resources + +{% method %} + +`resources` contains a list of Resource Config file paths to be customized. Each file may contain multiple +Resource Config definitions separated by `\n---\n`. + +| Name | Type | Desc | +| :------------ | :------ | :---------------------------------- | +| **resources** | []string | Paths to Resource Config files. | + + +{% sample lang="yaml" %} + +```yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +# list of files containing Resource Config to add +resources: +- path/to/resource.yaml +- another/path/to/resource.yaml +``` + +{% endmethod %} + +### secretGenerator + +{% method %} + +`secretGenerator` contains a list of Secrets to generate. + +By default, generated Secrets will have a hash appended to the name. The Secrets hash is +appended after a `nameSuffix`, if one is specified. Changes to Secrets data will cause a Secrets +with a new name to be generated, triggering a rolling update to Workloads referencing the Secrets. + +Resources such as PodTemplates should reference Secrets by the `name` secretsGenerator field, +and Kustomize will update the reference to match the generated name, +as well as `namePrefix`'s and `nameSuffix`'s. + +**Note:** Hash suffix generation can be disabled for a subset of Secret by creating a separate +`kustomization.yaml` and generating these Secret there. This `kustomization.yaml` must set +`generatorOptions.disableNameSuffixHash=true`, and be used as a `base`. See +[generatorOptions](#generatoroptions) for more details. + + + +| Name | Type | Desc | +| :------------ | :------ | :---------------------------------- | +| **secretGenerator** | []SecretGeneratorArgs | List of Secrets to generate. | + +##### SecretGeneratorArgs + +| Name | Type | Desc | +| :------------ | :------ | :---------------------------------- | +| **behavior** | string | Merge behavior when the Secret generator is defined in a base. May be one of `create`, `replace`, `merge. | +| **env** | string | Single file to generate Secret data entries from. Should be a path to a local *env* file, e.g. `path/to/file.env`, where each line of the file is a `key=value` pair. *Each line* will appear as an entry in the Secret data field. | +| **files** | []string | List of files to generate Secret data entries from. Each item should be a path to a local file, e.g. `path/to/file.config`, and the filename will appear as an entry in the ConfigMap data field with its contents as a value. | +| **literals** | []string | List of literal Secret data entries. Each item should be a key and literal value, e.g. `somekey=somevalue`, and the key/value will appear as an entry in the Secret data field.| +| **name** | string | Name for the Secret. Modified by the `namePrefix` and `nameSuffix` fields. | +| **namespace** | string | Namespace for the Secret. Overridden by kustomize-wide `namespace` field.| +| **type** | string | Type of Secret. If type is "kubernetes.io/tls", then "literals" or "files" must have exactly two keys: "tls.key" and "tls.crt". | + +{% sample lang="yaml" %} + +```yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +secretGenerator: + # generate a tls Secret +- name: app-tls + files: + - secret/tls.cert + - secret/tls.key + type: "kubernetes.io/tls" +- name: env_file_secret + # env is a path to a file to read lines of key=val + # you can only specify one env file per secret. + env: env.txt + type: Opaque +``` + +{% endmethod %} + +## Transformers + +Transformers modify Resources by adding, updating or deleting fields. Transformers work against Generated Resource +Config - e.g. + +- `resources` +- `bases` +- `configMapGenerator` +- `secretGenerator` + +### commonAnnotations + +{% method %} + +`commonAnnotations` sets annotations on all Resources. `commonAnnotations`'s from bases will stack - e.g. +if a `commonAnnotations` was set in a `base`, the new `commonAnnotations` will be added +to or override the base `commonAnnotations`. + +| Name | Type | Desc | +| :------------ | :------ | :---------------------------------- | +| **commonAnnotations** | map[string]string | Keys/Values for annotations. | + + +{% sample lang="yaml" %} + +```yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +commonAnnotations: + annotationKey1: "annotationValue2" + annotationKey2: "annotationValue2" +``` + +{% endmethod %} + +### commonLabels + +{% method %} + +This field sets labels on all Resources. `commonLabels`'s from bases will stack - e.g. +if a `commonLabels` was set in a `base`, the new `commonLabels` will be added +to or override the base `commonLabels`. + +`commonLabels` will also be applied both to Label Selector fields and Label fields in PodTemplates. + +**Note:** Because `commonLabels` are applied to Selectors, they cannot be changed for some objects. + +| Name | Type | Desc | +| :------------ | :------ | :---------------------------------- | +| **commonLabels** | map[string]string | Keys/Values for labels. | + + +{% sample lang="yaml" %} + +```yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +commonLabels: + labelKey1: "labelValue1" + labelKey2: "labelValue2" +``` + +{% endmethod %} + +### images + +{% method %} + +`images` overrides image names and tags in all `[spec.template.]spec.containers.image` fields matching the +`name`. This is an alternative to creating patches to change images. + +| Name | Type | Desc | +| :------------ | :------ | :---------------------------------- | +| **images** | []Image | Images to override. | + +##### Image + +Definitions: + +- *name*: portion of the `image` field value before the `:` - e.g. for `foo:v1` the name would be `foo`. +- *tag*: portion of the `image` field value after the `:` - e.g. for `foo:v1` the name would be `v1`. +- *digest*: alternative to tag for referencing an image. + +| Name | Type | Desc | +| :------------ | :------ | :---------------------------------- | +| **name** | string | Match all `image` fields with this value for the *name*| +| **nameName** | string | Replace the `image` field *name* with this value. | +| **newTag** | string | Replace the `image` field *tag* with this tag value. | +| **digest** | string | Replace the `image` field *tag* with this digest value. Includes the `sha256:` portion of the digest. | + +{% sample lang="yaml" %} + +```yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +images: + - name: postgres + newName: my-registry/my-postgres + newTag: v1 + - name: nginx + newTag: 1.8.0 + - name: my-demo-app + newName: my-app + - name: alpine + digest: sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3 +``` + +{% endmethod %} + +### patchesJson6902 + +{% method %} + +Each entry in this list should resolve to a kubernetes object and a JSON patch that will be applied +to the object. The JSON patch schema is documented at https://tools.ietf.org/html/rfc6902 + +| Name | Type | Desc | +| :------------ | :------ | :---------------------------------- | +| **patchesJson6902** | []Json6902 | List of patch definitions. | + + +##### Json6902 + +Target field points to a kubernetes object by the object's group, version, kind, name and namespace. +Path field is a relative file path of a JSON patch file. File contents can be either json or yaml. + +| Name | Type | Desc | +| :------------ | :------ | :---------------------------------- | +| **target** | Target | Target Resource for the patch. | +| **path** | string | Path to json patch file. Maybe json or yaml. | + + Example patch file: + +```yaml + - op: add + path: /some/new/path + value: value + - op: replace + path: /some/existing/path + value: new value +``` + +##### Target + +| Name | Type | Desc | +| :------------ | :------ | :---------------------------------- | +| **group** | string | Group of the Resource to patch. | +| **kind** | string | Kind of the Resource to patch. | +| **name** | string | Name of the Resource to patch. | +| **namespace** | string | Namespace of the Resource to patch. | +| **version** | string | Version of the Resource to patch. | + + +{% sample lang="yaml" %} + +```yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +patchesJson6902: +- target: + version: v1 + kind: Deployment + name: my-deployment + path: add_init_container.yaml +- target: + version: v1 + kind: Service + name: my-service + path: add_service_annotation.yaml +``` + +{% endmethod %} + +### patchesStrategicMerge + +{% method %} + +`patchesStrategicMerge` applies patches to the matching Resource Config (by Group/Version/Kind + Name/Namespace). Patch +files contain sparse Resource Config definitions - i.e. containing only the Resource Config fields to +add or override. Strategic merge patches are also called *overlays*. + +Small patches that do one thing are best, e.g. modify a memory request/limit. +Small patches are easy to review and easy to compose together. + +| Name | Type | Desc | +| :------------ | :------ | :---------------------------------- | +| **patchesStrategicMerge** | []string | Paths to files containing sparse Resource Config. | + +{% sample lang="yaml" %} + +```yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +patchesStrategicMerge: +- service_port_8888.yaml +- deployment_increase_replicas.yaml +- deployment_increase_memory.yaml +``` + +{% endmethod %} + +### namespace + +{% method %} + +This field sets the `namespace` of all namespaced Resources. If the namespace has already been set in the +Resource Config, this will override the namespace. + +| Name | Type | Desc | +| :------------ | :------ | :---------------------------------- | +| **namespace** | String | Namespace | + + +{% sample lang="yaml" %} + +```yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +namespace: "my-app-namespace" +``` + +{% endmethod %} + +### namePrefix + +{% method %} + +`namePrefix` sets a name prefix on all Resources. `namePrefix`'s from bases will stack - +e.g. if a `namePrefix` was set in a `base`, the new `namePrefix` will be pre-prended to the `namePrefix` in the +`base`. + +Fields that references another Resource will also have the `namePrefix` applied so that the reference is +updated. + +| Name | Type | Desc | +| :------------ | :------ | :---------------------------------- | +| **namePrefix** | String | Value to prepend to all Resource names and references. | + + +{% sample lang="yaml" %} + +```yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +namePrefix: "my-app-name-prefix-" +``` + +{% endmethod %} + +### nameSuffix + +{% method %} + +`nameSuffix` sets a `nameSuffix` on all Resources. `nameSuffix`'s from bases will stack - +e.g. if a `nameSuffix` was set in a `base`, the new `nameSuffix` will be appended to the `nameSuffix` in the +`base`. + +Fields that references another Resource will also have the `nameSuffix` applied so that the reference is +updated. + +| Name | Type | Desc | +| :------------ | :------ | :---------------------------------- | +| **nameSuffix** | String | Value to append to all Resource names and references. | + + +{% sample lang="yaml" %} + +```yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +nameSuffix: "-my-app-name-suffix" +``` + +{% endmethod %} + +### vars + +{% method %} + +`vars` defines values that can be substituted into Pod container arguments and environment variables. +This is necessary for wiring post-transformed fields into container arguments and environment variables. +e.g. Services names may be transformed by `namePrefix` and containers may need to refer to Service names +at runtime. + +Vars are similar to the Kubernetes [Downward API](https://kubernetes.io/docs/tasks/inject-data-application/environment-variable-expose-pod-information/#use-container-fields-as-values-for-environment-variables) +in that they allow Pods to reference information about the environment in which they are run. + +Variables are referenced from container argument using `$(MY_VAR_NAME)` + +Example: + +```yaml +containers: +- image: myimage + command: ["start", "--host", "$(MY_SERVICE_NAME)"] + env: + - name: SECRET_TOKEN + value: $(SOME_SECRET_NAME) +``` + + +| Name | Type | Desc | +| :------------ | :------ | :---------------------------------- | +| **vars** | []Var | List of variable declarations that may be referenced in container arguments. | + + +##### Var + +| Name | Type | Desc | +| :------------ | :------ | :---------------------------------- | +| **name** | string | Name of the variable. Referenced by `$(NAME)`. | +| **objref** | string | Reference to the object containing the field to be referenced. ObjRef should use the unTransformed object name | +| **fieldref** | string | Reference to the field in the object. Defaults to `metadata.name` if unspecified. | + +{% sample lang="yaml" %} + +```yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +vars: + - name: SOME_SECRET_NAME + objref: + kind: Secret + name: my-secret + apiVersion: v1 + - name: MY_SERVICE_NAME + objref: + kind: Service + name: my-service + apiVersion: v1 + fieldref: + fieldpath: metadata.name + - name: ANOTHER_DEPLOYMENTS_POD_RESTART_POLICY + objref: + kind: Deployment + name: my-deployment + apiVersion: apps/v1 + fieldref: + fieldpath: spec.template.spec.restartPolicy +``` + +{% endmethod %} + +## Meta Options + +Meta Options control how Kustomize generates and transforms Resource Config. + +### configurations + +`configurations` is used to configure the built-in Kustomize Transformers to work with CRDs. The built-in +Kustomize configurations can be found [here](https://github.com/kubernetes-sigs/kustomize/tree/master/pkg/transformers/config/defaultconfig) + +Examples: + +- *images* that should be updated by the `images` Transformer +- *object references* that should be updated by `namePrefix`, `nameSuffix` +- *secret* and *configmap* references that should be updated by `secretGenerator` and `configMapGenerator` + +| Name | Type | Desc | +| :------------ | :-------- | :---------------------------------- | +| **configurations** | []string | List of paths to yaml files containing Kustomize meta configuration. | + + +> kustomization.yaml + +```yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +configurations: +- mykind_configuration.yaml +``` + +##### commonAnnotations + +{% method %} + +Specify `commonAnnotations` in the **configuration file** to configure the Kustomize `commonAnnotations` field +to find additional annotation fields on CRDs. + +| Name | Type | Desc | +| :------------ | :-------- | :---------------------------------- | +| **commonAnnotations** | []Annotation | List of paths to annotations fields. | + +| Name | Type | Desc | +| :------------ | :-------- | :---------------------------------- | +| **create** | bool | If true, create the annotation field if it is not present on the Resource Config. | +| **group** | string | API Group of the object to add the annotation to. If unset, applies to all API Groups. | +| **kind** | string | Kind of the object to add the annotation to. If unset, applies to all Kinds. | +| **path** | string | Path to annotation field. | +| **version** | string | API Version of the object to add the annotation to. If unset, applies to all Versions. | + +[Built-in examples](https://github.com/kubernetes-sigs/kustomize/blob/master/pkg/transformers/config/defaultconfig/commonannotations.go) + +{% sample lang="yaml" %} + +> mykind_configuration.yaml file referenced by the configurations field + +```yaml +commonAnnotations: + # set labels at metadata.annotations for all types +- path: metadata/annotations + # create metadata.annotations if it doesn't exist + create: true +``` + +{% endmethod %} + +##### commonLabels + +{% method %} + +Specify `commonLabels` in the **configuration file** to configure the Kustomize `commonLabels` field find +additional labels and selector fields on CRDs. + +| Name | Type | Desc | +| :------------ | :-------- | :---------------------------------- | +| **commonLabels** | []Label | List of paths to label fields. | + +| Name | Type | Desc | +| :------------ | :-------- | :---------------------------------- | +| **create** | bool | If true, create the label field if it is not present on the Resource Config. | +| **group** | string | API Group of the object to add the label to. If unset, applies to all API Groups. | +| **kind** | string | Kind of the object to add the label to. If unset, applies to all Kinds. | +| **path** | string | Path to label field. | +| **version** | string | API Version of the object to add the label to. If unset, applies to all Versions. | + +[Built-in examples](https://github.com/kubernetes-sigs/kustomize/blob/master/pkg/transformers/config/defaultconfig/commonlabels.go) + +{% sample lang="yaml" %} + +> mykind_configuration.yaml file referenced by the configurations field + +```yaml +commonLabels: + # set labels at metadata.labels for all types +- path: metadata/labels + # create metadata.annotations if it doesn't exist + create: true + + # set labels at spec.selector for v1.Service types +- path: spec/selector + create: true + version: v1 + kind: Service + + # set labels at spec.selector.matchLabels for Deployment types +- path: spec/selector/matchLabels + create: true + kind: Deployment + + # set labels at spec...podAffinity...matchLabels for apps.Deployment types +- path: spec/template/spec/affinity/podAffinity/preferredDuringSchedulingIgnoredDuringExecution/podAffinityTerm/labelSelector/matchLabels + # do NOT create spec...podAffinity...matchLabels if it doesn't exist on the Deployment Resource Config + create: false + group: apps + kind: Deployment +``` + +{% endmethod %} + + +##### images + +{% method %} + +Specify `images` in the **configuration file** to configure the Kustomize `images` field find additional +image fields on CRDs. + +| Name | Type | Desc | +| :------------ | :-------- | :---------------------------------- | +| **images** | []Image |List of paths to image fields. | + +| Name | Type | Desc | +| :------------ | :-------- | :---------------------------------- | +| **group** | string | API Group of the object to add the label to. If unset, applies to all API Groups. | +| **kind** | string | Kind of the object to add the label to. If unset, applies to all Kinds. | +| **path** | string | Path to label field. | +| **version** | string | API Version of the object to add the label to. If unset, applies to all Versions. | + +{% sample lang="yaml" %} + +> mykind_configuration.yaml file referenced by the configurations field + +```yaml +images: + # set images at spec.runLatest.container.image for MyKind types +- path: spec/runLatest/container/image + kind: MyKind +``` + +{% endmethod %} + +##### Name References + +{% method %} + +Specify `nameReference` in the **configuration file** for CRDs that reference other objects by name - e.g. +Secrets, ConfigMaps, Services, etc. + +`nameReference` registers for a given type, that **it is referenced by name from another type** - e.g. +Secrets are referenced by Pods. + +Doing so will configure Generators and Transformers to update the field value with a new name when +names are modified - e.g. `namePrefix`, `secretGenerator`. + +| Name | Type | Desc | +| :------------ | :-------- | :---------------------------------- | +| **nameReference** | []Reference |List of types of objects that are referenced by other objects. | + +| Name | Type | Desc | +| :------------- | :-------- | :---------------------------------- | +| **group** | string | API Group of the object **that is being referenced**. If unset, applies to all API Groups. | +| **kind** | string | Kind of the object to **that is being referenced - e.g. Secret, ConfigMap**. | +| **fieldSpecs** | []FieldSpec | Object types that reference this object type. | +| **version** | string | API Version of the object **that is being referenced**. If unset, applies to all Versions. | + +| Name | Type | Desc | +| :------------- | :-------- | :---------------------------------- | +| **group** | string | API Group of the object **that contains a reference**. If unset, applies to all API Groups. | +| **kind** | string | Kind of the object *that contains a reference - e.g. Pod, Deployment**. If unset, applies to all Kinds. | +| **path** | string | Path to the name field that is a reference. | +| **version** | string | API Version of the object *that contains a reference**. If unset, applies to all Versions. | + +[Built-In Examples](https://github.com/kubernetes-sigs/kustomize/blob/master/pkg/transformers/config/defaultconfig/namereference.go) + +{% sample lang="yaml" %} + +> mykind_configuration.yaml file referenced by the configurations field + +```yaml +nameReference: +# Configure named references to Secret objects to be updated by Transformers and Generators - e.g. namePrefix, secretGenerator, etc +- kind: Secret + version: v1 + fieldSpecs: + # v1.Pods that reference a Secret in spec.volumes.secret.secretName will have it updated + - path: spec/volumes/secret/secretName + version: v1 + kind: Pod + # v1.Pods that reference a Secret in spec.containers.env.valueFrom.secretKeyRef.name will have it updated + - path: spec/containers/env/valueFrom/secretKeyRef/name + version: v1 + kind: Pod +``` +{% endmethod %} + +### generatorOptions + +{% method %} + +`generatorOptions` modifies behavior of all ConfigMap and Secret generators in the current `kustomization.yaml`. +generatorOptions from `bases` apply **only** to the Secrets and ConfigMaps generated within **the same +`kustomization.yaml`**. + +**Note** It is possible to define generatorOptions for a subset of generated Resources by defining a `base` to generate +the Resources and setting the options there. This supports generating some ConfigMaps with hash-suffixes, and some +without. + +| Name | Type | Desc | +| :------------ | :------ | :---------------------------------- | +| **generatorOptions** | GeneratorOptions | Options to define how Secrets and ConfigMaps are generated. | + +##### GeneratorOptions + +| Name | Type | Desc | +| :------------ | :------ | :---------------------------------- | +| **labels** | map[string]string | Labels to add to all Resources generated from this `kustomization.yaml`. | +| **annotations** | map[string]annotations | Annotations to add to all Resources generated from this `kustomization.yaml`. | +| **disableNameSuffixHash** | bool | If set to true, don't add a hash suffix to any Resources generated from this `kustomization.yaml`. | + +{% sample lang="yaml" %} + +```yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +generatorOptions: + # labels to add to all generated resources + labels: + kustomize.generated.resources: somevalue + # annotations to add to all generated resources + annotations: + kustomize.generated.resource: somevalue + # disableNameSuffixHash is true disables the default behavior of adding a + # suffix to the names of generated resources that is a hash of + # the resource contents. + disableNameSuffixHash: true +``` + +{% endmethod %} + diff --git a/docs/book/pages/resource_printing/cluster_information.md b/docs/book/pages/resource_printing/cluster_information.md new file mode 100644 index 00000000..caeb593e --- /dev/null +++ b/docs/book/pages/resource_printing/cluster_information.md @@ -0,0 +1,201 @@ +{% panel style="success", title="Providing Feedback" %} +**Provide feedback at the [survey](https://www.surveymonkey.com/r/JH35X82)** +{% endpanel %} + +{% panel style="info", title="TL;DR" %} +- Print information about the Cluster and Client versions +- Print information about the Control Plane +- Print information about Nodes +- Print information about APIs +{% endpanel %} + +# Cluster Info + +## Motivation + +It may be necessary to learn about the Kubernetes cluster itself, rather +than just the workloads running in it. This can be useful for debugging +unexpected behavior. + +## Versions + +{% method %} + +The `kubectl version` prints the client and server versions. Note that +the client version may not be present for clients built locally from +source. + +{% sample lang="yaml" %} + +```bash +kubectl version +``` + +```bash +Client Version: version.Info{Major:"1", Minor:"9", GitVersion:"v1.9.5", GitCommit:"f01a2bf98249a4db383560443a59bed0c13575df", GitTreeState:"clean", BuildDate:"2018-03-19T19:38:17Z", GoVersion:"go1.9.4", Compiler:"gc", Platform:"darwin/amd64"} +Server Version: version.Info{Major:"1", Minor:"11+", GitVersion:"v1.11.6-gke.2", GitCommit:"04ad69a117f331df6272a343b5d8f9e2aee5ab0c", GitTreeState:"clean", BuildDate:"2019-01-04T16:19:46Z", GoVersion:"go1.10.3b4", Compiler:"gc", Platform:"linux/amd64"} +``` +{% endmethod %} + +{% panel style="warning", title="Version Skew" %} +Kubectl supports +/-1 version skew with the Kubernetes cluster. Kubectl +versions that are more than 1 version ahead of or behind the cluster are +not guaranteed to be compatible. +{% endpanel %} + +## Control Plane and Addons + +{% method %} + +The `kubectl cluster-info` prints information about the control plane and +add-ons. + +{% sample lang="yaml" %} + +```bash +kubectl cluster-info +``` + +```bash + Kubernetes master is running at https://1.1.1.1 + GLBCDefaultBackend is running at https://1.1.1.1/api/v1/namespaces/kube-system/services/default-http-backend:http/proxy + Heapster is running at https://1.1.1.1/api/v1/namespaces/kube-system/services/heapster/proxy + KubeDNS is running at https://1.1.1.1/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy + Metrics-server is running at https://1.1.1.1/api/v1/namespaces/kube-system/services/https:metrics-server:/proxy +``` + +{% endmethod %} + +{% panel style="info", title="Kube Proxy" %} +The URLs printed by `cluster-info` can be access at `127.0.0.1:8001` by +running `kubectl proxy`. +{% endpanel %} + +## Nodes + + +{% method %} + +The `kubectl top node` and `kubectl top pod` print information about the +top nodes and pods. + +{% sample lang="yaml" %} + +```bash +kubectl top node +``` + +```bash + NAME CPU(cores) CPU% MEMORY(bytes) MEMORY% + gke-dev-default-pool-e1e7bf6a-cc8b 37m 1% 571Mi 10% + gke-dev-default-pool-e1e7bf6a-f0xh 103m 5% 1106Mi 19% + gke-dev-default-pool-e1e7bf6a-jfq5 139m 7% 1252Mi 22% + gke-dev-default-pool-e1e7bf6a-x37l 112m 5% 982Mi 17% +``` + +{% endmethod %} + +## APIs + +The `kubectl api-versions` and `kubectl api-resources` print information +about the available Kubernetes APIs. This information is read from the +Discovery Service. + +{% method %} + +Print the Resource Types available in the cluster. + +{% sample lang="yaml" %} + +```bash +kubectl api-resources +``` + +```bash +NAME SHORTNAMES APIGROUP NAMESPACED KIND +bindings true Binding +componentstatuses cs false ComponentStatus +configmaps cm true ConfigMap +endpoints ep true Endpoints +events ev true Event +limitranges limits true LimitRange +namespaces ns false Namespace +... +``` +{% endmethod %} + +{% method %} + +Print the API versions available in the cluster. + +{% sample lang="yaml" %} + +```bash +kubectl api-versions +``` + +```bash + admissionregistration.k8s.io/v1beta1 + apiextensions.k8s.io/v1beta1 + apiregistration.k8s.io/v1 + apiregistration.k8s.io/v1beta1 + apps/v1 + apps/v1beta1 + apps/v1beta2 + ... +``` + +{% endmethod %} + +{% panel style="info", title="Discovery" %} +The discovery information can be viewed at `127.0.0.1:8001/` by running +`kubectl proxy`. The Discovery for specific API can be found under either +`/api/v1` or `apis//`, depending on the API group - +e.g. `127.0.0.1:8001/apis/apps/v1` +{% endpanel %} + + +{% method %} + +The `kubectl explain` command can be used to print metadata about specific +Resource types. This is useful for learning about the type. + +{% sample lang="yaml" %} + +```bash +kubectl explain deployment --api-version apps/v1 +``` + +```bash +KIND: Deployment +VERSION: apps/v1 + +DESCRIPTION: + Deployment enables declarative updates for Pods and ReplicaSets. + +FIELDS: + apiVersion + APIVersion defines the versioned schema of this representation of an + object. Servers should convert recognized schemas to the latest internal + value, and may reject unrecognized values. More info: + https://git.k8s.io/community/contributors/devel/api-conventions.md#resources + + kind + Kind is a string value representing the REST resource this object + represents. Servers may infer this from the endpoint the client submits + requests to. Cannot be updated. In CamelCase. More info: + https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds + + metadata + Standard object metadata. + + spec + Specification of the desired behavior of the Deployment. + + status + Most recently observed status of the Deployment. +``` + +{% endmethod %} + + diff --git a/docs/book/pages/resource_printing/describe.md b/docs/book/pages/resource_printing/describe.md new file mode 100644 index 00000000..2f7af0db --- /dev/null +++ b/docs/book/pages/resource_printing/describe.md @@ -0,0 +1,68 @@ +{% panel style="success", title="Providing Feedback" %} +**Provide feedback at the [survey](https://www.surveymonkey.com/r/JH35X82)** +{% endpanel %} + +{% panel style="info", title="TL;DR" %} +- Print verbose debug information about a Resource +{% endpanel %} + +# Describe Resources + +## Motivation + +{% method %} +Describe is a **higher level printing operation that may aggregate data from other sources** in addition +to the Resource being queried (e.g. Events). + +Describe pulls out the most important information about a Resource from the Resource itself and related +Resources, and formats and prints this information on multiple lines. + +- Aggregates data from related Resources +- Formats Verbose Output for debugging + +{% sample lang="yaml" %} + +```bash +kubectl describe deployments +``` + +```bash +Name: nginx +Namespace: default +CreationTimestamp: Thu, 15 Nov 2018 10:58:03 -0800 +Labels: app=nginx +Annotations: deployment.kubernetes.io/revision=1 +Selector: app=nginx +Replicas: 1 desired | 1 updated | 1 total | 1 available | 0 unavailable +StrategyType: RollingUpdate +MinReadySeconds: 0 +RollingUpdateStrategy: 25% max unavailable, 25% max surge +Pod Template: + Labels: app=nginx + Containers: + nginx: + Image: nginx + Port: + Host Port: + Environment: + Mounts: + Volumes: +Conditions: + Type Status Reason + ---- ------ ------ + Progressing True NewReplicaSetAvailable + Available True MinimumReplicasAvailable +OldReplicaSets: +NewReplicaSet: nginx-78f5d695bd (1/1 replicas created) +Events: +``` + +{% endmethod %} + +{% panel style="info", title="Get vs Describe" %} +When Describing a Resource, it may aggregate information from several other Resources. For instance Describing +a Node will aggregate Pod Resources to print the Node utilization. + +When Getting a Resource, it will only print information available from reading that Resource. While Get may aggregate +data from the the *fields* of that Resource, it won't look at fields from other Resources. +{% endpanel %} diff --git a/docs/book/pages/resource_printing/fields.md b/docs/book/pages/resource_printing/fields.md new file mode 100644 index 00000000..362eb46e --- /dev/null +++ b/docs/book/pages/resource_printing/fields.md @@ -0,0 +1,187 @@ +{% panel style="success", title="Providing Feedback" %} +**Provide feedback at the [survey](https://www.surveymonkey.com/r/JH35X82)** +{% endpanel %} + +{% panel style="info", title="TL;DR" %} +- Format and print specific fields from Resources +- Use when scripting with Get +{% endpanel %} + +# Print Resource Fields + +## Motivation + +Kubectl Get is able to pull out fields from Resources it queries and format them as output. + +This may be **useful for scripting or gathering data** about Resources from a Kubernetes cluster. + +## Get + +The `kubectl get` reads Resources from the cluster and formats them as output. The examples in +this chapter will query for Resources by providing Get the *Resource Type* with the +Version and Group as an argument. +For more query options see [Queries and Options](queries_and_options.md). + +Kubectl can format and print specific fields from Resources using Json Path. + +{% panel style="warning", title="Scripting Pitfalls" %} +By default, if no API group or version is specified, kubectl will use the group and version preferred by +the apiserver. + +Because the **Resource structure may change between API groups and Versions**, users *should* specify the +API Group and Version when emitting fields from `kubectl get` to make sure the command does not break +in future releases. + +Failure to do this may result in the different API group / version being used after a cluster upgrade, and +this group / version may have changed the representation of fields. +{% endpanel %} + +### JSON Path + +Print the fields from the JSON Path + +**Note:** JSON Path can also be read from a file using `-o custom-columns-file`. + +- JSON Path template is composed of JSONPath expressions enclosed by {}. In addition to the original JSONPath syntax, several capabilities are added: + - The `$` operator is optional (the expression starts from the root object by default). + - Use "" to quote text inside JSONPath expressions. + - Use range operator to iterate lists. + - Use negative slice indices to step backwards through a list. Negative indices do not “wrap around” a list. They are valid as long as -index + listLength >= 0. + +### JSON Path Symbols Table + +| Function | Description | Example | Result | +|---|---|---|---| +| text | the plain text | kind is {.kind} | kind is List | +| @ | the current object | {@} | the same as input | +| . or [] | child operator | {.kind} or {[‘kind’]} | List | +| .. | recursive descent | {..name} | 127.0.0.1 127.0.0.2 myself e2e | +| * | wildcard. Get all objects | {.items[*].metadata.name} | [127.0.0.1 127.0.0.2] | +| [start:end :step] | subscript operator | {.users[0].name} | myself | +| [,] | union operator | {.items[*][‘metadata.name’, ‘status.capacity’]} |127.0.0.1 127.0.0.2 map[cpu:4] map[cpu:8] | +| ?() | filter | {.users[?(@.name==“e2e”)].user.password} | secret | +| range, end | iterate list | {range .items[*]}[{.metadata.name}, {.status.capacity}] {end} | [127.0.0.1, map[cpu:4]] [127.0.0.2, map[cpu:8]] | +| “ | quote interpreted string | {range .items[*]}{.metadata.name}{’\t’} {end} | 127.0.0.1 127.0.0.2| + +--- + +{% method %} + +Print the JSON representation of the first Deployment in the list on a single line. + +{% sample lang="yaml" %} + +```bash +kubectl get deployment.v1.apps -o=jsonpath='{.items[0]}{"\n"}' + +``` + +```bash +map[apiVersion:apps/v1 kind:Deployment...replicas:1 updatedReplicas:1]] +``` +{% endmethod %} + +--- + +{% method %} + +Print the `metadata.name` field for the first Deployment in the list. + +{% sample lang="yaml" %} + +```bash +kubectl get deployment.v1.apps -o=jsonpath='{.items[0].metadata.name}{"\n"}' +``` + +```bash +nginx +``` + +{% endmethod %} + +--- + +{% method %} + +For each Deployment, print its `metadata.name` field and a newline afterward. + +{% sample lang="yaml" %} + +```bash +kubectl get deployment.v1.apps -o=jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}' +``` + +```bash +nginx +nginx2 +``` + +{% endmethod %} + +--- + +{% method %} + +For each Deployment, print its `metadata.name` and `.status.availableReplicas`. + +{% sample lang="yaml" %} + +```bash +kubectl get deployment.v1.apps -o=jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.availableReplicas}{"\n"}{end}' +``` +```bash +nginx 1 +nginx2 1 +``` + +{% endmethod %} + +--- + +{% method %} + +Print the list of Deployments as single line. + +{% sample lang="yaml" %} + +```bash +kubectl get deployment.v1.apps -o=jsonpath='{@}{"\n"}' +``` + +```bash +map[kind:List apiVersion:v1 metadata:map[selfLink: resourceVersion:] items:[map[apiVersion:apps/v1 kind:Deployment...replicas:1 updatedReplicas:1]]]] +``` + +{% endmethod %} + +--- + +{% method %} + +Print each Deployment on a new line. + +{% sample lang="yaml" %} + +```bash +kubectl get deployment.v1.apps -o=jsonpath='{range .items[*]}{@}{"\n"}{end}' +``` + +```bash +map[kind:Deployment...readyReplicas:1]] +map[kind:Deployment...readyReplicas:1]] +``` + +{% endmethod %} + +--- + +{% panel style="info", title="Literal Syntax" %} +On Windows, you must double quote any JSONPath template that contains spaces (not single quote as shown above for bash). +This in turn means that you must use a single quote or escaped double quote around any literals in the template. + +For example: + +```bash +C:\> kubectl get pods -o=jsonpath="{range .items[*]}{.metadata.name}{'\t'}{.status.startTime}{'\n'}{end}" +``` +{% endpanel %} diff --git a/docs/book/pages/resource_printing/queries_and_options.md b/docs/book/pages/resource_printing/queries_and_options.md new file mode 100644 index 00000000..bc0bbd35 --- /dev/null +++ b/docs/book/pages/resource_printing/queries_and_options.md @@ -0,0 +1,180 @@ +{% panel style="success", title="Providing Feedback" %} +**Provide feedback at the [survey](https://www.surveymonkey.com/r/JH35X82)** +{% endpanel %} + +{% panel style="info", title="TL;DR" %} +- Queries for Getting or Describing Resources +{% endpanel %} + +# Matching Objects from Get and Describing + +## Motivation + +Match Resources with Queries when Getting or Describing them. + +{% method %} +## Resource Config By `kustomization.yaml` + +Get all Resources provided by the `kustomization.yaml` in project/. +{% sample lang="yaml" %} + +```bash +kubectl get -k project/ +``` + +{% endmethod %} + +{% method %} +## Resource Config By Dir + +Get all Resources present in the Resource Config for a directory. +{% sample lang="yaml" %} + +```bash +kubectl get -f configs/ +``` + +{% endmethod %} + +{% method %} +## Resource Types + +Get **all** Resources in a namespace for a given type. + +The Group and Version for the Resource are determined by the apiserver discovery service. + +The Singular, Plural, Short Name also apply to *Types with Name* and *Types with Selectors*. +{% sample lang="yaml" %} + +```bash +# Plural +kubectl get deployments +``` + +```bash +# Singular +kubectl get deployment +``` + +```bash +# Short name +kubectl get deploy +``` + +{% endmethod %} + +{% method %} +## Resource Types with Group / Version + +Get **all** Resources in a namespace for a given type. + +The Group and Version for the Resource are explicit. + +{% sample lang="yaml" %} + +```bash +kubectl get deployments.apps +``` + +```bash +kubectl get deployments.v1.apps +``` + +{% endmethod %} + +{% method %} +## Resource Types with Name + +Get named Resources in a namespace for a given type. + +{% sample lang="yaml" %} + +```bash +kubectl get deployment nginx +``` + +{% endmethod %} + +{% method %} +## Label Selector + +Get **all** Resources in a namespace **matching a label select** for a given type. +{% sample lang="yaml" %} + +```bash +kubectl get deployments -l app=nginx +``` + +{% endmethod %} + +{% method %} +## Namespaces + +By default Get and Describe will fetch resource in the default namespace or the namespace specified +with `--namespace`. + +The `---all-namespaces` flag will **fetch Resources from all namespaces**. + +{% sample lang="yaml" %} + +```bash +kubectl get deployments --all-namespaces +``` + +{% endmethod %} + + +{% method %} +## List multiple Resource types + +Get and Describe can accept **multiple Resource types**, and it will print them both in separate sections. + +{% sample lang="yaml" %} + +```bash +kubectl get deployments,services +``` + +{% endmethod %} + + +{% method %} +## List multiple Resource types by name + +Get and Describe can accept **multiple Resource types and names**. + +{% sample lang="yaml" %} + +```bash +kubectl get kubectl get rc/web service/frontend pods/web-pod-13je7 +``` + +{% endmethod %} + +{% method %} +## Uninitialized + +Kubernetes **Resources may be hidden until they have gone through an initialization process**. +These Resources can be view with the `--include-uninitialized` flag. + +{% sample lang="yaml" %} + +```bash +kubectl get deployments --include-uninitialized +``` + +{% endmethod %} + +{% method %} +## Not Found + +By default, Get or Describe **will return an error if an object is requested and doesn't exist**. +The `--ignore-not-found` flag will cause kubectl to exit 0 if the Resource is not found + +{% sample lang="yaml" %} + +```bash +kubectl get deployment nginx --ignore-not-found +``` + +{% endmethod %} diff --git a/docs/book/pages/resource_printing/raw.md b/docs/book/pages/resource_printing/raw.md new file mode 100644 index 00000000..c629f6d1 --- /dev/null +++ b/docs/book/pages/resource_printing/raw.md @@ -0,0 +1,229 @@ +{% panel style="success", title="Providing Feedback" %} +**Provide feedback at the [survey](https://www.surveymonkey.com/r/JH35X82)** +{% endpanel %} + +{% panel style="info", title="TL;DR" %} +- Get or List Raw Resources in a cluster as Yaml or Json +{% endpanel %} + +# Print Raw Resource + +## Motivation + +Inspecting or Debugging Resources. + +The Kubernetes Resources stored in etcd by the apiserver have **many more fields than +are shown in the summarized views**. Users can learn much more about a Resource by +viewing the Raw Resource as Yaml or Json. The Raw Resource will contain: + +- fields specified by the **user** in the Resource Config (e.g. `metadata.name`) +- metadata fields owned by the **apiserver** (e.g. `metadata.creationTimestamp`) +- fields defaulted by the **apiserver** (e.g. `spec..imagePullPolicy`) +- fields set by **Controllers** (e.g. `spec.clusterIp`, `status`) + +## Get + +The `kubectl get` reads Resources from the cluster and formats them as output. The examples in +this chapter will query for Resources by providing Get the *Resource Type* as an argument. +For more query options see [Queries and Options](queries_and_options.md). + +{% method %} + +### YAML + +Print the Raw Resource formatting it as YAML. + +{% sample lang="yaml" %} + +```bash +kubectl get deployments -o yaml +``` + +```yaml +apiVersion: v1 +items: +- apiVersion: extensions/v1beta1 + kind: Deployment + metadata: + annotations: + deployment.kubernetes.io/revision: "1" + creationTimestamp: 2018-11-15T18:58:03Z + generation: 1 + labels: + app: nginx + name: nginx + namespace: default + resourceVersion: "1672574" + selfLink: /apis/extensions/v1beta1/namespaces/default/deployments/nginx + uid: 6131547f-e908-11e8-9ff6-42010a8a00d1 + spec: + progressDeadlineSeconds: 600 + replicas: 1 + revisionHistoryLimit: 10 + selector: + matchLabels: + app: nginx + strategy: + rollingUpdate: + maxSurge: 25% + maxUnavailable: 25% + type: RollingUpdate + template: + metadata: + creationTimestamp: null + labels: + app: nginx + spec: + containers: + - image: nginx + imagePullPolicy: Always + name: nginx + resources: {} + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + dnsPolicy: ClusterFirst + restartPolicy: Always + schedulerName: default-scheduler + securityContext: {} + terminationGracePeriodSeconds: 30 + status: + availableReplicas: 1 + conditions: + - lastTransitionTime: 2018-11-15T18:58:10Z + lastUpdateTime: 2018-11-15T18:58:10Z + message: Deployment has minimum availability. + reason: MinimumReplicasAvailable + status: "True" + type: Available + - lastTransitionTime: 2018-11-15T18:58:03Z + lastUpdateTime: 2018-11-15T18:58:10Z + message: ReplicaSet "nginx-78f5d695bd" has successfully progressed. + reason: NewReplicaSetAvailable + status: "True" + type: Progressing + observedGeneration: 1 + readyReplicas: 1 + replicas: 1 + updatedReplicas: 1 +kind: List +metadata: + resourceVersion: "" + selfLink: "" +``` + +{% endmethod %} + +--- + +{% method %} + +### JSON + +Print the Raw Resource formatting it as JSON. + +{% sample lang="yaml" %} + +```bash +kubectl get deployments -o json +``` + +```json +{ + "apiVersion": "v1", + "items": [ + { + "apiVersion": "extensions/v1beta1", + "kind": "Deployment", + "metadata": { + "annotations": { + "deployment.kubernetes.io/revision": "1" + }, + "creationTimestamp": "2018-11-15T18:58:03Z", + "generation": 1, + "labels": { + "app": "nginx" + }, + "name": "nginx", + "namespace": "default", + "resourceVersion": "1672574", + "selfLink": "/apis/extensions/v1beta1/namespaces/default/deployments/nginx", + "uid": "6131547f-e908-11e8-9ff6-42010a8a00d1" + }, + "spec": { + "progressDeadlineSeconds": 600, + "replicas": 1, + "revisionHistoryLimit": 10, + "selector": { + "matchLabels": { + "app": "nginx" + } + }, + "strategy": { + "rollingUpdate": { + "maxSurge": "25%", + "maxUnavailable": "25%" + }, + "type": "RollingUpdate" + }, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "app": "nginx" + } + }, + "spec": { + "containers": [ + { + "image": "nginx", + "imagePullPolicy": "Always", + "name": "nginx", + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + } + ], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "terminationGracePeriodSeconds": 30 + } + } + }, + "status": { + "availableReplicas": 1, + "conditions": [ + { + "lastTransitionTime": "2018-11-15T18:58:10Z", + "lastUpdateTime": "2018-11-15T18:58:10Z", + "message": "Deployment has minimum availability.", + "reason": "MinimumReplicasAvailable", + "status": "True", + "type": "Available" + }, + { + "lastTransitionTime": "2018-11-15T18:58:03Z", + "lastUpdateTime": "2018-11-15T18:58:10Z", + "message": "ReplicaSet \"nginx-78f5d695bd\" has successfully progressed.", + "reason": "NewReplicaSetAvailable", + "status": "True", + "type": "Progressing" + } + ], + "observedGeneration": 1, + "readyReplicas": 1, + "replicas": 1, + "updatedReplicas": 1 + } + } + ], + "kind": "List", + "metadata": { + "resourceVersion": "", + "selfLink": "" + } +} +``` + +{% endmethod %} diff --git a/docs/book/pages/resource_printing/summaries.md b/docs/book/pages/resource_printing/summaries.md new file mode 100644 index 00000000..5fbaf0de --- /dev/null +++ b/docs/book/pages/resource_printing/summaries.md @@ -0,0 +1,150 @@ +{% panel style="success", title="Providing Feedback" %} +**Provide feedback at the [survey](https://www.surveymonkey.com/r/JH35X82)** +{% endpanel %} + +{% panel style="info", title="TL;DR" %} +- Get a Summary of Resources Running in the Cluster +{% endpanel %} + +# Summarizing Resources + +## Motivation + +Quickly summarizing a collection of Resources and their state. + +Summarizing Resource State using a columnar format is the most common way to view cluster +state when developing applications or triaging issues. The **columnar view gives a compact +summary of the most relevant information** for a collection of Resources. + +## Get + +The `kubectl get` reads Resources from the cluster and formats them as output. The examples in +this chapter will query for Resources by providing Get the *Resource Type* as an argument. +For more query options see [Queries and Options](queries_and_options.md). + +{% method %} +### Default + +If no output format is specified, Get will print a default set of columns. + +**Note:** Some columns *may* not directly map to fields on the Resource, but instead may +be a summary of fields. + +{% sample lang="yaml" %} + +```bash +kubectl get deployments nginx +``` + +```bash +NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE +nginx 1 1 1 0 5s +``` + +{% endmethod %} + +--- + +{% method %} +### Wide + +Print the default columns plus some additional columns. + +**Note:** Some columns *may* not directly map to fields on the Resource, but instead may +be a summary of fields. + +{% sample lang="yaml" %} + +```bash +kubectl get -o=wide deployments nginx +``` + +```bash +NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR +nginx 1 1 1 1 26s nginx nginx app=nginx +``` + +{% endmethod %} + +--- + +{% method %} +### Custom Columns + +Print out specific fields as Columns. + +**Note:** Custom Columns can also be read from a file using `-o custom-columns-file`. + +{% sample lang="yaml" %} + +```bash +kubectl get deployments -o custom-columns="Name:metadata.name,Replicas:spec.replicas,Strategy:spec.strategy.type" +``` + +```bash +Name Replicas Strategy +nginx 1 RollingUpdate +``` + +{% endmethod %} + +--- + +{% method %} +#### Labels + +Print out specific labels each as their own columns +{% sample lang="yaml" %} + +```bash +kubectl get deployments -L=app +``` + +```bash +NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE APP +nginx 1 1 1 1 8m nginx +``` + +{% endmethod %} + +--- + +{% method %} +### Show Labels + +Print out all labels on each Resource in a single column (last). +{% sample lang="yaml" %} + +```bash +kubectl get deployment --show-labels +``` + +```bash +NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE LABELS +nginx 1 1 1 1 7m app=nginx +``` + +{% endmethod %} + +--- + +{% method %} +### Show Kind + +Print out the Group.Kind as part of the Name column. + +**Note:** This can be useful if the user did not specify the group in the command and +they want to know which API is being used. + +{% sample lang="yaml" %} + +```bash +kubectl get deployments --show-kind +``` + +```bash +NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE +deployment.extensions/nginx 1 1 1 1 8m +``` + +{% endmethod %} diff --git a/docs/book/pages/resource_printing/watch.md b/docs/book/pages/resource_printing/watch.md new file mode 100644 index 00000000..2bfe34cd --- /dev/null +++ b/docs/book/pages/resource_printing/watch.md @@ -0,0 +1,51 @@ +{% panel style="success", title="Providing Feedback" %} +**Provide feedback at the [survey](https://www.surveymonkey.com/r/JH35X82)** +{% endpanel %} + +{% panel style="info", title="TL;DR" %} +- Continuously Watch and print Resources as they change +{% endpanel %} + +# Watching Resources for changes + +## Motivation + +Print Resources as they are updated. + +{% method %} + +It is possible to have `kubectl get` **continuously watch for changes to objects**, and print the objects +when they are changed or when the watch is reestablished. + +{% sample lang="yaml" %} + +```bash +kubectl get deployments --watch +``` + +```bash +NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE +nginx 1 1 1 1 6h +nginx2 1 1 1 1 21m +``` + +{% endmethod %} + +{% panel style="danger", title="Watch Timeouts" %} +Watch **timesout after 5 minutes**, after which kubectl will re-establish the watch and print the +resources. +{% endpanel %} + +{% method %} + +It is possible to have `kubectl get` continuously watch for changes to objects **without fetching them first** +using the `--watch-only` flag. + +{% sample lang="yaml" %} + +```bash +kubectl get deployments --watch-only +``` + +{% endmethod %} + diff --git a/docs/maintainers/MAINTAINERS.md b/docs/maintainers/MAINTAINERS.md new file mode 100644 index 00000000..7940c727 --- /dev/null +++ b/docs/maintainers/MAINTAINERS.md @@ -0,0 +1,79 @@ +# SIG cli maintainers Guide + +## Sustaining engineering tasks + +The following tasks need to be performed consistently as a part of maintaining the health +of SIG cli. We will be developing an oncall rotation for working on these tasks, where +the oncall is responsible to doing each task daily. + +### Issue triage + +Routinely monitor the newly filed issues and triage them to make sure we identify regressions. + +[Kubectl repo](https://github.com/kubernetes/kubectl/issues) + +[Kubernetes repo](https://github.com/kubernetes/kubernetes/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20label%3Asig%2Fcli) + +Look for: + +- Requests for help + - Don't spend a lot of time on these, but answer and close them if it is easy +- Regressions and bugs + - Find the root cause + - Triage the severity + - Issues only occurring in old versions but not in new versions are less severe +- Simple issues for new contributors + - Label these with "for-new-contributors" + - Give them a priority + - Make sure they are + - Small + - Well scoped + - In areas of code with minimal technical debt + - In areas of code with strong ownership already +- Feature requests + - Do one of + - Close them with an explanation along the lines of "Don't have capacity right now, try reopening in 6 months" + - Label them with a "priority" + +### Test triage + +Monitor [test grid](https://k8s-testgrid.appspot.com/sig-cli-master) +and make sure the tests are passing. + +If any tests are failing, debug them and send a fix. Ask for help if you get stuck. + +### PR review + +Make sure PRs aren't getting stuck without attention. If reviewers routinely don't respond +to PRs within a few days, we should take those reviewers out of the list. + +Look through the PR list with [SIG cli](https://github.com/kubernetes/kubernetes/pulls?utf8=%E2%9C%93&q=is%3Apr%20is%3Aopen%20label%3Asig%2Fcli) + +## New contributor assistance + +- Look through issues labeled "for-new-contributors" that are assigned, and make sure they are active. + If they haven't had activity in a couple days, ping the assignee and ask if help is needed. +- Identify issues for new contributors to pick up +- Figure out a progression for new contributors to become reviewers + +## Per-release tasks + +### At the start of the dev cycle + +- Write planned features for each release + - Use the [template](../template.md) + +### During code-freeze + +- Daily look at issues labeled with [sig/cli in the milestone](https://github.com/kubernetes/kubernetes/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20label%3Asig%2Fcli%20milestone%3Av1.9%20) and make sure they are owned and make progress + - **Note:** You will need to update the milestone in the link to the current milestone + +## Every 3-6 months tasks + +### (3 months) Report about SIG cli at the community meeting + +TODO: fill this in + +### (6 months) Setup a SIG cli face-to-face + +TODO: fill this in diff --git a/docs/maintainers/issue_backlog.md b/docs/maintainers/issue_backlog.md new file mode 100644 index 00000000..a4a6ac18 --- /dev/null +++ b/docs/maintainers/issue_backlog.md @@ -0,0 +1,192 @@ +# SIG CLI Issue Backlog + +Grooming work for new and existing contributors + +- Link: https://goo.gl/YEq33R +- Author: @pwittrock +- Last updated: 10/25/17 + + +## Background + +A goal of SIG CLI is to keep the SIG open to contributions from anyone willing to do the work to get involved. +While many folks have shown interest in contributing, we have struggled to keep most folks engaged. +Kubernetes recently conducted a survey of new contributors, and major themes were that: + +- Contributors don’t know where to start +- There are too many details to learn before contributing +- Communication is hard / everyone is too busy to help +- Hard to get reviewers on PRs + +These challenges can be reduced by: + +- Providing a backlog for contributors to browse and pull work from. +- Scoping work that can be done with minimal experience so folks can pick up and work on it. +- Marking issues as good first time issues if they can be done by someone with no experience. +- Reducing the need for constant communication by having the work be well defined and clearly scoped in the issues + themselves. +- Ensuring each issue has a stake holder that is committed to seeing that changes are reviewed. + +[New Contributors Project]: https://github.com/kubernetes/kubectl/projects/3 + +## Contribution lifecycle + +1. A [good issue](#what-makes-a-good-issue) is created with description and labels. +1. SIG agrees that work for issue will be accepted. +1. Issue moved to the _backlog_ column in the [New Contributors Project]. +1. Contributor assigns issue to self, or asks issue be assigned if they are not a Kubernetes org member. +1. Issue moved to the _assigned_ column in the [New Contributors Project]. +1. Contributor updates issue weekly with status updates, and pushes work to fork + - Periodic feedback provided + - Discussion between contributor and stakeholder occurs on issue +1. Contributor sends PR for review + - Stakeholder ensures the appropriate reviewers exist + - Discussion and updates occur on the PR +1. PR accepted and merged + +## What makes a good issue? + +### Stakeholder and Contributor + +A stakeholder typically files the issue, wants to see the work done, and will +find reviewers for PRs that address the issue. + +The contributor is the issue assignee - they provide PRs for review +to close the issue. + +The stakeholder may become the contributor. They must find a new stakeholder to +review the work and help follow through on issue closure. + +### Encapsulated + +Issues that require modifying large pieces of existing code are typically hard +to accept without multiple reviewers, require a high degree of communication and require knowledge of the +existing codebase. + +This makes them bad candidates for contributors looking to get started independently. + +Issues with good encapsulation have the following properties: + +- Minimal wiring or changes to existing code +- Can disable / enable with a flag +- Easy to review the contribution on its own without needing to examine other parts of the system +- Low chance of needing to rebase or conflicting with changes made in parallel + +### Consensus on work within the SIG + +Work described in issues in the backlog should be agreed upon by the SIG. PRs +sent for review should have the code reviewed, not the _reason_ for doing the +PR. + +SIG CLI needs to come up with low overhead a process for accepting proposed work. + +1. Create an issue for the work +2. SIG agrees to accept work for the issue (as described) if it is completed +3. Add issue to the issue backlog + +## Types of code contributions + +### Code documentation + +Documenting code is an excellent starter task. It is easier to merge and get consensus on than writing tests or +features. It also provides a structured approach to learning about the system and its components. +For the packages that need it most, understanding the code base well enough to document it may be an involved task. + +- Adding doc.go files to packages that are missing them +- Updating doc.go files that are empty placeholders +- Adding examples of how to use types and functions to packages +- Documenting functions with their purpose and usage + +### Test coverage + +Improving test coverage and augmenting e2e tests with integration tests is also a good candidate for 1st and +2nd time contributors. Writing tests for libraries requires understanding how they behave and are meant to be used. +Improving code coverage allows the project to move more quickly by reducing regressions issues that the SIG must field, +and by providing a safety net for code reviewers ensuring changes don’t break existing functionality. + +[e2e tests]: https://github.com/kubernetes/community/blob/master/contributors/devel/e2e-tests.md + +- Write unit tests for functionality currently only covered by integration and [e2e tests]. + > Integration tests may run processes, such as the apiserver, but do so locally. + > E2e tests run a full Kubernetes cluster (remote). +- Write integration tests for functionality currently only covered by [e2e tests]. +- Improve coverage for edge cases and different inputs to functions. +- Improve handling of invalid arguments. +- Refactoring existing tests to pull out common code into reusable functions. + > _This should be very well scoped as it impacts existing tests and reviewers need to make sure nothing breaks._ + +### New libraries + +Encapsulated libraries (collections of functions devoted to one simple purpose - e.g. date/time utils) +are great contributions for experienced contributors - either programming in Go, or +with Kubernetes. + +Because the libraries are encapsulated, it is easier for reviewers to determine the correctness +of their interactions with the existing system. If the functionality is new or can be disabled with a flag, the +risk of accepting the change is reduced, improving the chance the change will be accepted. + +### Modifying existing libraries + +Tasks to perform non-trivial changes to existing libraries should be reserved only for folks who have made +multiple successful contributions of code - either tests or libraries. PRs to modify existing libraries typically +have multiple reviewers, and can have subtle side effects that need to be carefully checked for. + +Improvements in documentation and testing (above) reduces the burden to modify existing code. + +## Managing a backlog issue + +### Setting Labels + +For contributors to pick up new tasks independently, the scope and complexity of the task must be well documented +on the issue. We use labels to define the most important metadata about the issues in the backlog. + +#### Size +- size/S + > 4-10 hours +- size/M + > 10-20 hours +- size/L + > 20+ hours + +#### Type (docs / tests / feature) + +- type/code-cleanup + > Usually some refactoring or small rewrites of code. +- type/code-documentation + > Write doc.go with package overview and examples or document types and functions. +- type/code-feature + > Usually a new go package / library for some functionality. Should be encapsulated. +- type/code-test-coverage + > Audit tests for a package. Run coverage tools and also manually look at what functions are missing unit or + > integration tests. Write tests for these functions. + +### Description + +- Clear description of what the outcome is +- Pointers to examples if they exist +- Clear stakeholder who will be responsive to the issue and is committed to getting the functionality added + +## Assigning an issue once work has started + +1. Contributor messages stakeholder on the issue, and maybe on slack +1. Stakeholder moves issue from backlog to assigned +1. Contributor updates issue weekly and publishes work in progress to a fork + > The issue should be updated with a link to the fork. +1. Once work is ready for review, contributor files a PR and notifies the stakeholder + +## What is expected as part of contributing a library? + +### Documentation + +- doc.go +- Comments on all functions and types + +### Tests + +- Unit tests for functions and types +- Integration tests with a local control plane (forthcoming) +- Maybe e2e tests (only a couple) + +### Ownership of addressing issues + +- Fix bugs discovered in the contribution after it has been accepted diff --git a/docs/roadmap/template.md b/docs/roadmap/template.md new file mode 100644 index 00000000..4660b1df --- /dev/null +++ b/docs/roadmap/template.md @@ -0,0 +1,26 @@ +Use this template for writing roadmaps for releases + +# Release 1.X roadmap + +## Planned Features + +### Feature Y + +Short description + +Owners + +- Link to design proposal +- Link to issue + +### Feature Z + +Short description + +- Link to design proposal +- Link to issue + +## Planned Technical Debt Cleanup + +## Planned Bug Fixes +