From efb6504c84081af6eacbf773330687a6905a6d47 Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Tue, 14 Jun 2022 17:12:08 -0400 Subject: [PATCH 1/3] Update README --- README.md | 453 +--------------------------------------- docs/getting-started.md | 388 ++++++++++++++++++++++++++++++++++ docs/installation.md | 74 +++++++ 3 files changed, 468 insertions(+), 447 deletions(-) create mode 100644 docs/getting-started.md create mode 100644 docs/installation.md diff --git a/README.md b/README.md index 198dd73..9fe4753 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,6 @@ [![Get it from the Snap Store](https://badgen.net/snapcraft/v/operator-builder)](https://snapcraft.io/operator-builder) ![Github Downloads (by Release)](https://img.shields.io/github/downloads/vmware-tanzu-labs/operator-builder/total.svg) -Operator Builder Logo - # Operator Builder **Accelerate the development of Kubernetes Operators.** @@ -33,459 +31,19 @@ The custom resource defined in the source code can be cluster-scoped or namespace-scoped based on the requirements of the project. More info [here](docs/resource-scope.md). -## Prerequisites - -- Make -- Go version 1.16 or later -- Docker (for building/pushing controller images) -- An available test cluster. A local kind or minikube cluster will work just - fine in many cases. -- Operator Builder [installed](#installation). -- [kubectl installed](https://kubernetes.io/docs/tasks/tools/#kubectl). -- A set of static Kubernetes manifests that can be used to deploy - your workload. It is highly recommended that you apply these manifests to a - test cluster and verify the resulting resources work as expected. - If you don't have a workload of your own to use, you can use the examples - provided in this guide. - -## Installation Options - -### [Download the latest binary](https://github.com/vmware-tanzu-labs/operator-builder/releases/latest) - -### wget -Use wget to download the pre-compiled binaries: - -```bash -wget https://github.com/vmware-tanzu-labs/operator-builder/releases/download/${VERSION}/${BINARY}.tar.gz -O - |\ - tar xz && sudo mv operator-builder /usr/bin/operator-builder -``` - -For instance, VERSION=v0.5.0 and BINARY=operator-builder_${VERSION}_Linux_x86_64 - -### MacOS / Linux via Homebrew install - -Using [Homebrew](https://brew.sh/) - -```bash -brew tap vmware-tanzu-labs/tap -brew install operator-builder -``` - -### Linux snap install - -```bash -snap install operator-builder -``` - ->**NOTE**: `operator-builder` installs with [_strict confinement_](https://docs.snapcraft.io/snap-confinement/6233) in snap, this means it doesn't have direct access to root files. - -### Docker image pull - -```bash -docker pull ghcr.io/vmawre-tanzu-labs/operator-builder -``` +## Installation -#### One-shot container use +See our [installation options](docs/installation.md) -```bash -docker run --rm -v "${PWD}":/workdir ghcr.io/vmware-tanzu-labs/operator-builder [flags] -``` - - -#### Run container commands interactively - -```bash -docker run --rm -it -v "${PWD}":/workdir --entrypoint sh ghcr.io/vmawre-tanzu-labs/operator-builder -``` - -It can be useful to have a bash function to avoid typing the whole docker command: - -```bash -operator-builder() { - docker run --rm -i -v "${PWD}":/workdir ghcr.io/vmware-tanzu-labs/operator-builder "$@" -} -``` - -### Go install - -```bash -GO111MODULE=on go get github.com/vmware-tanzu-labs/operator-builder/cmd/operator-builder -``` ## Getting Started -This guide will walk you through the creation of a Kubernetes operator for a -single workload. This workload can consist of any number of Kubernetes -resources and will be configured with a single custom resource. Please review -the [prerequisites](#prerequisites) prior to attempting to follow this guide. - -This guide consists of the following steps: - -1. [Create a repository](#step-1). -1. Determine what fields in your static manifests will need to be configurable for - deployment into different environments. [Add commented markers to the - manifests](#step-2). These will serve as instructions to Operator Builder. -1. [Create a workload configuration for your project](#step-3). -1. [Use the Operator Builder CLI to generate the source code for your operator](#step-4). -1. [Test the operator against your test cluster](#step-5). -1. [Build and install your operator's controller manager in your test cluster](#step-6). -1. [Build and test the operator's companion CLI](#step-7). - -### Step 1 - -Create a new directory for your operator's source code. We recommend you follow -the standard [code organization -guidelines](https://golang.org/doc/code#Organization). -In that directory initialize a new git repo. - - git init - -And intialize a new go module. The module should be the import path for your -project, usually something like `github.com/user-account/project-name`. Use the -command `go help importpath` for more info. - - go mod init [module] - -Lastly create a directory for your static manifests. Operator Builder will use -these as a source for defining resources in your operator's codebase. It must be a -hidden directory so as not to interfere with source code generation. - - mkdir .source-manifests - -Put your static manifests in this `.source-manifests` directory. In the next -step we will add commented markers to them. Note that these static manifests -can be in one or more files. And you can have one or more manifests (separated -by `---`) in each file. Just organize them in a way that makes sense to you. - -### Step 2 - -Look through your static manifests and determine which fields will need to be -configurable for deployment into different environments. Let's look at a simple -example to illustrate. Following is a Deployment, Ingress and Service that may -be used to deploy a workload. - - # .source-manifests/app.yaml - - apiVersion: apps/v1 - kind: Deployment - metadata: - name: webstore-deploy - spec: - replicas: 2 # <===== configurable - selector: - matchLabels: - app: webstore - template: - metadata: - labels: - app: webstore - spec: - containers: - - name: webstore-container - image: nginx:1.17 # <===== configurable - ports: - - containerPort: 8080 - --- - apiVersion: networking.k8s.io/v1beta1 - kind: Ingress - metadata: - name: webstore-ing - annotations: - nginx.ingress.kubernetes.io/rewrite-target: / - spec: - rules: - - host: app.acme.com - http: - paths: - - path: / - backend: - serviceName: webstorep-svc - servicePort: 80 - --- - kind: Service - apiVersion: v1 - metadata: - name: webstore-svc - spec: - selector: - app: webstore - ports: - - protocol: TCP - port: 80 - targetPort: 8080 - -There are two fields in the Deployment manifest that will need to be -configurable. They are noted with comments. The Deployment's replicas and the -Pod's container image will change between different environments. For example, -in a dev environment the number of replicas will be low and a development -version of the app will be run. In production, there will be more replicas and -a stable release of the app will be used. In this example we don't have any -configurable fields in the Ingress or Service. - -Next we need to use `+operator-builder:field` markers in comments to inform Operator Builder -that the operator will need to support configuration of these elements. -Following is the Deployment manifest with these markers in place. - - apiVersion: apps/v1 - kind: Deployment - metadata: - name: webstore-deploy - labels: - team: dev-team # +operator-builder:field:name=teamName,type=string - spec: - replicas: 2 # +operator-builder:field:name=webStoreReplicas,default=2,type=int - selector: - matchLabels: - app: webstore - template: - metadata: - labels: - app: webstore - team: dev-team # +operator-builder:field:name=teamName,type=string - spec: - containers: - - name: webstore-container - image: nginx:1.17 # +operator-builder:field:name=webStoreImage,type=string - ports: - - containerPort: 8080 - -These markers should always be provided as an in-line comment or as a head -comment. The marker always begins with `+operator-builder:field:` or -`+operator-builder:collection:field:` See [Markers](docs/markers.md) to learn -more. - -### Step 3 - -Operator Builder uses a workload configuration to provide important details for -your operator project. This guide uses a [standalone -workload](docs/standalone-workloads.md). Save a workload config to your -`.source-manifests` directory by using one of the following commands (or -simply copy/pasting the YAML below the commands): - - # generate a workload config with the path (-p) flag - operator-builder init-config standalone -p .source-manifests/workload.yaml - - # generate a workload config from stdout - operator-builder init-config standalone > .source-manifests/workload.yaml - -This will generate the following YAML: - - # .source-manifests/workload.yaml - name: webstore - kind: StandaloneWorkload - spec: - api: - domain: acme.com - group: apps - version: v1alpha1 - kind: WebStore - clusterScoped: false - companionCliRootcmd: - name: webstorectl - description: Manage webstore application - resources: - - app.yaml - -The `name` is arbitrary and can be whatever you like. - -In the `spec`, the following fields are required: - -- `api.domain`: This must be a globally unique name that will not be used by other - organizations or groups. It will contain groups of API types. -- `api.group`: This is a logical group of API types used as a namespacing - mechanism for your APIs. -- `api.version`: Provide the intiial version for your API. -- `api.kind`: The name of the API type that will represent the workload you are - managing with this operator. -- `resources`: An array of filenames where your static manifests live. List the - relative path from the workload manifest to all the files that contain the - static manifests we talked about in step 2. - -For more info about API groups, versions and kinds, check out the [Kubebuilder -docs](https://kubebuilder.io/cronjob-tutorial/gvks.html). - -The following fields in the `spec` are optional: - -- `api.clusterScoped`: If your workload includes cluster-scoped resources like - namespaces, this will need to be `true`. The default is `false`. -- `companionCLIRootcmd`: If you wish to generate source code for a companion CLI - for your operator, include this field. We recommend you do. Your end users - will appreciate it. - - `name`: The root command your end users will type when using the companion - CLI. - - `description`: The general information your end users will get if they use - the `help` subcommand of your companion CLI. - -At this point in our example, our `.source-manifests` directory looks as -follows: - - tree .source-manifests - - .source-manifests - ├── app.yaml - └── workload.yaml - -Our StandaloneWorkload config is in `workload.yaml` and the Deployment, Ingress -and Service manifests are in `app.yaml` and referenced under `spec.resources` in -our StandaloneWorkload config. - -We are now ready to generate our project's source code. - -### Step 4 - -We first use the `init` command to create the general scaffolding. We run this -command from the root of our repo and provide a single argument with the path to -our workload config. - - operator-builder init \ - --workload-config .source-manfiests/workload.yaml - -With the basic project now set up, we can now run the `create api` command to -create a new custom API for our workload. - - operator-builder create api \ - --workload-config .source-manfiests/workload.yaml \ - --controller \ - --resource - -We again provide the same workload config file. Here we also added the -`--controller` and `--resource` arguments. These indicate that we want both a -new controller and new custom resource created. - -You now have a new working Kubernetes Operator! Next, we will test it out. - -### Step 5 - -Assuming you have a kubeconfig in place that allows you to interact with your -cluster with kubectl, you are ready to go. - -First, install the new custom resource definition (CRD). - - make install - -Now we can run the controller locally to test it out. - - make run - -Operator Builder created a sample manifest in the `config/samples` directory. -For this example it looks like this: - - apiVersion: apps.acme.com/v1alpha1 - kind: WebStore - metadata: - name: webstore-sample - spec: - webStoreReplicas: 2 - webStoreImage: nginx:1.17 - teamName: dev-team - -You will notice the fields and values in the `spec` were derived from the -markers you added to your static manifests. - -Next, in another terminal, create a new instance of your workload with -the provided sample manifest. - - kubectl apply -f config/samples/ - -You should see your custom resource sample get created. Now use `kubectl` to -inspect your cluster to confirm the workload's resources got created. You should -find all the resources that were defined in your static manifests. - - kubectl get all - -Clean up by stopping your controller with ctrl-c in that terminal and then -remove all the resources you just created. - - make uninstall - -### Step 6 - -Now let's deploy your controller into the cluster. - -First export an environment variable for your container image. - - export IMG=myrepo/acme-webstore-mgr:0.1.0 - -Run the rest of the commands in this step 6 in this same terminal as most of -them will need this `IMG` env var. - -In order to run the controller in-cluster (as opposed to running locally with -`make run`) we will need to build a container image for it. - - make docker-build - -Now we can push it to a registry that is accessible from the test cluster. - - make docker-push - -Finally, we can deploy it to our test cluster. - - make deploy - -Next, perform the same tests from step 5 to ensure proper operation of our -operator. - - kubectl apply -f config/sample/ - -Again, verify that all the resources you expect are created. - -Once satisfied, remove the instance of your workload. - - kubectl delete -f config/sample/ - -For now, leave the controller running in your test cluster. We'll use it in -Step 7. - -### Step 7 - -Now let's build and test the companion CLI. - -You will have a make target that includes the name of your CLI. For this -example it is: - - make build-webstorectl - -We can view the help info as follows. - - ./bin/webstorectl help - -Your end users can use it to create a new custom resource manifest. - - ./bin/webstorectl init > /tmp/webstore.yaml - -If you would like to change any of the default values, edit the file. - - vim /tmp/webstore.yaml - -Then you can apply it to the cluster. - - kubectl apply -f /tmp/webstore.yaml - -If your end users find they wish to make changes to the resources that aren't -supported by the operator, they can generate the resources from the custom -resource. - - ./bin/webstorectl generate --workload-manifest /tmp/webstore.yaml - -This will print the resources to stdout. These may be piped into an overlay -tool or written to disk and modified before applying to a cluster. - -That's it! You have a working operator without manually writing a single line -of code. If you'd like to make any changes to your workload's API, you'll find -the code in the `apis` directory. The controller's source code is in -`controllers` directory. And the companion CLI code is in `cmd`. - -Don't forget to clean up. Remove the controller, CRD and the workload's -resources as follows. - - make undeploy - -For more information, checkout the [Operator Builder docs](docs/) as -well as the [Kubebuilder docs](https://kubebuilder.io/). +Follow our [getting started guide](docs/getting-started.md) ## Workload Collections Operator Builder can generate source code for operators that manage multiple -workloads. See [workload collections](docs/workload-collections.md) for more info. +related and dependent workloads. See [workload collections](docs/workload-collections.md) +for more info. ## Licensing @@ -495,3 +53,4 @@ info [here](docs/license.md). ## Testing Testing of Operator Builder is documented [here](docs/testing.md). + diff --git a/docs/getting-started.md b/docs/getting-started.md new file mode 100644 index 0000000..d0a02da --- /dev/null +++ b/docs/getting-started.md @@ -0,0 +1,388 @@ +# Getting Started + +## Prerequisites + +- Make +- Go version 1.16 or later +- Docker (for building/pushing controller images) +- An available test cluster. A local kind or minikube cluster will work just + fine in many cases. +- Operator Builder [installed](#installation). +- [kubectl installed](https://kubernetes.io/docs/tasks/tools/#kubectl). +- A set of static Kubernetes manifests that can be used to deploy + your workload. It is highly recommended that you apply these manifests to a + test cluster and verify the resulting resources work as expected. + If you don't have a workload of your own to use, you can use the examples + provided in this guide. + +## Guide + +This guide will walk you through the creation of a Kubernetes operator for a +single workload. This workload can consist of any number of Kubernetes +resources and will be configured with a single custom resource. Please review +the [prerequisites](#prerequisites) prior to attempting to follow this guide. + +This guide consists of the following steps: + +1. [Create a repository](#step-1). +1. Determine what fields in your static manifests will need to be configurable for + deployment into different environments. [Add commented markers to the + manifests](#step-2). These will serve as instructions to Operator Builder. +1. [Create a workload configuration for your project](#step-3). +1. [Use the Operator Builder CLI to generate the source code for your operator](#step-4). +1. [Test the operator against your test cluster](#step-5). +1. [Build and install your operator's controller manager in your test cluster](#step-6). +1. [Build and test the operator's companion CLI](#step-7). + +### Step 1 + +Create a new directory for your operator's source code. We recommend you follow +the standard [code organization +guidelines](https://golang.org/doc/code#Organization). +In that directory initialize a new git repo. + + git init + +And intialize a new go module. The module should be the import path for your +project, usually something like `github.com/user-account/project-name`. Use the +command `go help importpath` for more info. + + go mod init [module] + +Lastly create a directory for your static manifests. Operator Builder will use +these as a source for defining resources in your operator's codebase. It must be a +hidden directory so as not to interfere with source code generation. + + mkdir .source-manifests + +Put your static manifests in this `.source-manifests` directory. In the next +step we will add commented markers to them. Note that these static manifests +can be in one or more files. And you can have one or more manifests (separated +by `---`) in each file. Just organize them in a way that makes sense to you. + +### Step 2 + +Look through your static manifests and determine which fields will need to be +configurable for deployment into different environments. Let's look at a simple +example to illustrate. Following is a Deployment, Ingress and Service that may +be used to deploy a workload. + + # .source-manifests/app.yaml + + apiVersion: apps/v1 + kind: Deployment + metadata: + name: webstore-deploy + spec: + replicas: 2 # <===== configurable + selector: + matchLabels: + app: webstore + template: + metadata: + labels: + app: webstore + spec: + containers: + - name: webstore-container + image: nginx:1.17 # <===== configurable + ports: + - containerPort: 8080 + --- + apiVersion: networking.k8s.io/v1beta1 + kind: Ingress + metadata: + name: webstore-ing + annotations: + nginx.ingress.kubernetes.io/rewrite-target: / + spec: + rules: + - host: app.acme.com + http: + paths: + - path: / + backend: + serviceName: webstorep-svc + servicePort: 80 + --- + kind: Service + apiVersion: v1 + metadata: + name: webstore-svc + spec: + selector: + app: webstore + ports: + - protocol: TCP + port: 80 + targetPort: 8080 + +There are two fields in the Deployment manifest that will need to be +configurable. They are noted with comments. The Deployment's replicas and the +Pod's container image will change between different environments. For example, +in a dev environment the number of replicas will be low and a development +version of the app will be run. In production, there will be more replicas and +a stable release of the app will be used. In this example we don't have any +configurable fields in the Ingress or Service. + +Next we need to use `+operator-builder:field` markers in comments to inform Operator Builder +that the operator will need to support configuration of these elements. +Following is the Deployment manifest with these markers in place. + + apiVersion: apps/v1 + kind: Deployment + metadata: + name: webstore-deploy + labels: + team: dev-team # +operator-builder:field:name=teamName,type=string + spec: + replicas: 2 # +operator-builder:field:name=webStoreReplicas,default=2,type=int + selector: + matchLabels: + app: webstore + template: + metadata: + labels: + app: webstore + team: dev-team # +operator-builder:field:name=teamName,type=string + spec: + containers: + - name: webstore-container + image: nginx:1.17 # +operator-builder:field:name=webStoreImage,type=string + ports: + - containerPort: 8080 + +These markers should always be provided as an in-line comment or as a head +comment. The marker always begins with `+operator-builder:field:` or +`+operator-builder:collection:field:` See [Markers](docs/markers.md) to learn +more. + +### Step 3 + +Operator Builder uses a workload configuration to provide important details for +your operator project. This guide uses a [standalone +workload](docs/standalone-workloads.md). Save a workload config to your +`.source-manifests` directory by using one of the following commands (or +simply copy/pasting the YAML below the commands): + + # generate a workload config with the path (-p) flag + operator-builder init-config standalone -p .source-manifests/workload.yaml + + # generate a workload config from stdout + operator-builder init-config standalone > .source-manifests/workload.yaml + +This will generate the following YAML: + + # .source-manifests/workload.yaml + name: webstore + kind: StandaloneWorkload + spec: + api: + domain: acme.com + group: apps + version: v1alpha1 + kind: WebStore + clusterScoped: false + companionCliRootcmd: + name: webstorectl + description: Manage webstore application + resources: + - app.yaml + +The `name` is arbitrary and can be whatever you like. + +In the `spec`, the following fields are required: + +- `api.domain`: This must be a globally unique name that will not be used by other + organizations or groups. It will contain groups of API types. +- `api.group`: This is a logical group of API types used as a namespacing + mechanism for your APIs. +- `api.version`: Provide the intiial version for your API. +- `api.kind`: The name of the API type that will represent the workload you are + managing with this operator. +- `resources`: An array of filenames where your static manifests live. List the + relative path from the workload manifest to all the files that contain the + static manifests we talked about in step 2. + +For more info about API groups, versions and kinds, check out the [Kubebuilder +docs](https://kubebuilder.io/cronjob-tutorial/gvks.html). + +The following fields in the `spec` are optional: + +- `api.clusterScoped`: If your workload includes cluster-scoped resources like + namespaces, this will need to be `true`. The default is `false`. +- `companionCLIRootcmd`: If you wish to generate source code for a companion CLI + for your operator, include this field. We recommend you do. Your end users + will appreciate it. + - `name`: The root command your end users will type when using the companion + CLI. + - `description`: The general information your end users will get if they use + the `help` subcommand of your companion CLI. + +At this point in our example, our `.source-manifests` directory looks as +follows: + + tree .source-manifests + + .source-manifests + ├── app.yaml + └── workload.yaml + +Our StandaloneWorkload config is in `workload.yaml` and the Deployment, Ingress +and Service manifests are in `app.yaml` and referenced under `spec.resources` in +our StandaloneWorkload config. + +We are now ready to generate our project's source code. + +### Step 4 + +We first use the `init` command to create the general scaffolding. We run this +command from the root of our repo and provide a single argument with the path to +our workload config. + + operator-builder init \ + --workload-config .source-manfiests/workload.yaml + +With the basic project now set up, we can now run the `create api` command to +create a new custom API for our workload. + + operator-builder create api \ + --workload-config .source-manfiests/workload.yaml \ + --controller \ + --resource + +We again provide the same workload config file. Here we also added the +`--controller` and `--resource` arguments. These indicate that we want both a +new controller and new custom resource created. + +You now have a new working Kubernetes Operator! Next, we will test it out. + +### Step 5 + +Assuming you have a kubeconfig in place that allows you to interact with your +cluster with kubectl, you are ready to go. + +First, install the new custom resource definition (CRD). + + make install + +Now we can run the controller locally to test it out. + + make run + +Operator Builder created a sample manifest in the `config/samples` directory. +For this example it looks like this: + + apiVersion: apps.acme.com/v1alpha1 + kind: WebStore + metadata: + name: webstore-sample + spec: + webStoreReplicas: 2 + webStoreImage: nginx:1.17 + teamName: dev-team + +You will notice the fields and values in the `spec` were derived from the +markers you added to your static manifests. + +Next, in another terminal, create a new instance of your workload with +the provided sample manifest. + + kubectl apply -f config/samples/ + +You should see your custom resource sample get created. Now use `kubectl` to +inspect your cluster to confirm the workload's resources got created. You should +find all the resources that were defined in your static manifests. + + kubectl get all + +Clean up by stopping your controller with ctrl-c in that terminal and then +remove all the resources you just created. + + make uninstall + +### Step 6 + +Now let's deploy your controller into the cluster. + +First export an environment variable for your container image. + + export IMG=myrepo/acme-webstore-mgr:0.1.0 + +Run the rest of the commands in this step 6 in this same terminal as most of +them will need this `IMG` env var. + +In order to run the controller in-cluster (as opposed to running locally with +`make run`) we will need to build a container image for it. + + make docker-build + +Now we can push it to a registry that is accessible from the test cluster. + + make docker-push + +Finally, we can deploy it to our test cluster. + + make deploy + +Next, perform the same tests from step 5 to ensure proper operation of our +operator. + + kubectl apply -f config/sample/ + +Again, verify that all the resources you expect are created. + +Once satisfied, remove the instance of your workload. + + kubectl delete -f config/sample/ + +For now, leave the controller running in your test cluster. We'll use it in +Step 7. + +### Step 7 + +Now let's build and test the companion CLI. + +You will have a make target that includes the name of your CLI. For this +example it is: + + make build-webstorectl + +We can view the help info as follows. + + ./bin/webstorectl help + +Your end users can use it to create a new custom resource manifest. + + ./bin/webstorectl init > /tmp/webstore.yaml + +If you would like to change any of the default values, edit the file. + + vim /tmp/webstore.yaml + +Then you can apply it to the cluster. + + kubectl apply -f /tmp/webstore.yaml + +If your end users find they wish to make changes to the resources that aren't +supported by the operator, they can generate the resources from the custom +resource. + + ./bin/webstorectl generate --workload-manifest /tmp/webstore.yaml + +This will print the resources to stdout. These may be piped into an overlay +tool or written to disk and modified before applying to a cluster. + +That's it! You have a working operator without manually writing a single line +of code. If you'd like to make any changes to your workload's API, you'll find +the code in the `apis` directory. The controller's source code is in +`controllers` directory. And the companion CLI code is in `cmd`. + +Don't forget to clean up. Remove the controller, CRD and the workload's +resources as follows. + + make undeploy + +For more information, checkout the [Operator Builder docs](docs/) as +well as the [Kubebuilder docs](https://kubebuilder.io/). + diff --git a/docs/installation.md b/docs/installation.md new file mode 100644 index 0000000..09df1fc --- /dev/null +++ b/docs/installation.md @@ -0,0 +1,74 @@ +# Installation + +You have the following options to install the operator-builder CLI: +* [Download the latest binary with your browser](https://github.com/nukleros/operator-builder/releases/latest) +* [Download with wget](#wget) +* [Homebrew](#homebrew) +* [Snap](#snap) +* [Docker Image](#docker-image) +* [Go Install](#go-install) + +### wget +Use wget to download the pre-compiled binaries: + +```bash +wget https://github.com/vmware-tanzu-labs/operator-builder/releases/download/${VERSION}/${BINARY}.tar.gz -O - |\ + tar xz && sudo mv operator-builder /usr/bin/operator-builder +``` + +For instance, VERSION=v0.5.0 and BINARY=operator-builder_${VERSION}_Linux_x86_64 + +### Homebrew + +Available for Mac and Linux. + +Using [Homebrew](https://brew.sh/) + +```bash +brew tap vmware-tanzu-labs/tap +brew install operator-builder +``` + +### Snap + +Available for Linux only. + +```bash +snap install operator-builder +``` + +>**NOTE**: `operator-builder` installs with [_strict confinement_](https://docs.snapcraft.io/snap-confinement/6233) in snap, this means it doesn't have direct access to root files. + +### Docker Image + +```bash +docker pull ghcr.io/vmawre-tanzu-labs/operator-builder +``` + +#### One-shot container use + +```bash +docker run --rm -v "${PWD}":/workdir ghcr.io/vmware-tanzu-labs/operator-builder [flags] +``` + + +#### Run container commands interactively + +```bash +docker run --rm -it -v "${PWD}":/workdir --entrypoint sh ghcr.io/vmawre-tanzu-labs/operator-builder +``` + +It can be useful to have a bash function to avoid typing the whole docker command: + +```bash +operator-builder() { + docker run --rm -i -v "${PWD}":/workdir ghcr.io/vmware-tanzu-labs/operator-builder "$@" +} +``` + +### Go Install + +```bash +GO111MODULE=on go get github.com/vmware-tanzu-labs/operator-builder/cmd/operator-builder +``` + From c6efc89cfb9cec99c99c9aafa2b90bd588d8a7d1 Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Wed, 15 Jun 2022 15:53:19 -0400 Subject: [PATCH 2/3] Reorganize README, fix formatting --- README.md | 36 ++-- docs/api-updates-upgrades.md | 64 +++---- docs/companion-cli.md | 4 +- docs/getting-started.md | 318 +++++++++++++++++++++-------------- docs/installation.md | 12 +- docs/license.md | 79 +++++---- docs/markers.md | 127 ++++++++------ docs/resource-scope.md | 25 +-- docs/testing.md | 57 ++++--- 9 files changed, 412 insertions(+), 310 deletions(-) diff --git a/README.md b/README.md index 9fe4753..cdc2d1b 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,10 @@ **Accelerate the development of Kubernetes Operators.** +Operator Builder is a command line tool that ingests Kubernetes manifests and +generates the source code for a working Kubernetes operator based on the +resources defined in those manifests. + Operator Builder extends [Kubebuilder](https://github.com/kubernetes-sigs/kubebuilder) to facilitate development and maintenance of Kubernetes operators. It is especially helpful if you need to take large numbers of resources defined with static or @@ -31,26 +35,20 @@ The custom resource defined in the source code can be cluster-scoped or namespace-scoped based on the requirements of the project. More info [here](docs/resource-scope.md). -## Installation - -See our [installation options](docs/installation.md) - -## Getting Started - -Follow our [getting started guide](docs/getting-started.md) - -## Workload Collections - -Operator Builder can generate source code for operators that manage multiple -related and dependent workloads. See [workload collections](docs/workload-collections.md) -for more info. - -## Licensing +User Documentation: -Operator Builder can help manage licensing for the resulting project. More -info [here](docs/license.md). +* [Installation](docs/installation.md) +* [Getting Started](docs/getting-started.md) +* [Workloads](docs/workloads.md) +* [Standalone Workloads](docs/standalone-workloads.md) +* [Workload Collections](docs/workload-collections.md) +* [Markers](docs/markers.md) +* [Resource Scope](docs/resource-scope.md) +* [Companion CLI](docs/companion-cli.md) +* [API Updates & Upgrades](docs/api-updates-upgrades.md) +* [License Manaagement](docs/license.md) -## Testing +Develpoer Documentation -Testing of Operator Builder is documented [here](docs/testing.md). +* [Testing](docs/testing.md) diff --git a/docs/api-updates-upgrades.md b/docs/api-updates-upgrades.md index f92df62..f116f34 100644 --- a/docs/api-updates-upgrades.md +++ b/docs/api-updates-upgrades.md @@ -18,11 +18,13 @@ describe how to overwrite an existing API to update the existing spec. After making the necessary changes to your manifests run the following: - operator-builder create api \ - --workload-config [path/to/workload/config] \ - --controller=false \ - --resource \ - --force +```bash +operator-builder create api \ + --workload-config [path/to/workload/config] \ + --controller=false \ + --resource \ + --force +``` You will pass the same workload config file. The `--controller=false` flag will skip generating controller code but `--resource` and `--force` will cause the @@ -111,7 +113,7 @@ the software when other features not related to an API are released. To create a new version of an existing API, update the `spec.api.version` value in your workload config, for example: -``` +```yaml name: webstore kind: StandaloneWorkload spec: @@ -130,11 +132,13 @@ spec: Now reference the config in a new `create api` command: - operator-builder create api \ - --workload-config [path/to/workload/config] \ - --controller \ - --resource \ - --force +```bash +operator-builder create api \ + --workload-config [path/to/workload/config] \ + --controller \ + --resource \ + --force +``` Note that we _do_ want to re-generate the controller in this case. A new API definition will be create alongside the previous version. If the @@ -143,24 +147,26 @@ version. For example if your APIs look as follows: - tree apis/apps - apis/apps - ├── v1alpha1 - │   ├── groupversion_info.go - │   ├── webstore - │   │   ├── app.go - │   │   └── resources.go - │   ├── webstore_types.go - │   └── zz_generated.deepcopy.go - └── v1alpha2 - ├── groupversion_info.go - ├── webstore - │   ├── app.go - │   └── resources.go - ├── webstore_types.go - └── zz_generated.deepcopy.go - - 4 directories, 10 files +```bash +tree apis/apps +apis/apps +├── v1alpha1 +│   ├── groupversion_info.go +│   ├── webstore +│   │   ├── app.go +│   │   └── resources.go +│   ├── webstore_types.go +│   └── zz_generated.deepcopy.go +└── v1alpha2 + ├── groupversion_info.go + ├── webstore + │   ├── app.go + │   └── resources.go + ├── webstore_types.go + └── zz_generated.deepcopy.go + +4 directories, 10 files +``` You will delete the earlier version with `rm -rf apis/apps/v1alpha1`. diff --git a/docs/companion-cli.md b/docs/companion-cli.md index 86a6ac5..17e021e 100644 --- a/docs/companion-cli.md +++ b/docs/companion-cli.md @@ -1,6 +1,8 @@ # Companion CLI -Generate source code for a companion CLI to a Kubernetes operator. +When you generate the source code for a Kubernetes operator with Operator +Builder, it can include the code for a companion CLI. The source code for the +companion CLI will be found in the `cmd` directory of the generated codebase. The companion CLI does three things: 1. Generate Sample Manifests: the `init` command will save a sample manifest to diff --git a/docs/getting-started.md b/docs/getting-started.md index d0a02da..7602158 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -34,88 +34,96 @@ This guide consists of the following steps: 1. [Build and install your operator's controller manager in your test cluster](#step-6). 1. [Build and test the operator's companion CLI](#step-7). -### Step 1 +### Step 1: Create a Repo Create a new directory for your operator's source code. We recommend you follow the standard [code organization guidelines](https://golang.org/doc/code#Organization). In that directory initialize a new git repo. - git init +```bash +git init +``` And intialize a new go module. The module should be the import path for your project, usually something like `github.com/user-account/project-name`. Use the command `go help importpath` for more info. - go mod init [module] +```bash +go mod init [module] +``` Lastly create a directory for your static manifests. Operator Builder will use these as a source for defining resources in your operator's codebase. It must be a hidden directory so as not to interfere with source code generation. - mkdir .source-manifests +```bash +mkdir .source-manifests +``` Put your static manifests in this `.source-manifests` directory. In the next step we will add commented markers to them. Note that these static manifests can be in one or more files. And you can have one or more manifests (separated by `---`) in each file. Just organize them in a way that makes sense to you. -### Step 2 +### Step 2: Add Manifest Markers Look through your static manifests and determine which fields will need to be configurable for deployment into different environments. Let's look at a simple example to illustrate. Following is a Deployment, Ingress and Service that may be used to deploy a workload. - # .source-manifests/app.yaml - - apiVersion: apps/v1 - kind: Deployment - metadata: - name: webstore-deploy - spec: - replicas: 2 # <===== configurable - selector: - matchLabels: - app: webstore - template: - metadata: - labels: - app: webstore - spec: - containers: - - name: webstore-container - image: nginx:1.17 # <===== configurable - ports: - - containerPort: 8080 - --- - apiVersion: networking.k8s.io/v1beta1 - kind: Ingress +```yaml +# .source-manifests/app.yaml + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: webstore-deploy +spec: + replicas: 2 # <===== configurable + selector: + matchLabels: + app: webstore + template: metadata: - name: webstore-ing - annotations: - nginx.ingress.kubernetes.io/rewrite-target: / - spec: - rules: - - host: app.acme.com - http: - paths: - - path: / - backend: - serviceName: webstorep-svc - servicePort: 80 - --- - kind: Service - apiVersion: v1 - metadata: - name: webstore-svc - spec: - selector: + labels: app: webstore - ports: - - protocol: TCP - port: 80 - targetPort: 8080 + spec: + containers: + - name: webstore-container + image: nginx:1.17 # <===== configurable + ports: + - containerPort: 8080 +--- +apiVersion: networking.k8s.io/v1beta1 +kind: Ingress +metadata: + name: webstore-ing + annotations: + nginx.ingress.kubernetes.io/rewrite-target: / +spec: + rules: + - host: app.acme.com + http: + paths: + - path: / + backend: + serviceName: webstorep-svc + servicePort: 80 +--- +kind: Service +apiVersion: v1 +metadata: + name: webstore-svc +spec: + selector: + app: webstore + ports: + - protocol: TCP + port: 80 + targetPort: 8080 +``` There are two fields in the Deployment manifest that will need to be configurable. They are noted with comments. The Deployment's replicas and the @@ -129,35 +137,37 @@ Next we need to use `+operator-builder:field` markers in comments to inform Oper that the operator will need to support configuration of these elements. Following is the Deployment manifest with these markers in place. - apiVersion: apps/v1 - kind: Deployment +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: webstore-deploy + labels: + team: dev-team # +operator-builder:field:name=teamName,type=string +spec: + replicas: 2 # +operator-builder:field:name=webStoreReplicas,default=2,type=int + selector: + matchLabels: + app: webstore + template: metadata: - name: webstore-deploy labels: + app: webstore team: dev-team # +operator-builder:field:name=teamName,type=string spec: - replicas: 2 # +operator-builder:field:name=webStoreReplicas,default=2,type=int - selector: - matchLabels: - app: webstore - template: - metadata: - labels: - app: webstore - team: dev-team # +operator-builder:field:name=teamName,type=string - spec: - containers: - - name: webstore-container - image: nginx:1.17 # +operator-builder:field:name=webStoreImage,type=string - ports: - - containerPort: 8080 + containers: + - name: webstore-container + image: nginx:1.17 # +operator-builder:field:name=webStoreImage,type=string + ports: + - containerPort: 8080 +``` These markers should always be provided as an in-line comment or as a head comment. The marker always begins with `+operator-builder:field:` or `+operator-builder:collection:field:` See [Markers](docs/markers.md) to learn more. -### Step 3 +### Step 3: Create a Workload Config Operator Builder uses a workload configuration to provide important details for your operator project. This guide uses a [standalone @@ -165,29 +175,33 @@ workload](docs/standalone-workloads.md). Save a workload config to your `.source-manifests` directory by using one of the following commands (or simply copy/pasting the YAML below the commands): - # generate a workload config with the path (-p) flag - operator-builder init-config standalone -p .source-manifests/workload.yaml +```bash +# generate a workload config with the path (-p) flag +operator-builder init-config standalone -p .source-manifests/workload.yaml - # generate a workload config from stdout - operator-builder init-config standalone > .source-manifests/workload.yaml +# generate a workload config from stdout +operator-builder init-config standalone > .source-manifests/workload.yaml +``` This will generate the following YAML: - # .source-manifests/workload.yaml - name: webstore - kind: StandaloneWorkload - spec: - api: - domain: acme.com - group: apps - version: v1alpha1 - kind: WebStore - clusterScoped: false - companionCliRootcmd: - name: webstorectl - description: Manage webstore application - resources: - - app.yaml +```yaml +# .source-manifests/workload.yaml +name: webstore +kind: StandaloneWorkload +spec: + api: + domain: acme.com + group: apps + version: v1alpha1 + kind: WebStore + clusterScoped: false + companionCliRootcmd: + name: webstorectl + description: Manage webstore application + resources: + - app.yaml +``` The `name` is arbitrary and can be whatever you like. @@ -222,11 +236,13 @@ The following fields in the `spec` are optional: At this point in our example, our `.source-manifests` directory looks as follows: - tree .source-manifests +```bash +tree .source-manifests - .source-manifests - ├── app.yaml - └── workload.yaml +.source-manifests +├── app.yaml +└── workload.yaml +``` Our StandaloneWorkload config is in `workload.yaml` and the Deployment, Ingress and Service manifests are in `app.yaml` and referenced under `spec.resources` in @@ -234,22 +250,26 @@ our StandaloneWorkload config. We are now ready to generate our project's source code. -### Step 4 +### Step 4: Generate Operator Source Code We first use the `init` command to create the general scaffolding. We run this command from the root of our repo and provide a single argument with the path to our workload config. - operator-builder init \ - --workload-config .source-manfiests/workload.yaml +```bash +operator-builder init \ + --workload-config .source-manfiests/workload.yaml +``` With the basic project now set up, we can now run the `create api` command to create a new custom API for our workload. - operator-builder create api \ - --workload-config .source-manfiests/workload.yaml \ - --controller \ - --resource +```bash +operator-builder create api \ + --workload-config .source-manfiests/workload.yaml \ + --controller \ + --resource +``` We again provide the same workload config file. Here we also added the `--controller` and `--resource` arguments. These indicate that we want both a @@ -257,30 +277,36 @@ new controller and new custom resource created. You now have a new working Kubernetes Operator! Next, we will test it out. -### Step 5 +### Step 5: Run & Test the Operator Assuming you have a kubeconfig in place that allows you to interact with your cluster with kubectl, you are ready to go. First, install the new custom resource definition (CRD). - make install +```bash +make install +``` Now we can run the controller locally to test it out. - make run +```bash +make run +``` Operator Builder created a sample manifest in the `config/samples` directory. For this example it looks like this: - apiVersion: apps.acme.com/v1alpha1 - kind: WebStore - metadata: - name: webstore-sample - spec: - webStoreReplicas: 2 - webStoreImage: nginx:1.17 - teamName: dev-team +```yaml +apiVersion: apps.acme.com/v1alpha1 +kind: WebStore +metadata: + name: webstore-sample +spec: + webStoreReplicas: 2 + webStoreImage: nginx:1.17 + teamName: dev-team +``` You will notice the fields and values in the `spec` were derived from the markers you added to your static manifests. @@ -288,26 +314,34 @@ markers you added to your static manifests. Next, in another terminal, create a new instance of your workload with the provided sample manifest. - kubectl apply -f config/samples/ +```bash +kubectl apply -f config/samples/ +``` You should see your custom resource sample get created. Now use `kubectl` to inspect your cluster to confirm the workload's resources got created. You should find all the resources that were defined in your static manifests. - kubectl get all +```bash +kubectl get all +``` Clean up by stopping your controller with ctrl-c in that terminal and then remove all the resources you just created. - make uninstall +```bash +make uninstall +``` -### Step 6 +### Step 6: Build & Deploy the Controller Manager Now let's deploy your controller into the cluster. First export an environment variable for your container image. - export IMG=myrepo/acme-webstore-mgr:0.1.0 +```bash +export IMG=myrepo/acme-webstore-mgr:0.1.0 +``` Run the rest of the commands in this step 6 in this same terminal as most of them will need this `IMG` env var. @@ -315,60 +349,82 @@ them will need this `IMG` env var. In order to run the controller in-cluster (as opposed to running locally with `make run`) we will need to build a container image for it. - make docker-build +```bash +make docker-build +``` Now we can push it to a registry that is accessible from the test cluster. - make docker-push +```bash +make docker-push +``` Finally, we can deploy it to our test cluster. - make deploy +```bash +make deploy +``` Next, perform the same tests from step 5 to ensure proper operation of our operator. - kubectl apply -f config/sample/ +```bash +kubectl apply -f config/sample/ +``` Again, verify that all the resources you expect are created. Once satisfied, remove the instance of your workload. - kubectl delete -f config/sample/ +```bash +kubectl delete -f config/sample/ +``` For now, leave the controller running in your test cluster. We'll use it in Step 7. -### Step 7 +### Step 7: Build & Test Companion CLI Now let's build and test the companion CLI. You will have a make target that includes the name of your CLI. For this example it is: - make build-webstorectl +```bash +make build-webstorectl +``` We can view the help info as follows. - ./bin/webstorectl help +```bash +./bin/webstorectl help +``` Your end users can use it to create a new custom resource manifest. - ./bin/webstorectl init > /tmp/webstore.yaml +```bash +./bin/webstorectl init > /tmp/webstore.yaml +``` If you would like to change any of the default values, edit the file. - vim /tmp/webstore.yaml +```bash +vim /tmp/webstore.yaml +``` Then you can apply it to the cluster. - kubectl apply -f /tmp/webstore.yaml +```bash +kubectl apply -f /tmp/webstore.yaml +``` If your end users find they wish to make changes to the resources that aren't supported by the operator, they can generate the resources from the custom resource. - ./bin/webstorectl generate --workload-manifest /tmp/webstore.yaml +```bash +./bin/webstorectl generate --workload-manifest /tmp/webstore.yaml +``` This will print the resources to stdout. These may be piped into an overlay tool or written to disk and modified before applying to a cluster. @@ -381,7 +437,9 @@ the code in the `apis` directory. The controller's source code is in Don't forget to clean up. Remove the controller, CRD and the workload's resources as follows. - make undeploy +```bash +make undeploy +``` For more information, checkout the [Operator Builder docs](docs/) as well as the [Kubebuilder docs](https://kubebuilder.io/). diff --git a/docs/installation.md b/docs/installation.md index 09df1fc..0a421ce 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -12,17 +12,18 @@ You have the following options to install the operator-builder CLI: Use wget to download the pre-compiled binaries: ```bash -wget https://github.com/vmware-tanzu-labs/operator-builder/releases/download/${VERSION}/${BINARY}.tar.gz -O - |\ - tar xz && sudo mv operator-builder /usr/bin/operator-builder +VERSION=v0.6.0 +OS=Linux +ARCH=x86_64 +wget https://github.com/nukleros/operator-builder/releases/download/${VERSION}/operator-builder_${VERSION}_${OS}_${ARCH}.gz -O - |\ + gzip -d && sudo mv operator-builder_${VERSION}_${OS}_${ARCH} /usr/local/bin/operator-builder ``` -For instance, VERSION=v0.5.0 and BINARY=operator-builder_${VERSION}_Linux_x86_64 - ### Homebrew Available for Mac and Linux. -Using [Homebrew](https://brew.sh/) +Using [Homebrew](https://brew.sh/) ```bash brew tap vmware-tanzu-labs/tap @@ -51,7 +52,6 @@ docker pull ghcr.io/vmawre-tanzu-labs/operator-builder docker run --rm -v "${PWD}":/workdir ghcr.io/vmware-tanzu-labs/operator-builder [flags] ``` - #### Run container commands interactively ```bash diff --git a/docs/license.md b/docs/license.md index 6fb449b..251f280 100644 --- a/docs/license.md +++ b/docs/license.md @@ -6,42 +6,46 @@ Manage the creation and update of licensing for your Kubebuilder project. Create two license files for testing: - cat > /tmp/project.txt < /tmp/source-header.txt < /tmp/project.txt < /tmp/source-header.txt < Date: Thu, 16 Jun 2022 07:25:25 -0400 Subject: [PATCH 3/3] Fix typo, improve formatting --- README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index cdc2d1b..ec84c82 100644 --- a/README.md +++ b/README.md @@ -35,20 +35,22 @@ The custom resource defined in the source code can be cluster-scoped or namespace-scoped based on the requirements of the project. More info [here](docs/resource-scope.md). -User Documentation: +## Documentation + +### User Docs * [Installation](docs/installation.md) * [Getting Started](docs/getting-started.md) * [Workloads](docs/workloads.md) -* [Standalone Workloads](docs/standalone-workloads.md) -* [Workload Collections](docs/workload-collections.md) + * [Standalone Workloads](docs/standalone-workloads.md) + * [Workload Collections](docs/workload-collections.md) * [Markers](docs/markers.md) * [Resource Scope](docs/resource-scope.md) * [Companion CLI](docs/companion-cli.md) * [API Updates & Upgrades](docs/api-updates-upgrades.md) * [License Manaagement](docs/license.md) -Develpoer Documentation +### Developer Docs * [Testing](docs/testing.md)