{"id":204,"date":"2019-07-11T06:00:30","date_gmt":"2019-07-11T13:00:30","guid":{"rendered":"http:\/\/blog.nillsf.com\/?p=204"},"modified":"2019-08-18T20:12:37","modified_gmt":"2019-08-19T03:12:37","slug":"ckad-series-part-2-core-concepts","status":"publish","type":"post","link":"https:\/\/nillsf.com\/index.php\/2019\/07\/11\/ckad-series-part-2-core-concepts\/","title":{"rendered":"CKAD series part 2: Core Concepts"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">This is part 2 in a multi-part series on my CKAD learning experience. For the other parts in the series, please check out the following links:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><a href=\"https:\/\/blog.nillsf.com\/index.php\/2019\/07\/09\/ckad-series-part-1-intro-exam-topics-my-study-plan\/\">Part 1: intro, exam topics and my study plan<\/a><\/li><li><a href=\"https:\/\/blog.nillsf.com\/index.php\/2019\/07\/21\/ckad-series-part-3-configuration\/\">Part 3: Configuration<\/a><\/li><li><a href=\"https:\/\/blog.nillsf.com\/index.php\/2019\/07\/28\/ckad-series-part-4-multi-container-pods\/\">Part 4: multi-container pods<\/a><\/li><li><a href=\"https:\/\/blog.nillsf.com\/index.php\/2019\/08\/01\/ckad-part-5-observability\/\">Part 5: Observability<\/a> <\/li><li><a href=\"https:\/\/blog.nillsf.com\/index.php\/2019\/08\/05\/ckad-series-part-6-pod-design\/\">Part 6: Pod Design<\/a><\/li><li><a href=\"https:\/\/blog.nillsf.com\/index.php\/2019\/08\/18\/ckad-series-part-7-services-and-networking\/\">Part 7: Networking<\/a> <\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">As I mentioned in the intro to this blog series, my study plan was to cover the topics in the <a href=\"https:\/\/github.com\/cncf\/curriculum\">official curriculum for the CKAD<\/a> one by one &#8211; and share my learnings with you. Topic number 1 are core concepts, with 2 learning objectives:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Understand Kubernetes API primitives<\/li><li>Create and configure basic Pods<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Let&#8217;s cover each of those two topics<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Kubernetes API primitives<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Kubernetes\nis a container orchestrator. To orchestrate those containers, Kubernetes\nessentially behaves like a desired state controller. You define your desired\nstate to the kubernetes system, and the system will take the necessary actions\nto achieve that desired state.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The communication to kubernetes through the <a href=\"https:\/\/kubernetes.io\/docs\/concepts\/overview\/kubernetes-api\/\">kubernetes REST api<\/a>. Clients tools &#8211; such as kubectl &#8211; convert kubectl commands to REST calls to the kubernetes API. That API is continuously updated, and you might have come across the following &#8216;versions&#8217; of the API (or versions of apigroups):<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><strong>Alpha<\/strong>: this API is in development, the feature might even be dropped in the future, while changes to the API and bugs are highly likely.<\/li><li><strong>Beta<\/strong>: the code for this API is well tested, and the feature is considered safe. However, the schema and\/or semantics might still change and bugs might occur. <\/li><li><strong>Stable<\/strong>: Stable versions of features will appear in released software for many subsequent versions.<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">The API itself is evolving with every kubernetes release, and the architecture of the API itself has also evolved with the introduction of API groups. The initial kubernetes API, which is available on the path \/api\/v1, wasn&#8217;t easy to extend. API groups make it easier to extend the kubernetes API and the evolve certain functionalities without changes the main (core) api. This also makes it possible to extend the API with custom resources through CRDs (CustomResourceDefinitions). <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Objects<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/kubernetes.io\/docs\/concepts\/overview\/working-with-objects\/kubernetes-objects\/\">Kubernetes Objects<\/a> are persistent entities in the Kubernetes system. By creating an object, you\u2019re effectively telling the Kubernetes system what you want your cluster\u2019s workload to look like; this is your cluster\u2019s desired state. An object could be a pod, service, deployment\u2026<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Every kubernetes\nobject has two nested object fields:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>The spec, which the end-user provides.<\/li><li>The status, which the kubernetes control plane generates.<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">It kubernetes&#8217;s job\nto make sure status matches spec. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">One thing I learned in reading these docs, it that the kubernetes API itself talks JSON (not YAML). While typically you write yaml to interface with kubectl, kubectl converts this YAML into JSON when talking to the API. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/kubernetes.io\/docs\/concepts\/overview\/working-with-objects\/object-management\/ \">Three ways to create objects: <\/a><\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Imperative commands: <ul><li>kubectl run nginx &#8211;image nginx<\/li><\/ul><\/li><li>Imperative object configuration<ul><li>kubectl create\/delete\/replace commands<\/li><\/ul><\/li><li>Declarative object configuration<ul><li>kubectl apply command<\/li><\/ul><\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">I never paid close attention to the difference between the last two. I&#8217;ve done kubectl create and kubectl apply interchangeably, and have gotten errors when I ran create against an object that I wanted to change. The kubernetes docs on this topic list a number of pros\/cons for each approach if you want to learn more.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Naming<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/kubernetes.io\/docs\/concepts\/overview\/working-with-objects\/names\/ \">Object names<\/a> need to be unique per object type per namespace. You cannot have two pod definitions with the same name in the same namespace, but you can across namespaces. If you delete an object and recreate it with the same name, this is allowed. However, the Kubernetes API generated a UID per object that is also historically unique. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If you want to get\nthe UID of a resource, you can with the following command:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code>kubectl get pod captureorder-5d6fd597d4-jhdqf -o json | jq .metadata.uid<\/code><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Namespaces<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/kubernetes.io\/docs\/concepts\/overview\/working-with-objects\/namespaces\/ \">Namespaces <\/a>are a mechanism to create &#8216;virtual clusters&#8217; on top of one kubernetes cluster. As I mentioned before, names need to be unique only within one namespace. You can also attach resource quota to namespaces. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To use namespaces, just add the following flag to your command <code>--namespace=xxx<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Three cool tricks with namespaces that might come in handy:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>How to get resources in all namespaces: via the <code>--all-namespaces<\/code> flag<\/li><li>How to set the default namespace:<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><code>kubectl config set-context --current --namespace=xxx<\/code><\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>How to view default namespace in your kube config:<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><code>kubectl config view | grep namespace<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A final note on namespaces: they are also important for the default DNS resolution. Every service gets a DNS entry, in the form of <code>service.namespace.svc.cluster.local<\/code>. If you need to reach a service in a separate namespace, you&#8217;ll need to use the FQDN, rather than just the simple service name. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Labels, selectors and annotation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Within Kubernetes, you can use <a href=\"http:\/\/ https:\/\/kubernetes.io\/docs\/concepts\/overview\/working-with-objects\/labels\/\">labels and selectors<\/a> to organize and select sets of objects. If you need to create a service and link that service to a certain deployment, you label the deployment, and use a selector in the service to select the pods that deployment generated. For example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>apiVersion: apps\/v1beta1\nkind: Deployment\nmetadata:\n  name: azure-vote-front\nspec:\n  replicas: 1\n  template:\n    metadata:\n      <strong>labels:\n        app: azure-vote-front<\/strong>\n    spec:\n      containers:\n      - name: azure-vote-front\n        image: microsoft\/azure-vote-front:redis-v1\n        ports:\n        - containerPort: 80\n        env:\n        - name: REDIS\n          value: \"azure-vote-back\"\n---\napiVersion: v1\nkind: Service\nmetadata:\n  name: azure-vote-front\nspec:\n  type: LoadBalancer\n  ports:\n  - port: 80\n  <strong>selector:\n    app: azure-vote-front<\/strong><\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">As you can see in the example above, we create a deployment with the label <code>app: azure-vote-front<\/code>. Afterwards we create a service, which references that deployment with the selector <code>app: azure-vote-front<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Some facts about\nlabels and selectors:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>They are by design not unique (multiple pods\/deployments\/services can have the same labels attached to them)<\/li><li>When selecting a label through a selector, you can an equals (through = or ==, they have the same effect) or a does-not-equals (through !=). You can also use sets, such as the following examples:<ul><li><code>app in (web, db, backend)<\/code><\/li><li><code>app notin (monitoring, backup)<\/code><\/li><\/ul><\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">On the other hand you have <a href=\"https:\/\/kubernetes.io\/docs\/concepts\/overview\/working-with-objects\/annotations\/ \">annotations<\/a>, which are arbitrary metadata. This doesn&#8217;t mean however that that metadata can&#8217;t have a technical impact. For example, if you create a service with an Azure load balancer, you&#8217;ll use an annotation to set the load-balancer to the internal type:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>apiVersion: v1\nkind: Service\nmetadata:\n  name: internal-app\n  <strong>annotations:\n    service.beta.kubernetes.io\/azure-load-balancer-internal: \"true\"<\/strong>\nspec:\n  type: LoadBalancer\n  ports:\n  - port: 80\n  selector:\n    app: internal-app<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Create and configure basic Pods<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A pod is the basic\nexecution unit within Kubernetes. A pod can contain multiple containers in it.\nWithin a pod, containers share their networking and shared storage access. A\npod is scheduled as a whole on one of the nodes in your cluster, meaning all containers\nin a pod will run on the same node. You can run multiple instances of a pod,\nand those multiple instances can be spread across multiple nodes though. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">By design, pods are\nephemeral. They can be killed or moved to another node by the system, meaning\nany state not stored on a persistent store will be lost. Typically, you won&#8217;t\ncreate pods directly; rather, you&#8217;ll create a deployment, which will create pods\nfor you.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A simple (basic?) pod design is the following:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>apiVersion: v1\nkind: Pod\nmetadata:\n  name: basic-pod\nspec:\n  containers:\n    - name: basic\n      image: nginx\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">You can save this snippet of code as a file, and then create this in your kubernetes cluster using the following command:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code>kubectl apply -f simplepod.yaml<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If you then do <code>kubectl get pods<\/code>, you&#8217;ll see that pod was created. If you want to verify that nginx is running, you can do the following commands to verify everything works in the pod:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl exec -it basic-pod \/bin\/bash\napt update\napt install curl -y\ncurl localhost\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">When scheduling and monitoring a pod &#8211; and more specifically traffic to a pod &#8211; Kubernetes uses <code>readinessProbes <\/code>and <code>livenessProbes<\/code>. As we haven&#8217;t created a service yet, we can&#8217;t use a <code>readinessProbe <\/code>yet, but we can play around with a <code>livenessProbe<\/code>. Let&#8217;s try the following with our basic-pod:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>apiVersion: v1\nkind: Pod\nmetadata:\n  name: basic-pod\nspec:\n  containers:\n    - name: basic\n      image: nginx\n      livenessProbe:\n        httpGet:\n          path: \/\n          port: 80\n        initialDelaySeconds: 15\n        timeoutSeconds: 1\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">As we are adding a livenessProbe to our pod, we cannot update the pod, we have to delete and recreate it:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl delete -f simplepod.yaml\nkubectl apply -f simplepod.yaml\nkubectl get pods --watch\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Now open up a second terminal, and do the following:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kubectl exec -it basic-pod \/bin\/bash\nmv \/usr\/share\/nginx\/html\/index.html \/usr\/share\/nginx\/html\/index.html.backup \n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This last bit will make our livenessProbe fail. You will notice in the first terminal (where we are watching the pods in the cluster) that Kubernetes will restart our pod. In that restarted pod, we&#8217;ll have the original filesystem again (our move command will have been &#8216;undone&#8217;), and the livenessProbe will be succesfull again. If you want even more info on the restart of your pod, execute the following command:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code>kubectl describe pod\/basic-pod<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Which output should look like this, indicating the failed probe and the pod restart:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Type     Reason     Age               From                                        Message\n  ----     ------     ----              ----                                        -------\n  Normal   Scheduled  62s               default-scheduler                           Successfully assigned default\/basic-pod to aks-nodepool1-14406582-vmss000001\n  Warning  Unhealthy  9s (x3 over 29s)  kubelet, aks-nodepool1-14406582-vmss000001  <strong>Liveness probe failed: HTTP probe failed with statuscode: 403<\/strong>\n  Normal   Killing    9s                kubelet, aks-nodepool1-14406582-vmss000001  <strong>Container basic failed liveness probe, will be restarted<\/strong>\n  Normal   Pulling    8s (x2 over 60s)  kubelet, aks-nodepool1-14406582-vmss000001  Pulling image \"nginx\"\n  Normal   Pulled     7s (x2 over 58s)  kubelet, aks-nodepool1-14406582-vmss000001  Successfully pulled image \"nginx\"\n  Normal   Created    6s (x2 over 58s)  kubelet, aks-nodepool1-14406582-vmss000001  Created container basic\n  Normal   Started    6s (x2 over 58s)  kubelet, aks-nodepool1-14406582-vmss000001  Started container basic\n\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Summary<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">I believe this should cover our first exam topic, Core Concepts. We have briefly touched on the Core API Primitives, and then created a basic pod, in which we also played around with a livenessProbe.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Up to our next topic in part 3: Configuration!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This is part 2 in a multi-part series on my CKAD learning experience. For the other parts in the series, please check out the following links: Part 1: intro, exam topics and my study plan Part 3: Configuration Part 4: multi-container pods Part 5: Observability Part 6: Pod Design Part 7: Networking As I mentioned [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[20],"tags":[19,17,18],"class_list":["post-204","post","type-post","status-publish","format-standard","hentry","category-ckad","tag-certification","tag-ckad","tag-kubernetes"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/nillsf.com\/index.php\/wp-json\/wp\/v2\/posts\/204","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nillsf.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nillsf.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nillsf.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/nillsf.com\/index.php\/wp-json\/wp\/v2\/comments?post=204"}],"version-history":[{"count":12,"href":"https:\/\/nillsf.com\/index.php\/wp-json\/wp\/v2\/posts\/204\/revisions"}],"predecessor-version":[{"id":293,"href":"https:\/\/nillsf.com\/index.php\/wp-json\/wp\/v2\/posts\/204\/revisions\/293"}],"wp:attachment":[{"href":"https:\/\/nillsf.com\/index.php\/wp-json\/wp\/v2\/media?parent=204"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nillsf.com\/index.php\/wp-json\/wp\/v2\/categories?post=204"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nillsf.com\/index.php\/wp-json\/wp\/v2\/tags?post=204"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}