1

My Bash script using kubectl create/apply -f ... to deploy lots of Kubernetes resources has grown too large for Bash. I'm converting it to Python using the PyPI kubernetes package.

Is there a generic way to create resources given the YAML manifest? Otherwise, the only way I can see to do it would be to create and maintain a mapping from Kind to API method create_namespaced_<kind>. That seems tedious and error prone to me.

Update: I'm deploying many (10-20) resources to many (10+) GKE clusters.

2
  • Have you had a look at Helm yet? docs.helm.sh/chart_template_guide/… Commented Aug 29, 2017 at 21:05
  • I have, but does Helm help me deploy to many clusters? Because if not, I'm basically in the same boat Commented Aug 30, 2017 at 21:51

3 Answers 3

4

Update in the year 2020, for anyone still interested in this (since the docs for the python library is mostly empty).

At the end of 2018 this pull request has been merged, so it's now possible to do:

from kubernetes import client, config
from kubernetes import utils

config.load_kube_config()
api = client.ApiClient()

file_path = ... # A path to a deployment file
namespace = 'default'

utils.create_from_yaml(api, file_path, namespace=namespace)

EDIT: from a request in a comment, a snippet for skipping the python error if the deployment already exists

from kubernetes import client, config
from kubernetes import utils

config.load_kube_config()
api = client.ApiClient()


def skip_if_already_exists(e):
    import json
    # found in https://github.com/kubernetes-client/python/blob/master/kubernetes/utils/create_from_yaml.py#L165
    info = json.loads(e.api_exceptions[0].body)
    if info.get('reason').lower() == 'alreadyexists':
        pass
    else
        raise e


file_path = ... # A path to a deployment file
namespace = 'default'

try:
    utils.create_from_yaml(api, file_path, namespace=namespace)
except utils.FailToCreateError as e:
    skip_if_already_exists(e)
Sign up to request clarification or add additional context in comments.

3 Comments

The function fails when resources already exist. With kubectl apply, it either updates the resource or skips it entirely. Is there a way to do that with the python client?
@BenDavis I've updated the answer to skip if already exists. Not sure how to update the resource instead.
I don't have the code in question at hand to test, but looks like it'd work to me :)
3

I have written a following piece of code to achieve the functionality of creating k8s resources from its json/yaml file:

def create_from_yaml(yaml_file):
    """

    :param yaml_file:
    :return:
    """

    yaml_object = yaml.loads(common.load_file(yaml_file))
    group, _, version = yaml_object["apiVersion"].partition("/")
    if version == "":
        version = group
        group = "core"

    group = "".join(group.split(".k8s.io,1"))
    func_to_call = "{0}{1}Api".format(group.capitalize(), version.capitalize())

    k8s_api = getattr(client, func_to_call)()

    kind = yaml_object["kind"]
    kind = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', kind)
    kind = re.sub('([a-z0-9])([A-Z])', r'\1_\2', kind).lower()

    if "namespace" in yaml_object["metadata"]:
        namespace = yaml_object["metadata"]["namespace"]
    else:
        namespace = "default"

    try:
        if hasattr(k8s_api, "create_namespaced_{0}".format(kind)):
            resp = getattr(k8s_api, "create_namespaced_{0}".format(kind))(
                body=yaml_object, namespace=namespace)
        else:
            resp = getattr(k8s_api, "create_{0}".format(kind))(
                body=yaml_object)
    except Exception as e:
        raise e

    print("{0} created. status='{1}'".format(kind, str(resp.status)))

    return k8s_api

In above function, If you provide any object yaml/json file, it will automatically pick up the API type and object type and create the object like statefulset, deployment, service etc.

PS: The above code doesn't handler multiple kubernetes resources in one file, so you should have only one object per yaml file.

Comments

1

I see what you are looking for. This is possible with other k8s clients available in other languages. Here is an example in java. Unfortunately the python client library does not support that functionality yet. I opened a new feature request requesting the same and you can either choose to track it or contribute yourself :). Here is the link for the issue on GitHub.

The other way to still do what you are trying to do is to use java/golang client and put your code in a docker container.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.