From 005692a642e14b3134b2454654892bf2cd78bbd7 Mon Sep 17 00:00:00 2001 From: Eric Stroczynski Date: Thu, 1 Nov 2018 16:31:19 -0700 Subject: [PATCH 1/6] README.md: update to reflect changes in operator-sdk --- README.md | 336 +++++++++++++++++++++++++++++++++++++----------- handler.go.tmpl | 158 ----------------------- 2 files changed, 262 insertions(+), 232 deletions(-) delete mode 100644 handler.go.tmpl diff --git a/README.md b/README.md index bf99a35..7788c68 100644 --- a/README.md +++ b/README.md @@ -1,137 +1,319 @@ # Getting Started -The [Operator Framework](https://github.com/operator-framework/) ([intro blog post][blog_post]) is an open source toolkit to manage Kubernetes native applications, called Operators, in an effective, automated, and scalable way. Operators take advantage of Kubernetes's extensibility to deliver the automation advantages of cloud services like provisioning, scaling, and backup/restore while being able to run anywhere that Kubernetes can run. +The [Operator Framework][org_operator_framework] ([intro blog post][site_blog_post]) is an open source toolkit to manage Kubernetes native applications, called operators, in an effective, automated, and scalable way. operators take advantage of Kubernetes's extensibility to deliver the automation advantages of cloud services like provisioning, scaling, and backup/restore while being able to run anywhere that Kubernetes can run. -This guide shows how to build a simple Memcached Operator and how to manage its lifecycle from install to update to a new version. For that, we will use two center pieces of the framework: -* **Operator SDK**: Allows your developers to build an Operator based on your expertise without requiring knowledge of Kubernetes API complexities. -* **Operator Lifecycle Manager**: Helps you to install, update, and generally manage the lifecycle of all of the Operators (and their associated services) running across your clusters. +This guide shows how to build a simple [memcached][site_memcached] operator and how to manage its lifecycle from install to update to a new version. For that, we will use two center pieces of the framework: + +* **Operator SDK**: Allows your developers to build an operator based on your expertise without requiring knowledge of Kubernetes API complexities. +* **o Lifecycle Manager**: Helps you to install, update, and generally manage the lifecycle of all of the operators (and their associated services) running across your clusters. > **Requirements**: Please make sure that the [Operator SDK][operator_sdk] is installed on the development machine. Additionally, the [Operator Lifecycle Manager][operator_lifecycle_manager] must be installed in the cluster (1.8 or above to support the apps/v1beta2 API group) before running this guide. -## Build an Operator using the Operator SDK +## Build an operator using the Operator SDK The Operator SDK makes it easier to build Kubernetes native applications, a process that can require deep, application-specific operational knowledge. The SDK not only lowers that barrier, but it also helps reduce the amount of boilerplate code needed for many common management capabilities, such as metering or monitoring. -This section walks through an example of building a simple Memcached Operator using tools and libraries provided by the Operator SDK. +This section walks through an example of building a simple memcached operator using tools and libraries provided by the Operator SDK. This walkthrough is not exhaustive; for an in-depth explanation of these steps, see the SDK's [user guide][doc_sdk_user_guide]. ### Create a new project +If you do not have the SDK installed, see the [installation instructions][doc_sdk_install_instr]. + Use the CLI to create a new `memcached-operator` project: ```sh +$ mkdir -p $GOPATH/src/github.com/example-inc/ $ cd $GOPATH/src/github.com/example-inc/ -$ operator-sdk new memcached-operator --api-version=cache.example.com/v1alpha1 --kind=Memcached +$ operator-sdk new memcached-operator +Create cmd/manager/main.go +... +Run dep ensure ... +... +Run dep ensure done +Run git init ... +... +Run git init done $ cd memcached-operator ``` -This creates the `memcached-operator` project specifically for watching the `Memcached` resource with APIVersion `cache.example.com/v1apha1` and Kind `Memcached`. +This creates the `memcached-operator` project. Learn more about the project directory structure from the SDK [project layout][layout_doc] documentation. -### Customize the Operator logic +#### Define the Memcached spec and status -For this example, the Memcached Operator will execute the following reconciliation logic for each `Memcached` custom resource: +Modify the spec and status of the `Memcached` Custom Resource(CR) at `pkg/apis/cache/v1alpha1/memcached_types.go`: -* Create a Memcached Deployment if it doesn't exist -* Ensure that the Deployment size is the same as specified by the `Memcached` [CustomResource][kubernetes_cr] (CR) spec -* Update the `Memcached` CR status with the names of the memcached pods +```Go +type MemcachedSpec struct { + // Size is the size of the memcached deployment + Size int32 `json:"size"` +} +type MemcachedStatus struct { + // Nodes are the names of the memcached pods + Nodes []string `json:"nodes"` +} +``` + +After modifying the `*_types.go` file always run the following command to update the generated code for that resource type: -#### Watch for the Memcached custom resource definition +```sh +$ operator-sdk generate k8s +``` -By default, the memcached-operator watches `Memcached` resource events as shown in `cmd/memcached-operator/main.go`. +### Manager + +The main program for the operator `cmd/manager/main.go` initializes and runs the [Manager][manager_go_doc]. + +The Manager will automatically register the scheme for all custom resources defined under `pkg/apis/...` and run all controllers under `pkg/controller/...`. + +The Manager can restrict the namespace that all controllers will watch for resources: ```Go -func main() { - sdk.Watch("cache.example.com/v1alpha1", "Memcached", "default", 5) - sdk.Handle(stub.NewHandler()) - sdk.Run(context.TODO()) -} +mgr, err := manager.New(cfg, manager.Options{Namespace: namespace}) ``` -#### Define the Memcached spec and status - -Modify the spec and status of the `Memcached` CRD at `pkg/apis/cache/v1alpha1/types.go`: +By default this will be the namespace that the operator is running in. To watch all namespaces leave the namespace option empty: ```Go -type MemcachedSpec struct { - // Size is the size of the memcached deployment - Size int32 `json:"size"` -} -type MemcachedStatus struct { - // Nodes are the names of the memcached pods - Nodes []string `json:"nodes"` -} +mgr, err := manager.New(cfg, manager.Options{Namespace: ""}) ``` -Update the generated code for the CR: + +## Add a new Custom Resource Definition + +Add a new Custom Resource Definition (CRD) API called `Memcached`, with APIVersion `cache.example.com/v1apha1` and Kind `Memcached`. ```sh -$ cd $GOPATH/src/github.com/example-inc/ -$ cd memcached-operator -$ operator-sdk generate k8s +$ operator-sdk add api --api-version=cache.example.com/v1alpha1 --kind=Memcached +``` + +This will scaffold the `Memcached` resource API under `pkg/apis/cache/v1alpha1/...`. + +## Add a new Controller + +Add a new [Controller][controller_go_doc] to the project that will watch and reconcile the `Memcached` resource: + +```sh +$ operator-sdk add controller --api-version=cache.example.com/v1alpha1 --kind=Memcached ``` -#### Define the Handler +This will scaffold a new Controller implementation under `pkg/controller/memcached/...`. + +For this example replace the generated Controller file `pkg/controller/memcached/memcached_controller.go` with the example [`memcached_controller.go`][memcached_controller] implementation. -The reconciliation loop for an event is defined in the `Handle()` function at `pkg/stub/handler.go`. +The example Controller executes the following reconciliation logic for each `Memcached` CR: + +* Create a memcached Deployment if it doesn't exist +* Ensure that the Deployment size is the same as specified by the `Memcached` CR spec +* Update the `Memcached` CR status with the names of the memcached pods -Replace this file with the reference implementation found [here][handler_go]. You will need to update the highlighted line if you have changed the import path of this project to something other than “example-inc”. +The next two subsections explain how the Controller watches resources and how the reconcile loop is triggered. Skip to the [Build](#build-and-run-the-operator) section to see how to build and run the operator. -> **Note**: The provided handler implementation is only meant to demonstrate the use of the SDK APIs and is not representative of the best practices of a reconciliation loop. +### Resources watched by the Controller -### Build and run the Operator +Inspect the Controller implementation at `pkg/controller/memcached/memcached_controller.go` to see how the Controller watches resources. -Build the `memcached-operator` image and push it to a registry. Please make sure you have a an account on [Quay.io][quay_io] for the next step, or substitute your preferred container registry. On the registry, [create a new public image][create_public_image] repository named “memcached-operator”. +The first watch is for the `Memcached` type as the primary resource. For each Add/Update/Delete event the reconcile loop will be sent a reconcile `Request` (a namespace/name key) for that `Memcached` object: + +```Go +err := c.Watch( + &source.Kind{Type: &cachev1alpha1.Memcached{}}, + &handler.EnqueueRequestForObject{}, + ) +``` +The next watch is for Deployments but the event handler will map each event to a reconcile `Request` for the owner of the Deployment. Which in this case is the `Memcached` object for which the Deployment was created. This allows the controller to watch Deployments as a secondary resource. + +```Go +err := c.Watch( + &source.Kind{Type: &appsv1.Deployment{}}, + &handler.EnqueueRequestForOwner{ + IsController: true, + OwnerType: &cachev1alpha1.Memcached{}}, + ) +``` + +### Reconcile loop + +Every Controller has a Reconciler object with a `Reconcile()` method that implements the reconcile loop. The reconcile loop is passed the [`Request`][request_go_doc] argument which is a Namespace/Name key used to lookup the primary resource object, `Memcached`, from the cache: + +```Go +func (r *ReconcileMemcached) Reconcile(request reconcile.Request) (reconcile.Result, error) { + // Lookup the Memcached instance for this reconcile request + memcached := &cachev1alpha1.Memcached{} + err := r.client.Get(context.TODO(), request.NamespacedName, memcached) + ... +} +``` + +For a guide on Reconcilers, Clients, and interacting with resource Events, see the [Client API doc][doc_client_api]. + +## Build and run the operator + +Before running the operator, the CRD must be registered with the Kubernetes apiserver: + +```sh +$ kubectl create -f deploy/crds/cache_v1alpha1_memcached_crd.yaml +``` + +Once this is done, there are two ways to run the operator: + +* As a Deployment inside a Kubernetes cluster +* As Go program outside a cluster + +### 1. Run as a Deployment inside the cluster + +Build the memcached-operator image and push it to a registry: ```sh -$ cd $GOPATH/src/github.com/example-inc/ -$ cd memcached-operator $ operator-sdk build quay.io/example/memcached-operator:v0.0.1 +$ sed -i 's|REPLACE_IMAGE|quay.io/example/memcached-operator:v0.0.1|g' deploy/operator.yaml $ docker push quay.io/example/memcached-operator:v0.0.1 ``` -Kubernetes deployment manifests are generated in `deploy/operator.yaml`. The deployment image is set to the container image specified above. +The Deployment manifest is generated at `deploy/operator.yaml`. Be sure to update the deployment image as shown above since the default is just a placeholder. -Deploy the Memcached Operator: +Setup RBAC and deploy the memcached-operator: ```sh -$ kubectl create -f deploy/sa.yaml -$ kubectl create -f deploy/rbac.yaml -$ kubectl create -f deploy/crd.yaml +$ kubectl create -f deploy/service_account.yaml +$ kubectl create -f deploy/role.yaml +$ kubectl create -f deploy/role_binding.yaml $ kubectl create -f deploy/operator.yaml ``` -Verify that `memcached-operator` is up and running: +Verify that the memcached-operator is up and running: + +```sh +$ kubectl get deployment +NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE +memcached-operator 1 1 1 1 1m +``` + +### 2. Run locally outside the cluster + +This method is preferred during development cycle to deploy and test faster. + +Set the name of the operator in an environment variable: + +```sh +export OPERATOR_NAME=memcached-operator +``` + +Run the operator locally with the default kubernetes config file present at `$HOME/.kube/config`: + +```sh +$ operator-sdk up local --namespace=default +2018/09/30 23:10:11 Go Version: go1.10.2 +2018/09/30 23:10:11 Go OS/Arch: darwin/amd64 +2018/09/30 23:10:11 operator-sdk Version: 0.0.6+git +2018/09/30 23:10:12 Registering Components. +2018/09/30 23:10:12 Starting the Cmd. +``` + +You can use a specific kubeconfig via the flag `--kubeconfig=`. + +## Create a Memcached CR + +Create the example `Memcached` CR that was generated at `deploy/crds/cache_v1alpha1_memcached_cr.yaml`: + +```sh +$ cat deploy/crds/cache_v1alpha1_memcached_cr.yaml +apiVersion: "cache.example.com/v1alpha1" +kind: "Memcached" +metadata: + name: "example-memcached" +spec: + size: 3 + +$ kubectl apply -f deploy/crds/cache_v1alpha1_memcached_cr.yaml +``` + +Ensure that the memcached-operator creates the deployment for the CR: + +```sh +$ kubectl get deployment +NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE +memcached-operator 1 1 1 1 2m +example-memcached 3 3 3 3 1m +``` + +Check the pods and CR status to confirm the status is updated with the memcached pod names: ```sh $ kubectl get pods NAME READY STATUS RESTARTS AGE -memcached-operator-75c4b4c665-8jnj5 1/1 Running 0 20s +example-memcached-6fd7c98d8-7dqdr 1/1 Running 0 1m +example-memcached-6fd7c98d8-g5k7v 1/1 Running 0 1m +example-memcached-6fd7c98d8-m7vn7 1/1 Running 0 1m +memcached-operator-7cc7cfdf86-vvjqk 1/1 Running 0 2m +``` + +```sh +$ kubectl get memcached/example-memcached -o yaml +apiVersion: cache.example.com/v1alpha1 +kind: Memcached +metadata: + clusterName: "" + creationTimestamp: 2018-03-31T22:51:08Z + generation: 0 + name: example-memcached + namespace: default + resourceVersion: "245453" + selfLink: /apis/cache.example.com/v1alpha1/namespaces/default/memcacheds/example-memcached + uid: 0026cc97-3536-11e8-bd83-0800274106a1 +spec: + size: 3 +status: + nodes: + - example-memcached-6fd7c98d8-7dqdr + - example-memcached-6fd7c98d8-g5k7v + - example-memcached-6fd7c98d8-m7vn7 ``` -Now let’s clean everything up: +### Update the size + +Change the `spec.size` field in the memcached CR from 3 to 4 and apply the change: ```sh -$ kubectl delete -f deploy/operator.yaml -$ kubectl delete -f deploy/crd.yaml -$ kubectl delete -f deploy/rbac.yaml -$ kubectl delete -f deploy/sa.yaml +$ cat deploy/crds/cache_v1alpha1_memcached_cr.yaml +apiVersion: "cache.example.com/v1alpha1" +kind: "Memcached" +metadata: + name: "example-memcached" +spec: + size: 4 + +$ kubectl apply -f deploy/crds/cache_v1alpha1_memcached_cr.yaml ``` -## Manage the Operator using the Operator Lifecycle Manager -The previous section has covered manually running an Operator. In the next sections, we will explore using the Operator Lifecycle Manager which is what enables a more robust deployment model for Operators being run in production environments. +Confirm that the operator changes the deployment size: + +```sh +$ kubectl get deployment +NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE +example-memcached 4 4 4 4 5m +``` + +## Reference implementation + +The above walkthrough follows the actual implementation process used to produce the `memcached-operator` in the SDK [samples repo][repo_sdk_samples_memcached]. + +## Manage the operator using the Operator Lifecycle Manager + +The previous section has covered manually running an operator. In the next sections, we will explore using the operator Lifecycle Manager which is what enables a more robust deployment model for operators being run in production environments. -The Operator Lifecycle Manager helps you to install, update, and generally manage the lifecycle of all of the Operators (and their associated services) on a Kubernetes cluster. It runs as an Kubernetes extension and lets you use `kubectl` for all the lifecycle management functions without any additional tools. +The Operator Lifecycle Manager helps you to install, update, and generally manage the lifecycle of all of the operators (and their associated services) on a Kubernetes cluster. It runs as an Kubernetes extension and lets you use `kubectl` for all the lifecycle management functions without any additional tools. -### Generate an Operator manifest +### Generate an operator manifest -The first step to leveraging the Operator Lifecycle Manager is to create a manifest. An Operator manifest describes how to display, create and manage the application, in this case Memcached, as a whole. It is required for the Operator Lifecycle Manager to function. +The first step to leveraging the Operator Lifecycle Manager is to create a manifest. An operator manifest describes how to display, create and manage the application, in this case memcached, as a whole. It is required for the Operator Lifecycle Manager to function. -For the purpose of this guide, we will continue with this [predefined manifest][manifest_v1] file for the next steps. If you’d like, you can alter the image field within this manifest to reflect the image you built in previous steps, but it is unnecessary. In the future, the Operator SDK CLI will generate an Operator manifest for you, a feature that is planned for the next release of the Operator SDK. +For the purpose of this guide, we will continue with this [predefined manifest][manifest_v1] file for the next steps. If you’d like, you can alter the image field within this manifest to reflect the image you built in previous steps, but it is unnecessary. In the future, the Operator SDK CLI will generate an operator manifest for you, a feature that is planned for the next release of the Operator SDK. ### Deploy the Operator -Deploying an Operator is as simple as applying the Operator’s manifest to the desired namespace in the cluster. +Deploying an operator is as simple as applying the operator’s manifest to the desired namespace in the cluster. ```sh $ curl -Lo memcachedoperator.0.0.1.csv.yaml https://raw.githubusercontent.com/operator-framework/getting-started/master/memcachedoperator.0.0.1.csv.yaml @@ -139,20 +321,20 @@ $ kubectl apply -f memcachedoperator.0.0.1.csv.yaml $ kubectl get ClusterServiceVersion memcachedoperator.v0.0.1 -o json | jq '.status' ``` -After applying this manifest, nothing has happened yet, because the cluster does not meet the requirements specified in our manifest. Create the CustomResourceDefinition and RBAC rules for the Memcached type managed by the Operator: +After applying this manifest, nothing has happened yet, because the cluster does not meet the requirements specified in our manifest. Create the CustomResourceDefinition and RBAC rules for the `Memcached` type managed by the operator: ```sh $ kubectl apply -f deploy/rbac.yaml $ kubectl apply -f deploy/crd.yaml ``` -Because the Operator Lifecycle Manager creates Operators in a particular namespace when a manifest has been applied, administrators can leverage the native Kubernetes RBAC permission model to restrict which users are allowed to install Operators. +Because the Operator Lifecycle Manager creates operators in a particular namespace when a manifest has been applied, administrators can leverage the native Kubernetes RBAC permission model to restrict which users are allowed to install operators. ### Create an application instance -The Memcached Operator is now running in the `memcached` namespace. Users interact with Operators via instances of CustomResources; in this case, the resource has the Kind `Memcached`. Native Kubernetes RBAC also applies to CustomResources, providing administrators control over who can interact with each Operator. +The memcached operator is now running in the `memcached` namespace. Users interact with operators via instances of CustomResources; in this case, the resource has the Kind `Memcached`. Native Kubernetes RBAC also applies to CustomResources, providing administrators control over who can interact with each operator. -Creating instances of Memcached in this namespace will now trigger the Memcached Operator to instantiate pods running the memcached server that are managed by the Operator. The more CustomResources you create, the more unique instances of Memcached will be managed by the Memcached Operator running in this namespace. +Creating instances of memcached in this namespace will now trigger the memcached operator to instantiate pods running the memcached server that are managed by the operator. The more CustomResources you create, the more unique instances of memcached will be managed by the memcached operator running in this namespace. ```sh $ cat < -[blog_post]: https://coreos.com/blog/introducing-operator-framework +[org_operator_framework]: https://github.com/operator-framework/ +[site_blog_post]: https://coreos.com/blog/introducing-operator-framework [operator_sdk]: https://github.com/operator-framework/operator-sdk [operator_lifecycle_manager]: https://github.com/operator-framework/operator-lifecycle-manager +[site_memcached]: https://memcached.org/ +[doc_sdk_user_guide]: https://github.com/operator-framework/operator-sdk/blob/master/doc/user-guide.md +[doc_sdk_install_instr]: https://github.com/operator-framework/operator-sdk/blob/master/doc/user-guide.md#install-the-operator-sdk-cli [layout_doc]: https://github.com/operator-framework/operator-sdk/blob/master/doc/project_layout.md -[quay_io]: https://www.quay.io -[kubernetes_cr]: https://kubernetes.io/docs/concepts/api-extension/custom-resources/ -[handler_go]: https://github.com/operator-framework/getting-started/blob/master/handler.go.tmpl#L7 -[create_public_image]: https://quay.io/new/ +[manager_go_doc]: https://godoc.org/github.com/kubernetes-sigs/controller-runtime/pkg/manager#Manager +[controller_go_doc]: https://godoc.org/github.com/kubernetes-sigs/controller-runtime/pkg#hdr-Controller +[request_go_doc]: https://godoc.org/github.com/kubernetes-sigs/controller-runtime/pkg/reconcile#Request +[result_go_doc]: https://godoc.org/github.com/kubernetes-sigs/controller-runtime/pkg/reconcile#Result +[doc_client_api]: https://github.com/operator-framework/operator-sdk/blob/master/doc/user/client.md +[repo_sdk_samples_memcached]: https://github.com/operator-framework/operator-sdk-samples/memcached-operator/ [manifest_v1]: memcachedoperator.0.0.1.csv.yaml [manifest_v2]: memcachedoperator.0.0.2.csv.yaml [mailing_list]: https://groups.google.com/forum/#!forum/operator-framework diff --git a/handler.go.tmpl b/handler.go.tmpl deleted file mode 100644 index 7d1ce50..0000000 --- a/handler.go.tmpl +++ /dev/null @@ -1,158 +0,0 @@ -package stub - -import ( - "fmt" - "reflect" - - "github.com/example-inc/memcached-operator/pkg/apis/cache/v1alpha1" - - "github.com/operator-framework/operator-sdk/pkg/sdk" - appsv1 "k8s.io/api/apps/v1" - "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" - "context" -) - -func NewHandler() sdk.Handler { - return &Handler{} -} - -type Handler struct { -} - -func (h *Handler) Handle(ctx context.Context, event sdk.Event) error { - switch o := event.Object.(type) { - case *v1alpha1.Memcached: - memcached := o - - // Ignore the delete event since the garbage collector will clean up all secondary resources for the CR - // All secondary resources must have the CR set as their OwnerReference for this to be the case - if event.Deleted { - return nil - } - - // Create the deployment if it doesn't exist - dep := deploymentForMemcached(memcached) - err := sdk.Create(dep) - if err != nil && !apierrors.IsAlreadyExists(err) { - return fmt.Errorf("failed to create deployment: %v", err) - } - - // Ensure the deployment size is the same as the spec - err = sdk.Get(dep) - if err != nil { - return fmt.Errorf("failed to get deployment: %v", err) - } - size := memcached.Spec.Size - if *dep.Spec.Replicas != size { - dep.Spec.Replicas = &size - err = sdk.Update(dep) - if err != nil { - return fmt.Errorf("failed to update deployment: %v", err) - } - } - - // Update the Memcached status with the pod names - podList := podList() - labelSelector := labels.SelectorFromSet(labelsForMemcached(memcached.Name)).String() - listOps := &metav1.ListOptions{LabelSelector: labelSelector} - err = sdk.List(memcached.Namespace, podList, sdk.WithListOptions(listOps)) - if err != nil { - return fmt.Errorf("failed to list pods: %v", err) - } - podNames := getPodNames(podList.Items) - if !reflect.DeepEqual(podNames, memcached.Status.Nodes) { - memcached.Status.Nodes = podNames - err := sdk.Update(memcached) - if err != nil { - return fmt.Errorf("failed to update memcached status: %v", err) - } - } - } - return nil -} - -// deploymentForMemcached returns a memcached Deployment object -func deploymentForMemcached(m *v1alpha1.Memcached) *appsv1.Deployment { - ls := labelsForMemcached(m.Name) - replicas := m.Spec.Size - - dep := &appsv1.Deployment{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "apps/v1", - Kind: "Deployment", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: m.Name, - Namespace: m.Namespace, - }, - Spec: appsv1.DeploymentSpec{ - Replicas: &replicas, - Selector: &metav1.LabelSelector{ - MatchLabels: ls, - }, - Template: v1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: ls, - }, - Spec: v1.PodSpec{ - Containers: []v1.Container{{ - Image: "memcached:1.4.36-alpine", - Name: "memcached", - Command: []string{"memcached", "-m=64", "-o", "modern", "-v"}, - Ports: []v1.ContainerPort{{ - ContainerPort: 11211, - Name: "memcached", - }}, - }}, - }, - }, - }, - } - addOwnerRefToObject(dep, asOwner(m)) - return dep -} - -// labelsForMemcached returns the labels for selecting the resources -// belonging to the given memcached CR name. -func labelsForMemcached(name string) map[string]string { - return map[string]string{"app": "memcached", "memcached_cr": name} -} - -// addOwnerRefToObject appends the desired OwnerReference to the object -func addOwnerRefToObject(obj metav1.Object, ownerRef metav1.OwnerReference) { - obj.SetOwnerReferences(append(obj.GetOwnerReferences(), ownerRef)) -} - -// asOwner returns an OwnerReference set as the memcached CR -func asOwner(m *v1alpha1.Memcached) metav1.OwnerReference { - trueVar := true - return metav1.OwnerReference{ - APIVersion: m.APIVersion, - Kind: m.Kind, - Name: m.Name, - UID: m.UID, - Controller: &trueVar, - } -} - -// podList returns a v1.PodList object -func podList() *v1.PodList { - return &v1.PodList{ - TypeMeta: metav1.TypeMeta{ - Kind: "Pod", - APIVersion: "v1", - }, - } -} - -// getPodNames returns the pod names of the array of pods passed in -func getPodNames(pods []v1.Pod) []string { - var podNames []string - for _, pod := range pods { - podNames = append(podNames, pod.Name) - } - return podNames -} From 8f445834ca92cf918bcd7a0d538bc3dd563e1834 Mon Sep 17 00:00:00 2001 From: Eric Stroczynski Date: Thu, 1 Nov 2018 16:56:10 -0700 Subject: [PATCH 2/6] cosmetic changes --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 7788c68..cc06f7a 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,7 @@ The [Operator Framework][org_operator_framework] ([intro blog post][site_blog_po This guide shows how to build a simple [memcached][site_memcached] operator and how to manage its lifecycle from install to update to a new version. For that, we will use two center pieces of the framework: * **Operator SDK**: Allows your developers to build an operator based on your expertise without requiring knowledge of Kubernetes API complexities. -* **o Lifecycle Manager**: Helps you to install, update, and generally manage the lifecycle of all of the operators (and their associated services) running across your clusters. - -> **Requirements**: Please make sure that the [Operator SDK][operator_sdk] is installed on the development machine. Additionally, the [Operator Lifecycle Manager][operator_lifecycle_manager] must be installed in the cluster (1.8 or above to support the apps/v1beta2 API group) before running this guide. +* **Lifecycle Manager**: Helps you to install, update, and generally manage the lifecycle of all of the operators (and their associated services) running across your clusters. ## Build an operator using the Operator SDK @@ -15,12 +13,13 @@ The Operator SDK makes it easier to build Kubernetes native applications, a proc This section walks through an example of building a simple memcached operator using tools and libraries provided by the Operator SDK. This walkthrough is not exhaustive; for an in-depth explanation of these steps, see the SDK's [user guide][doc_sdk_user_guide]. -### Create a new project +**Requirements**: Please make sure that the Operator SDK is [installed][doc_sdk_install_instr] on the development machine. Additionally, the Operator Lifecycle Manager must be [installed][doc_olm_install_instr] in the cluster (1.8 or above to support the apps/v1beta2 API group) before running this guide. -If you do not have the SDK installed, see the [installation instructions][doc_sdk_install_instr]. +### Create a new project Use the CLI to create a new `memcached-operator` project: + ```sh $ mkdir -p $GOPATH/src/github.com/example-inc/ $ cd $GOPATH/src/github.com/example-inc/ @@ -393,13 +392,14 @@ Hopefully, this guide was an effective demonstration of the value of the Operato [site_memcached]: https://memcached.org/ [doc_sdk_user_guide]: https://github.com/operator-framework/operator-sdk/blob/master/doc/user-guide.md [doc_sdk_install_instr]: https://github.com/operator-framework/operator-sdk/blob/master/doc/user-guide.md#install-the-operator-sdk-cli +[doc_olm_install_instr]: https://github.com/operator-framework/operator-lifecycle-manager/blob/master/Documentation/install/install.md [layout_doc]: https://github.com/operator-framework/operator-sdk/blob/master/doc/project_layout.md [manager_go_doc]: https://godoc.org/github.com/kubernetes-sigs/controller-runtime/pkg/manager#Manager [controller_go_doc]: https://godoc.org/github.com/kubernetes-sigs/controller-runtime/pkg#hdr-Controller [request_go_doc]: https://godoc.org/github.com/kubernetes-sigs/controller-runtime/pkg/reconcile#Request [result_go_doc]: https://godoc.org/github.com/kubernetes-sigs/controller-runtime/pkg/reconcile#Result [doc_client_api]: https://github.com/operator-framework/operator-sdk/blob/master/doc/user/client.md -[repo_sdk_samples_memcached]: https://github.com/operator-framework/operator-sdk-samples/memcached-operator/ +[repo_sdk_samples_memcached]: https://github.com/operator-framework/operator-sdk-samples/tree/master/memcached-operator/ [manifest_v1]: memcachedoperator.0.0.1.csv.yaml [manifest_v2]: memcachedoperator.0.0.2.csv.yaml [mailing_list]: https://groups.google.com/forum/#!forum/operator-framework From 3d1df7a54442920a009429cd9a592a8dc41b0408 Mon Sep 17 00:00:00 2001 From: Alexander Pavel Date: Mon, 5 Nov 2018 15:17:05 -0800 Subject: [PATCH 3/6] Update README.md Co-Authored-By: estroz --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cc06f7a..76108dd 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Getting Started -The [Operator Framework][org_operator_framework] ([intro blog post][site_blog_post]) is an open source toolkit to manage Kubernetes native applications, called operators, in an effective, automated, and scalable way. operators take advantage of Kubernetes's extensibility to deliver the automation advantages of cloud services like provisioning, scaling, and backup/restore while being able to run anywhere that Kubernetes can run. +The [Operator Framework][org_operator_framework] ([intro blog post][site_blog_post]) is an open source toolkit to manage Kubernetes native applications, called operators, in an effective, automated, and scalable way. Operators take advantage of Kubernetes's extensibility to deliver the automation advantages of cloud services like provisioning, scaling, and backup/restore while being able to run anywhere that Kubernetes can run. This guide shows how to build a simple [memcached][site_memcached] operator and how to manage its lifecycle from install to update to a new version. For that, we will use two center pieces of the framework: From 30bea8a461fa77abd81371ad636c69723910e8a4 Mon Sep 17 00:00:00 2001 From: Alexander Pavel Date: Mon, 5 Nov 2018 15:17:16 -0800 Subject: [PATCH 4/6] Update README.md Co-Authored-By: estroz --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 76108dd..ad9f632 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ Learn more about the project directory structure from the SDK [project layout][l #### Define the Memcached spec and status -Modify the spec and status of the `Memcached` Custom Resource(CR) at `pkg/apis/cache/v1alpha1/memcached_types.go`: +Modify the spec and status of the `Memcached` Custom Resource (CR) at `pkg/apis/cache/v1alpha1/memcached_types.go`: ```Go type MemcachedSpec struct { From a9384a371179680d663ba8d3146d53260efad134 Mon Sep 17 00:00:00 2001 From: Eric Stroczynski Date: Mon, 5 Nov 2018 15:21:11 -0800 Subject: [PATCH 5/6] note on sed usage --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index ad9f632..242d7ef 100644 --- a/README.md +++ b/README.md @@ -167,6 +167,8 @@ Build the memcached-operator image and push it to a registry: ```sh $ operator-sdk build quay.io/example/memcached-operator:v0.0.1 $ sed -i 's|REPLACE_IMAGE|quay.io/example/memcached-operator:v0.0.1|g' deploy/operator.yaml +# On OSX use: +$ sed -i "" 's|REPLACE_IMAGE|quay.io/example/memcached-operator:v0.0.1|g' deploy/operator.yaml $ docker push quay.io/example/memcached-operator:v0.0.1 ``` From 02d9a4803d8f84dc7e2f46fa82cabbdaa850074a Mon Sep 17 00:00:00 2001 From: Eric Stroczynski Date: Mon, 5 Nov 2018 16:33:42 -0800 Subject: [PATCH 6/6] add link --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 242d7ef..9398688 100644 --- a/README.md +++ b/README.md @@ -398,6 +398,7 @@ Hopefully, this guide was an effective demonstration of the value of the Operato [layout_doc]: https://github.com/operator-framework/operator-sdk/blob/master/doc/project_layout.md [manager_go_doc]: https://godoc.org/github.com/kubernetes-sigs/controller-runtime/pkg/manager#Manager [controller_go_doc]: https://godoc.org/github.com/kubernetes-sigs/controller-runtime/pkg#hdr-Controller +[memcached_controller]: https://github.com/operator-framework/operator-sdk/blob/master/example/memcached-operator/memcached_controller.go.tmpl [request_go_doc]: https://godoc.org/github.com/kubernetes-sigs/controller-runtime/pkg/reconcile#Request [result_go_doc]: https://godoc.org/github.com/kubernetes-sigs/controller-runtime/pkg/reconcile#Result [doc_client_api]: https://github.com/operator-framework/operator-sdk/blob/master/doc/user/client.md