Lets have a look: You will first notice we have split up starting the webconsole itself and running code on it. As a thank you, everyone, who subscribes will get a 50% discount on the book , drwxr-xr-x 6 alixedi staff 192B Jul 31 13:01 . kubectl - the CLI tool for Kubernetes lets us do just that. 4 - Create an object for our web application. * Debug mode: off So far we can only create a deployment in Kubernetes, delete it, or scale it. webconsole-5b559bf485-rtsk5 1/1 Running 0 8m35s, NAME READY STATUS RESTARTS AGE Namespace: default I will be sad if this doesnt turn out to be a self-parody for tech careers. Its running a VM on our machine essentially. resource it exposes. Example resource specifications include: webconsole 1/1 1 1 9s, NAME READY STATUS RESTARTS AGE Configure application resources This tutorial is squarely aimed at beginners and it is not very ambitious. edit Edit a resource on the server Step 1/3 : FROM python:alpine We will revisit this pretty soon. run Run a particular image on the cluster. kubectl patch pod valid-pod --type='json' -p='[{"op": "replace", "path": "/spec/containers/0/image", "value":"new (To be clear, I press the tab 2 times in the first row, this will give usually give me some suggestions in the python CLI). of your pods. Ok, lets try again, we are not running in the cluster, so maybe we should load the config somewhere else? Remember, pods will only live as long as they run on the same server. Kubernetes has your back. The only interesting thing here is that we are choosing not to use venv. For starters, we should just type kubectl in our terminal and see what that goes: Lots of interesting things under the ellipses but honestly, do we feel like reading beyond create? I promise. If only we could expose our application to the universe outside the cluster. [GCC 9.3.0] on linux explain Documentation of resources Kubernetes provides it out of the box. The metadata declares the same labels as the matchLabels in the selector, and the spec is something you would write for a pod. Action leads to Stack Overflow. Sometimes. The following little mini-application can build with the same docker file from the previous chapter: Ok, you got me there. When I started writing this in my head, I decided that I will not go into too many details about the why of Kubernetes. consisting of local port (for example 3306) that the proxy listens on, and A Label is a key-value pair that can be attached to any Kubernetes resource. The toast at the bottom of the sandwich takes whatever the function returns and passes it back to the client that hit the root of our web application. Sandboxes are a cool idea. On the other hand, having just written the chapter on Docker, half of which - to be honest - was expanding on why I feel uncomfortable in stopping short of putting down something on the why of Kubernetes. Here is a decent first go: Now wouldnt it be fun if we can get that beautiful Hello World back? kubectl expose rc nginx --port=80 --target-port=8000. Remember our setup? create Create a resource from a file or from stdin. Nothing like a bug to regulate those endorphins: Now, can you figure out whats happening here and why? Did you spot that in the last code snippet? We need to create a user which gives us enough access to do the operations we need. Try and follow along. -rw-r--r-- 1 alixedi staff 1300 Jul 31 13:01 activate.csh In the first step, we will capture the dependencies required by our web application. Downloading Jinja2-2.11.2-py2.py3-none-any.whl (125 kB) run Run a particular image on the cluster We wont build the front end, just the JSON API which would power it. Lets break it down: The command: kubectl create deployment webconsole just says we want to create a deployment with the name webconsole, we then provide some options like the image and a port number. * Environment: production created by clients and scheduled onto hosts. Too many books on this subject have too much theory, require you to get on AWS etc. Remember: you might want to use the docker daemon which is running inside minikube. What do we do with it? We split our API into 2 services because we had endpoints with drastic variances in load characteristics. As it turns out, there are the 2 types of services in Kubernetes that you should be aware of at this instant in time: The attentive reader might ask at this point: Why do we need a service for exposing our application inside the cluster?. bindings true Binding Looming in the shadows. If you are running a Linux machine, you can observe this like so: So while the Python virtual environment provides nice isolation within the Python universe, it still relies on being able to make a bunch of calls to operating system libraries (syscalls) that are not bundled inside the virtual environment. You can run many modules in Python by using the -m flag. The most popular one no less. Containers provide security. It could keep a list of pods belonging to a specific deployment, but what if one of them disappears. python alpine 872c3118ec53 2 days ago 42.7MB, The push refers to repository [docker.io/alixedi/hello], fa9b430b6d13: Pushing [==================================================>, 2e628e2d9dc4: Pushing [==================>, 26e08b3268b4: Pushing [==================================================>, 408e53c5e3b2: Waiting Ok, fair enough, some companies do this, and sometimes it is needed. Well done . Same story here. Also if no labels are specified, the new service will re-use the labels from the Not because of resume-driven development. Flask==1.1.2 One popular WHY is versions. There are two possible whys of Kubernetes. Like cattle and not like pets. For this case, the name of our file is hello.py so the name of Did I tell you that we will be using Python 3 in this book? patch Update field(s) of a resource using strategic merge patch webconsole-5b559bf485-6bm5j 0/1 Terminating 0 117s -rwxr-xr-x 1 alixedi staff 281 Jul 31 13:01 easy_install Once you are happy that the thing works, you can assign a production tag to it. COPY requirements.txt / This is just for us to cheat, and simplify the code . The examples in this book will use Flask. Back to the image. Running code on the created webconsole is fairly simple. Some of these opinions are informed by the difference in nature between a docker sandbox to a Python venv sandbox. We are about to feed that image into kubectl: It seems that we have succeeded in creating something called deployment.apps/webconsole. Downloading itsdangerous-1.1.0-py2.py3-none-any.whl (16 kB) webconsole-5b559bf485-rtsk5 1/1 Running 0 10m, NAME READY STATUS RESTARTS AGE -rwxr-xr-x 1 alixedi staff 263 Jul 31 13:01 pip Intermediate layers are squashed in the resulting image. Looks promising. It should be pretty simple and easy to follow. Virtual environments are cool because they let you install packages on per-project bases without polluting your global Python installation. Not only is it telling me what I am missing but it goes one step further and provides me with examples. Aliases: On top of that, the demand for our service had huge variances. Rest of the world for your web application would mean the internet. For instance: You might want to put our Hello World application in a code repository like GitHub. You can install and run it locally. You can request the logs from any pod with kubectl: We got a 403 Forbidden from the Kubernetes API. It bridges the service that has now been exposed to the Minikube VM with your localhost: We should try one more trick at this point. Standard naming convention dictates that we call this file Dockerfile. This includes the python binary, pip etc. drwxr-xr-x 9 alixedi staff 288B Jul 31 13:09 Flask-1.1.2.dist-info Lets step back and take stock of what we have right now. The function at line 18 will make it possible to start a webconsole. Lets deploy all this YAML, and cleanup the manually created job. But also I realise that we havent run the damned thing yet! Inside a VM. A very basic Dockerfile for our application would look like the following: 1 - Every docker container has a base image (More on images in the following paras). I have one last trick left up my sleeve. To do this, we will use the normal YAML manifests we have already seen before. Maybe to 8. Pods are the smallest deployable object in Kubernetes. deployment Create a deployment with the specified name. The abstraction would mean that the containers could ephemeral all they like and the rest of the cluster wouldnt care. Tear them apart to see how they work. Finally, we were 2 engineers in total. Its just a day that comes around every week. And this is why we should probably use the apply command, you just send the same document with (minor) changes over, and Kubernetes will make it happen. Python 3.7.4 (default, Oct 12 2019, 18:55:28) Lets continue, and try to create a job: Thats a lot better! get Display one or many resources Downloading Werkzeug-1.0.1-py2.py3-none-any.whl (298 kB) You know - try and run arbitrary Python code for ourselves? Sounds simple. While the Kubernetes API works with JSON, for use humans kubectl translates this to and from YAML (or a nice little table), as this is way easier to read & write. Break the COPY statement in your Dockerfile: And compare the layers with those of hello:v1. kubectl is now configured to use the "minikube" cluster and "default" namespace by default, kubectl controls the Kubernetes cluster manager. df20fa9351a1: Pull complete Removing intermediate container 9527747772b7, REPOSITORY TAG IMAGE ID CREATED SIZE, python alpine 872c3118ec53 2 days ago 42.7MB, REPOSITORY TAG IMAGE ID CREATED SIZE hello v1 1ddb10e93851 11 minutes ago 53.4MB Turns out we could. access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) Kubectl patch looks very complicated, and you dont even know what you are merging (probably some file). This is an actual picture of me from 2 years ago: We still havent figured out how to talk to our thing. Remember that old Dockerfile? Imagine a world where every time you release a new version of your app, you build an image and push it to an image store of sorts. The name in metadata is used to point to a single object: gimme that deployment! In a different terminal: I managed to write my excitement in the right window this time . In case you are not familiar with Python or Flask, we will walk you through the code. Its just software. 7 - This is how you define a function in Python. webconsole-5b559bf485-6bm5j 1/1 Running 0 4s Your CTO - in his/her infinite wisdom - have chosen to use Kubernetes to orchestrate all those microservices. We can use these labels later to find back our running webconsole. While the document still looks a bit long, a lot of it is pretty straightforward, and once you are familiar they dont feel difficult. DESCRIPTION: port is specified via --port and the exposed resource has multiple ports, all will be re-used by the ^ Namespace: default image"}]', $ kubectl create deployment webconsole --image webconsole:v1 \, HTTP response headers: HTTPHeaderDict({'Content-Type': 'application/json', 'X-Content-Type-Options': 'nosniff', 'Date': 'Mon, 25 Jan 2021 11:29:21 GMT', 'Content-Length': '366'}), "/usr/local/lib/python3.9/site-packages/kubernetes/client/api/batch_v1_api.py", "/usr/local/lib/python3.9/site-packages/kubernetes/client/api_client.py", "/usr/local/lib/python3.9/site-packages/kubernetes/client/rest.py", "/home/paul/anaconda3/envs/tut-ex/lib/python3.9/site-packages/kubernetes/config/incluster_config.py", 'http://172.17.0.2:32535/api/paul/start/', by tinkering instead of looking at block diagrams, by doing instead of listening to how its done, Demonstrate Kubernetes to their colleagues, Manage your deployment e.g. To solve our bug, we create a new service consolehub. Service selector label resource blah blah blah blah.. Take your time. close(3) = 0 Might as well: Yes. Lets see if kubectl does a better job of explaining that these are: Not bad but perhaps I can expand on this with an example. Python venv as the analogy for Docker died as soon as we moved from the What (isolation) to the How (API). mmap(NULL, 17010, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f8719d60000 We have - by now - figured out: How to deploy our application to a Kubernetes cluster. For instance, you might be running a Web application as well as a Redis cache inside your Kubernetes cluster. Its time we smooth this out. A Selector is a string that selects a set of resources in a Kubernetes cluster based on their labels. run=webconsole, Usage: Examples: kubectl patch node k8s-node-1 -p '{"spec":{"unschedulable":true}}', kubectl patch -f node.json -p '{"spec":{"unschedulable":true}}', 's image; spec.containers[*].name is required because it', kubectl patch pod valid-pod -p '{"spec":{"containers":[{"name":"kubernetes-serve-hostname","image":"new image"}]}}'. Lets start by exploring scale. As always with development, having a proof of concept is nothing compared to creating something you can run on production. Lets have a look at what the job template looks like: Most of this should look familiar. If you havent figured it out yourself, it would be good to have a try to do this yourself. Instead of sending this manifest as is, we treat it as a template! Python.org conveniently publishes a bunch of base images that we can use to run Python applications. kubectl set SUBCOMMAND [options]. " In line 14 we initialize the Kubernetes API and load the configuration from the cluster. NAME SHORTNAMES APIGROUP NAMESPACED KIND The deployment also declares an update strategy, but its empty. webconsole-5b559bf485-rtsk5 1/1 Running 0 10m, expose Take a replication controller, service, deployment or pod and expose it as a new Kubernetes Service, error: You must provide one or more resources by argument or filename. For instance, I recently built an app that needed to send some metrics to a Prometheus server. Twice. The second block of Basic Commands sounds promising but more importantly, Intermediate already **(!) 78538f72d6a9: Pull complete You should change the base image from. Go make an account at Dockerhub. -P, --publish-all Publish all exposed ports to random ports, "FLASK_APP=hello.py flask run -h 0.0.0.0", FROM python:alpine access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) Kubectl set looks very limiting. Building wheel for MarkupSafe (setup.py): started cronjob Create a cronjob with the specified name. There is no reason to expose your Redis cache to the internet, right? If all requests to create a new python interpreter lands on the same instance we still have only one instance which holds all those interpreters ! You would need some way to differentiate hello 1.0 from hello 2.0. It uses the default strategy (the other one is not worth mentioning) called RollingUpdate, with the default options. This will push the hello:v1 image to dockerhub. * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit), click==7.1.2 You wont write them from scratch as you will copy the output of a kubectl create command, copy little snippets from the documentation, or your codebase. autoscale Auto-scale a Deployment, ReplicaSet, or ReplicationController. This is where repositories come in. [--target-port=number-or-name] [--name=name] [--external-ip=external-ip-of-service] [--type=type] Like we said the code in the decorator sandwiches the code in our function. A process running in a container can only access the memory and CPU that has been assigned to it. If it happens to land on the wrong one, our code wont execute ! Lets create our first container. --health-retries int Consecutive failures needed to report unhealthy rollout Manage the rollout of a resource scaling up and down, rolling updates and rollbacks, Describe the Kubernetes API to their colleagues. Installing collected packages: click, Werkzeug, MarkupSafe, Jinja2, itsdangerous, Flask service supports, i.e. '--filename=rsrc.json', See 'kubectl expose -h' for help and examples. drwxr-xr-x 2 alixedi staff 64B Jul 31 13:01 include This is fine. A virtual environment is nothing but a copy of all the files that are needed to run Python applications. 5433ece6bdd7 9 minutes ago /bin/sh -c pip install -r requirements.txt 10.8MB, a320b983dea1 9 minutes ago /bin/sh -c #, 57d793585c4c 9 minutes ago /bin/sh -c #, 872c3118ec53 2 days ago /bin/sh -c #, 2,3c2,4 Lets check the error in a more readable form. [options]. As we established earlier, a service is an abstraction that exposes a deployment to the rest of the world. Lets recover from that. Kubernetes ensures that all the containers in a Pod are run on the same host, managed as a single entity and be able to share resources such as network and storage. With that out of the way, the output of our kubectl explains deployment mentions 2 other things: Pods and ReplicaSets. webconsole-5b559bf485-fvb6c 0/1 Terminating 0 117s the proxy. Not because we had a million teams and services were the only way to stop them from treading on toes. Kubernetes will then see what it needs to do to make this happen if anything needs to. We do not declare any resources yet, thats something for later. Here you go: P.S. access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) This needs a bit of an explainer. for more information about a given command. We should now - by all accounts - have a way of pointing to our application from outside the cluster. The Kubernetes service acts as a load balancer, and we dont control which one. As this book is about Kubernetes we will address most of these issues with Kubernetes. Basic Commands (Beginner): Collecting Flask==1.1.2 expose Take a replication controller, service, deployment or pod and expose it as a new Kubernetes Service Dont you it when the API is this good? You got 2 new junior engineers on your team. ENV FLASK_APP=/hello.py I was lying, this is not a full web app. create Create a resource from a file or from stdin. Advanced Commands: At which point, they will iron out some of the bugs, rework some features etc. I think I have an idea on how to do example #3 for our thing. KIND: Service Back to the bit where we were trying to expose our application running inside a Kubernetes cluster to the internet. pod (po), service (svc), replicationcontroller (rc), deployment (deploy), replicaset (rs) Installing flask in a venv would mean that it is not available globally: We wrote ourselves an exciting little application in Flask. We have something reproducible and not a . To make it easier you can copy the whole YAML file below. Our python interpreter is of course only running on one of them. Anything or anyone who wants to run our web application should be able to do so by following some simple steps: You can put these steps in a console script and it would work beautifully. We have Minikube. Each layer can be re-used by an unlimited number of images. 2 - This copies our files to the root of our container. Type "help", "copyright", "credits" or "license" for more information. Someone would set out to do it and 3 days later, everyone will get a slice of cake. Lets have a look at the spec of the deployment: replicas declares how many pods you want to run, the selector declares how to find your already pods, the strategy how to update when you change something (like the image), and the template is the template (that explains a lot!) Name: webconsole This one has been there all along. RUN pip install -r requirements.txt, IMAGE CREATED CREATED BY SIZE COMMENT KIND: ReplicaSet We have tried to make it practical and approachable. You can use the last Dockerfile for this. There are several options but to learn about repositories, we would run with Dockerhub. This one is straightforward: we have a list of containers that this pod should run with a name and an image. RUN pip install -r requirements.txt Minikube runs a kubernetes cluster inside a VM. kubectl expose (-f FILENAME | TYPE NAME) [--port=port] [--protocol=TCP|UDP|SCTP] Lets refer to the help and pay close attention to the Usage: You will notice the switch that specifies the service type. Collecting itsdangerous==1.1.0 Once you have the features working, you might want to release the latest version of your application to your users. So far we only used the Kubernetes API with kubectl, and minikube automatically configures kubectl to have superuser permissions . We have figured out a way to expose our service to the world outside the cluster but that world is just a VM. Usage: We finish it with --dry-run=client -oyaml which says two things: we dont want to create this object on the cluster, and then we ask to see the actual object as YAML. Here is how: Looks promising. Sort of. 50644c29ef5a: Waiting, FROM python:alpine One more thing: All the commands produce layers but except for FROM, COPY and RUN, the layers are intermediate. Sorry. Finally, Docker is a type of container. replica set will be exposed as a service only if its selector is convertible to a selector that c9fdb169601a: Pull complete WARNING: This is a development server. expose Take a replication controller, service, deployment or pod and expose it as a new Kubernetes Service Use a production WSGI server instead. Lets see if it works. Using a Hello World application was a bit of a necessity because we wanted complete attention to the container and not what was running inside it. But if you are doing a bunch of work in Python, you would end up with 100s and 1000s of packages on your system. I can explain what a deployment is if we can take a step back and let kubectl help us explore the size and shape of what we have just done here. The first thing you could do is to run your container with a shell and faff about: I would also invite you at this point to summon the help and find out what interactive and tty means: Nice innit? We should run it. Who is excited? [Clang 11.0.3 (clang-1103.0.32.62)] on darwin Everything in Kubernetes from the pod running your software, a deployment managing those pods (recreate crashed and other nice features), to exposing something on the network (a service) is an object. Lets try the publish bit: I am taking it as a win but lets be honest. Use "kubectl api-resources" for a complete list of supported resources. openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 and try to push out a new release. That would be virtual machines. A deployment or JSON and YAML formats are accepted. Available Commands: You might not find a lot of paragraphs either. As a user, we will generally deal with Deployments and Pods instead of ReplicaSets. webconsole-5b559bf485-fvb6c 1/1 Running 0 4s In these API groups, we request access to the resources we use: jobs (9) and pods (15). Instead of the one that is running on your machine, outside the VM. -rw-r--r-- 1 alixedi staff 2452 Jul 31 13:01 activate.fish hello:v1 . apply Apply a configuration to a resource by filename or stdin Perhaps its time to dive back into the kubectl and see what else we have at our hand . I started on this spiel of names and tags; Conveniently ignoring a small but important detail: There is no name. We touched upon docker images and how to build them. webconsole-5b559bf485-2zkt5 0/1 Terminating 0 117s The next 3 top-level elements are also common to all Kubernetes objects: metadata, spec, status. 6 - This is a decorator. Annotations: deployment.kubernetes.io/revision: 1 Success! Finally, hopefully, someone would realize that the first version of the awesome product was shit. * Debug mode: off Luckily a lot of that is kind of redundant or even not relevant. Break things. Update field(s) of a resource using strategic merge patch, a JSON merge patch, or a JSON patch. Collecting MarkupSafe==1.1.1 Lets nail down what that means before we move on with the rest of our story. So firstly, lets create a virtual environment for our little Hello World project. drwxr-xr-x 9 alixedi staff 288B Jul 31 13:09 Jinja2-2.11.2.dist-info Or what I said on the tin: One final check. Jinja2==2.11.2 I am one for trying: Lets see if you can find out how to map ports from the host to the container? Now what? To run this fun little application, we can do the following: Firstly, we need to install flask. It looks like this: Making an interactive Python web console might sound complicated but we will be doing it one step at a time and we get a nice helping hand from Python: In less than 10 lines of code, we have something that behaves like a primitive Python command line: We can easily combine this with our Docker hello world example and we have a (multi-user) interactive web console. And our pod have a label that matches the selector. And what is even a tag anyway? webconsole 1/1 1 1 37m, NAME READY STATUS RESTARTS AGE I have worked at companies where a release was like a ceremony. VERSION: v1 It seems like a Service is an abstraction over a Deployment that handles the comms between pods in deployment and the rest of the world. A process running in a container cannot access the file system outside of the container. COPY hello.py / Our function returns the famous Hello World string. -rw-r--r-- 1 alixedi staff 2244 Jul 31 13:01 activate, -rwxr-xr-x 1 alixedi staff 263 Jul 31 13:01 pip, drwxr-xr-x 21 alixedi staff 672B Jul 31 13:09 . This call looks fairly similar to how it would work with kubectl. Assigning staging and production tags wouldnt automatically deploy your application to the staging and production environment respectively. Spec describes the actual object and is different for every type. Dont worry if you dont, we will still explain it. Kubernetes has a Job payload. It will happily distribute the traffic to ensure a stable deployment. You can see for yourself: We can spot the whole cast in there including the python binary and pip. We need some way to forward a port from our host to the container. More or less. There are also tools to help you, we briefly touch on that in chapter <>. Well done attentive reader. We hope that this investment will pay dividends in your understanding and confidence when it comes to applying things that you learn here to your projects. You must specify the type of resource to get. clusterrole Create a ClusterRole. Installing Minikube is about following this excellent guide. -rwxr-xr-x 1 alixedi staff 281 Jul 31 13:01 easy_install-3.7 This would give us a Python environment running on Alpine Linux - a lightweight distribution that is popular in the container world. GitHub actions. A little bit of history. A little reminder of what a Python virtual environment is. We think that this would be enough to learn Kubernetes. Type "help", "copyright", "credits" or "license" for more information. If a pod misbehaves, and Kubernetes decided to kill it for everyones safety, the pod wont be relocated, but the deployment will create a new pod. fstat(3, {st_mode=S_IFREG|0644, st_size=17010, }) = 0 It also includes the packages that are needed by our application e.g. The python image sort of makes sense. Python 3.8.5 (default, Aug 4 2020, 04:11:56) * Environment: production Status: Downloaded newer image for python:alpine, Step 2/3 : COPY hello.py requirements.txt /, Step 3/3 : RUN pip install -r requirements.txt, Collecting click==7.1.2 Examples: cat pod.json | kubectl create -f -.. Expose a resource as a new Kubernetes service. Without any obvious exceptions, the most awesome thing you could do with a Dockerfile is to use it to produce a Docker image. drwxr-xr-x 36 alixedi staff 1.1K Jul 31 13:01 .. Containers provide namespace isolation i.e. Or maybe we missed something else Lets start a python interpreter on our local machine (Make sure you have the above python packages installed! Isnt that convenient ? Type "help", "copyright", "credits" or "license" for more information. Back to service types. Lets wrap this in an image and run it. set Set specific features on objects. We also declare a port and optionally give it a name. If you are having problems, give us a shout. Looks up a deployment, service, replica set, replication controller or pod by name and uses the