Getting Started

Quickstart

  • Install from PyPi

pip install django-kubernetes-manager
  • In settings.py (or module) add the app

INSTALLED_APPS = [
  ... ,
  rest_framework,
  kubernetes_manager,
]
  • In urls.py include the package urls

urlpatterns = [
  ... ,
  path('dkm/', include('kubernetes_manager.urls')),
]
  • Run migrations and start server

./manage.py migrate
./manage.py runserver
  • Navigate to django admin and create a TargetCluster

  • Sample request

curl http://127.0.0.1:8000/dkm/api/namespaces/?format=json
[
  {
    "title": "veridian-dynamics-aerodynamic-bagels",
    "description": null,
    "cluster": "http://127.0.0.1:8000/dkm/api/clusters/1/?format=json",
    "config": {},
    "labels": {
      "project": "aerodynamic-bagels",
      "organization": "veridian-dynamics"
    },
    "annotations": {},
    "api_version": "v1",
    "kind": "Namespace",
    "exists": true
  }
]

Sample Use-cases

  • Creating a labelled namespace for a client project:

from kubernetes_manager.models import KubernetesNamespace, TargetCluster
from django.db import models
from django_extensions.models import TitleDescriptionModel

class AppNamespace(TitleDescriptionModel):
  project = models.OneToOneField("client.Project", on_delete=models.CASCADE)
  organization = models.ForeignKey("client.Org", on_delete=models.CASCADE)
  cluster = models.ForeignKey("kubernetes_manager.TargetCluster", on_delete=models.CASCADE)
  namespace = models.ForeignKey("kubernetes_manager.KubernetesNamespace", null=True, blank=True, on_delete=models.CASCADE)
  status = models.CharField(max_length = 128, null=True, blank=True)

  def save(self, *args, **kwargs):
      if not self.status == "{'phase': 'Active'}":
          self.namespace = KubernetesNamespace.objects.create(
              title = "ns-" + self.organization.slug + "-" + self.project.slug,
              cluster = self.cluster,
              labels = {"organization":self.organization.slug, "project": self.project.slug},
              kind = "Namespace"
          )
          self.status = self.namespace.deploy()
      super().save(*args, **kwargs)

  def remove(self, *args, **kwargs):
      self.status = self.namespace.k_delete()

  def delete(self, *args, **kwargs):
      self.remove()
      super().delete(*args, **kwargs)
  • Creating a two-container deployment:

from kubernetes_manager.models import KubernetesNamespace, TargetCluster
from django.db import models
from django_extensions.models import TitleDescriptionModel

from .ns import AppNamespace

class FileServer(TitleDescriptionModel):
    name = models.CharField(max_length=128)
    organization = models.ForeignKey("client.Org", on_delete=models.CASCADE)
    project = models.ForeignKey("client.Project", on_delete=models.CASCADE)
    cluster = models.ForeignKey("kubernetes_manager.TargetCluster", on_delete=models.CASCADE)
    namespace = models.ForeignKey(AppNamespace, on_delete=models.CASCADE)
    file = models.ForeignKey("library.FileItem", on_delete=models.CASCADE)
    docker_image = models.CharField(max_length=256, help_text="Docker repo path for image")
    docker_tag = models.CharField(max_length=16, help_text="Docker tag for image")
    definition = JSONField(null=True, blank=True)

    # define volume
    def vol(self, *args, **kwargs):
        volume = KubernetesVolume.objects.create(
            title = self.name + "-vol",
            cluster = self.cluster
        )
        return volume

    # create primary container
    def container_spec(self, *args, **kwargs):
        container = KubernetesContainer.objects.create(
            title = self.name,
            cluster = self.cluster,
            image_name = self.docker_image,
            image_tag = self.docker_tag,
            volume_mount = KubernetesVolumeMount.objects.create(
                title = self.name + "-vol",
                cluster = self.cluster
            ) if not kwargs.get("mount", None) else kwargs.get("mount"),
            command = "ls",
            args ="/media"
        )
        return container

    # create download sidecar
    def sidecar_spec(self, *args, **kwargs):
        sidecar = KubernetesContainer.objects.create(
            title = self.name,
            cluster = self.cluster,
            image_name = "curlimages/curl",
            image_tag = "7.69.1",
            volume_mount = KubernetesVolumeMount.objects.create(
                title = self.name + "-vol",
                cluster = self.cluster
            ) if not kwargs.get("mount", None) else kwargs.get("mount"),
            command = "/bin/sh",
            args = '-c,curl -oL {} {}'.format(self.file.name, self.file.url)
        )
        return sidecar

    # create pod template
    def pod_template_spec(self, *args, **kwargs):
        volume_mount = KubernetesVolumeMount.objects.create(
            title = self.name + "-vol",
            cluster = self.cluster
        )
        pod = KubernetesPodTemplate.objects.create(
            title = self.name,
            cluster = self.cluster,
            volume = self.vol(),
            primary_container = self.container_spec(mount=volume_mount),
            secondary_container = self.sidecar_spec(mount=volume_mount),
            restart_policy = "Always",
            labels = {"project": self.project.slug}
        )
        return pod

    # tie it up and deplioy
    def deploy(self):
        pod = self.pod_template_spec()
        deployment = KubernetesDeployment.objects.create(
            title = self.name,
            cluster = self.cluster,
            api_version = "apps/v1",
            kind = "Deployment",
            namespace = self.namespace.namespace.slug,
            labels = {"project": self.project.slug},
            selector = {"project": self.project.slug},
            pod_template = pod
        )
        self.definition = deployment.get_obj().to_dict()
        self.save()
        return deployment.deploy()