From 58b51ebffc8a57192fd1f4e0604fc8d42e922ab5 Mon Sep 17 00:00:00 2001 From: prubenda Date: Tue, 23 Jun 2020 15:59:23 -0400 Subject: [PATCH] Adding kraken containerization with readme instructions --- containers/README.md | 18 +++++++++++++ containers/kraken.yml | 42 +++++++++++++++++++++++++++++ kraken/kubernetes/client.py | 53 +++++++++++++++++++++++++++++++++++++ run_kraken.py | 3 +++ 4 files changed, 116 insertions(+) create mode 100644 containers/kraken.yml diff --git a/containers/README.md b/containers/README.md index 1862accc..00c665f0 100644 --- a/containers/README.md +++ b/containers/README.md @@ -4,3 +4,21 @@ Container image gets automatically built by quay.io at [Kraken image](https://qu ### Run containerized version Refer [instructions](https://github.com/openshift-scale/kraken#Run-containerized-version) for information on how to run the containerized version of kraken. + + +### Kraken as a KubeApp + +To run containerized Kraken as a Kubernetes/OpenShift Deployment, follow these steps: +1. Configure the [config.yaml](https://github.com/openshift-scale/kraken/tree/master/config/config.yaml) file according to your requirements. +2. Create a namespace under which you want to run the kraken pod using `kubectl create ns `. +3. Switch to `` namespace: + - In Kubernetes, use `kubectl config set-context --current --namespace=` + - In OpenShift, use `oc project ` +4. Create a ConfigMap named kube-config using `kubectl create configmap kube-config --from-file=` +5. Create a ConfigMap named kraken-config using `kubectl create configmap kraken-config --from-file=` +6. Create a ConfigMap named scenarios-config using `kubectl create configmap scenarios-config --from-file=` +7. Create a serviceaccount to run the kraken pod `kubectl create serviceaccount useroot`. +8. In Openshift, add privileges to service account and execute `oc adm policy add-scc-to-user privileged -z useroot`. +9. Create a Deployment and a NodePort Service using `kubectl apply -f kraken.yml` + +NOTE: It is not recommended to run Kraken internal to the cluster as the pod which is running Kraken might get disrupted. \ No newline at end of file diff --git a/containers/kraken.yml b/containers/kraken.yml new file mode 100644 index 00000000..383b32d5 --- /dev/null +++ b/containers/kraken.yml @@ -0,0 +1,42 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: kraken-deployment +spec: + replicas: 1 + selector: + matchLabels: + tool: Kraken + template: + metadata: + labels: + tool: Kraken + spec: + serviceAccountName: useroot + containers: + - name: kraken + securityContext: + privileged: true + image: quay.io/openshift-scale/kraken + command: ["/bin/sh", "-c"] + args: ["python3 run_kraken.py -c config/config.yaml"] + ports: + - containerPort: 8080 + volumeMounts: + - mountPath: "/root/.kube" + name: config + - mountPath: "/root/kraken/config" + name: kraken-config + - mountPath: "/root/kraken/scenarios" + name: scenarios-config + volumes: + - name: config + configMap: + name: kube-config + - name: kraken-config + configMap: + name: kraken-config + - name: scenarios-config + configMap: + name: scenarios-config diff --git a/kraken/kubernetes/client.py b/kraken/kubernetes/client.py index 657b4bff..2a180843 100644 --- a/kraken/kubernetes/client.py +++ b/kraken/kubernetes/client.py @@ -1,6 +1,10 @@ from kubernetes import client, config from kubernetes.client.rest import ApiException import logging +import kraken.invoke.command as runcommand +import json + +kraken_node_name = "" # Load kubeconfig and initialize kubernetes python client @@ -22,6 +26,21 @@ def list_nodes(): return nodes +# List nodes in the cluster that can be killed +def list_killable_nodes(): + nodes = [] + try: + ret = cli.list_node(pretty=True) + except ApiException as e: + logging.error("Exception when calling CoreV1Api->list_node: %s\n" % e) + for node in ret.items: + if kraken_node_name != node.metadata.name: + for cond in node.status.conditions: + if str(cond.type) == "Ready" and str(cond.status) == "True": + nodes.append(node.metadata.name) + return nodes + + # List pods in the given namespace def list_pods(namespace): pods = [] @@ -35,6 +54,14 @@ def list_pods(namespace): return pods +def get_all_pods(): + pods = [] + ret = cli.list_pod_for_all_namespaces(pretty=True) + for pod in ret.items: + pods.append([pod.metadata.name, pod.metadata.namespace]) + return pods + + # Monitor the status of the cluster nodes and set the status to true or false def monitor_nodes(): nodes = list_nodes() @@ -96,3 +123,29 @@ def monitor_component(iteration, component_namespace): logging.info("Iteration %s: %s: %s" % (iteration, component_namespace, watch_component_status)) return watch_component_status, failed_component_pods + + +# Find the node kraken is deployed on +# Set global kraken node to not delete +def find_kraken_node(): + pods = get_all_pods() + kraken_pod_name = None + for pod in pods: + if "kraken-deployment" in pod[0]: + kraken_pod_name = pod[0] + kraken_project = pod[1] + break + # have to switch to proper project + + if kraken_pod_name: + # get kraken-deployment pod, find node name + runcommand.invoke("kubectl config set-context --current --namespace=" + str(kraken_project)) + pod_json_str = runcommand.invoke("kubectl get pods/" + str(kraken_pod_name) + " -o json") + pod_json = json.loads(pod_json_str) + node_name = pod_json['spec']['nodeName'] + + # Reset to the default project + runcommand.invoke("kubectl config set-context --current --namespace=default") + + global kraken_node_name + kraken_node_name = node_name diff --git a/run_kraken.py b/run_kraken.py index ef860f85..9be279c6 100644 --- a/run_kraken.py +++ b/run_kraken.py @@ -35,6 +35,9 @@ def main(cfg): logging.info("Initializing client to talk to the Kubernetes cluster") kubecli.initialize_clients(kubeconfig_path) + # find node kraken might be running on + kubecli.find_kraken_node() + # Cluster info logging.info("Fetching cluster info") cluster_version = runcommand.invoke("kubectl get clusterversion")