{ "cells": [ { "cell_type": "markdown", "id": "196d72c3", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Who am I?\n", "## Cesare Placanica" ] }, { "cell_type": "markdown", "id": "e0f0188a", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "## That was easy... :-)" ] }, { "cell_type": "markdown", "id": "f4aa1f90", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "* Telco engineer @ Red Hat\n", " * Formerly in Cisco Photonics for many years\n", "* Always worked in Telecommunication industry\n", " * Which is good since I dig big labs a lot!\n", "* Linux and Python addicted since ever.\n", "* Eventually, I'm trying to be an event organizer for PyMI\n", " * Pythonistas interviewer!" ] }, { "cell_type": "markdown", "id": "cfa7d1a6", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Thanks Python Biella Group for having me!" ] }, { "cell_type": "markdown", "id": "9e2be79b", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Agenda" ] }, { "cell_type": "markdown", "id": "5785a264", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "## What we will do" ] }, { "cell_type": "markdown", "id": "63cbea57", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "* Debunk Container (and Docker)\n", "* Why Kubernetes? What is his purpose?\n", "* Hopefully, install it and start play with it." ] }, { "cell_type": "markdown", "id": "017ad50f", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Poll Time!" ] }, { "cell_type": "markdown", "id": "e1db7274", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## The Poll is [here](https://www.menti.com/alohc38qh79q)" ] }, { "cell_type": "markdown", "id": "205016ae", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Kubernetes\n", "## What I learned in the last year." ] }, { "cell_type": "markdown", "id": "fdaf2efd", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# What Kubernetes is?" ] }, { "cell_type": "markdown", "id": "9aef7d0a", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "## Linux Day 2022\n", "Lorenzo Soligo [GitOps 101 - da dove veniamo, dove stiamo andando](https://github.com/unixMiB/events/blob/master/Linux%20Day%20Milano%202022/GitOps%20101%20-%20da%20dove%20veniamo%2C%20dove%20stiamo%20andando%20-%20Lorenzo%20Soligo%20-%20Giant%20Swarm.pdf)" ] }, { "cell_type": "markdown", "id": "8e3ee7fb", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Kubernetes is a ([Game](https://fabiensanglard.net/quakeSource/)) Loop!" ] }, { "cell_type": "markdown", "id": "bb448afd", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Are you nuts?" ] }, { "cell_type": "markdown", "id": "e7587e9e", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "## Let me write it, in Python of course" ] }, { "cell_type": "markdown", "id": "703d5466", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "```python\n", "while True:\n", " current_state = get_current_state()\n", " desidered_state = get_desidered_state()\n", " reconcile(current_state, desidered_state)\n", "```" ] }, { "cell_type": "markdown", "id": "5b9e881f", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "OK, this is a super high level description to the thing but can help to set the context about what Kubernetes is" ] }, { "cell_type": "markdown", "id": "ff54d327", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Somebody calls the simple loop above a reconciliation loop, a sort of pattern." ] }, { "cell_type": "markdown", "id": "dec987fc", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "This enables you to be \"declarative\", just state what you need from the system, not *how* reach a \"desidered\" condition." ] }, { "cell_type": "markdown", "id": "3848986f", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "And enable Kubernetes to be \"Intent based\": match the resources with users \"desire\"." ] }, { "cell_type": "markdown", "id": "d522e756", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Why Kubernetes happened?" ] }, { "cell_type": "markdown", "id": "ccede758", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "## The official history" ] }, { "cell_type": "markdown", "id": "51d66df7", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "* The Kubernetes Documentary, [part 1](https://www.youtube.com/watch?v=BE77h7dmoQU&t=4s) and [part 2](https://www.youtube.com/watch?v=318elIq37PE)" ] }, { "cell_type": "markdown", "id": "71eb612f", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# The path to Kubernetes, what I think?" ] }, { "cell_type": "markdown", "id": "15a50cd8", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "New ideas is Software Engineering and Information Technology." ] }, { "cell_type": "markdown", "id": "32e1ff87", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "New ways of working." ] }, { "cell_type": "markdown", "id": "6616faa5", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Internet, hardware disaggregation, virtualization." ] }, { "cell_type": "markdown", "id": "469b96e5", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Software Engineering" ] }, { "cell_type": "markdown", "id": "7a3b7508", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## Clean Architecture" ] }, { "cell_type": "markdown", "id": "81fb2445", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Decouple and isolate business logic from \"infrastructural\" stuff." ] }, { "cell_type": "markdown", "id": "ae60428f", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "[Entities, Use cases, Repositories](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html)." ] }, { "cell_type": "markdown", "id": "653f7413", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Use of \"Dependency Inversion\" for enabling pluggability." ] }, { "cell_type": "markdown", "id": "2732e161", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "[Synergy with TDD](https://www.amazon.com/Growing-Object-Oriented-Software-Guided-Tests/dp/0321503627)." ] }, { "cell_type": "markdown", "id": "650a016e", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## Domain Driven Design" ] }, { "cell_type": "markdown", "id": "6ea33b51", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "A thing can have multiple contexts ([bounded contexts](https://martinfowler.com/bliki/BoundedContext.html)), or multiple point of view." ] }, { "cell_type": "markdown", "id": "9b7ce596", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "For example a \"Customer\" in a CRM can have some attributes relevant for the \"Sales\" department, but not so much for \"Support\" department." ] }, { "cell_type": "markdown", "id": "9a89a15b", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "A complex application can have many business logic." ] }, { "cell_type": "markdown", "id": "a84580b7", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## Microservices" ] }, { "cell_type": "markdown", "id": "ca06381d", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Break the monolith to enable horizontal scaling." ] }, { "cell_type": "markdown", "id": "044e4e56", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "\"Sales\" and \"Support\" can be separated and talk via an interface." ] }, { "cell_type": "markdown", "id": "29a8edca", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "\"Sales\" and \"Support\" can be developed by different teams." ] }, { "cell_type": "markdown", "id": "b64ed2e3", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "The application deployment is part of the application and should be easy. [The Twelve-Factor App](https://12factor.net/)." ] }, { "cell_type": "markdown", "id": "a468daa8", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## API centricity" ] }, { "cell_type": "markdown", "id": "3cfafbad", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Migration from in memory interfaces to Web / REST Application Programming Interface." ] }, { "cell_type": "markdown", "id": "94f2c8ab", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Concept of \"Resource\"." ] }, { "cell_type": "markdown", "id": "1c0f38af", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Concept of \"Single Source of Truth\"." ] }, { "cell_type": "markdown", "id": "060978ff", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# New ways of working" ] }, { "cell_type": "markdown", "id": "fcac44b8", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## Agile" ] }, { "cell_type": "markdown", "id": "067c8115", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Too much to say. I'll stop here. Just a mention for [Team Topologies](https://teamtopologies.com/) (2019).\n", "Build teams around projects and not in functional silos." ] }, { "cell_type": "markdown", "id": "a51333ce", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## Devops Movement" ] }, { "cell_type": "markdown", "id": "39a0f939", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Infrastructure as code." ] }, { "cell_type": "markdown", "id": "4cdbebf4", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Automation." ] }, { "cell_type": "markdown", "id": "e5d3fb5e", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "[Infrastructure as a service (IaaS), Platform as a Service (PaaS), Software as a Service (SaaS)](https://www.redhat.com/en/topics/cloud-computing/iaas-vs-paas-vs-saas)" ] }, { "cell_type": "markdown", "id": "2bbb2465", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Cloud Computing." ] }, { "cell_type": "markdown", "id": "bbce2379", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## Site Reliability Engineering" ] }, { "cell_type": "markdown", "id": "acc892b0", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Distributed Systems is hard. Many things can go wrong, see [Designing Data-Intensive Applications](https://www.oreilly.com/library/view/designing-data-intensive-applications/9781491903063/) chapter 8." ] }, { "cell_type": "markdown", "id": "306888cb", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Distributed System are built upon cheap but unreliable components. " ] }, { "cell_type": "markdown", "id": "44a23e71", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Write a platform where lessons learned while implementing distributed system become code that can help to operate and monitor a system." ] }, { "cell_type": "markdown", "id": "06b58dae", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Possibility to plug-in or extend the resources under control." ] }, { "cell_type": "markdown", "id": "58439aab", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# What's under the hood?" ] }, { "cell_type": "markdown", "id": "6b14ecf4", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "What is the techie stuff that made Kubernetes even possible?" ] }, { "cell_type": "markdown", "id": "2960226d", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# It started with..." ] }, { "cell_type": "markdown", "id": "50296622", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "## Virtual machines" ] }, { "cell_type": "markdown", "id": "9b781aa1", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "* Hardware disaggregation\n", "* Slice and dice servers\n", "* HW becames software" ] }, { "cell_type": "markdown", "id": "a920b8e4", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Docker" ] }, { "cell_type": "markdown", "id": "4963186a", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "## Containers" ] }, { "cell_type": "markdown", "id": "b15cd229", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Operative systems capabilities to isolate Resources." ] }, { "cell_type": "markdown", "id": "e292d464", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Are containers Linux?" ] }, { "cell_type": "markdown", "id": "5b23aa46", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "## Almost" ] }, { "cell_type": "markdown", "id": "69001b41", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "* [Just debunk them and look under the hood!](https://linuxera.org/containers-under-the-hood/)\n", "* Which Linux tecnologies make containers possible?" ] }, { "cell_type": "markdown", "id": "19638748", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Linux Kernel stuff that enables containerization." ] }, { "cell_type": "markdown", "id": "bbc7c3d8", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "* Rootfs - Containers's file system." ] }, { "cell_type": "markdown", "id": "03a9ca3a", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "* chroot - change a root directory of a process, first step for isolation." ] }, { "cell_type": "markdown", "id": "bc50cb5b", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "* Linux namespace, or to be honest, namespaces!" ] }, { "cell_type": "markdown", "id": "d7ddc531", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Once upon a time under /proc/PID_N/ns in the [Unshare](https://man7.org/linux/man-pages/man2/unshare.2.html) Land..." ] }, { "cell_type": "markdown", "id": "6eb106be", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "|Namespace | Isolates|\n", "|----------|---------|\n", "|Cgroup | Cgroup root directory|\n", "|IPC | System V IPC, POSIX message queues|\n", "|Network | Network devices, stacks, prots, etc.\n", "|Mount | Mount points|\n", "|PID |Process IDs|\n", "|Time | Boot and monotonic clocks|\n", "|User | User and Group IDs|\n", "|UTS | Hostname and NIS domain name|" ] }, { "cell_type": "markdown", "id": "b96ee082", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "Docker automated all this and added a specific way to build images and handle process communication, but we can build our \"containers\" just with Linux." ] }, { "cell_type": "markdown", "id": "cdaf2167", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Crossing fingers..." ] }, { "cell_type": "markdown", "id": "c8586bed", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "## Demotime! Containers under the hood." ] }, { "cell_type": "markdown", "id": "971a0073", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Closing toughts\n", "\n", "Tools like Podman or Docker make running containers easy for everyone by abstracting the different Linux technologies used under the hood from the user." ] }, { "cell_type": "markdown", "id": "4c0c9baa", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "Anyway these tools are doing more than what we showed in the previous demo.\n", "\n", "* They provide a truly isolated environments via Network Namespaces\n", "* They provide a way for building container images (Dockerfile)\n", "* They provide a specification to create, run and distribute images to the Open Container Initiative [OCI](https://github.com/opencontainers)\n", "* In particular Docker donated to OCI the reference implementation of the runtime-spec, *runc*" ] }, { "cell_type": "markdown", "id": "ff4a6098", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# How isolated Container can communicate?" ] }, { "cell_type": "markdown", "id": "205b1e97", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "## Enter Linux Kernel Namespaces, and Linux Kernel Networking." ] }, { "cell_type": "markdown", "id": "1d33384d", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "Linux Networking capabilities:\n", "* Interfaces\n", " * Physical\n", " * Virtual (Using Network Namespaces)\n", "* Routing Tables\n", "* Firewall / IPTables (Netfilter command)\n", "* A bunch of networking commands to configure the network stack that use the \"net\" Namespaces. " ] }, { "cell_type": "markdown", "id": "cf6d60c4", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Crossing fingers!" ] }, { "cell_type": "markdown", "id": "8f61f615", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "## Almost Demotime! Linux Networking " ] }, { "cell_type": "markdown", "id": "729d475b", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "This time I will draw something with https://excalidraw.com/" ] }, { "cell_type": "markdown", "id": "784921ce", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "For reference look at these videos:\n", "* [KodeKloud](https://www.youtube.com/watch?v=j_UUnlVC2Ss)\n", "* [Cisco's net academy](https://developer.cisco.com/netdevops/live/#s02t13)" ] }, { "cell_type": "markdown", "id": "61b72deb", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# So, you said debunk Docker?" ] }, { "cell_type": "markdown", "id": "ef2ee71e", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## What if I tell you...?" ] }, { "cell_type": "markdown", "id": "b7434327", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "That our v-net-0 Linux Bridge it's docker0?" ] }, { "cell_type": "markdown", "id": "f9df7b84", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "* Docker uses a Linux Bridge: docker0 for host networking, by default!\n", "* It uses netns to truly isolate coontainers.\n", "* And uses cgroup for resorce limitation." ] }, { "cell_type": "markdown", "id": "beb44c4a", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "Let us see another sketch on https://excalidraw.com/" ] }, { "cell_type": "markdown", "id": "a6077f3d", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "For Container to Container communication, Docker can expose a service to the host, or to other containers by mapping a port. But we have to be explicit and tell to do so:\n", "\n", "```shell\n", "docker run --name nginx -p 8080:80 ngnix\n", "```\n", "\n", "The inside port 80 is exposed as 8080 to the host, and to other containers" ] }, { "cell_type": "markdown", "id": "54ee72c0", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "Docker has other ways to handle the host network.\n", "* Host Network: no netns isolation, the container shares host's interface and IP.\n", "* Custom bridge Network\n", "* Container-defined network\n", "* No network." ] }, { "cell_type": "markdown", "id": "237be080", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Custom bridge\n", "In custom bridge mode, more container can share the same netns, this means they can communicate with localhost:port, so you can have a web API app container and a database container on a custom bridge, and you can expose just the API port (security is enhanced).\n", "```shell\n", "docker network create mynetwork\n", "docker run -it --rm --name=container-a --network=mynetwork busybox /bin/sh\n", "docker run -it --rm --name=container-b --network=mynetwork busybox /bin/sh\n", "```" ] }, { "cell_type": "markdown", "id": "3cdabc41", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Container defined Network\n", "This is a special case of custom networking where another container joins the network of another container, same here, the containers are on the same netns. **This is similar to how a Pod works on Kubernetes**.\n", "```shell\n", "docker run -it --rm --name=container-a busybox /bin/sh\n", "docker run -it --rm --name=container-b --network=container:container-a busybox /bin/sh\n", "```" ] }, { "cell_type": "markdown", "id": "e56c0c33", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# No network\n", "```shell\n", "docker run --net=none --name busybox busybox ip a\n", "```" ] }, { "cell_type": "markdown", "id": "e4b411de", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Docker with multiple hosts" ] }, { "cell_type": "markdown", "id": "d8872379", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Cross-host networking usually uses an overlay network, which builds a mesh between hosts and employs a large\n", "block of IP addresses within that mesh.\n", "**The overlay network functionality built into Docker is called Swarm**.\n", "When you connect a host to a swarm, the Docker engine on each host handles communication and routing between the hosts." ] }, { "cell_type": "markdown", "id": "f0023b97", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# So far so good, are going to tell us about Kubernetes?" ] }, { "cell_type": "markdown", "id": "39363725", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "OK, I said Docker donated **runc** to the Open Container Initiative, and donated the runtime and image specification, then what happened?" ] }, { "cell_type": "markdown", "id": "85d4479f", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "The truth is that Kubernetes is made of multiple projects!\n", "Under the Linux Foundation started a specification work that produced\n", "\n", "* The [Container Runtime Interface](https://kubernetes.io/docs/concepts/architecture/cri/#:~:text=The%20Container%20Runtime%20Interface%20(CRI,components%20kubelet%20and%20container%20runtime) that teels how containers are launched by kubelet (more below).\n", "* And the [Container Network Interface](https://github.com/containernetworking/cni), an api for networking plugins." ] }, { "cell_type": "markdown", "id": "f8404a9e", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "Did I spoke about pluggability at the beginning of this thing? Here is the result, we have two CRI reference implementations:\n", "* [Containerd](https://github.com/containerd)\n", "* [CRI-O](https://cri-o.io/#:~:text=What%20is%20CRI%2DO%3F,as%20the%20runtime%20for%20kubernetes)" ] }, { "cell_type": "markdown", "id": "67db1126", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Both of them call **runc** (or some sort of fork of it) to launch containers." ] }, { "cell_type": "markdown", "id": "0793b178", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "**But why the CNI?** Because people realized that container networking implemented in: the Linux Kernel Network Namespaces, Docker, rkt, Mesos, Kubernetes and bla bla, everybody do the same things:\n", "* Create a Network Namespace\n", "* Create Bridge Network/Interface\n", "* Create VETH pairs (Pipe, Virtual Cable)\n", "* Attach veth to Namespace\n", "* Attach other veth to bridge\n", "* Assign IP addresses\n", "* Bring up interfaces\n", "* Enable NAT - IP Masquerade\n", "\n", "All the stuff needed for building the [Kubernetes Network Model](https://kubernetes.io/docs/concepts/services-networking/#the-kubernetes-network-model)." ] }, { "cell_type": "markdown", "id": "1e43a739", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "So they: Linux Foundation and Kubernetes, created this application interface, but as I told ya this enabled pluggabilty, and so we have tons of CNI compliant network plugins, using different network protocols in some cases." ] }, { "cell_type": "markdown", "id": "89339cd3", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Ovelay Network, a dumb definition. It's often used in network plugins.\n", "A logical network built on top of a physical one. In practice is implemented by encapsulate an \"inner\" IP into an \"outer\" IP. A trivial overlay is IP-over-IP overlay. Real life examples: VxLAN, IPSec, VPN." ] }, { "cell_type": "markdown", "id": "1fb5d398", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "* Flannel (Overlay layer 3 network using VxLAN or IPSec)\n", "* Calico (BGP, can fallback to overlay Network)\n", "* Multus (can expose many interfaces to a Container)\n", "* Cilium ([eBPF](https://ebpf.io/) the new gig in the Linux Kernel)\n", "* [The full list](https://kubernetes.io/docs/concepts/cluster-administration/addons/) (???)" ] }, { "cell_type": "markdown", "id": "63c218a9", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Part 2" ] }, { "cell_type": "markdown", "id": "5873d398", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## Agenda\n", "\n", "* The Kubernetes Architecture.\n", "* The Kubernetes Purpose.\n", "* Build a cluster example.\n", "* The Kubernetes Resources (Pod, Deployments etc.).\n", "* Doing some demos along the way, hopefully.\n" ] }, { "cell_type": "markdown", "id": "84c1eef3", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Kubernetes architecture, an very light overview... hopefully" ] }, { "cell_type": "markdown", "id": "49adf3a3", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Bret Fisher is better than me, we seat on Giants shoulders!\n", "* [Here it is](https://slides.kubernetesmastery.com/#74)!" ] }, { "cell_type": "markdown", "id": "dee0665d", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "* [A better sketch](https://slides.kubernetesmastery.com/#80)!\n", "* [Official Docs](https://kubernetes.io/it/docs/concepts/overview/components/)." ] }, { "cell_type": "markdown", "id": "5164d9d5", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# What the advantages over Docker are? My 0.01." ] }, { "cell_type": "markdown", "id": "ec69ea7f", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "* Kubernetes came out many lessons learned by people who actually built a lot of distributed system.\n", "* It's made to build computer clusters and have a standard way to deal with them.\n", "* Has the \"single source of truth for the cluster\", the etcd database, you can recovery from crashes by doing backups.\n", "* Is API centric.\n", "* **It's declarative!**\n", "* It's extendable using the [Custom Resource Definition](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/)\n", "* Even the loop is extendable, using the [Operator Pattern](https://kubernetes.io/docs/concepts/extend-kubernetes/operator/), you can add custom maintenance automation scripts for your application." ] }, { "cell_type": "markdown", "id": "2f5c4ffc", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# What are the drawbacks? My second 0.01." ] }, { "cell_type": "markdown", "id": "b2fa147a", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Since it's an aggregate of open source projects [it's not simple to install it](https://www.youtube.com/watch?v=uUupRagM7m0&list=PL2We04F3Y_41jYdadX55fdJplDvgNGENo). Sometimes one of these projects break each other." ] }, { "cell_type": "markdown", "id": "e6b30ccf", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "This is true for Vanilla's Kubernetes. It's very much the same as Linux, but, as Linux you can choose a \"Kubernetes Distribution\" from a Linux provider that developed \"installers\" for you to simplify the installation, or look at managed versions From a Cloud provider like EKS, GCP, AKS." ] }, { "cell_type": "markdown", "id": "e4bf0535", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Kubernetes purpose... again" ] }, { "cell_type": "markdown", "id": "d9e55944", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "* Kubernetes networking builds on top of the Docker and Netfilter constructs to tie multiple components together into applications.\n", "* Kubernetes uses Docker just low level stuff: processes and volumes.\n", "* Kubernetes operates at higher level providing orchestration services such as self-healing, scaling, updates and load balancing." ] }, { "cell_type": "markdown", "id": "80e63b08", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Crossing fingers... try to build a Vanilla cluster..." ] }, { "cell_type": "markdown", "id": "e5a4714c", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "* [A Funny picture](https://slides.kubernetesmastery.com/#119) of a \"Cluster for learning\".\n", "* [Some ways to do this](https://slides.kubernetesmastery.com/#102)\n", "* My loved preferred way [Just me and open source](https://github.com/justmeandopensource/kubernetes), it's a minimal Vanilla Installation.\n", "* [Kubernetes the Hard Way](https://github.com/kelseyhightower/kubernetes-the-hard-way). Requires Google Cloud.\n", "* [k8s-the-ansible-way](https://github.com/prometherion/k8s-the-ansible-way). Does not requires Google Cloud, but 2018.\n", "* minikube (at the moment on a Mac is possible to use Podman)." ] }, { "cell_type": "markdown", "id": "9b0cd253", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Issues\n", "\n", "At the time of this writing.\n", "\n", "* Ventura broke VirtualBox 6, hence upgraded to 7\n", "* VirtualBox 7, due to Ventura, deprecated \"host-only\", hence minikube + VirtualBox is broken.\n", "* Containerd version 1.5.9 broke kubeadm 1.24" ] }, { "cell_type": "markdown", "id": "3ee4d605", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "# Workarounds\n", "* Use minikube with the experimental Podman driver\n", "* For just me and opensounce / Vanilla Kubernetes 1.24, for Ubuntu 22.04 there's a [fix](https://serverfault.com/questions/1118051/failed-to-run-kubelet-validate-service-connection-cri-v1-runtime-api-is-not-im), I used the #2." ] }, { "cell_type": "markdown", "id": "9c3a00da", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Let's do a quick code walk-through...\n", "\n", "https://github.com/keobox/kubernetes/tree/fix-containerd-issue" ] }, { "cell_type": "markdown", "id": "7630f25c", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Start the Cluster\n", "\n", "```shell\n", "cd vagrant-provisioning\n", "vagrant up\n", "```\n", "\n", "Note: I started browsing this [Kubernetes Books](https://github.com/book-of-kubernetes/examples) just after the first meeting and seems nice 'cause is following the same \"white box\" approach I'm following.\n", "The nice thing that the Cluster built with this book have, althought is minimal, is an HA cluster:\n", "* There are 3 nodes with the control plane running: the minimum for HA, and these have both the master and worker roles.\n", "* There's just one worker node.\n", "\n", "Ours Cluster is not a HA Cluster." ] }, { "cell_type": "markdown", "id": "963291b8", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Exploring the cluster\n", "\n", "```shell\n", "cd vagrant-provisioning\n", "vagrant up\n", "vagrant ssh kmaster\n", "mkdir -p $HOME/.kube\n", "sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config\n", "sudo chown $(id -u):$(id -g) $HOME/.kube/config\n", "sudo systemctl status containerd\n", "sudo systemctl status kubelet\n", "kubectl get nodes\n", "```" ] }, { "cell_type": "markdown", "id": "98f363ad", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Hint: grab kubeconfig file\n", "To use **kubectl** on the host machine, hence outside the cluster, you can take it from the cluster.\n", "```shell\n", "mkdir -p ~/.kube\n", "scp -P 2222 -i .vagrant/machines/kmaster/virtualbox/private_key vagrant@127.0.0.1:.kube/config ~/.kube/playground-config\n", "export KUBECONFIG=~/.kube/playground-config\n", "```" ] }, { "cell_type": "markdown", "id": "137abfd6", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Demo\n", "```shell\n", "kubectl get nodes\n", "kubecrl get nodes -o wide\n", "```" ] }, { "cell_type": "markdown", "id": "ec82cf2a", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Adding a web console\n", "## Please please please do not this in production\n", "\n", "Is possible to add an **INSECURE** Kubernetes Web console in just one line:\n", "\n", "```shell\n", "kubectl apply -f https://k8smastery.com/insecure-dashboard.yaml\n", "```\n", "\n", "This installs a NodePort service (more on this below), and is possible to connect like this:\n", "\n", "```shell\n", "kubectl get svc dashboard\n", "```\n", "\n", "Note down the node port and connect with a browser to http://172.16.16.100:3XXXXX and press \"skip\"." ] }, { "cell_type": "markdown", "id": "481f7d53", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Kubernetes Resources" ] }, { "cell_type": "markdown", "id": "a2e25466", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Pods" ] }, { "cell_type": "markdown", "id": "87714ae4", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "* A Pod is the smallest unit of deployment in a Kubernetes cluster.\n", "* Pod encapsulates one or more containers. Containers in the same Pod always run on the same host. They share resources such as the network namespace and storage.\n", "* **Each Pod has a routable IP address assigned to it**, not to the containers running within it. Having a shared network space for all containers means that the containers inside **can communicate with one another over the localhost address**, a feature not present in traditional Docker networking.\n", "* Every Pod in the Cluster is reachable via an IP Address (But a Network Policy can change this).\n", "* All this is explained in the [Kubernetes Network Model](https://kubernetes.io/docs/concepts/cluster-administration/networking/#the-kubernetes-network-model)." ] }, { "cell_type": "markdown", "id": "3f22c027", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Demo!\n", "```shell\n", "kubectl run web --image=nginx\n", "kubectl get pods -o wide\n", "kubectl logs nginx\n", "kubectl delete pod web\n", "```" ] }, { "cell_type": "markdown", "id": "0fcb8cc8", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Workloads" ] }, { "cell_type": "markdown", "id": "2b8f6d71", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "The Kubernetes engineers recognized that a Cluster may have many use case, for this reason they created some abstractios to address this use cases, so there are some **kinds** of workloads." ] }, { "cell_type": "markdown", "id": "735cbebd", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## ReplicaSet\n", "The ReplicaSet maintains the desired number of copies of a Pod running within the cluster. If a Pod or the host on which it’s running fails, Kubernetes launches a replacement." ] }, { "cell_type": "markdown", "id": "fdb8879d", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## Deployment\n", "A Deployment manages a ReplicaSet." ] }, { "cell_type": "markdown", "id": "43510328", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "```shell\n", "kubectl create deployment web --image=nginx --replicas=3\n", "kubectl get all -n default\n", "```" ] }, { "cell_type": "markdown", "id": "43b86181", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "What happened? A [Walkthrought](https://slides.kubernetesmastery.com/#232)! The \"Loop\" in action!" ] }, { "cell_type": "markdown", "id": "75815d84", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Demo\n", "* Where are the pod?\n", "```shell\n", "kubectl get pods -o wide\n", "```\n", "* Self-healing\n", "```shell\n", "kubectl delete pod web-xxx-yyy && kubectl get pods -w\n", "```\n", "* Scale up\n", "```shell\n", "kubectl scale deployment web --replicas=4 && kubectl get pods -w\n", "```\n", "* Scale down\n", "```shell\n", "kubectl scale deployment web --replicas=2 && kubectl get pods -w\n", "```" ] }, { "cell_type": "markdown", "id": "645a5d5c", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Demo of an update\n", "\n", "```shell\n", "kubectl get deployment web -o yaml > web.yaml\n", "```\n", "\n", "The **ReplicaSet** managed by the **Deployment** has 2 important parameters in the **spec** for a **RollingUpdate**: **maxSurge** which is the percentage of the pods launched on a new version and **maxUnavailable** which is the percentage of pods deleted in the old version." ] }, { "cell_type": "markdown", "id": "b12b39ca", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Suppose to do an update to nginx version 1.23 but that does not exists eh eh.\n", "\n", "Check the image name in a pod\n", "```shell\n", "kubectl describe pod web-xxx-yyy\n", "```\n", "try the update\n", "```shell\n", "kubectl scale deployment web --replicas=10\n", "kubectl set image deployments/web nginx==nginx:1.23 && kubectl get replicasets -w\n", "kubectl rollout status deploy web\n", "kubectl rollout undo deploy web\n", "```" ] }, { "cell_type": "markdown", "id": "ee1ad37b", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## DaemonSet\n", "\n", "A DaemonSet runs one copy of the Pod on each node in the Kubernetes cluster. This workload model provides the flexibility to run daemon processes such as log management, monitoring, storage providers, or network providers that handle Pod networking for the cluster." ] }, { "cell_type": "markdown", "id": "024dda89", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## Demo\n", "Calico, our CNI implementation is implemented as a DaemonSet. This means we can see 1 daemon per node, hence 3 Pods.\n", "\n", "```shell\n", "kubectl get daemonset -n kube-system calico-node\n", "kubectl get pods -n kube-system -o wide | grep calico-node\n", "```" ] }, { "cell_type": "markdown", "id": "0d1444f7", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## StatefulSet\n", "A StatefulSet controller ensures that the **Pods it manages have durable storage and persistent identity**. StatefulSets are appropriate for situations where Pods have a similar definition but need a unique identity, ordered deployment and scaling, and storage that persists across Pods rescheduling." ] }, { "cell_type": "markdown", "id": "88eddc40", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Since StatefulSet deal with Storage they depend of the presence of an implementation of the CSI, Container Storage Interface, installed in the cluster. The main resources to deal with storage are **PersistentVolumeClaim** and **PersistentVolume**." ] }, { "cell_type": "markdown", "id": "118e3a6c", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Difference respect to normal (stateless) deployments\n", "\n", "* Is necessary to define a **serviceName** for creating a DNS entry for every Pod in the StatefulSet.\n", "* Is necessary to request a persistent volume for the containers." ] }, { "cell_type": "markdown", "id": "64048428", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## Demo\n", "\n", "### Prerequisites\n", "Required packages installation on nodes plus longhorn installation.\n", "\n", "\n", "Patch servers:\n", "```shell\n", "sudo apt install -y nfs-common\n", "sudo systemctl enable --now iscsid\n", "```\n", "\n", "Install long horn in the cluster\n", "```shell\n", "curl -LO https://raw.githubusercontent.com/longhorn/longhorn/v1.2.4/deploy/longhorn.yaml\n", "kubectl apply -f longhorn.yaml\n", "```" ] }, { "cell_type": "markdown", "id": "11b45e79", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "[Code used: Book of Kubernetes](https://github.com/book-of-kubernetes/examples/blob/main/chapter-07/files/sleep-set.yaml)\n", "\n", "```shell\n", "vagrant ssh kmaster\n", "cd examples/chapter-07/files\n", "cat sleep-set.yaml\n", "kubectl apply -f sleep-set.yaml\n", "kubectl get statefulset\n", "kubectl get service\n", "```" ] }, { "cell_type": "markdown", "id": "9782f615", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "```shell\n", "kubectl exec sleep-0 -- /bin/sh -c 'hostname > /storagedir/myhost'\n", "kubectl exec sleep-0 -- /bin/cat /storagedir/myhost\n", "\n", "kubectl exec sleep-1 -- /bin/sh -c 'hostname > /storagedir/myhost'\n", "kubectl exec sleep-1 -- /bin/cat /storagedir/myhost\n", "```" ] }, { "cell_type": "markdown", "id": "537c29ff", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "Now if I delete a Pod the replacement will take the same storage\n", "```shell\n", "kubectl delete pod sleep-0\n", "kubectl get pods -w\n", "\n", "kubectl exec sleep-0 -- /bin/cat /storagedir/myhost\n", "```" ] }, { "cell_type": "markdown", "id": "4646b564", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Clean up\n", "```shell\n", "vagrant ssh kmaster\n", "kubectl delete -f examples/chapter-07/files/sleep-set.yaml\n", "```" ] }, { "cell_type": "markdown", "id": "33b4758f", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Other workloads\n", "\n", "There are other simpler workloads that Kubernetes supports like **Job** and **CronJob**.\n", "Some examples [here](https://github.com/book-of-kubernetes/examples/tree/main/chapter-07/files)" ] }, { "cell_type": "markdown", "id": "f9e36dc2", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Services" ] }, { "cell_type": "markdown", "id": "4d5d5c1e", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "* **Pods are ephemeral**. The services that they provide may be critical, but because Kubernetes can terminate Pods at any time, they are unreliable endpoints for direct communication.\n", "* Kubernetes offers the Service resource, which provides a stable IP address and **balances traffic** across all of the Pods behind it. This abstraction brings stability and a reliable mechanism for communication between microservices." ] }, { "cell_type": "markdown", "id": "67325c64", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "* Although Services solve this by providing a stable address in front of a group of Pods, consumers of the Service still want to avoid using an IP address.\n", "* Kubernetes solves this by using DNS for service discovery.\n", "* That's why there's the presence of **CoreDNS** pods inside the cluster." ] }, { "cell_type": "markdown", "id": "66fa65d5", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "* The default internal domain name for a cluster is cluster.local. When you create a Service, it assembles a subdomain of **namespace.svc.cluster.local** (where namespace is the namespace in which the service is running) and sets its name as the hostname.\n", "* For example: **nginx.default.svc.cluster.local**. If the service’s IP changes, the hostname remains the same." ] }, { "cell_type": "markdown", "id": "490821e1", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "* The **kube-proxy** The kube-proxy daemon that runs on all nodes of the cluster allows the Service to map traffic from one port to another. The kube-proxy daemon that runs on all nodes of the cluster allows the Service to map traffic from one port to another. This component configures the Netfilter rules on all of the nodes according to the Service’s definition in the API server.\n", "* Basically **is the guy who maps ports with IPTables** like we show earlier when we spoke about Network Namespaces." ] }, { "cell_type": "markdown", "id": "0c8340ed", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Type of Services" ] }, { "cell_type": "markdown", "id": "8a9ab8ca", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## ClusterIP\n", "\n", "This type of Service is the default and exists on an IP that is only visible within the cluster. It enables cluster resources to reach one another via a known address while maintaining the security boundaries of the cluster itself." ] }, { "cell_type": "markdown", "id": "07b312af", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## NodePort\n", "\n", "* A Service of type NodePort exposes the same port on every node of the cluster.\n", "* This type of Service automatically creates a ClusterIP Service as its target, and the ClusterIP Service routes traffic to the Pods.\n", "* External load balancers frequently use NodePort services. They receive traffic for a specific site or address and forward it to the cluster on that specific port." ] }, { "cell_type": "markdown", "id": "01ceeefe", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## LoadBalancer\n", "* When working with a cloud provider for whom support exists within Kubernetes, a Service of type LoadBalancer creates a load balancer in that provider’s infrastructure. The exact details of how this happens differ between providers.\n", "* There is a limitation for Layer 4 Cloud load balancers: 1 load balancer per service, hence high costs.\n", "* It's quite painful create a load balancer outside a cloud provider, but is doable using an [Ingress Controller](https://kubernetes.github.io/ingress-nginx/deploy/baremetal/). Alternatives: kube-vip, metal lb." ] }, { "cell_type": "markdown", "id": "0aa5d9aa", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Demo of a NodePort\n", "**Pingolo!**\n", "\n", "A Show me the code moment, then...\n", "\n", "```shell\n", "cd ~/src/pingolo\n", "kubectl apply -f kubernetes/deploy.yaml\n", "kubectl get all -n pingolo\n", "# try to connect to http://172.16.16.100\n", "kubectl logs -n pingolo -l usecase=ping-from-pod\n", "# try to ping something outside to cluster\n", "kubectl apply -f shpod.yaml\n", "kubectl get pods -n shpod\n", "# try to ping the shpod\n", "```" ] }, { "cell_type": "markdown", "id": "2a77ac56", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Ingress Resource and Ingress Controller\n", "A way for exposing applications outside the Cluster.\n", "\n", "* An [Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/) is a Kubernetes resource for configuring a HTTP Load Balancer, basically it defines HTTP routes\n", " * Host-based routing. For example, routing requests with the host header foo.example.com to one group of services and the host header bar.example.com to another group.\n", " * Path-based routing. For example, routing requests with the URI that starts with /serviceA to service A and requests with the URI that starts with /serviceB to service B.\n", "* It's used also for SSL termination\n", "\n", "The Ingress Controller is an application that runs in a cluster and configures an HTTP load balancer according to Ingress resources." ] }, { "cell_type": "markdown", "id": "000e629a", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Demo for Ingress Controller\n", "From the kubernetes book. **NOT WORKING** on my Cluster at least for ports 80 and 443, cause I have to do tweaks on Calico I'm not able to, so that the load balancer can bind on port 80 and 443.\n", "\n", "```shell\n", "curl -Lo ingress-controller.yaml https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.1.1/deploy/static/provider/cloud/deploy.yaml\n", "\n", "cp examples/setup/roles/k8s/templates/ingress-patch.yaml.j2 ingress-patch.yaml\n", "\n", "kubectl apply -f ingress-controller.yaml\n", "kubectl patch -n ingress-nginx service/ingress-nginx-controller --patch-file ingress-patch.yaml\n", "```" ] }, { "cell_type": "markdown", "id": "403b1be9", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Final Thoughts" ] }, { "cell_type": "markdown", "id": "4a67ef2d", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Kubernetes distributions" ] }, { "cell_type": "markdown", "id": "827bdeb4", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "There are many Kubernetes distributions out there. All of them has \"opinions\".\n", "Their basic functions is to provide installer or applications to make Kubernetes installation less painful then the vanilla installation." ] }, { "cell_type": "markdown", "id": "6cf2239f", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "* Openshift\n", " * Has an all in approach, comes with a web console.\n", " * User Management and RBAC is not an option, is mandatory.\n", " * Has any easy way to expose web apps with Route.\n", " * Autoscale always on.\n", " * Monitoring always on (Prometheus).\n", " * Support applications builds and deployments even from github.\n", " * Can run in Cloud Providers." ] }, { "cell_type": "markdown", "id": "89311a56", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "* Microk8s\n", " * Starts minimal.\n", " * but is possible to add services on demand." ] }, { "cell_type": "markdown", "id": "69548a55", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Books and resources" ] }, { "cell_type": "markdown", "id": "85ca3799", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "* [Nigel Poulton's The Kubernetes Book](https://nigelpoulton.com/books/).\n", "* [Networking and Kubernetes A Layered Approach](https://www.oreilly.com/library/view/networking-and-kubernetes/9781492081647/).\n", "* [The Book of Kubernetes A Complete Guide to Container Orchestration](https://nostarch.com/book-kubernetes). Hands on!\n", "* [Kubernetes Cheatsheet](https://kubernetes.io/docs/reference/kubectl/cheatsheet/)" ] }, { "cell_type": "markdown", "id": "cc9904bc", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# We didn't talk about... a lot of things" ] }, { "cell_type": "markdown", "id": "fbe0df31", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "* [Healt checks](https://slides.kubernetesmastery.com/#556)\n", "* [ConfigMaps](https://kubernetes.io/docs/concepts/configuration/configmap/) & [Secrets](https://kubernetes.io/docs/concepts/configuration/secret/)\n", "* [Limits and Quotas](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/)\n", "* [Persistence Storage](https://kubernetes.io/docs/concepts/storage/)\n", "* [Custom Resources](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/)\n", "* [Operators](https://kubernetes.io/docs/concepts/extend-kubernetes/operator/)" ] } ], "metadata": { "celltoolbar": "Slideshow", "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.12" }, "rise": { "theme": "sky" } }, "nbformat": 4, "nbformat_minor": 5 }