github.com/mkimuram/operator-sdk@v0.7.1-0.20190410172100-52ad33a4bda0/doc/helm/user-guide.md (about)

     1  # User Guide
     2  
     3  This guide walks through an example of building a simple nginx-operator
     4  powered by Helm using tools and libraries provided by the Operator SDK.
     5  
     6  ## Prerequisites
     7  
     8  - [git][git_tool]
     9  - [docker][docker_tool] version 17.03+.
    10  - [kubectl][kubectl_tool] version v1.11.3+.
    11  - [dep][dep_tool] version v0.5.0+. (Optional if you aren't installing from source)
    12  - [go][go_tool] version v1.10+. (Optional if you aren't installing from source)
    13  - Access to a Kubernetes v.1.11.3+ cluster.
    14  
    15  **Note**: This guide uses [minikube][minikube_tool] version v0.25.0+ as the
    16  local Kubernetes cluster and [quay.io][quay_link] for the public registry.
    17  
    18  ## Install the Operator SDK CLI
    19  
    20  The Operator SDK has a CLI tool that helps the developer to create, build, and
    21  deploy a new operator project.
    22  
    23  Checkout the desired release tag and install the SDK CLI tool:
    24  
    25  ```sh
    26  mkdir -p $GOPATH/src/github.com/operator-framework
    27  cd $GOPATH/src/github.com/operator-framework
    28  git clone https://github.com/operator-framework/operator-sdk
    29  cd operator-sdk
    30  git checkout master
    31  make dep
    32  make install
    33  ```
    34  
    35  This installs the CLI binary `operator-sdk` at `$GOPATH/bin`.
    36  
    37  Alternatively, if you are using [Homebrew][homebrew_tool], you can install the SDK CLI tool with the following command:
    38  
    39  ```sh
    40  $ brew install operator-sdk
    41  ```
    42  
    43  ## Create a new project
    44  
    45  Use the CLI to create a new Helm-based nginx-operator project:
    46  
    47  ```sh
    48  operator-sdk new nginx-operator --api-version=example.com/v1alpha1 --kind=Nginx --type=helm
    49  cd nginx-operator
    50  ```
    51  
    52  This creates the nginx-operator project specifically for watching the
    53  Nginx resource with APIVersion `example.com/v1alpha1` and Kind
    54  `Nginx`.
    55  
    56  To learn more about the project directory structure, see the
    57  [project layout][layout_doc] doc.
    58  
    59  ### Use an existing chart
    60  
    61  Instead of creating your project with a boilerplate Helm chart, you can also use `--helm-chart`, `--helm-chart-repo`, and `--helm-chart-version` to use an existing chart, either from your local filesystem or a remote chart repository.
    62  
    63  If `--helm-chart` is specified, `--api-version` and `--kind` become optional. If left unset, the SDK will default `--api-version` to `charts.helm.k8s.io/v1alpha1` and will deduce `--kind` from the specified chart.
    64  
    65  If `--helm-chart` is a local chart archive or directory, it will be validated and unpacked or copied into the project.
    66  
    67  Otherwise, the SDK will attempt to fetch the specified helm chart from a remote repository.
    68  
    69  If a custom repository URL is not specified by `--helm-chart-repo`, the following chart reference formats are supported:
    70  
    71  - `<repoName>/<chartName>`: Fetch the helm chart named `chartName` from the helm
    72                              chart repository named `repoName`, as specified in the
    73                              $HELM_HOME/repositories/repositories.yaml file.
    74  
    75  - `<url>`: Fetch the helm chart archive at the specified URL.
    76  
    77  If a custom repository URL is specified by `--helm-chart-repo`, the only supported format for `--helm-chart` is:
    78  
    79  - `<chartName>`: Fetch the helm chart named `chartName` in the helm chart repository
    80                   specified by the `--helm-chart-repo` URL.
    81  
    82  If `--helm-chart-version` is not set, the SDK will fetch the latest available version of the helm chart. Otherwise, it will fetch the specified version. `--helm-chart-version` is not used when `--helm-chart` itself refers to a specific version, for example when it is a local path or a URL.
    83  
    84  ### Operator scope
    85  
    86  A namespace-scoped operator (the default) watches and manages resources in a single namespace, whereas a cluster-scoped operator watches and manages resources cluster-wide. Namespace-scoped operators are preferred because of their flexibility. They enable decoupled upgrades, namespace isolation for failures and monitoring, and differing API definitions. However, there are use cases where a cluster-scoped operator may make sense. For example, the [cert-manager](https://github.com/jetstack/cert-manager) operator is often deployed with cluster-scoped permissions and watches so that it can manage issuing certificates for an entire cluster.
    87  
    88  If you'd like to create your nginx-operator project to be cluster-scoped use the following `operator-sdk new` command instead:
    89  
    90  ```sh
    91  operator-sdk new nginx-operator --cluster-scoped --api-version=example.com/v1alpha1 --kind=Nginx --type=helm
    92  ```
    93  
    94  Using `--cluster-scoped` will scaffold the new operator with the following modifications:
    95  * `deploy/operator.yaml` - Set `WATCH_NAMESPACE=""` instead of setting it to the pod's namespace
    96  * `deploy/role.yaml` - Use `ClusterRole` instead of `Role`
    97  * `deploy/role_binding.yaml`:
    98    * Use `ClusterRoleBinding` instead of `RoleBinding`
    99    * Use `ClusterRole` instead of `Role` for roleRef
   100    * Set the subject namespace to `REPLACE_NAMESPACE`. This must be changed to the namespace in which the operator is deployed.
   101  
   102  ## Customize the operator logic
   103  
   104  For this example the nginx-operator will execute the following
   105  reconciliation logic for each `Nginx` Custom Resource (CR):
   106  
   107  - Create a nginx Deployment if it doesn't exist
   108  - Create a nginx Service if it doesn't exist
   109  - Create a nginx Ingress if it is enabled and doesn't exist
   110  - Ensure that the Deployment, Service, and optional Ingress match the desired configuration (e.g. replica count, image, service type, etc) as specified by the `Nginx` CR
   111  
   112  ### Watch the Nginx CR
   113  
   114  By default, the nginx-operator watches `Nginx` resource events as shown
   115  in `watches.yaml` and executes Helm releases using the specified chart:
   116  
   117  ```yaml
   118  ---
   119  - version: v1alpha1
   120    group: example.com
   121    kind: Nginx
   122    chart: /opt/helm/helm-charts/nginx
   123  ```
   124  
   125  ### Reviewing the Nginx Helm Chart
   126  
   127  When a Helm operator project is created, the SDK creates an example Helm chart
   128  that contains a set of templates for a simple Nginx release.
   129  
   130  For this example, we have templates for deployment, service, and ingress
   131  resources, along with a NOTES.txt template, which Helm chart developers use
   132  to convey helpful information about a release.
   133  
   134  If you aren't already familiar with Helm Charts, take a moment to review
   135  the [Helm Chart developer documentation][helm_charts].
   136  
   137  ### Understanding the Nginx CR spec
   138  
   139  Helm uses a concept called [values][helm_values] to provide customizations
   140  to a Helm chart's defaults, which are defined in the Helm chart's `values.yaml`
   141  file.
   142  
   143  Overriding these defaults is as simple as setting the desired values in the CR
   144  spec. Let's use the number of replicas as an example.
   145  
   146  First, inspecting `helm-charts/nginx/values.yaml`, we see that the chart has a
   147  value called `replicaCount` and it is set to `1` by default. If we want to have
   148  2 nginx instances in our deployment, we would need to make sure our CR spec
   149  contained `replicaCount: 2`.
   150  
   151  Update `deploy/crds/example_v1alpha1_nginx_cr.yaml` to look like the following:
   152  
   153  ```yaml
   154  apiVersion: example.com/v1alpha1
   155  kind: Nginx
   156  metadata:
   157    name: example-nginx
   158  spec:
   159    replicaCount: 2
   160  ```
   161  
   162  Similarly, we see that the default service port is set to `80`, but we would
   163  like to use `8080`, so we'll again update `deploy/crds/example_v1alpha1_nginx_cr.yaml`
   164  by adding the service port override:
   165  
   166  ```yaml
   167  apiVersion: example.com/v1alpha1
   168  kind: Nginx
   169  metadata:
   170    name: example-nginx
   171  spec:
   172    replicaCount: 2
   173    service:
   174      port: 8080
   175  ```
   176  
   177  As you may have noticed, the Helm operator simply applies the entire spec as if
   178  it was the contents of a values file, just like `helm install -f ./overrides.yaml`
   179  works.
   180  
   181  ## Build and run the operator
   182  
   183  Before running the operator, Kubernetes needs to know about the new custom
   184  resource definition the operator will be watching.
   185  
   186  Deploy the CRD:
   187  
   188  ```sh
   189  kubectl create -f deploy/crds/example_v1alpha1_nginx_crd.yaml
   190  ```
   191  
   192  Once this is done, there are two ways to run the operator:
   193  
   194  - As a pod inside a Kubernetes cluster
   195  - As a go program outside the cluster using `operator-sdk`
   196  
   197  ### 1. Run as a pod inside a Kubernetes cluster
   198  
   199  Running as a pod inside a Kubernetes cluster is preferred for production use.
   200  
   201  Build the nginx-operator image and push it to a registry:
   202  
   203  ```sh
   204  operator-sdk build quay.io/example/nginx-operator:v0.0.1
   205  docker push quay.io/example/nginx-operator:v0.0.1
   206  ```
   207  
   208  Kubernetes deployment manifests are generated in `deploy/operator.yaml`. The
   209  deployment image in this file needs to be modified from the placeholder
   210  `REPLACE_IMAGE` to the previous built image. To do this run:
   211  
   212  ```sh
   213  sed -i 's|REPLACE_IMAGE|quay.io/example/nginx-operator:v0.0.1|g' deploy/operator.yaml
   214  ```
   215  
   216  If you created your operator using `--cluster-scoped=true`, update the service account namespace in the generated `ClusterRoleBinding` to match where you are deploying your operator.
   217  
   218  ```sh
   219  export OPERATOR_NAMESPACE=$(kubectl config view --minify -o jsonpath='{.contexts[0].context.namespace}')
   220  sed -i "s|REPLACE_NAMESPACE|$OPERATOR_NAMESPACE|g" deploy/role_binding.yaml
   221  ```
   222  
   223  **Note**  
   224  If you are performing these steps on OSX, use the following commands instead:
   225  
   226  ```sh
   227  sed -i "" 's|REPLACE_IMAGE|quay.io/example/nginx-operator:v0.0.1|g' deploy/operator.yaml
   228  sed -i "" "s|REPLACE_NAMESPACE|$OPERATOR_NAMESPACE|g" deploy/role_binding.yaml
   229  ```
   230  
   231  Deploy the nginx-operator:
   232  
   233  ```sh
   234  kubectl create -f deploy/service_account.yaml
   235  kubectl create -f deploy/role.yaml
   236  kubectl create -f deploy/role_binding.yaml
   237  kubectl create -f deploy/operator.yaml
   238  ```
   239  
   240  Verify that the nginx-operator is up and running:
   241  
   242  ```sh
   243  $ kubectl get deployment
   244  NAME                 DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
   245  nginx-operator       1         1         1            1           1m
   246  ```
   247  
   248  ### 2. Run outside the cluster
   249  
   250  This method is preferred during the development cycle to speed up deployment and testing.
   251  
   252  It is important that the `chart` path referenced in `watches.yaml` exists
   253  on your machine. By default, the `watches.yaml` file is scaffolded to work with
   254  an operator image built with `operator-sdk build`. When developing and
   255  testing your operator with `operator-sdk up local`, the SDK will look in your
   256  local filesystem for this path. The SDK team recommends creating a symlink at
   257  this location to point to your helm chart's path:
   258  
   259  ```sh
   260  sudo mkdir -p /opt/helm/helm-charts
   261  sudo ln -s $PWD/helm-charts/nginx /opt/helm/helm-charts/nginx
   262  ```
   263  
   264  Run the operator locally with the default Kubernetes config file present at
   265  `$HOME/.kube/config`:
   266  
   267  ```sh
   268  $ operator-sdk up local
   269  INFO[0000] Go Version: go1.10.3
   270  INFO[0000] Go OS/Arch: linux/amd64
   271  INFO[0000] operator-sdk Version: v0.1.1+git
   272  ```
   273  
   274  Run the operator locally with a provided Kubernetes config file:
   275  
   276  ```sh
   277  $ operator-sdk up local --kubeconfig=<path_to_config>
   278  INFO[0000] Go Version: go1.10.3
   279  INFO[0000] Go OS/Arch: linux/amd64
   280  INFO[0000] operator-sdk Version: v0.2.0+git
   281  ```
   282  
   283  ## Deploy the Nginx custom resource
   284  
   285  Apply the nginx CR that we modified earlier:
   286  
   287  ```sh
   288  kubectl apply -f deploy/crds/example_v1alpha1_nginx_cr.yaml
   289  ```
   290  
   291  Ensure that the nginx-operator creates the deployment for the CR:
   292  
   293  ```sh
   294  $ kubectl get deployment
   295  NAME                                           DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
   296  example-nginx-b9phnoz9spckcrua7ihrbkrt1        2         2         2            2           1m
   297  ```
   298  
   299  Check the pods to confirm 2 replicas were created:
   300  
   301  ```sh
   302  $ kubectl get pods
   303  NAME                                                      READY     STATUS    RESTARTS   AGE
   304  example-nginx-b9phnoz9spckcrua7ihrbkrt1-f8f9c875d-fjcr9   1/1       Running   0          1m
   305  example-nginx-b9phnoz9spckcrua7ihrbkrt1-f8f9c875d-ljbzl   1/1       Running   0          1m
   306  ```
   307  
   308  Check that the service port is set to `8080`:
   309  
   310  ```sh
   311  $ kubectl get service
   312  NAME                                      TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE
   313  example-nginx-b9phnoz9spckcrua7ihrbkrt1   ClusterIP   10.96.26.3   <none>        8080/TCP   1m
   314  ```
   315  
   316  ### Update the replicaCount and remove the port
   317  
   318  Change the `spec.replicaCount` field from 2 to 3, remove the `spec.service`
   319  field, and apply the change:
   320  
   321  ```sh
   322  $ cat deploy/crds/example_v1alpha1_nginx_cr.yaml
   323  apiVersion: "example.com/v1alpha1"
   324  kind: "Nginx"
   325  metadata:
   326    name: "example-nginx"
   327  spec:
   328    replicaCount: 3
   329  
   330  $ kubectl apply -f deploy/crds/example_v1alpha1_nginx_cr.yaml
   331  ```
   332  
   333  Confirm that the operator changes the deployment size:
   334  
   335  ```sh
   336  $ kubectl get deployment
   337  NAME                                           DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
   338  example-nginx-b9phnoz9spckcrua7ihrbkrt1        3         3         3            3           1m
   339  ```
   340  
   341  Check that the service port is set to the default (`80`):
   342  
   343  ```sh
   344  $ kubectl get service
   345  NAME                                      TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)  AGE
   346  example-nginx-b9phnoz9spckcrua7ihrbkrt1   ClusterIP   10.96.26.3   <none>        80/TCP   1m
   347  ```
   348  
   349  ### Cleanup
   350  
   351  Clean up the resources:
   352  
   353  ```sh
   354  kubectl delete -f deploy/crds/example_v1alpha1_nginx_cr.yaml
   355  kubectl delete -f deploy/operator.yaml
   356  kubectl delete -f deploy/role_binding.yaml
   357  kubectl delete -f deploy/role.yaml
   358  kubectl delete -f deploy/service_account.yaml
   359  kubectl delete -f deploy/crds/example_v1alpha1_nginx_crd.yaml
   360  ```
   361  
   362  [layout_doc]:./project_layout.md
   363  [homebrew_tool]:https://brew.sh/
   364  [dep_tool]:https://golang.github.io/dep/docs/installation.html
   365  [git_tool]:https://git-scm.com/downloads
   366  [go_tool]:https://golang.org/dl/
   367  [docker_tool]:https://docs.docker.com/install/
   368  [kubectl_tool]:https://kubernetes.io/docs/tasks/tools/install-kubectl/
   369  [minikube_tool]:https://github.com/kubernetes/minikube#installation
   370  [helm_charts]:https://helm.sh/docs/developing_charts/
   371  [helm_values]:https://helm.sh/docs/using_helm/#customizing-the-chart-before-installing
   372  [quay_link]:https://quay.io