# Kubernetes Python Client in Minikube Suppose the goal is to delegate some tasks from a pod to another pod using HTTP requests, then it's necessary to know to IP of each pod. [Kubernetes Python Client](https://github.com/kubernetes-client/python) can do the job. --- ###### tags: `Kubernetes` `Python` --- ## Pip Install For testing purposes, it is convenient to use shell in the running container. ``` root@api-minikube-7f4b5d6dd6-56z8s:/app# which python /app/venv/bin/python root@api-minikube-7f4b5d6dd6-56z8s:/app# pip install kubernetes ``` ## Try It Out After installing successfully, open python shell in the container. ``` root@api-minikube-7f4b5d6dd6-56z8s:/app# python Python 3.8.10 (default, May 12 2021, 15:56:47) [GCC 8.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> from kubernetes import client >>> from kubernetes import config ``` [According to the example here](https://github.com/kubernetes-client/python#examples) ``` >>> config.load_kube_config() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/app/venv/lib/python3.8/site-packages/kubernetes/config/kube_config.py", line 813, in load_kube_config loader = _get_kube_config_loader( File "/app/venv/lib/python3.8/site-packages/kubernetes/config/kube_config.py", line 772, in _get_kube_config_loader raise ConfigException( kubernetes.config.config_exception.ConfigException: Invalid kube-config file. No configuration found. ``` So, the above command does not work in clusters. In clusters, the command as shown below should be used. ``` config.load_incluster_config() ``` Then, the next step would be listing all pods using `list_pod_for_all_namespaces` function. If it's desired to list only pods in a specific namespace, the function `list_namespaced_pod` should be used. ``` >>> v1 = client.CoreV1Api() >>> ret = v1.list_pod_for_all_namespaces(watch=False) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/app/venv/lib/python3.8/site-packages/kubernetes/client/api/core_v1_api.py", line 16864, in list_pod_for_all_namespaces return self.list_pod_for_all_namespaces_with_http_info(**kwargs) # noqa: E501 File "/app/venv/lib/python3.8/site-packages/kubernetes/client/api/core_v1_api.py", line 16967, in list_pod_for_all_namespaces_with_http_info return self.api_client.call_api( File "/app/venv/lib/python3.8/site-packages/kubernetes/client/api_client.py", line 348, in call_api return self.__call_api(resource_path, method, File "/app/venv/lib/python3.8/site-packages/kubernetes/client/api_client.py", line 180, in __call_api response_data = self.request( File "/app/venv/lib/python3.8/site-packages/kubernetes/client/api_client.py", line 373, in request return self.rest_client.GET(url, File "/app/venv/lib/python3.8/site-packages/kubernetes/client/rest.py", line 239, in GET return self.request("GET", url, File "/app/venv/lib/python3.8/site-packages/kubernetes/client/rest.py", line 233, in request raise ApiException(http_resp=r) kubernetes.client.exceptions.ApiException: (403) Reason: Forbidden HTTP response headers: HTTPHeaderDict({'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'X-Content-Type-Options': 'nosniff', 'X-Kubernetes-Pf-Flowschema-Uid': '7efca18f-3cc3-4a99-be09-59586a316041', 'X-Kubernetes-Pf-Prioritylevel-Uid': 'c1eae4b0-1a62-4ba2-8ec6-677d6541bc5d', 'Date': 'Tue, 22 Jun 2021 04:47:02 GMT', 'Content-Length': '274'}) HTTP response body: {"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"pods is forbidden: User \"system:serviceaccount:default:default\" cannot list resource \"pods\" in API group \"\" at the cluster scope","reason":"Forbidden","details":{"kind":"pods"},"code":403} ``` The most important part in this error message is `cannot list resource \"pods\" in API group`. Clearly, the issue relates to authorization. To solve this issue, it's necessary to use [RBAC Authorization](https://hackmd.io/AoMPVOpBTSiBBI24ABtaFA) The YAML file below is from the [here](https://github.com/kubernetes-client/python/issues/605#issuecomment-415217369) ``` # rbac_authorization.yml kind: apiVersion: rbac.authorization.k8s.io/v1 metadata: name: pods-list rules: - apiGroups: [""] resources: ["pods"] verbs: ["list"] --- kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: pods-list subjects: - kind: ServiceAccount name: default namespace: default roleRef: kind: Role name: pods-list ``` Then, apply this YAML file using kubectl. ``` > kubectl apply -f rbac_authorization.yml clusterrole.rbac.authorization.k8s.io/pods-list created clusterrolebinding.rbac.authorization.k8s.io/pods-list created ``` Inspect the change using kubectl. ``` > kubectl describe roles pods-list Name: pods-list Labels: <none> Annotations: <none> PolicyRule: Resources Non-Resource URLs Resource Names Verbs --------- ----------------- -------------- ----- pods [] [] [list] ``` As shown above, the information shown on the terminal is identical to the YAML file. Go to the python shell in the container again. ``` >>> ret = v1.list_pod_for_all_namespaces(watch=False) >>> pod_ips = [i.status.pod_ip for i in ret.items] >>> pod_ips ['172.17.0.7', '172.17.0.6', '172.17.0.5', '172.17.0.8', '172.17.0.3', '172.17.0.4'] ``` Now, it works. If it is preferred to use `read_namespaced_pod_status` function, instead of `list_pod_for_all_namespaces` or `list_namespaced_pod`,. For example, ``` >>> import os >>> POD_NS = os.environ['MY_POD_NAMESPACE'] >>> from kubernetes import client, config >>> config.load_incluster_config() >>> >>> v1 = client.CoreV1Api() >>> ret = v1.list_namespaced_pod(namespace=POD_NS) >>> pod_nm = [i.metadata.name for i in ret.items] >>> pod_stat = [v1.read_namespaced_pod_status(i, namespace=POD_NS) for i in pod_nm] ``` The error message would be similar as below. ``` Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 1, in <listcomp> File "/app/venv/lib/python3.8/site-packages/kubernetes/client/api/core_v1_api.py", line 23089, in read_namespaced_pod_status return self.read_namespaced_pod_status_with_http_info(name, namespace, **kwargs) # noqa: E501 File "/app/venv/lib/python3.8/site-packages/kubernetes/client/api/core_v1_api.py", line 23176, in read_namespaced_pod_status_with_http_info return self.api_client.call_api( File "/app/venv/lib/python3.8/site-packages/kubernetes/client/api_client.py", line 348, in call_api return self.__call_api(resource_path, method, File "/app/venv/lib/python3.8/site-packages/kubernetes/client/api_client.py", line 180, in __call_api response_data = self.request( File "/app/venv/lib/python3.8/site-packages/kubernetes/client/api_client.py", line 373, in request return self.rest_client.GET(url, File "/app/venv/lib/python3.8/site-packages/kubernetes/client/rest.py", line 239, in GET return self.request("GET", url, File "/app/venv/lib/python3.8/site-packages/kubernetes/client/rest.py", line 233, in request raise ApiException(http_resp=r) kubernetes.client.exceptions.ApiException: (403) Reason: Forbidden HTTP response headers: HTTPHeaderDict({'Cache-Control': 'no-cache, private', 'Content-Type': 'application/json', 'X-Content-Type-Options': 'nosniff', 'X-Kubernetes-Pf-Flowschema-Uid': '7efca18f-3cc3-4a99-be09-59586a316041', 'X-Kubernetes-Pf-Prioritylevel-Uid': 'c1eae4b0-1a62-4ba2-8ec6-677d6541bc5d', 'Date': 'Fri, 25 Jun 2021 10:27:02 GMT', 'Content-Length': '363'}) HTTP response body: {"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"pods \"api-minikube-7b9d4659db-8pjq8\" is forbidden: User \"system:serviceaccount:default:default\" cannot get resource \"pods/status\" in API group \"\" in the namespace \"default\"","reason":"Forbidden","details":{"name":"api-minikube-7b9d4659db-8pjq8","kind":"pods"},"code":403} ``` In particular, `cannot get resource \"pods/status\" in API group` Modify the above YAML file. ``` # rbac_authorization.yml kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: name: pods-list rules: - apiGroups: [""] resources: ["pods", "pods/status"] verbs: ["list"] --- kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: pods-list subjects: - kind: ServiceAccount name: default namespace: default roleRef: kind: Role name: pods-list apiGroup: rbac.authorization.k8s.io ``` The only difference is adding another resources called "pods/status". Apply the YAML file again. ``` > kubectl apply -f rbac_authorization.yml clusterrole.rbac.authorization.k8s.io/pods-list configured clusterrolebinding.rbac.authorization.k8s.io/pods-list unchanged ``` It turns out the above modified YAML file does not work either. To make it work, other verbs should be added. ``` # rbac_authorization.yml kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: name: pods-list rules: - apiGroups: [""] resources: ["pods", "pods/status"] verbs: ["get", "watch", "list"] --- kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: pods-list subjects: - kind: ServiceAccount name: default namespace: default roleRef: kind: Role name: pods-list apiGroup: rbac.authorization.k8s.io ``` Apply the YAML file again. ``` > kubectl apply -f rbac_authorization.yml clusterrole.rbac.authorization.k8s.io/pods-list configured clusterrolebinding.rbac.authorization.k8s.io/pods-list unchanged ``` Inspect the change using kubectl. ``` > kubectl describe roles pods-list Name: pods-list Labels: <none> Annotations: <none> PolicyRule: Resources Non-Resource URLs Resource Names Verbs --------- ----------------- -------------- ----- pods/status [] [] [get watch list] pods [] [] [get watch list] ``` By adding verbs `get` and `watch`, it should work as expected. ``` >>> pod_stat = [v1.read_namespaced_pod_status(i, namespace=POD_NS) for i in pod_nm] >>> [pod.status.phase for pod in pod_stat] ['Running', 'Running', 'Running', 'Running', 'Running', 'Running'] ``` # Reference - [**Official DOCS**](https://github.com/kubernetes-client/python/blob/master/kubernetes/docs/AutoscalingV1Api.md) - [Using RBAC Authorization](https://kubernetes.io/docs/reference/access-authn-authz/rbac/) - https://github.com/kubernetes-client/python/issues/519 - https://github.com/kubernetes-client/python/issues/605 - https://github.com/kubernetes-client/python/blob/master/examples/in_cluster_config.py