Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Alice and the lost pod: practical guide to Kube...

Roksolana
February 13, 2021

Alice and the lost pod: practical guide to Kubernetes in Scala

"Following Alice’s adventure to the world of pods and higher-order functions. Now Alice is a professional Scala developer and over the years she has forgotten her trip to the world of pods and higher-order functions. But this time a new adventure found her. Alice needs to bring back the pod home using her knowledge of Scala. Will she be able to discover the link between Scala and Kubernetes and save her friend? You will find it out in this talk."
Presented at Scala Love in the City 2021 - virtually
ScalaCon 2021 - virtually

Roksolana

February 13, 2021
Tweet

More Decks by Roksolana

Other Decks in Technology

Transcript

  1. Roksolana Diachuk • Big Data Developer at Captify • Diversity

    & Inclusion ambassador for Captify Kyiv o ff ice • Women Who Code Kyiv Data Engineering Lead and Mentor • Speaker and traveller
  2. “Why these houses look like constructor details?” - asks Alice.

    “This is one of our interesting features. All of our objects constitute type system and they are immutable”
  3. Alice is a successful Scala developer working in a big

    city. Getting tired of work s h e d e c i d e d t o spend some time in the countryside in her uncle’s house.
  4. On one of the days Alice was walking in the

    forest around the house. It kept a lot of memories of childhood she held dear.
  5. cave@k8s % kubectl describe pv magic-db- p v Name: magic-db-pv

    Namespace: default StorageClass: hostpath Status: Running Volume: Labels: <none>
  6. “But how can I help you?” magic-db- cluster-0 You can

    use the power of your Scala knowledge to help me.
  7. Data model Object kinds List kinds Pods, ReplicationController ObjectResource Pod.Spec,

    ReplicationController.Status ListResource[Pod], ListResource[Node]
  8. val container = Container( name = “magic-link”, image = “magic-link:1.7.9”)

    val labels = “app" -> "magic-link" val template = Pod.Spec() .addContainer(container).addLabel(labels) k8s.create(Pod(“magic-link-pod”, template))
  9. apiVersion: v1 kind: Pod metadata: name: magic-link-pod labels: app: magic-link

    spec: containers: - name: magic-link image: magic-link:1.7.9
  10. val container = Container( name = “magic-link”, image = “magic-link:1.7.9”)

    val labels = “app" -> "magic-link" val template = Pod.Template.Spec .addContainer(container) .addLabel(labels)
  11. val container = Container( name = “magic-link”, image = “magic-link:1.8”)

    container.exposePort(80) val deployment = Deployment(“magic-link“) .withReplicas(3) .withTemplate(template) val created = k8s.create(deployment)
  12. created.recoverWith { case ex: K8SException if (ex.status.code.contains(409)) => { println("Deployment

    object already exists”) (k8s get[Deployment] deployment.name) fl atMap { currentDep => println("retrieved latest deployment, now updating”)
 val updated = deployment.withResourceVersion( currentDep.metadata.resourceVersion) k8s update updated> }
  13. NAME READY STATUS AGE pod/magic-link-wjnr 1/1 Running 15s pod/magic-link-eh8f 1/1

    Running 11s pod/magic-link-eu2r 1/1 Running 7s magic-link- eu2r magic-link- eh8f magic-link- wjnr
  14. NAME READY STATUS AGE pod/magic-link-7wjr 1/1 Running 32s pod/magic-link-eh8f 1/1

    Running 28s pod/magic-link-eu2r 1/1 Running 23s pod/magic-link-uew 1/1 Running 12s pod/magic-link-omr8 1/1 Running 8s pod/magic-link-yt8p 1/1 Running 5s
  15. … pods.map { pod: Pod => val name = pod.name

    val ns = pod.namespace val phaseOpt = for { status <- pod.status phase <- status.phase } yield phase } …
  16. NAME NAMESPACE STATUS pod/magic-link-7wjr default Running pod/magic-link-eh8f default Running pod/magic-link-eu2r

    default Running pod/magic-link-uew default Running pod/magic-link-omr8 default Running pod/magic-link-yt8p default Running
  17. magic-svc: df-np: Is that really you? We thought we’ve lost

    you! magic-svc: It’s magic-db-cluster-0 df-np: Who’s that? Hello!
  18. “But I really don’t know what else I can build

    help you” magic-db- cluster-0
  19. But Alice, you can build anything you want magic-db- cluster-0

    “But I really don’t know what else I can build help you”
  20. “You’re a genius! And I know exactly what to build

    for you.” Something that will let me fly back home magic-db- cluster-0
  21. case class CustomResource[Sp, St] ( override val kind: String, override

    val apiVersion: String, override val metadata: String,
 spec: Sp,
 status: Option[St] extends ObjectResource { …
  22. … def withMetadata(metadata: ObjectMetadata) def withName(name: String) def withGenerateName(generateName: String)

    def withNamespace(namespace: String) def withLabels(labels: Tuple2[String, String]*) def withAnnotations(generateName: Tuple2[String, String]*) def withFinalizers(namespace: String*) def withStatus(status: St) }
  23. object CustomResource { def statusMethodEnabler[C <: CustomResource[_,_]] (implicit rd: ResourceDe

    fi nition[C]: HasStatusSubresource[C]) = { if (!rd.spec.subresources.map(_.status).isDe fi ned) throw new K8sException(Status(message = Some(“Status sub resource must be de fi ned”)))
 new HasStatusSubresource[C] {} } …
  24. val crd = CustomResourceDe fi nition( name = “launcher.io”, kind

    = “launcher”, scope = Scope.Cluster) implicit val system = ActorSystem() implicit val dispatcher = system.dispatcher val saved = saveCrd(crd)
  25. def saveCrd(crd: CustomResourceDe fi nition) = { k8s.create(crd).recoverWith { case

    notFound: K8sException if (notFound.status.code.contains(404)) => { println(“Unable to create CRD”) throw notFound } …
  26. case alreadyExists: K8sException if (alreadyExists.status.code.contains(404)) => { (k8s get[CustomResourceDe fi

    nition] crd.name) fl atMap { existing => val currentVersion = existing.metadata.resourceVersion val newMeta = crd.metadata.copy( resourceVersion = currentVersion) val updatedObj = crd.copy(metadata = newMeta) k8s update updatedObj> }
  27. Now Alice knew that her knowledge of Scala could help

    her to build a link between Scala and Kubernetes. And she could build anything she wanted!