From bf34eb94f66384ac43ce8823a7a03376a7a13185 Mon Sep 17 00:00:00 2001 From: Bobby Brennan Date: Mon, 17 Jun 2019 14:28:01 -0400 Subject: [PATCH] update documentation (#265) * update documentation * split up example readmes * Minor tweaks * recommend a safer flow for k8s auth * add docs for cloud provider auth --- CODE_OF_CONDUCT.md | 74 ++++++++++ Makefile | 6 + README.md | 64 +++++--- docs/gcp.md | 15 +- docs/helm.md | 3 + docs/index.md | 76 +++++++--- docs/kubernetes_auth.md | 137 ++++++++++++++++++ docs/without_helm.md | 3 + examples/README.md | 42 +----- examples/ci/README.md | 8 + examples/external-secrets-manager/README.md | 6 + examples/helm/README.md | 2 + examples/minimal/.circleci/config.yml | 60 ++++++++ examples/minimal/Dockerfile | 11 +- examples/minimal/README.md | 81 +++++++++++ examples/minimal/circle.yml | 32 ---- .../deploy/minimal-production.deployment.yml | 12 +- .../deploy/minimal-production.service.yml | 6 +- .../minimal/{ => deploy}/production.config | 6 +- examples/minimal/package.json | 7 +- examples/minimal/server.js | 16 ++ examples/optional-components/README.md | 7 + examples/production-ready/README.md | 20 +++ examples/sops-secrets/README.md | 12 ++ 24 files changed, 577 insertions(+), 129 deletions(-) create mode 100644 CODE_OF_CONDUCT.md create mode 100644 Makefile create mode 100644 docs/kubernetes_auth.md create mode 100644 examples/ci/README.md create mode 100644 examples/external-secrets-manager/README.md create mode 100644 examples/helm/README.md create mode 100644 examples/minimal/.circleci/config.yml create mode 100644 examples/minimal/README.md delete mode 100644 examples/minimal/circle.yml rename examples/minimal/{ => deploy}/production.config (61%) create mode 100644 examples/minimal/server.js create mode 100644 examples/optional-components/README.md create mode 100644 examples/production-ready/README.md create mode 100644 examples/sops-secrets/README.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..d05f4bc0 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,74 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +nationality, personal appearance, race, religion, or sexual identity and +orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or +advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at [INSERT EMAIL ADDRESS]. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..44d0fd72 --- /dev/null +++ b/Makefile @@ -0,0 +1,6 @@ +docs-index: + cat README.md \ + | sed 's/\[\(.*\)\](\(\w\+\.md\))/[\1](https:\/\/github.com\/reactiveops\/rok8s-scripts\/tree\/master\/\2)/g' \ + | sed 's/\[\(.*\)\](\/\?docs\/\(.*\))/[\1](\2)/g' \ + | sed 's/\[\(.*\)\](\(\/.*\))/[\1](https:\/\/github.com\/reactiveops\/rok8s-scripts\/tree\/master\2)/g' \ + > docs/index.md diff --git a/README.md b/README.md index 7cf0487e..7f040c79 100644 --- a/README.md +++ b/README.md @@ -1,31 +1,64 @@ -[![CircleCI](https://circleci.com/gh/reactiveops/rok8s-scripts.svg?style=svg)](https://circleci.com/gh/reactiveops/rok8s-scripts) +[![Version][version-image]][version-link] [![CircleCI][circleci-image]][circleci-link] + +[version-image]: https://img.shields.io/static/v1.svg?label=Version&message=8.0.2&color=239922 +[version-link]: https://github.com/reactiveops/rok8s-scripts +[circleci-image]: https://circleci.com/gh/reactiveops/rok8s-scripts.svg?style=svg +[circleci-link]: https://circleci.com/gh/reactiveops/rok8s-scripts # rok8s-scripts -This is a set of opinionated scripts for managing application development and deployment lifecycle using Kubernetes. These simplify secure secrets management, environment specific config, Docker build caching, and much more. +rok8s-scripts is a framework for building GitOps workflows with Docker and Kubernetes. +By adding rok8s-scripts to your CI/CD pipeline, you can build, push, and deploy your applications using the +set of best practices we've built at ReactiveOps. + +In addition to building Docker images and deploying them to Kubernetes, rok8s-scripts is a great way to handle +secure secrets management, environment specific configuration, Docker build caching, and much more. **Want to learn more?** ReactiveOps holds [office hours on Zoom](https://zoom.us/j/242508205) the first Friday of every month, at 12pm Eastern. You can also reach out via email at `opensource@reactiveops.com` -## CI Images +### Quickstart +To help you get started quickly, we've built a [minimal example](/examples/minimal) +that shows how to use rok8s-scripts to build Docker images and deploy to Kubernetes +using Circle CI. This example will serve as a helpful introduction regardless of your CI platform. -Each new release of rok8s-scripts comes with a new set of CI images for simple workflows. These CI images include a set of common CI/CD dependencies, including Docker, Kubernetes, Helm, AWS, and Google Cloud client libraries. Starting with these images as a base for deployment workflows should ensure that you don't need to spend any build time installing extra dependencies. +## Documentation +We've created documentation for several different use cases and workflows where rok8s-scripts can help. -We currently include a variety of CI Images, including Alpine and Debian Stretch as our recommended starting points. In certain cases you may want to use our images that include Node.js or Golang. +* [Build and push Docker images](docs/docker.md) - This is the place to start to get a sense +for rok8s-scripts project structure and a very basic use case +* [Deploy to Kubernetes](docs/without_helm.md) - Learn how to get your applications into staging +and production. +* [Deploy to Kubernetes with Helm](docs/helm.md) - If you've built a Helm chart for your application, +rok8s-scripts is a great way to deploy your chart to staging and production +* [Manage secrets](docs/secrets.md) - Learn how rok8s-scripts can simplify and secure your secret management workflows -The latest Debian Stretch release can be pulled from `quay.io/reactiveops/ci-images:v8-stretch`. A full list of the latest image tags is available on our [Quay repository](https://quay.io/repository/reactiveops/ci-images). +### Cloud-specific Documentation +* [Deploy to AWS](docs/aws.md) - Learn how to authenticate and deploy using rok8s-scripts with aws-cli +* [Deploy to GCP](docs/gcp.md) - Learn how to authenticate and deploy using rok8s-scripts with gcloud ## Examples -rok8s-scripts is designed to work well in a wide variety of environments. That includes Bitbucket Pipelines, CircleCI, GitLab CI, and more. There are many valid ways to configure CI pipelines, we've includes a variety of [examples](/examples) in this repository. - -Most notably, the CI example includes sample configuration for the following platforms: +rok8s-scripts is designed to work well with a wide variety of use cases and environments. +There are many valid ways to configure CI pipelines, but to help you get started, we've included a variety of [examples](/examples) in this repository. +### CI Platforms - [Bitbucket Pipelines](/examples/ci/bitbucket-pipelines.yml) - [CircleCI](/examples/ci/.circleci/config.yml) - [GitLab CI](/examples/ci/.gitlab-ci.yml) - [Jenkins](/examples/ci/Jenkinsfile) -On their own, these examples may not make a lot of sense. There's a lot more documentation below that should cover everything included in these examples and more. +### Miscellaneous examples +- [External secrets manager](/examples/external-secrets-manager) +- [SOPS secrets](/examples/sops-secrets) - Shows how to use [sops](https://github.com/mozilla/sops) with rok8s-scripts +- [Using Helm](/examples/helm) - We recommend using Helm to manage your deployments +- [Optional components](/examples/optional-components) - Turn components (e.g. Horizontal Pod Audoscaler) on and off depending on whether you're deploying to staging or production +- [Production ready](/examples/production-ready) - Includes a number of recommended production features + +## CI Images + +Each new release of rok8s-scripts generates CI images for common workflows. These images include a set of common CI/CD dependencies, including Docker, Kubernetes, Helm, AWS, and Google Cloud client libraries. Starting with these images as a base for deployment workflows ensures that you don't need to spend any build time installing extra dependencies. + +We currently include CI Images based on Alpine and Debian Stretch as our recommended starting points. The latest Debian Stretch release can be pulled from `quay.io/reactiveops/ci-images:v8-stretch`. A full list of image tags is available on our [Quay repository](https://quay.io/repository/reactiveops/ci-images). ## Versioning v8.0.0 and beyond @@ -47,18 +80,9 @@ You are okay with your pipeline breaking occasionally and having to upgrade thin In this case, go ahead and pin to a major version such as `v8-alpine` -## Further Reading - -- [Building and Pushing Docker Images](/docs/docker.md) -- [Deploying to Kubernetes with Helm](/docs/helm.md) -- [Deploying to Kubernetes without Helm](/docs/without_helm.md) -- [Managing Kubernetes Secrets Securely](/docs/secrets.md) - -### Cloud Specific Documentation -- [Amazon Web Services](/docs/aws.md) -- [Google Cloud](/docs/gcp.md) ### Contributing +- [Code of Conduct](CODE_OF_CONDUCT.md) - [Releasing New Versions of rok8s-scripts](/docs/releasing.md) ## License diff --git a/docs/gcp.md b/docs/gcp.md index 437453aa..3937640c 100644 --- a/docs/gcp.md +++ b/docs/gcp.md @@ -2,10 +2,19 @@ It's quite straightforward to push Docker images to Google Container Registry and deploy to GKE clusters with rok8s-scripts. ## Google Cloud Credentials -To connect to Google Cloud from a CI workflow, a GCP service account is recommended. This can be created from the Google Cloud Console. Credentials for this service account can be downloaded in JSON form. To load those into a rok8s-scripts CI workflow, they'll need to be base64 encoded. This can be accomplished with a command like this: +To connect to Google Cloud from a CI workflow, a [GCP service account](https://console.cloud.google.com/iam-admin/serviceaccounts) +is recommended. To create a service account: +* [Go to the service accounts page](https://console.cloud.google.com/iam-admin/serviceaccounts) +* Choose a name for the account (e.g. `rok8s-scripts`) and hit "Create" +* For "Service account permissions", choose `Kubernetes Engine Developer` and hit "continue" +* Click "Create Key" and choose "JSON" + + +To load the JSON credentials into a rok8s-scripts CI workflow, they'll need to be base64 encoded. +This can be accomplished with a command like this: ```bash -cat downloaded_google_credentials.json | base64 +cat downloaded_google_credentials.json | base64 -w 0 ``` With those credentials in base64 format, you'll need to add them as a protected environment variable in your CI tool of choice. This environment variable needs to be named `GCLOUD_KEY`, and contain a base64 encoded copy of GCP Service Account credentials. It's important that this value is not checked into your codebase, as the credentials could potentially provide a great deal of access into your systems. @@ -41,4 +50,4 @@ With the above environment variables in place, it's time to run a script to pull ```bash prepare-gcloud -``` \ No newline at end of file +``` diff --git a/docs/helm.md b/docs/helm.md index 84837b10..06a04cd9 100644 --- a/docs/helm.md +++ b/docs/helm.md @@ -43,6 +43,9 @@ HELM_VALUES=('development/app') You'll see that some of these configurations reference _similar_, but not exact, matches to the files above. Note `deploy/development/app.values.yml` translates to `HELM_VALUES=('development/app')`. The `deploy/development/app-env.secret.sops.yml` file translates to `SOPS_SECRETS=('development/app-env')`. **Note that if the files are not named with the expected extensions then rok8s-scripts will not work**. +## Credentials +See [Kubernetes auth](kubernetes_auth.md) to learn how to grant your CI pipeline access to your Kubernetes cluster + ## Helm Values Files Helm uses values files to fill in chart templates. In this example, our values file is reference in rok8s-scripts config as `HELM_VALUES=('development/app')`, which maps to reading the `deploy/development/app.values.yml` file. A simple values file might look something like this: diff --git a/docs/index.md b/docs/index.md index 59f6cc36..be947fd1 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,40 +1,82 @@ +[![Version][version-image]][version-link] [![CircleCI][circleci-image]][circleci-link] + +[version-image]: https://img.shields.io/static/v1.svg?label=Version&message=8.0.2&color=239922 +[version-link]: https://github.com/reactiveops/rok8s-scripts +[circle-image]: https://circleci.com/gh/reactiveops/rok8s-scripts.svg?style=svg +[circle-link]: https://circleci.com/gh/reactiveops/rok8s-scripts + # rok8s-scripts -This is a set of opinionated scripts for managing application development and deployment lifecycle using Kubernetes. These simplify secure secrets management, environment specific config, Docker build caching, and much more. +rok8s-scripts is a framework for managing application development and deployment lifecycles using Kubernetes. +By adding rok8s-scripts to your CI/CD pipeline, you can build, push, and deploy your applications using the +set of best practices we've built at ReactiveOps. -## CI Images +In addition to building and deploying docker images, rok8s-scripts is a great way to handle +secure secrets management, environment specific configuration, Docker build caching, and much more. -Each new release of rok8s-scripts comes with a new set of CI images for simple workflows. These CI images include a set of common CI/CD dependencies, including Docker, Kubernetes, Helm, AWS, and Google Cloud client libraries. Starting with these images as a base for deployment workflows should ensure that you don't need to spend any build time installing extra dependencies. +**Want to learn more?** ReactiveOps holds [office hours on Zoom](https://zoom.us/j/242508205) the first Friday of every month, at 12pm Eastern. You can also reach out via email at `opensource@reactiveops.com` -We currently include a variety of CI Images, including Alpine and Debian Stretch as our recommended starting points. In certain cases you may want to use our images that include Node.js or Golang. +### Quickstart +To help you get started quickly, we've built a [minimal example](https://github.com/reactiveops/rok8s-scripts/tree/master/examples/minimal) +that shows how to use rok8s-scripts to build Docker images and deploy to Kubernetes +using Circle CI. This example will serve as a helpful introduction regardless of your CI platform. -The latest Debian Stretch release can be pulled from `quay.io/reactiveops/ci-images:v8-stretch`. A full list of the latest image tags is available on our [Quay repository](https://quay.io/repository/reactiveops/ci-images). +## Documentation +We've created documentation for several different use cases and workflows where rok8s-scripts can help. -## Examples +* [Build and push Docker images](docker.md) - This is the place to start to get a sense +for rok8s-scripts project structure and a very basic use case +* [Deploy to Kubernetes](without_helm.md) - Learn how to get your applications into staging +and production. +* [Deploy to Kubernetes with Helm](helm.md) - If you've built a Helm chart for your application, +rok8s-scripts is a great way to deploy your chart to staging and production +* [Manage secrets](secrets.md) - Learn how rok8s-scripts can simplify and secure your secret management workflows -rok8s-scripts is designed to work well in a wide variety of environments. That includes Bitbucket Pipelines, CircleCI, GitLab CI, and more. There are many valid ways to configure CI pipelines, we've includes a variety of [examples](https://github.com/reactiveops/rok8s-scripts/tree/master/examples) in this repository. +### Cloud-specific Documentation +* [Deploy to AWS](aws.md) - Learn how to authenticate and deploy using rok8s-scripts with aws-cli +* [Deploy to GCP](gcp.md) - Learn how to authenticate and deploy using rok8s-scripts with gcloud -Most notably, the CI example includes sample configuration for the following platforms: +## Examples + +rok8s-scripts is designed to work well in a wide variety of environments. That includes Bitbucket Pipelines, CircleCI, GitLab CI, and more. There are many valid ways to configure CI pipelines, but to help you get started, we've included a variety of [examples](https://github.com/reactiveops/rok8s-scripts/tree/master/examples) in this repository. +### CI Platforms - [Bitbucket Pipelines](https://github.com/reactiveops/rok8s-scripts/tree/master/examples/ci/bitbucket-pipelines.yml) - [CircleCI](https://github.com/reactiveops/rok8s-scripts/tree/master/examples/ci/.circleci/config.yml) - [GitLab CI](https://github.com/reactiveops/rok8s-scripts/tree/master/examples/ci/.gitlab-ci.yml) - [Jenkins](https://github.com/reactiveops/rok8s-scripts/tree/master/examples/ci/Jenkinsfile) -On their own, these examples may not make a lot of sense. There's a lot more documentation below that should cover everything included in these examples and more. +## CI Images + +Each new release of rok8s-scripts comes with a set of CI images for simple workflows. These images include a set of common CI/CD dependencies, including Docker, Kubernetes, Helm, AWS, and Google Cloud client libraries. Starting with these images as a base for deployment workflows ensures that you don't need to spend any build time installing extra dependencies. + +We currently include a variety of CI Images, including Alpine and Debian Stretch as our recommended starting points. In certain cases you may want to use our images that include Node.js or Golang. + +The latest Debian Stretch release can be pulled from `quay.io/reactiveops/ci-images:v8-stretch`. A full list of the latest image tags is available on our [Quay repository](https://quay.io/repository/reactiveops/ci-images). + +## Versioning v8.0.0 and beyond + +Rok8s-scripts contains a number of dependencies that have various ways of versioning themselves. Most notably, Helm tends to break backward compatibility with every minor release. We have decided that post v8 of rok8s-scripts, we will update our versions according to the version change of the underlying tool. For example, if Helm changes from `2.13.0` to `2.14.0`, we will change the version of rok8s scripts by one minor version. This will be clearly mentioned in the release notes. This means that a minor version of rok8s-scripts could introduce breaking changes to the CI/CD pipelines that are using it. + +Please note that we will still commit to any patch version releases being backward-compatible. We will never release a patch version that upgrades an underlying tool beyond a patch version, and we will not release any patch versions of rok8s-scripts that introduce a breaking change. + +Here is a set of guidelines to follow when deciding what version of ci-images (and thus rok8s-scripts) to use: + +#### You are very risk-averse + +You want rok8s-scripts to be stable, and just keep working until you decide to upgrade. + +In this scenario, you should pin to a minor version of rok8s-scripts such as `v8.0-alpine`. + +#### You like to live dangerously -## Further Reading +You are okay with your pipeline breaking occasionally and having to upgrade things as they break. -- [Building and Pushing Docker Images](docker.md) -- [Deploying to Kubernetes with Helm](helm.md) -- [Deploying to Kubernetes without Helm](without_helm.md) -- [Managing Kubernetes Secrets Securely](secrets.md) +In this case, go ahead and pin to a major version such as `v8-alpine` -### Cloud Specific Documentation -- [Amazon Web Services](aws.md) -- [Google Cloud](gcp.md) ### Contributing +- [Code of Conduct](https://github.com/reactiveops/rok8s-scripts/tree/master/CODE_OF_CONDUCT.md) - [Releasing New Versions of rok8s-scripts](releasing.md) ## License diff --git a/docs/kubernetes_auth.md b/docs/kubernetes_auth.md new file mode 100644 index 00000000..99d82134 --- /dev/null +++ b/docs/kubernetes_auth.md @@ -0,0 +1,137 @@ +# Authenticating with Kubernetes + +In order to connect to your Kubernetes cluster, you'll need to set the environment +variable `KUBECONFIG_DATA`. This variable should contain a valid base64 encoded +[kubeconfig](https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/) + +## Using an Existing Kubeconfig +> Note: Using your local kubeconfig is NOT recommended. It is much more secure +> to use cloud provider credentials or create a service account, as shown below + +The easiest way to authenticate is to pass a valid kubeconfig to the `base64` command. + +``` +cat ~/.kube/config | base64 -w 0 +``` + +The output of this command should be set as the environment variable `KUBECONFIG_DATA` +in the settings for your CI platform. + +## Using Cloud Providers +If you're using EKS or GKE, the preferred method of authentication is to create a deployment +account on AWS or GCP. Using the credentials for that account, rok8s-scripts can use the +`aws-cli` and `gcloud` tools to authenticate with your cluster. + +See the documentation for [AWS](aws.md) or [GCP](gcp.md) for more information. + +## Using a Service Account +[Service accounts](https://kubernetes.io/docs/reference/access-authn-authz/service-accounts-admin/) +are the best method for granting automated access to the Kubernetes API if you're not using +a managed Kubernetes service like EKS or GKE. You can use +these instructions to generate a kubeconfig for a service account. + +### Creating a Service Account +> If you've already got a service account set up with the necessary permissions, +> you can skip this section + +Use these commands to create a new namespace `rok8s-scripts`, along with a ServiceAccount. +``` +kubectl create namespace rok8s-scripts +kubectl create serviceaccount rok8s-scripts -n rok8s-scripts +``` + +#### Super-user permissions +> It's recommended that you use a tighter ClusterRole than `cluster-admin` in order +> to follow the principle of least privilege. See "Safter permissions" for details +Depending on what features of rok8s-scripts you're using, you'll need different permissions. +This example simply grants `cluster-admin` access to the service account, which grants +super-user access to rok8s-scripts. +``` +kubectl create clusterrolebinding rok8s-scripts \ + --clusterrole=cluster-admin \ + --serviceaccount=rok8s-scripts:rok8s-scripts +``` + +#### Safer permissions +> The examples below use [rbac-manager](https://github.com/reactiveops/rbac-manager) +> to simplify the permissions model + +One common pattern is to only grant `cluster-admin` permissions on namespaces that +have been explicitly given the label `rok8s-scripts-admin` + +```yaml +apiVersion: rbacmanager.reactiveops.io/v1beta1 +kind: RBACDefinition +metadata: + name: rok8s-scripts +rbacBindings: + - name: rok8s-scripts + subjects: + - kind: ServiceAccount + name: rok8s-scripts + namespace: rok8s-scripts + roleBindings: + - clusterRole: cluster-admin + namespaceSelector: + matchLabels: + rok8s-scripts-admin: "true" +``` + +Or, if you'll be using Helm to push your deployments, and all those deployments will live +in the same namespace, you can simply grant access to Tiller: + +```yaml +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: tiller-manager + namespace: tiller-world +rules: +- apiGroups: ["", "batch", "extensions", "apps"] + resources: ["*"] + verbs: ["*"] +--- +apiVersion: rbacmanager.reactiveops.io/v1beta1 +kind: RBACDefinition +metadata: + name: rbac-definition +rbacBindings: + - name: circleci + subjects: + - kind: ServiceAccount + name: rok8s-scripts + namespace: rok8s-scripts + roleBindings: + - clusterRole: tiller-manager + namespace: tiller-world +``` + +### Generating the kubeconfig +Assuming your service account is named `rok8s-scripts` and is in the `rok8s-scripts` namespace, +you can use the below to generate the necessary `KUBECONFIG_DATA` value. + +```bash +namespace="rok8s-scripts" +serviceaccount="rok8s-scripts" + +sa_secret_name=$(kc get serviceaccount "${serviceaccount}" -o 'jsonpath={.secrets[0].name}') + +context_name="$(kubectl config current-context)" +kubeconfig_old="${KUBECONFIG}" +cluster_name="$(kubectl config view -o "jsonpath={.contexts[?(@.name==\"${context_name}\")].context.cluster}")" +server_name="$(kubectl config view -o "jsonpath={.clusters[?(@.name==\"${cluster_name}\")].cluster.server}")" +cacert="$(kc get secret "${sa_secret_name}" -o "jsonpath={.data.ca\.crt}" | base64 --decode)" +token="$(kc get secret "${sa_secret_name}" -o "jsonpath={.data.token}" | base64 --decode)" + +export KUBECONFIG="$(mktemp)" +kubectl config set-credentials "${serviceaccount}" --token="${token}" >/dev/null +ca_crt="$(mktemp)"; echo "${cacert}" > ${ca_crt} +kubectl config set-cluster "${cluster_name}" --server="${server_name}" --certificate-authority="$ca_crt" --embed-certs >/dev/null +kubectl config set-context "${cluster_name}" --cluster="${cluster_name}" --user="${serviceaccount}" >/dev/null +kubectl config use-context "${cluster_name}" >/dev/null + +KUBECONFIG_DATA=$(cat "${KUBECONFIG}" | base64 -w 0) +rm ${KUBECONFIG} +export KUBECONFIG="${kubeconfig_old}" +echo "${KUBECONFIG_DATA}" +``` diff --git a/docs/without_helm.md b/docs/without_helm.md index 5ee4e355..1a859d16 100644 --- a/docs/without_helm.md +++ b/docs/without_helm.md @@ -46,6 +46,9 @@ k8s-deploy-and-verify -f deploy/development.config More indepth examples are available in the [examples directory](https://github.com/reactiveops/rok8s-scripts/tree/master/examples). +## Credentials +See [Kubernetes auth](kubernetes_auth.md) to learn how to grant your CI pipeline access to your Kubernetes cluster + ## Versioning **If a Docker image is used in the file then any cases of `:latest` will be replaced with th `CI_SHA1` if it is defined.** This allows a set image tag to be used when deploying from a CI system. When files that could use `CI_SHA1` are deployed, a new file will be created with that value as part of the filename. diff --git a/examples/README.md b/examples/README.md index 48d1c136..36abf343 100644 --- a/examples/README.md +++ b/examples/README.md @@ -2,46 +2,6 @@ This examples are to help give a basic overview of what a repository using `rok8-scripts` might look like. -## Jenkins-K8s-Plugin +Click on any example to learn more about it. -An example Jenkins [Kubernetes plugin](https://github.com/jenkinsci/kubernetes-plugin) build and deploy via Helm chart with development, staging, and production configuration. -## CircleCI-20 - -An example CircleCI 2.0 build and deploy via Helm chart with development, staging, and production configuration. - -## Minimal - -A small example of CircleCI building/deploying an app consisting of a Deployment and Service. It attempts to be the minimum needed to get a service working inside of Kubernetes but is missing features expected of a true production deployment. - -## Production-Ready - -An example including: - -* Staging and Production environments -* DB migrations with BlockingJob -* Internal ELB for staging -* Horizontal Pod Autoscaler for setting number of replicas -* Usage `namespace` metadata to ensure application to the correct Kube namespace -* Linting of your config and deploy files - -Deployment Features: -* `revisionHistoryLimit` to remove old ReplicaSets -* Volume mounting of Secrets and ConfigMap -* Resource requests and limits -* Liveness Probe - -## Optional-Components - -An example where production uses a Horizontal Pod Autoscaler but staging does -not. - -## sops-secrets - -An example showing the decryption of a sops-encrypted file and deployment of the secret to Kubernetes. - -The encrypted file can be created with a command similar to: - -``` -sops --encrypt --gcp-kms projects/example-project/locations/global/keyRings/example-keyring/cryptoKeys/example-key example.secret.yml -``` diff --git a/examples/ci/README.md b/examples/ci/README.md new file mode 100644 index 00000000..80a03c57 --- /dev/null +++ b/examples/ci/README.md @@ -0,0 +1,8 @@ +This example demonstrates how to use rok8s-scripts with four different CI platforms: +- [Bitbucket Pipelines](/examples/ci/bitbucket-pipelines.yml) +- [CircleCI](/examples/ci/.circleci/config.yml) +- [GitLab CI](/examples/ci/.gitlab-ci.yml) +- [Jenkins](/examples/ci/Jenkinsfile) + + + diff --git a/examples/external-secrets-manager/README.md b/examples/external-secrets-manager/README.md new file mode 100644 index 00000000..97b8620c --- /dev/null +++ b/examples/external-secrets-manager/README.md @@ -0,0 +1,6 @@ +# external-secrets-manager example + +**Note:** this example uses CircleCI v1 + +This example shows how to use rok8s-scripts with an external secrets manager + diff --git a/examples/helm/README.md b/examples/helm/README.md new file mode 100644 index 00000000..d7fa1b9b --- /dev/null +++ b/examples/helm/README.md @@ -0,0 +1,2 @@ +# Helm example +This example show how to deploy your Helm chart using rok8s-scripts diff --git a/examples/minimal/.circleci/config.yml b/examples/minimal/.circleci/config.yml new file mode 100644 index 00000000..3bf9d446 --- /dev/null +++ b/examples/minimal/.circleci/config.yml @@ -0,0 +1,60 @@ +version: 2 + +references: + set_environment_variables: &set_environment_variables + run: + name: Set Environment Variables + command: | + echo 'export CI_SHA1=$CIRCLE_SHA1' >> ${BASH_ENV} + echo 'export CI_BRANCH=$CIRCLE_BRANCH' >> ${BASH_ENV} + echo 'export CI_BUILD_NUM=$CIRCLE_BUILD_NUM' >> ${BASH_ENV} + echo 'export CI_TAG=$CIRCLE_TAG' >> ${BASH_ENV} + echo 'export ROK8S_INSTALL_PATH=${HOME}' >> ${BASH_ENV} + + build_image: &build_image + run: + name: Build Docker Image + command: | + docker login quay.io -u="${quay_robot}" -p="${quay_token}" + docker-pull -f deploy/production.config + docker-build -f deploy/production.config + + deploy: &deploy + run: + name: Deploy to Production + command: | + docker-push -f deploy/production.config + prepare-kubectl + k8s-deploy-and-verify -f deploy/production.config + +jobs: + build_image: + docker: + - image: quay.io/reactiveops/ci-images:v8.0-stretch + steps: + - checkout + - setup_remote_docker + - *set_environment_variables + - *build_image + deploy: + docker: + - image: quay.io/reactiveops/ci-images:v8.0-stretch + steps: + - checkout + - setup_remote_docker + - *set_environment_variables + - *build_image + - *deploy + +workflows: + version: 2 + build: + jobs: + - build_image + - deploy: + requires: + - build_image + filters: + branches: + only: master + diff --git a/examples/minimal/Dockerfile b/examples/minimal/Dockerfile index 7e6d8c05..79113466 100644 --- a/examples/minimal/Dockerfile +++ b/examples/minimal/Dockerfile @@ -1 +1,10 @@ -Your Dockerfile here! +FROM node:8 + +WORKDIR /usr/src/app + +COPY package*.json ./ +RUN npm install +COPY . . + +EXPOSE 8080 +CMD [ "npm", "start" ] diff --git a/examples/minimal/README.md b/examples/minimal/README.md new file mode 100644 index 00000000..9b34670e --- /dev/null +++ b/examples/minimal/README.md @@ -0,0 +1,81 @@ +# Minimal Example for rok8s-scripts + +This is an example rok8s-scripts configuration that deploys a NodeJS application +to proudction. It is built for CircleCI, but should help give a basic overview of +the pieces of a rok8s-scripts deployment regardless of your CI platform. + +## Configuration +The file `./deploy/production.config` is the main entry point for rok8s-scripts. +It tells rok8s-scripts how to build the image and what registry to push it to. + +## CI/CD +The file `./.circleci/config.yml` is the main entry point for CircleCI. In it, +we run some of the scripts provided by rok8s-scripts. In particular, we use: +* `docker-pull` to get the last image we pushed, which warms the local docker cache for faster builds +* `docker-build` to build the image for the current comment +* `docker-push` to push the image for the current commit to our image repository +* `prepare-kubectl` to set up for pushing the latest image to our Kubernetes cluster +* `k8s-deploy-and-verify` to push our image to Kubernetes and make sure the deployment succeeded + +We also use the rok8s-scripts CI image, `quay.io/reactiveops/ci-images:v8-stretch`, +to ensure rok8s-scripts and its dependencies are all available during the build and deploy jobs. + +## Try it out + +* Run the following to copy this directory to a new git repository: +``` +git clone https://github.com/reactiveops/rok8s-scripts +cp -r rok8s-scripts/examples/minimal rok8s-scripts-test +cd rok8s-scripts-test +git init +git add . +git commit -m "testing rok8s scripts" +``` +* Create a new repository on GitHub +* Follow the instructions on GitHub to push your code to your new repo +* Go to circleci.com and add your repo as a new project +* Click "Start Building" to kick off your first build + +You'll see CircleCI start two jobs - one to build the image, and one to deploy. +The build job should succeed, but the deploy job will fail, because we haven't set +up credentials for our image repository or Kubernetes cluster. + +### Setting up the image repository +These instructions are for quay.io, and will have to be adapted if you're +using another image registry like AWS ECR or DockerHub. + +* Set up a new repo on quay.io +* Create a new [robot account](https://docs.quay.io/glossary/robot-accounts.html) +* Click the settings icon next to the robot account, and click "View credentials" +* In your project settings on CircleCI, go to "Environment Variables" +* Add an environment variable named `quay_robot`, and paste in the value from Quay +* Add an environment variable named `quay_token`, and paste in the value from Quay +on Quay. We'll pass credentials for this account to CircleCI so that it can +* Edit `./deploy/production.config` with your quay username and repository +* Edit `./deploy/minimal-production.deployment.yml` with your quay username and repository + +### Setting up Kubernetes +> Note: Using your personal kubeconfig is NOT recommended. It is much more secure +> to create a service account. See the docs on [Kubernetes auth](/docs/kubernetes_auth.md) +> for more details +In order to deploy to Kubernetes, you'll need to base64 encode a valid kubeconfig +and set it as an environment variable in CircleCI. We recommend +[creating a service account](/docs/kubernetes_auth.md) for this, but for simplicity +the example below uses the kubeconfig stored in your home directory. +* Run: +``` +cat ~/.kube/config | base64 -w 0 > kube-config-encoded.txt +``` +* Create a new environment variable in CircleCI called `KUBECONFIG_DATA` +* Paste the contents of `kube-config-encoded.txt` as the environment variable value + +### Rerun the build +Commit and push your changes to the master branch to trigger another build. +Everything should run successfully this time, and you should see your app +running inside your Kubernetes cluster. + +You can check your app by running +``` +kubectl port-forward --namespace rok8s-example svc/rok8s-example 3000:80 +``` +and visiting `localhost:3000` in your browser. diff --git a/examples/minimal/circle.yml b/examples/minimal/circle.yml deleted file mode 100644 index 6d00e869..00000000 --- a/examples/minimal/circle.yml +++ /dev/null @@ -1,32 +0,0 @@ -machine: - environment: - PATH: $PATH:node_modules/.bin - - CI_SHA1: $CIRCLE_SHA1 - CI_BRANCH: $CIRCLE_BRANCH - CI_BUILD_NUM: $CIRCLE_BUILD_NUM - - services: - - docker - -dependencies: - pre: - - npm install - - docker-pull -f deploy/production.config - - docker-build -f deploy/production.config - - override: - - echo "overriding inferred dependencies" - -test: - override: - - echo "No tests for now!" - -deployment: - production: - branch: [master] - commands: - - install-rok8s-requirements - - docker-push -f deploy/production.config - - prepare-kubectl - - k8s-deploy-and-verify -f deploy/production.config diff --git a/examples/minimal/deploy/minimal-production.deployment.yml b/examples/minimal/deploy/minimal-production.deployment.yml index af434bfd..3489c41b 100644 --- a/examples/minimal/deploy/minimal-production.deployment.yml +++ b/examples/minimal/deploy/minimal-production.deployment.yml @@ -1,21 +1,19 @@ apiVersion: extensions/v1beta1 kind: Deployment metadata: - name: minimal-example + name: rok8s-example spec: replicas: 2 template: metadata: labels: - app: minimal-example + app: rok8s-example spec: containers: - - name: minimal-example + - name: rok8s-example # `latest` will be replaced with $CI_SHA1 by k8s-deploy - image: quay.io/example-org/example-app:latest - command: - - 'sleep 86400' + image: quay.io/example-org/rok8s-scripts-test:latest ports: - - containerPort: 5000 + - containerPort: 8080 name: http diff --git a/examples/minimal/deploy/minimal-production.service.yml b/examples/minimal/deploy/minimal-production.service.yml index 0f989c65..a92e2b0d 100644 --- a/examples/minimal/deploy/minimal-production.service.yml +++ b/examples/minimal/deploy/minimal-production.service.yml @@ -2,9 +2,9 @@ apiVersion: v1 kind: Service metadata: - name: minimal-example + name: rok8s-example labels: - app: minimal-example + app: rok8s-example spec: type: LoadBalancer ports: @@ -13,4 +13,4 @@ spec: port: 80 targetPort: http selector: - app: minimal-example + app: rok8s-example diff --git a/examples/minimal/production.config b/examples/minimal/deploy/production.config similarity index 61% rename from examples/minimal/production.config rename to examples/minimal/deploy/production.config index 5e2c1cc0..571a762e 100644 --- a/examples/minimal/production.config +++ b/examples/minimal/deploy/production.config @@ -1,10 +1,10 @@ DOCKERFILE='Dockerfile' EXTERNAL_REGISTRY_BASE_DOMAIN=quay.io/example-org -REPOSITORY_NAME='minimal-example' -DOCKERTAG=quay.io/example-org/minimal-example +REPOSITORY_NAME='rok8s-scripts-test' +DOCKERTAG=${EXTERNAL_REGISTRY_BASE_DOMAIN}/${REPOSITORY_NAME} -NAMESPACE='production' +NAMESPACE='rok8s-example' CONFIGMAPS=() SECRETS=() diff --git a/examples/minimal/package.json b/examples/minimal/package.json index c871ba41..2061ba11 100644 --- a/examples/minimal/package.json +++ b/examples/minimal/package.json @@ -1,5 +1,5 @@ { - "name": "example", + "name": "rok8s-minimal-example", "version": "0.0.0", "description": "Example app deployment with rok8s-scripts", "repository": { @@ -8,8 +8,11 @@ }, "author": "ReactiveOps", "license": "Apache-2.0", + "scripts": { + "start": "node server.js" + }, "dependencies": { - "rok8s-scripts": "*" + "express": "^4.16.1" } } diff --git a/examples/minimal/server.js b/examples/minimal/server.js new file mode 100644 index 00000000..5a381658 --- /dev/null +++ b/examples/minimal/server.js @@ -0,0 +1,16 @@ +'use strict'; + +const express = require('express'); + +// Constants +const PORT = 8080; +const HOST = '0.0.0.0'; + +// App +const app = express(); +app.get('/', (req, res) => { + res.send('Hello world\n'); +}); + +app.listen(PORT, HOST); +console.log(`Running on http://${HOST}:${PORT}`); diff --git a/examples/optional-components/README.md b/examples/optional-components/README.md new file mode 100644 index 00000000..1f2cef74 --- /dev/null +++ b/examples/optional-components/README.md @@ -0,0 +1,7 @@ +## Optional-Components + +**Note:** this example uses CircleCI v1 + +An example where production uses a Horizontal Pod Autoscaler but staging does +not. + diff --git a/examples/production-ready/README.md b/examples/production-ready/README.md new file mode 100644 index 00000000..e1d97424 --- /dev/null +++ b/examples/production-ready/README.md @@ -0,0 +1,20 @@ +## Production-Ready + +**Note:** this example uses CircleCI v1 + +An example including: + +* Staging and Production environments +* DB migrations with BlockingJob +* Internal ELB for staging +* Horizontal Pod Autoscaler for setting number of replicas +* Usage `namespace` metadata to ensure application to the correct Kube namespace +* Linting of your config and deploy files + +Deployment Features: +* `revisionHistoryLimit` to remove old ReplicaSets +* Volume mounting of Secrets and ConfigMap +* Resource requests and limits +* Liveness Probe + + diff --git a/examples/sops-secrets/README.md b/examples/sops-secrets/README.md new file mode 100644 index 00000000..4e90dc0c --- /dev/null +++ b/examples/sops-secrets/README.md @@ -0,0 +1,12 @@ +## sops-secrets + +**Note:** this example uses CircleCI v1 + +An example showing the decryption of a sops-encrypted file and deployment of the secret to Kubernetes. + +The encrypted file can be created with a command similar to: + +``` +sops --encrypt --gcp-kms projects/example-project/locations/global/keyRings/example-keyring/cryptoKeys/example-key example.secret.yml +``` +