github.skymusic.top/operator-framework/operator-sdk@v0.8.2/doc/ansible/user-guide.md (about)

     1  # User Guide
     2  
     3  This guide walks through an example of building a simple memcached-operator powered by Ansible using tools and libraries provided by the Operator SDK.
     4  
     5  ## Prerequisites
     6  
     7  - [git][git_tool]
     8  - [docker][docker_tool] version 17.03+.
     9  - [kubectl][kubectl_tool] version v1.9.0+.
    10  - [ansible][ansible_tool] version v2.6.0+
    11  - [ansible-runner][ansible_runner_tool] version v1.1.0+
    12  - [ansible-runner-http][ansible_runner_http_plugin] version v1.0.0+
    13  - [dep][dep_tool] version v0.5.0+. (Optional if you aren't installing from source)
    14  - [go][go_tool] version v1.12+. (Optional if you aren't installing from source)
    15  - Access to a Kubernetes v.1.9.0+ cluster.
    16  
    17  **Note**: This guide uses [minikube][minikube_tool] version v0.25.0+ as the
    18  local Kubernetes cluster and [quay.io][quay_link] for the public registry.
    19  
    20  ## Install the Operator SDK CLI
    21  
    22  Follow the steps in the [installation guide][install_guide] to learn how to install the Operator SDK CLI tool.
    23  
    24  ## Create a new project
    25  
    26  Use the CLI to create a new Ansible-based memcached-operator project:
    27  
    28  ```sh
    29  $ operator-sdk new memcached-operator --api-version=cache.example.com/v1alpha1 --kind=Memcached --type=ansible
    30  $ cd memcached-operator
    31  ```
    32  
    33  This creates the memcached-operator project specifically for watching the
    34  Memcached resource with APIVersion `cache.example.com/v1apha1` and Kind
    35  `Memcached`.
    36  
    37  To learn more about the project directory structure, see [project
    38  layout][layout_doc] doc.
    39  
    40  #### Operator scope
    41  
    42  Read the [operator scope][operator_scope] documentation on how to run your operator as namespace-scoped vs cluster-scoped.
    43  
    44  ### Watches file
    45  
    46  The Watches file contains a list of mappings from custom resources, identified
    47  by it's Group, Version, and Kind, to an Ansible Role or Playbook. The Operator
    48  expects this mapping file in a predefined location: `/opt/ansible/watches.yaml`
    49  
    50  * **group**:  The group of the Custom Resource that you will be watching.
    51  * **version**:  The version of the Custom Resource that you will be watching.
    52  * **kind**:  The kind of the Custom Resource that you will be watching.
    53  * **role** (default):  This is the path to the role that you have added to the
    54    container.  For example if your roles directory is at `/opt/ansible/roles/`
    55    and your role is named `busybox`, this value will be
    56    `/opt/ansible/roles/busybox`. This field is mutually exclusive with the
    57    "playbook" field.
    58  * **playbook**:  This is the path to the playbook that you have added to the
    59    container. This playbook is expected to be simply a way to call roles. This
    60    field is mutually exclusive with the "role" field.
    61  * **reconcilePeriod** (optional): The reconciliation interval, how often the
    62    role/playbook is run, for a given CR.
    63  * **manageStatus** (optional): When true (default), the operator will manage
    64    the status of the CR generically. Set to false, the status of the CR is
    65    managed elsewhere, by the specified role/playbook or in a separate controller.
    66  
    67  An example Watches file:
    68  
    69  ```yaml
    70  ---
    71  # Simple example mapping Foo to the Foo role
    72  - version: v1alpha1
    73    group: foo.example.com
    74    kind: Foo
    75    role: /opt/ansible/roles/Foo
    76  
    77  # Simple example mapping Bar to a playbook
    78  - version: v1alpha1
    79    group: bar.example.com
    80    kind: Bar
    81    playbook: /opt/ansible/playbook.yml
    82  
    83  # More complex example for our Baz kind
    84  # Here we will disable requeuing and be managing the CR status in the playbook
    85  - version: v1alpha1
    86    group: baz.example.com
    87    kind: Baz
    88    playbook: /opt/ansible/baz.yml
    89    reconcilePeriod: 0
    90    manageStatus: false
    91  ```
    92  
    93  ## Customize the operator logic
    94  
    95  For this example the memcached-operator will execute the following
    96  reconciliation logic for each `Memcached` Custom Resource (CR):
    97  - Create a memcached Deployment if it doesn't exist
    98  - Ensure that the Deployment size is the same as specified by the `Memcached`
    99  CR
   100  
   101  ### Watch the Memcached CR
   102  
   103  By default, the memcached-operator watches `Memcached` resource events as shown
   104  in `watches.yaml` and executes Ansible Role `Memcached`:
   105  
   106  ```yaml
   107  ---
   108  - version: v1alpha1
   109    group: cache.example.com
   110    kind: Memcached
   111  ```
   112  
   113  #### Options
   114  **Role**
   115  Specifying a `role` option in `watches.yaml` will configure the operator to use
   116  this specified path when launching `ansible-runner` with an Ansible Role. By
   117  default, the `new` command will fill in an absolute path to where your role
   118  should go.
   119  ```yaml
   120  ---
   121  - version: v1alpha1
   122    group: cache.example.com
   123    kind: Memcached
   124    role: /opt/ansible/roles/memcached
   125  ```
   126  
   127  **Playbook**
   128  Specifying a `playbook` option in `watches.yaml` will configure the operator to
   129  use this specified path when launching `ansible-runner` with an Ansible
   130  Playbook
   131  ```yaml
   132  ---
   133  - version: v1alpha1
   134    group: cache.example.com
   135    kind: Memcached
   136    playbook: /opt/ansible/playbook.yaml
   137  ```
   138  
   139  ## Building the Memcached Ansible Role
   140  
   141  The first thing to do is to modify the generated Ansible role under
   142  `roles/memcached`. This Ansible Role controls the logic that is executed when a
   143  resource is modified.
   144  
   145  ### Define the Memcached spec
   146  
   147  Defining the spec for an Ansible Operator can be done entirely in Ansible. The
   148  Ansible Operator will simply pass all key value pairs listed in the Custom
   149  Resource spec field along to Ansible as
   150  [variables](https://docs.ansible.com/ansible/2.5/user_guide/playbooks_variables.html#passing-variables-on-the-command-line).
   151  The names of all variables in the spec field are converted to snake_case
   152  by the operator before running ansible. For example, `serviceAccount` in
   153  the spec becomes `service_account` in ansible.
   154  It is recommended that you perform some type validation in Ansible on the
   155  variables to ensure that your application is receiving expected input.
   156  
   157  First, set a default in case the user doesn't set the `spec` field by modifying
   158  `roles/memcached/defaults/main.yml`:
   159  ```yaml
   160  size: 1
   161  ```
   162  
   163  ### Defining the Memcached deployment
   164  
   165  Now that we have the spec defined, we can define what Ansible is actually
   166  executed on resource changes. Since this is an Ansible Role, the default
   167  behavior will be to execute the tasks in `roles/memcached/tasks/main.yml`. We
   168  want Ansible to create a deployment if it does not exist which runs the
   169  `memcached:1.4.36-alpine` image. Ansible 2.5+ supports the [k8s Ansible
   170  Module](https://docs.ansible.com/ansible/2.6/modules/k8s_module.html) which we
   171  will leverage to control the deployment definition.
   172  
   173  Modify `roles/memcached/tasks/main.yml` to look like the following:
   174  ```yaml
   175  ---
   176  - name: start memcached
   177    k8s:
   178      definition:
   179        kind: Deployment
   180        apiVersion: apps/v1
   181        metadata:
   182          name: '{{ meta.name }}-memcached'
   183          namespace: '{{ meta.namespace }}'
   184        spec:
   185          replicas: "{{size}}"
   186          selector:
   187            matchLabels:
   188              app: memcached
   189          template:
   190            metadata:
   191              labels:
   192                app: memcached
   193            spec:
   194              containers:
   195              - name: memcached
   196                command:
   197                - memcached
   198                - -m=64
   199                - -o
   200                - modern
   201                - -v
   202                image: "docker.io/memcached:1.4.36-alpine"
   203                ports:
   204                  - containerPort: 11211
   205  
   206  ```
   207  
   208  It is important to note that we used the `size` variable to control how many
   209  replicas of the Memcached deployment we want. We set the default to `1`, but
   210  any user can create a Custom Resource that overwrites the default.
   211  
   212  ### Build and run the operator
   213  
   214  Before running the operator, Kubernetes needs to know about the new custom
   215  resource definition the operator will be watching.
   216  
   217  Deploy the CRD:
   218  
   219  ```sh
   220  $ kubectl create -f deploy/crds/cache_v1alpha1_memcached_crd.yaml
   221  ```
   222  
   223  Once this is done, there are two ways to run the operator:
   224  
   225  - As a pod inside a Kubernetes cluster
   226  - As a go program outside the cluster using `operator-sdk`
   227  
   228  #### 1. Run as a pod inside a Kubernetes cluster
   229  
   230  Running as a pod inside a Kubernetes cluster is preferred for production use.
   231  
   232  Build the memcached-operator image and push it to a registry:
   233  ```
   234  $ operator-sdk build quay.io/example/memcached-operator:v0.0.1
   235  $ docker push quay.io/example/memcached-operator:v0.0.1
   236  ```
   237  
   238  Kubernetes deployment manifests are generated in `deploy/operator.yaml`. The
   239  deployment image in this file needs to be modified from the placeholder
   240  `REPLACE_IMAGE` to the previous built image. To do this run:
   241  ```
   242  $ sed -i 's|{{ REPLACE_IMAGE }}|quay.io/example/memcached-operator:v0.0.1|g' deploy/operator.yaml
   243  ```
   244  
   245  The `imagePullPolicy` also requires an update.  To do this run:
   246  ```
   247  $ sed -i 's|{{ pull_policy\|default('\''Always'\'') }}|Always|g' deploy/operator.yaml
   248  ```
   249  
   250  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.
   251  ```
   252  $ export OPERATOR_NAMESPACE=$(kubectl config view --minify -o jsonpath='{.contexts[0].context.namespace}')
   253  $ sed -i "s|REPLACE_NAMESPACE|$OPERATOR_NAMESPACE|g" deploy/role_binding.yaml
   254  ```
   255  
   256  **Note**
   257  If you are performing these steps on OSX, use the following commands instead:
   258  ```
   259  $ sed -i "" 's|{{ REPLACE_IMAGE }}|quay.io/example/memcached-operator:v0.0.1|g' deploy/operator.yaml
   260  $ sed -i "" "s|REPLACE_NAMESPACE|$OPERATOR_NAMESPACE|g" deploy/role_binding.yaml
   261  $ sed -i "" 's|{{ pull_policy\|default('\''Always'\'') }}|Always|g' deploy/operator.yaml
   262  ```
   263  
   264  Deploy the memcached-operator:
   265  
   266  ```sh
   267  $ kubectl create -f deploy/service_account.yaml
   268  $ kubectl create -f deploy/role.yaml
   269  $ kubectl create -f deploy/role_binding.yaml
   270  $ kubectl create -f deploy/operator.yaml
   271  ```
   272  
   273  Verify that the memcached-operator is up and running:
   274  
   275  ```sh
   276  $ kubectl get deployment
   277  NAME                     DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
   278  memcached-operator       1         1         1            1           1m
   279  ```
   280  
   281  #### 2. Run outside the cluster
   282  
   283  This method is preferred during the development cycle to speed up deployment and testing.
   284  
   285  **Note**: Ensure that [Ansible Runner][ansible_runner_tool] and [Ansible Runner
   286  HTTP Plugin][ansible_runner_http_plugin] is installed or else you will see
   287  unexpected errors from Ansible Runner when a Custom Resource is created.
   288  
   289  It is also important that the `role` path referenced in `watches.yaml` exists
   290  on your machine. Since we are normally used to using a container where the Role
   291  is put on disk for us, we need to manually copy our role to the configured
   292  Ansible Roles path (e.g `/etc/ansible/roles`.
   293  
   294  Run the operator locally with the default Kubernetes config file present at
   295  `$HOME/.kube/config`:
   296  
   297  ```sh
   298  $ operator-sdk up local
   299  INFO[0000] Go Version: go1.10
   300  INFO[0000] Go OS/Arch: darwin/amd64
   301  INFO[0000] operator-sdk Version: 0.0.5+git
   302  ```
   303  
   304  Run the operator locally with a provided Kubernetes config file:
   305  
   306  ```sh
   307  $ operator-sdk up local --kubeconfig=config
   308  INFO[0000] Go Version: go1.10
   309  INFO[0000] Go OS/Arch: darwin/amd64
   310  INFO[0000] operator-sdk Version: 0.0.5+git
   311  ```
   312  
   313  ### Create a Memcached CR
   314  
   315  Modify `deploy/crds/cache_v1alpha1_memcached_cr.yaml` as shown and create a `Memcached` custom resource:
   316  
   317  ```sh
   318  $ cat deploy/crds/cache_v1alpha1_memcached_cr.yaml
   319  apiVersion: "cache.example.com/v1alpha1"
   320  kind: "Memcached"
   321  metadata:
   322    name: "example-memcached"
   323  spec:
   324    size: 3
   325  
   326  $ kubectl apply -f deploy/crds/cache_v1alpha1_memcached_cr.yaml
   327  ```
   328  
   329  Ensure that the memcached-operator creates the deployment for the CR:
   330  
   331  ```sh
   332  $ kubectl get deployment
   333  NAME                     DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
   334  memcached-operator       1         1         1            1           2m
   335  example-memcached        3         3         3            3           1m
   336  ```
   337  
   338  Check the pods to confirm 3 replicas were created:
   339  
   340  ```sh
   341  $ kubectl get pods
   342  NAME                                  READY     STATUS    RESTARTS   AGE
   343  example-memcached-6fd7c98d8-7dqdr     1/1       Running   0          1m
   344  example-memcached-6fd7c98d8-g5k7v     1/1       Running   0          1m
   345  example-memcached-6fd7c98d8-m7vn7     1/1       Running   0          1m
   346  memcached-operator-7cc7cfdf86-vvjqk   2/2       Running   0          2m
   347  ```
   348  
   349  ### View the Ansible logs
   350  
   351  The `memcached-operator` deployment creates a Pod with two containers, `operator` and `ansible`.
   352  The `ansible` container exists only to expose the standard Ansible stdout logs that most Ansible
   353  users will be familiar with. In order to see the logs from a particular container, you can run
   354  
   355  ```sh
   356  kubectl logs deployment/memcached-operator -c ansible
   357  kubectl logs deployment/memcached-operator -c operator
   358  ```
   359  
   360  The `ansible` logs contain all of the information about the Ansible run and will make it much easier to debug issues within your Ansible tasks,
   361  whereas the `operator` logs will contain much more detailed information about the Ansible Operator's internals and interface with Kubernetes.
   362  
   363  ### Additional Ansible debug
   364  
   365  Occasionally while developing additional debug in the Operator logs is nice to have. To enable Ansible debug output, ie `-vvvv`.
   366  Add the following to the `operator.yaml` manifest.
   367  
   368  ```yaml
   369            env:
   370             ...
   371             - name: ANSIBLE_VERBOSITY
   372               value: "4"
   373  ```
   374  
   375  ### Update the size
   376  
   377  Change the `spec.size` field in the memcached CR from 3 to 4 and apply the
   378  change:
   379  
   380  ```sh
   381  $ cat deploy/crds/cache_v1alpha1_memcached_cr.yaml
   382  apiVersion: "cache.example.com/v1alpha1"
   383  kind: "Memcached"
   384  metadata:
   385    name: "example-memcached"
   386  spec:
   387    size: 4
   388  
   389  $ kubectl apply -f deploy/crds/cache_v1alpha1_memcached_cr.yaml
   390  ```
   391  
   392  Confirm that the operator changes the deployment size:
   393  
   394  ```sh
   395  $ kubectl get deployment
   396  NAME                 DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
   397  example-memcached    4         4         4            4           5m
   398  ```
   399  
   400  ### Cleanup
   401  
   402  Clean up the resources:
   403  
   404  ```sh
   405  $ kubectl delete -f deploy/crds/cache_v1alpha1_memcached_cr.yaml
   406  $ kubectl delete -f deploy/operator.yaml
   407  $ kubectl delete -f deploy/role_binding.yaml
   408  $ kubectl delete -f deploy/role.yaml
   409  $ kubectl delete -f deploy/service_account.yaml
   410  $ kubectl delete -f deploy/crds/cache_v1alpha1_memcached_crd.yaml
   411  ```
   412  
   413  [operator_scope]:./../operator-scope.md
   414  [install_guide]: ../user/install-operator-sdk.md
   415  [layout_doc]:./project_layout.md
   416  [homebrew_tool]:https://brew.sh/
   417  [dep_tool]:https://golang.github.io/dep/docs/installation.html
   418  [git_tool]:https://git-scm.com/downloads
   419  [go_tool]:https://golang.org/dl/
   420  [docker_tool]:https://docs.docker.com/install/
   421  [kubectl_tool]:https://kubernetes.io/docs/tasks/tools/install-kubectl/
   422  [minikube_tool]:https://github.com/kubernetes/minikube#installation
   423  [ansible_tool]:https://docs.ansible.com/ansible/latest/index.html
   424  [ansible_runner_tool]:https://ansible-runner.readthedocs.io/en/latest/install.html
   425  [ansible_runner_http_plugin]:https://github.com/ansible/ansible-runner-http
   426  [quay_link]:https://quay.io