Repository: jina-ai/serve
Pull request: docs: document behaviour when things go wrong and redo k8s howto
**ToDO**
- [x] document error handling behaviour. See here: https://docs-failures--jina-docs.netlify.app/fundamentals/flow/when-things-go-wrong/
- [x] polish k8s HowTo. See here: https://docs-failures--jina-docs.netlify.app/how-to/kubernetes/
- [x] @samsja edit the "expose flow" details

Problem statement:
Document error handling behaviour
Explain what happens when different kinds of error occur

Docs: explain error modelling and failures
Explain how (connection) errors are handled, locally, in docker and k8s, and how errors are reported to the user.
  Also explain that retrying in service mesh is potentially dangerous because we also retry.

**ToDo:**
- [x] error retry mechanism
  - [x] in-house solution
  - [x] k8s and service mesh

Hints from issue discussion:

Commit message: docs: add hint box about service meshes

Patch to review:
diff --git a/docs/fundamentals/executor/containerize-executor.md b/docs/fundamentals/executor/containerize-executor.md
index b03c56358069a..14e946eef6dc3 100644
--- a/docs/fundamentals/executor/containerize-executor.md
+++ b/docs/fundamentals/executor/containerize-executor.md
@@ -1,3 +1,4 @@
+(dockerize-exec)=
 # Dockerize your Executor
 
 Once you have understood what an `Executor` is and how it can be used inside a `Flow`, you may be interested in wrapping this Executor into a container
diff --git a/docs/fundamentals/flow/index.md b/docs/fundamentals/flow/index.md
index 9a5c55257af8f..08e742f75a138 100644
--- a/docs/fundamentals/flow/index.md
+++ b/docs/fundamentals/flow/index.md
@@ -146,6 +146,7 @@ flow-api
 access-flow-api
 client
 monitoring-flow
+when-things-go-wrong
 yaml-spec
 remarks
 ```
diff --git a/docs/fundamentals/flow/when-things-go-wrong.md b/docs/fundamentals/flow/when-things-go-wrong.md
new file mode 100644
index 0000000000000..02a0611969a6c
--- /dev/null
+++ b/docs/fundamentals/flow/when-things-go-wrong.md
@@ -0,0 +1,94 @@
+(flow-error-handling)=
+# Error handling
+
+When building a complex solution, unfortunately things go wrong sometimes.
+Jina does its best to recover from failures, handle them gracefully, and report useful failure information to the user.
+
+The following outlines a number of (more or less) common failure cases, and explains how Jina responds to each one of them.
+
+## Exceptions in Executor code
+
+In general there are two places where an Executor level error can be introduced.
+
+If an Executor's `__init__` method raises and Exception, the Flow cannot start.
+In this case this Exception is gets raised by the Executor runtime, and the Flow throws a `RuntimeFailToStart` Exception.
+
+If one of the Executor's `@requests` methods raises and Exception, the offending error message gets added to the response
+and is sent back to the client.
+If the gRPC or WebSocket protocols are used, the networking stream is not interrupted and can accept further requests.
+
+In all cases, the {ref}`Jina Client <client>` will raise an Exception.
+
+## Network errors
+
+When an {ref}`Executor or Head <architecture-overview>` can't be reached by the Flow's gateway, it attempts to re-connect
+to the faulty deployment according to a retry policy.
+The specifics of this policy depend on the environment the Flow find itself in, and are outlined below.
+
+If, during the complete execution of this policy, no successful call to any Executor replica could be made, the request is aborted
+and the failure is {ref}`reported to the client <failure-reporting>`.
+
+### Request retries: Local deployment
+
+If a Flow is deployed locally (with or without {ref}`containerized Executors <dockerize-exec>`), the following policy
+for failed requests applies on a per-Executor basis:
+
+- If there are multiple replicas of the target Executor, try each replica at least once, or until the request succeeds
+- Irrespective of the number of replicas, try the request at least 3 times, or until it succeeds. If there are fewer than 3 replicas, try them in a round-robin fashion
+
+### Request retries: Deployment with Kubernetes
+
+If a Flow is {ref}`deployed in Kubernetes <kubernetes>` without a service mesh, retries cannot be distributed to different replicas of the same Executor.
+
+````{admonition} See Also
+:class: seealso
+
+The impossibility of retries across different replicas is a limitation of Kubernetes in combination with gRPC.
+If you want to learn more about this limitation, see [this](https://kubernetes.io/blog/2018/11/07/grpc-load-balancing-on-kubernetes-without-tears/) Kubernetes Blog post.
+
+An easy way to overcome this limitation is to use a service mesh like [Linkerd](https://linkerd.io/).
+````
+
+Concretely, this results in the following per-Executor retry policy:
+
+- Try the request 3 times, or until it succeeds, always on the same replica of the Executor
+
+### Request retries: Deployment with Kubernetes and service mesh
+
+A Kubernetes service mesh can enable load balancing, and thus retries, between replicas of an Executor.
+
+````{admonition} Hint
+:class: hint
+While Jina supports any service mesh, the output of `f.to_k8s_yaml()` already includes the necessary annotations for [Linkerd](https://linkerd.io/).
+````
+
+If a service mesh is installed alongside Jina in the Kubernetes cluster, the following retry policy applies for each Executor:
+
+- Try the request at least 3 times, or until it succeeds
+- Distribute the requests to the replicas according to the service mesh's configuration
+
+
+````{admonition} Caution
+:class: caution
+
+Many service meshes have the ability to perform retries themselves.
+Be careful about setting up service mesh level retries in combination with Jina, as it may lead to unwanted behaviour in combination with
+Jina's own retry policy.
+````
+
+(failure-reporting)=
+### Failure reporting
+
+If the retry policy is exhausted for a given request, the error is reported back to the corresponding client.
+
+The resulting error message will contain the *network address* of the failing Executor.
+If multiple replicas are present, all addresses will be reported - unless the Flow is deployed using Kubernetes, in which
+case the replicas are managed by k8s and only a single address is available.
+
+Depending on the client-to-gateway protocol, the error message will be returned in one of the following ways:
+
+- **gRPC**: A response with the gRPC status code 14 (*UNAVAILABLE*) is issued, and the error message is contained in the `details` field
+- **HTTP**: A response with the HTTP status code 503 (*SERVICE_UNAVAILABLE*) is issued, and the error message is contained in `response['header']['status']['description']`
+- **WebSocket**: The stream closes with close code 1011 (*INTERNAL_ERROR*) and the message is contained in the WS close message
+
+For any of these protocols, the {ref}`Jina Client <client>` will raise a `ConnectionError` containing the error message.
\ No newline at end of file
diff --git a/docs/how-to/kubernetes.md b/docs/how-to/kubernetes.md
index 8dffda3ed2c12..fba743ff4f584 100644
--- a/docs/how-to/kubernetes.md
+++ b/docs/how-to/kubernetes.md
@@ -1,122 +1,197 @@
 (kubernetes)=
 # How to deploy Jina on Kubernetes
 
-Jina natively supports deploying your Flow and Executors on Kubernetes.
+Deploying a Flow in Kubernetes is the recommended way of using Jina in production.
 
-A `Flow` is composed of `Executors` which run Python code
-defined to operate on a `DocumentArray`. These Executors live in different runtimes depending on how you want to deploy
-your Flow. 
+Since a `Flow` is composed of `Executors` which can run in different runtimes depending on how you want to deploy
+your Flow, Kubernetes can easily take over the lifetime management of Executors. 
 
-When deployed in Kubernetes, these Executors will run inside Kubernetes Pods as containers and their lifetime will be handled
-by Kubernetes.
+In general, Jina follows the following principle when it comes to deploying in Kubernetes:
+You, the user, know your use case and requirements the best.
+This means that while Jina generates configurations for you that run out of the box, as a professional user you should
+always see them as just a starting point to get you off the ground.
 
-Deploying a Flow in Kubernetes is the recommended way of using Jina in production.
+In this how-to you will go through how to deploy a simple Flow using Kubernetes, how to customize the Kubernetes configuration
+to your needs, and how to scale Executors using replicas and shards.
 
+## Preliminaries
 
-## Jina relies on Service Mesh 
-Jina's Kubernetes support comes with a built-in integration for [Linkerd](https://linkerd.io/) as the service mesh for connecting all the Jina services in Kubernetes. All Jina deployment resources are annotated with the necessary [Linkerd annotations](https://linkerd.io/2.11/tasks/adding-your-service/#meshing-a-service-with-annotations). So we recommend every Jina user to [install Linkerd](https://linkerd.io/2.11/getting-started/#step-3-install-the-control-plane-onto-your-cluster) into the Kubernetes cluster they are using Jina in.
+To follow along with this how-to, you will need access to a Kubernetes cluster.
 
-Linkerd will automatically load balance traffic between all replicas of an Executor. It also has [additional features](https://linkerd.io/2.11/features/).
+You can either set up [`minikube`](https://minikube.sigs.k8s.io/docs/start/), or use one of many managed Kubernetes
+solutions in the cloud:
+- [Google Kubernetes Engine](https://cloud.google.com/kubernetes-engine)
+- [Amazon EKS](https://aws.amazon.com/eks)
+- [Azure Kubernetes Service](https://azure.microsoft.com/en-us/services/kubernetes-service)
+- [Digital Ocean](https://www.digitalocean.com/products/kubernetes/)
 
-It is also generally possible to use other service mesh providers (like [Istio](https://istio.io/)) with Jina. You need to manually change Jina's deployment configurations in the generated YAML files for this.
 
-````{admonition} Caution
-:class: caution
+(kubernetes-deploy)=
+## Deploy a simple Flow
 
-If you don't install a third party service mesh (like Linkerd), you will not be able to scale the number of replicas per Executor to more than one. A single replica will always handle all the traffic. No matter how many replicas will be running.
-````
+By *simple* in this context we mean a Flow without replicated or sharded Executors - you will see how to use those in
+Kubernetes {ref}`later on <kubernetes-replicas>`.
 
-(kubernetes-deploy)=
-## Deploy your Flow
+For now, define a Flow.
+You can either do this through the Flow {ref}`YAML interface <flow-yaml-spec>` or directly in Python, like we do here:
 
-To deploy a Flow on `Kubernetes`, first, you have to generate Kubernetes YAML configuration files from a Jina Flow.
-Then, you can use the `kubectl apply` command to create or update your Flow resources within your cluster.
+```python
+from jina import Flow
 
-```{caution}
-All Executors in the Flow should be used with `jinahub+docker://...` or `docker://...`.
+f = (
+    Flow(port=8080)
+    .add(name='encoder', uses='jinahub+docker://CLIPEncoder')
+    .add(name='indexer', uses='jinahub+docker://AnnLiteIndexer', uses_with={'dim': 512})
+)
 ```
 
-To generate YAML configurations for Kubernetes from a Jina Flow, one just needs to call:
+Here you can essentially define any Flow of your liking.
+Just make sure that all Executors are containerized, either by using *'jinahub+docker'*, or by {ref}`containerizing your local
+Executors <dockerize-exec>`.
+
+The example Flow here simply encodes and indexes text or image data using two Executors from the [Jina Hub](https://hub.jina.ai/).
+ 
+Next, you can generate Kubernetes YAML configs from the Flow.
+It is good practice to define a new Kubernetes namespace for that purpose:
 
 ```python
-flow.to_k8s_yaml('flow_k8s_configuration')
+f.to_kubernetes_yaml('./k8s_flow', k8s_namespace='custom-namespace')
 ```
 
-This will create a folder 'flow_k8s_configuration' with a set of Kubernetes YAML configurations for all the deployments composing the Flow
+You should expect the following file structure to be generated - don't worry if it is slightly different, there can be 
+changes to this from one Jina version to the other:
 
-````{admonition} Hint
-:class: hint
-You can use a custom Docker image for the Gateway deployment. Just set the envrironment variable `JINA_GATEWAY_IMAGE` to the desired image before generating the configuration.
-````
-```{admonition} Caution
+```
+.
+└── k8s_flow
+    ├── gateway
+    │   └── gateway.yml
+    └── encoder
+    │   └── encoder.yml
+    └── indexer
+        └── indexer.yml
+```
+
+You can inspect these files to see how Flow concepts are mapped to Kubernetes entities.
+And as always, feel free to modify these config files as you see fit for your use case.
+
+````{admonition} Caution: Executor YAML configurations
 :class: caution
-The default deployment configurations generated by the Flow contain no special configuration objects. You may want to 
-adapt it to your own needs. For instance, no Persistent Volume Object is added. 
+
+As a general rule, the configuration files produced by `to_kubernets_yaml()` should run out of the box, and if you strictly
+follow this how-to they will.
+
+However, there is an exception to this: If you use a local dockerized Executor, and this Executors configuration is stored
+in a file other than `config.yaml`, you will have to adapt this Executor's Kubernetes YAML.
+To do this, open the file and replace `config.yaml` with the actual path to the Executor configuration.
+
+The reason for this is that when a Flow is defined by being passed a Docker image, it has no knowledge of what Executor
+configuration was used to create that image.
+Since all of our Tutorials use `config.yaml` for this purpose, the Flow can only use this as a best guess.
+Please adapt this if you used a differently named Executor configuration file.
+````
+
+Next you can actually apply these configuration files to your cluster, using `kubectl`.
+This will launch all Flow microservices.
+
+First, create the namespace you defined earlier:
+
+```shell
+kubectl create namespace custom-namespace
 ```
 
-## Scaling Executors on Kubernetes
+Now, you can deploy this Flow to you cluster in the following way:
+```shell
+kubectl apply -R -f ./k8s_flow
+```
 
-In Jina we support two ways of scaling:
+We can check that the pods were created:
+```shell
+kubectl get pods -n custom-namespace
+```
 
-- **Replicas** can be used with any Executor type and is typically used for performance and availability.
-- **Shards** are used for partitioning data and should only be used with indexers since they store state.
+```text
+NAME                              READY   STATUS    RESTARTS   AGE
+encoder-8b5575cb9-bh2x8           1/1     Running   0          60m
+gateway-7df8765bd9-xf5tf          1/1     Running   0          60m
+indexer-8f676fc9d-4fh52           1/1     Running   0          60m
+indexer-head-6fcc679d95-8mrm6     1/1     Running   0          60m
+```
 
-Check {ref}`here <scale-out>` for more information.
+Note that the Jina gateway was deployed with name `gateway-7df8765bd9-xf5tf`.
 
-Jina creates a separate Deployment in Kubernetes per Shard and uses [Kubernetes native replica scaling](https://kubernetes.io/docs/tutorials/kubernetes-basics/scale/scale-intro/) to create multiple Replicas of a Deployment.
+Once we see that all the Deployments in the Flow are ready, we can start indexing documents.
 
-Once the Flow is deployed on Kubernetes, you can use all the native Kubernetes tools like `kubeclt` to perform operations on the Pods and Deployments. 
+```python
+import portforward
 
-You can use this to [add or remove replicas](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#scaling-a-deployment), to run [rolling update](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#updating-a-deployment) operations, etc ...
+from jina.clients import Client
+from docarray import DocumentArray
 
-### Scaling the Gateway
-The Gateway is responsible for providing the API of the {ref}`Flow <flow>`. If you have a large Flow with many Clients and many replicated Executors, the Gateway can become the bottleneck. In this case you can also scale up the Gateway deployment to be backed by multiple Kubernetes Pods.
-This is done by the regular means of Kubernetes: Either increase the number of replicas in the  {ref}`generated yaml configuration files <kubernetes-deploy>` or [add replicas while running](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#scaling-a-deployment).
-To expose your Gateway replicas outside Kubernetes, you can add a load balancer as described {ref}`here <kubernetes-expose>`.
+with portforward.forward('custom-namespace', 'gateway-7df8765bd9-xf5tf', 8080, 8080):
+    client = Client(host='localhost', port=8080)
+    client.show_progress = True
+    docs = client.post(
+        '/index',
+        inputs=DocumentArray.from_files('./imgs/*.png').apply(
+            lambda d: d.convert_uri_to_datauri()
+        ),
+    )
 
-## Extra Kubernetes options
+    print(f' Indexed documents: {len(docs)}')
+```
 
-One could see that you can't add basic Kubernetes feature like `Secrets`, `ConfigMap` or `Lables` via the pythonic interface. That is intended
-and it does not mean that we don't support these features. On the contrary we allow you to fully express your Kubernetes configuration by using the Kubernetes API so that you can add you own Kubernetes standard to jina.
+(kubernetes-replicas)=
+## Scaling Executors: Flow with replicas and shards
 
-````{admonition} Hint
-:class: hint
-We recommend dumping the Kubernetes configuration files and then editing the files to suit your needs.
-````
+Jina supports two ways of scaling:
 
-Here are possible configuration options you may need to add or change
+- **Replicas** can be used with any Executor type and is typically used for performance and availability.
+- **Shards** are used for partitioning data and should only be used with indexers since they store state.
 
-- Add labels `selector`s to the Deployments to suit your case
-- Add `requests` and `limits` for the resources of the different Pods 
-- Setup persistent volume storage to save your data on disk
-- Pass custom configuration to your Executor with `ConfigMap` 
-- Manage the credentials of your Executor with secrets
-- Edit the default rolling update configuration
+Check {ref}`here <scale-out>` for more information about these scaling mechanisms.
 
+For shards, Jina creates a separate Deployment in Kubernetes per Shard.
+Setting `f.add(..., shards=num_shards)` is sufficient to create a corresponding Kubernetes configuration.
 
-## Example : Deploying a Flow with Kubernetes
+For replicas, Jina uses [Kubernetes native replica scaling](https://kubernetes.io/docs/tutorials/kubernetes-basics/scale/scale-intro/) and **relies on a service mesh** to load balance request between replicas of the same Executor.
+Without a service mesh installed in your Kubernetes cluster, all the traffic will be routed to the same replica.
 
-### Preliminaries
+````{admonition} See Also
+:class: seealso
 
-Set up a Kubernetes cluster and configure cluster access locally.
+The impossibility of load balancing between different replicas is a limitation of Kubernetes in combination with gRPC.
+If you want to learn more about this limitation, see [this](https://kubernetes.io/blog/2018/11/07/grpc-load-balancing-on-kubernetes-without-tears/) Kubernetes Blog post.
+````
 
-```{tip}
-For local testing [`minikube`](https://minikube.sigs.k8s.io/docs/start/) is recommended.
-```
+### Install a service mesh
 
-```{seealso}
+Service meshes work by attaching a tiny proxy to each of your Kubernetes pods, allowing for smart rerouting, load balancing,
+request retrying, and host of other [features](https://linkerd.io/2.11/features/).
 
-Here are some managed `Kubernetes` cluster solutions you could use:
+Jina relies on a service mesh to load balance request between replicas of the same Executor.
+You can use your favourite Kubernetes service mesh in combination with your Jina Flow, but the configuration files
+generated by `to_kubernetes_config()` already include all necessary annotations for the [Linkerd service mesh](https://linkerd.io).
 
-- [Google Kubernetes Engine](https://cloud.google.com/kubernetes-engine),
-- [Amazon EKS](https://aws.amazon.com/eks),
-- [Azure Kubernetes Service](https://azure.microsoft.com/en-us/services/kubernetes-service),
-- [Digital Ocean](https://www.digitalocean.com/products/kubernetes/)
-```
+````{admonition} Hint
+:class: hint
+You can use any service mesh with Jina, but Jina Kubernetes configurations come with Linkerd annotations out of the box.
+````
+
+To install Linkerd, you first have to [install the Linkerd CLI](https://linkerd.io/2.11/getting-started/).
+After that, you [install its control plane](https://linkerd.io/2.11/getting-started/) in your cluster.
+This is what will automatically set up and manage the service mesh proxies when you deploy your Flow.
+
+
+Once the Flow is deployed on Kubernetes, you can use all the native Kubernetes tools like `kubectl` to perform operations on the Pods and Deployments. 
+
+You can use this to [add or remove replicas](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#scaling-a-deployment), to run [rolling update](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#updating-a-deployment) operations, etc ...
 
-### Indexing and searching images using CLIP image encoder and PQLiteIndexer
 
-This example shows how to build and deploy a Flow in Kubernetes with [`CLIPImageEncoder`](https://hub.jina.ai/executor/0hnlmu3q) as encoder and [`PQLiteIndexer`](https://hub.jina.ai/executor/pn1qofsj) as indexer.
+### Deploy your Flow with shards and replicas
+
+After your service mesh is installed, your cluster is ready to run a Flow with scaled Executors.
+You can adapt your Flow from above to work with two replicas for the encoder, and two shards for the indexer:
 
 ```python
 from jina import Flow
@@ -126,20 +201,20 @@ f = (
     .add(name='encoder', uses='jinahub+docker://CLIPEncoder', replicas=2)
     .add(
         name='indexer',
-        uses='jinahub+docker://PQLiteIndexer',
+        uses='jinahub+docker://ANNLiteIndexer',
         uses_with={'dim': 512},
         shards=2,
     )
 )
 ```
 
-Now, we can generate Kubernetes YAML configs from the Flow:
+Again, you can generate your Kubernetes configurations:
 
 ```python
 f.to_k8s_yaml('./k8s_flow', k8s_namespace='custom-namespace')
 ```
 
-You should expect the following file structure generated:
+Now you should see the following file structure:
 
 ```
 .
@@ -147,66 +222,55 @@ You should expect the following file structure generated:
     ├── gateway
     │   └── gateway.yml
     └── encoder
-    │   ├── encoder.yml
-    │   └── encoder-head.yml
+    │   └─ encoder.yml
     └── indexer
         ├── indexer-0.yml
         ├── indexer-1.yml
         └── indexer-head.yml
 ```
-You may need to edit these files to add your custom configuration
-
-As you can see, the Flow contains configuration for the gateway and the rest of executors
 
-Let's create a Kubernetes namespace for our Flow:
+And you can apply your configuration like usual:
 
-```shell
-kubectl create namespace custom-namespace
-```
+````{admonition} Hint: Cluster cleanup
+:class: hint
+If you already have the simple Flow from the first example running on your cluster, make sure to delete it using `kubectl delete -R -f ./k8s_flow`.
+````
 
-Now, you can deploy this Flow to you cluster in the following way:
 ```shell
 kubectl apply -R -f ./k8s_flow
 ```
 
-We can check that the pods were created:
-```shell
-kubectl get pods -n custom-namespace
-```
 
-```text
-NAME                              READY   STATUS    RESTARTS   AGE
-encoder-8b5575cb9-bh2x8           1/1     Running   0          60m
-encoder-8b5575cb9-gx78g           1/1     Running   0          60m
-encoder-head-55bbb477ff-p2bmk   1/1     Running   0          60m
-gateway-7df8765bd9-xf5tf          1/1     Running   0          60m
-indexer-0-8f676fc9d-4fh52         1/1     Running   0          60m
-indexer-1-55b6cc9dd8-gtpf6        1/1     Running   0          60m
-indexer-head-6fcc679d95-8mrm6   1/1     Running   0          60m
-```
+## Scaling the Gateway
+The Gateway is responsible for providing the API of the {ref}`Flow <flow>`.
+If you have a large Flow with many Clients and many replicated Executors, the Gateway can become the bottleneck.
+In this case you can also scale up the Gateway deployment to be backed by multiple Kubernetes Pods.
+This is done by the regular means of Kubernetes: Either increase the number of replicas in the  {ref}`generated yaml configuration files <kubernetes-deploy>` or [add replicas while running](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#scaling-a-deployment).
+To expose your Gateway replicas outside Kubernetes, you can add a load balancer as described {ref}`here <kubernetes-expose>`.
 
-Note that the Jina gateway was deployed with name `gateway-7df8765bd9-xf5tf`.
+````{admonition} Hint
+:class: hint
+You can use a custom Docker image for the Gateway deployment. Just set the envrironment variable `JINA_GATEWAY_IMAGE` to the desired image before generating the configuration.
+````
 
-Once we see that all the Deployments in the Flow are ready, we can start indexing documents.
+## Extra Kubernetes options
 
-```python
-import portforward
+One could see that you can't add basic Kubernetes feature like `Secrets`, `ConfigMap` or `Lables` via the pythonic interface. That is intended
+and it does not mean that we don't support these features. On the contrary we allow you to fully express your Kubernetes configuration by using the Kubernetes API so that you can add you own Kubernetes standard to jina.
 
-from jina.clients import Client
-from docarray import DocumentArray
+````{admonition} Hint
+:class: hint
+We recommend dumping the Kubernetes configuration files and then editing the files to suit your needs.
+````
 
-with portforward.forward('custom-namespace', 'gateway-7df8765bd9-xf5tf', 8080, 8080):
-    client = Client(host='localhost', port=8080)
-    client.show_progress = True
-    docs = client.post(
-        '/index',
-        inputs=DocumentArray.from_files('./imgs/*.png').apply(
-            lambda d: d.convert_uri_to_datauri()
-        ),
-    )
+Here are possible configuration options you may need to add or change
 
-    print(f' Indexed documents: {len(docs)}')
-```
+- Add labels `selector`s to the Deployments to suit your case
+- Add `requests` and `limits` for the resources of the different Pods 
+- Setup persistent volume storage to save your data on disk
+- Pass custom configuration to your Executor with `ConfigMap` 
+- Manage the credentials of your Executor with secrets
+- Edit the default rolling update configuration
 
 (kubernetes-expose)=
 ## Exposing your Flow
@@ -251,4 +315,18 @@ queried_docs = client.post("/search", inputs=docs)
 
 matches = queried_docs[0].matches
 print(f"Matched documents: {len(matches)}")
-```
\ No newline at end of file
+```
+
+## Key takeaways
+
+To put it succinctly, there are just three key takeaways about deploying a Jina Flow using Kubernetes:
+
+1. Use `f.to_kubernetes_yaml()` to generate Kubernetes configuration files from a Jina Flow object
+2. Modify the generated files freely - you know better what you need than we do!
+3. To enable replicated Executors, use a service mesh
+
+## See also
+
+- {ref}`Monitor your Flow once it is deployed <monitoring>`
+- {ref}`See how failures and retries are handled <flow-error-handling>`
+- {ref}`Learn more about scaling Executors <scale-out>`
\ No newline at end of file


Code review comments:
diff_hunk: @@ -1,122 +1,197 @@
 (kubernetes)=
 # How to deploy Jina on Kubernetes
 
-Jina natively supports deploying your Flow and Executors on Kubernetes.
+Deploying a Flow in Kubernetes is the recommended way of using Jina in production.
 
-A `Flow` is composed of `Executors` which run Python code
-defined to operate on a `DocumentArray`. These Executors live in different runtimes depending on how you want to deploy
-your Flow. 
+Since a `Flow` is composed of `Executors` which can run in different runtimes depending on how you want to deploy
+your Flow, Kubernetes can easily take over the lifetime management of Executors. 
 
-When deployed in Kubernetes, these Executors will run inside Kubernetes Pods as containers and their lifetime will be handled
-by Kubernetes.
+In general, Jina follows the following principle when it comes to deploying in Kubernetes:
+You, the user, know your use case and requirements the best.
+This means that while Jina generates configurations for you that run out of the box, as a professional user you should
+always see them as just a starting point to get you off the ground.
path: docs/how-to/kubernetes.md
text: @user1:
For me it is unclear. The user does not know yet that he will dump any files. Maybe we need one sentence before to say that the spirit of our k8s is to generate k8s files.