From c6efc89cfb9cec99c99c9aafa2b90bd588d8a7d1 Mon Sep 17 00:00:00 2001 From: Rich Lander Date: Wed, 15 Jun 2022 15:53:19 -0400 Subject: [PATCH] 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 <