1"use strict";(self.webpackChunkgo_micro=self.webpackChunkgo_micro||[]).push([[3433],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>h});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function l(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?o(Object(n),!0).forEach((function(t){a(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):o(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function s(e,t){if(null==e)return{};var n,r,a=function(e,t){if(null==e)return{};var n,r,a={},o=Object.keys(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var i=r.createContext({}),p=function(e){var t=r.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},u=function(e){var t=p(e.components);return r.createElement(i.Provider,{value:t},e.children)},c="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,i=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),c=p(n),d=a,h=c["".concat(i,".").concat(d)]||c[d]||m[d]||o;return n?r.createElement(h,l(l({ref:t},u),{},{components:n})):r.createElement(h,l({ref:t},u))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,l=new Array(o);l[0]=d;var s={};for(var i in t)hasOwnProperty.call(t,i)&&(s[i]=t[i]);s.originalType=e,s[c]="string"==typeof e?e:a,l[1]=s;for(var p=2;p<o;p++)l[p]=n[p];return r.createElement.apply(null,l)}return r.createElement.apply(null,n)}d.displayName="MDXCreateElement"},5467:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>i,contentTitle:()=>l,default:()=>m,frontMatter:()=>o,metadata:()=>s,toc:()=>p});var r=n(7462),a=(n(7294),n(3905));const o={title:"Kubernetes Tutorial for Beginners",description:"Kubernetes Tutorial for Beginners",tags:["kubernetes","tutorial","devops","kube","kubectl"],hide_table_of_contents:!1},l=void 0,s={permalink:"/2019/09/06/kubernetes-tutorial-for-beginners",source:"@site/blog/2019-09-06-kubernetes-tutorial-for-beginners.md",title:"Kubernetes Tutorial for Beginners",description:"Kubernetes Tutorial for Beginners",date:"2019-09-06T00:00:00.000Z",formattedDate:"September 6, 2019",tags:[{label:"kubernetes",permalink:"/tags/kubernetes"},{label:"tutorial",permalink:"/tags/tutorial"},{label:"devops",permalink:"/tags/devops"},{label:"kube",permalink:"/tags/kube"},{label:"kubectl",permalink:"/tags/kubectl"}],readingTime:6.78,hasTruncateMarker:!0,authors:[],frontMatter:{title:"Kubernetes Tutorial for Beginners",description:"Kubernetes Tutorial for Beginners",tags:["kubernetes","tutorial","devops","kube","kubectl"],hide_table_of_contents:!1},prevItem:{title:"Flutter Theme Demo",permalink:"/2019/09/10/flutter-theme-demo"},nextItem:{title:"Docker Tutorial for Beginners",permalink:"/2019/09/04/docker-tutorial-for-beginners"}},i={authorsImageUrls:[]},p=[{value:"Installing Kube Control (kubectl)",id:"installing-kube-control-kubectl",level:3},{value:"Deploying a Kubernetes Application",id:"deploying-a-kubernetes-application",level:3}],u={toc:p},c="wrapper";
1function m(e){let{components:t,...n}=e;return(0,a.kt)(c,(0,r.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"Kubernetes is an open-source system for automating deployment, scaling and managing containerized applications. With this platform, we can decompose (or orchestrate) our applications into smaller systems (called microservices) while developing."),(0,a.kt)("p",null,"Currently, several services around the global provide different Kubernetes implementations:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"Minikube"),": An open-source tool that we can install in our local machine to use Kubernetes locally. This tool uses a virtualization solution (like VirtualBox or similar) to set up a local Kubernetes cluster."),(0,a.kt)("li",{parentName:"ul"},"Google Kubernetes Engine (",(0,a.kt)("strong",{parentName:"li"},"GKE"),"), Amazon Elastic Kubernetes Service (",(0,a.kt)("strong",{parentName:"li"},"EKS"),"), Azure Kubernetes Service (",(0,a.kt)("strong",{parentName:"li"},"AKS"),"), OpenShift Kubernetes.")),(0,a.kt)("p",null,"Among the most popular above, ",(0,a.kt)("strong",{parentName:"p"},"Minikube")," is the only solution that is free forever, but it is also not that useful, as it runs locally only. Some of the other solutions offer free tiers that will allow to get started without paying a dime, they will charge we money to keep our clusters running eventually."),(0,a.kt)("p",{align:"center"},(0,a.kt)("img",{src:"/assets/thoughts/devops/hello_kube_with_go/kube_ingress.png",width:"100%",alt:"Ingress Model - kubernetes.io"})),(0,a.kt)("h3",{id:"installing-kube-control-kubectl"},"Installing Kube Control (kubectl)"),(0,a.kt)("p",null,"Before spinning up a Kubernetes cluster, we'll need a tool called ",(0,a.kt)("strong",{parentName:"p"},"kubectl"),". This tool will allow we to manage our Kubernetes cluster with easy from a terminal. To install ",(0,a.kt)("em",{parentName:"p"},"kubectl"),", we should head to this resource and choose from the list shown - the instructions for our operating system."),(0,a.kt)("p",null,"Once the installation is complete, type the following command to start a Kubernetes cluster:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-console"},'$ minikube start\n\ud83d\ude04 minikube v1.3.1 on Darwin 10.14.1\n\ud83d\udd25 Creating virtualbox VM (CPUs=2, Memory=2000MB, Disk=20000MB) ...\n\ud83d\udc33 Preparing Kubernetes v1.15.2 on Docker 18.09.8 ...\n\ud83d\ude9c Pulling images ...\n\ud83d\ude80 Launching Kubernetes ...\n\u231b Waiting for: apiserver proxy etcd scheduler controller dns\n\ud83c\udfc4 Done! kubectl is now configured to use "minikube"\n')),(0,a.kt)("p",null,"After following these instructions, installing and starting ",(0,a.kt)("em",{parentName:"p"},"kubectl")," in our machine, we can confirm that the tool is indeed available by terminal command:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-console"},'$ kubectl version\nClient Version: version.Info{Major:"1", Minor:"15", GitVersion:"v1.15.2", GitCommit:"f6278300bebbb750328ac16ee6dd3aa7d3549568", GitTreeState:"clean", BuildDate:"2019-08-05T16:54:35Z", GoVersion:"go1.12.7", Compiler:"gc", Platform:"darwin/amd64"}\nServer Version: version.Info{Major:"1", Minor:"15", GitVersion:"v1.15.2", GitCommit:"f6278300bebbb750328ac16ee6dd3aa7d3549568", GitTreeState:"clean", BuildDate:"2019-08-05T09:15:22Z", GoVersion:"go1.12.5", Compiler:"gc", Platform:"linux/amd64"}\n')),(0,a.kt)("p",null,"The output of the above command will show the client version, the release of ",(0,a.kt)("em",{parentName:"p"},"kubectl"),". And this means is that we have ",(0,a.kt)("em",{parentName:"p"},"kubectl")," properly installed successfully."),(0,a.kt)("h3",{id:"deploying-a-kubernetes-application"},"Deploying a Kubernetes Application"),(0,a.kt)("p",null,"After all this setup, now it is time to deploy our first Kubernetes application. As such, to speed up the process, instead of creating a new application for that, we will deploy a sample application that we already exists. ",(0,a.kt)("a",{parentName:"p",href:"/2019/09/04/docker-tutorial-for-beginners/"},"Yes, we had one :)")),(0,a.kt)("p",null,"The first thing we'll do is to create a lot of YAML files, because while using Kubernetes, we'll often use this ",(0,a.kt)("strong",{parentName:"p"},"markup language")," to describe the resources that we'll orchestrate in our
1clusters."),(0,a.kt)("p",null,"The first, create a file called ",(0,a.kt)("strong",{parentName:"p"},"hello-kube-deployment.yaml")," inside our project's directory, and add the following code to it, like this:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-yaml"},"apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: hello-kube-deployment\nspec:\n replicas: 2\n selector:\n matchLabels:\n app: hello-kube-deployment\n template:\n metadata:\n labels:\n app: hello-kube-deployment\n spec:\n containers:\n - name: hello-kube-app\n image: devexps/hello-kube-app\n ports:\n - containerPort: 12345\n")),(0,a.kt)("p",null,"Well, this configuration file is not struggle to understand. Basically, this file define a deployment object (",(0,a.kt)("strong",{parentName:"p"},"kind: Deployment"),") that creates a container named ",(0,a.kt)("strong",{parentName:"p"},"hello-kube-app"),". This container uses an image called ",(0,a.kt)("strong",{parentName:"p"},"devexps/hello-kube-app")," to run the sample go application. By default, Kubernetes will try to fetch images from the public ",(0,a.kt)("a",{parentName:"p",href:"https://hub.docker.com/u/devexps"},"Docker Hub")," registry. However, we can also use private registries if we want to keep our images."),(0,a.kt)("p",null,"Now, We don't worry about the other properties of this file, we'll learn about them when the time comes. However, we need to focus on some important parts first:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},(0,a.kt)("strong",{parentName:"p"},"Deployment"),": a description of the desired state of the system. In this case, we want to tell with Kubernetes cluster that how many ",(0,a.kt)("strong",{parentName:"p"},"pods")," of a particular application we want running. And we're specifying that we want two ",(0,a.kt)("em",{parentName:"p"},"pods")," (",(0,a.kt)("strong",{parentName:"p"},"replicas: 2"),")")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},(0,a.kt)("strong",{parentName:"p"},"Container"),": a part of a ",(0,a.kt)("em",{parentName:"p"},"pod")," that holds running applications, libraries, dependencies, etc. ",(0,a.kt)("em",{parentName:"p"},"Containers")," can be exposed to the world through an external IP address.")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("p",{parentName:"li"},(0,a.kt)("strong",{parentName:"p"},"Pod"),": is the smallest deployable unit of computing that can be created and managed in Kubernetes (",(0,a.kt)("a",{parentName:"p",href:"https://kubernetes.io/docs/concepts/workloads/pods/pod/"},"the official document"),"). In this case, our pods containt a single container - the sample go application."))),(0,a.kt)("p",null,"Then, to run this deployment in our kubernetes cluster, make sure we're just inside our project's directory, and following the command line:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-console"},"$ kubectl apply -f hello-kube-deployment.yaml\ndeployment.apps/hello-kube-deployment created\n")),(0,a.kt)("p",null,"After running above command, cluster will be starting and it make an effort to run both ",(0,a.kt)("em",{parentName:"p"},"pods")," (",(0,a.kt)("em",{parentName:"p"},"replicas: 2"),") on our cluster's nodes. Now, typing the command to confirm that our pods are indeed up and running:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-console"},"$ kubectl get pods\nNAME READY STATUS RESTARTS AGE\nhello-kube-deployment-7ffbc4f9f9-99442 1/1 Running 0 19s\nhello-kube-deployment-7ffbc4f9f9-jqn45 1/1 Running 0 19s\n")),(0,a.kt)("p",null,"We'll see a list of available pods in our Kubernetes cluster. On that list, we can see that we have two pods and each pod containers we also see their ",(0,a.kt)("em",{parentName:"p"},"READY"),", ",(0,a.kt)("em",{parentName:"p"},"STATUS"),", how many times ",(0,a.kt)("em",{parentName:"p"},"RESTARTS")," and ",(0,a.kt)("em",{parentName:"p"},"AGE"),"."),(0,a.kt)("p",null,'Now, we might be thinking that "great, I just deployed a sample Go application into my Kubernetes cluster, now I can start using it with a browser". Well, you can try using it :). But things are not that simple, the problem is that each pods by itself is not accessible by the outside world. Each one of these pods has a different ',(0,a.kt)("em",{parentName:"p"},"IP address")," inside our cluster, if one of them stops working (for whatever reason), Kubernetes will launch a new pod and will give another ",(0,a.kt)("em",{parentName:"p"},"IP address")," for that pod. Therefore, it would be difficult for our to keep and track these ",(0,a.kt)("em",{parentName:"p"},"IP addresses")," manually. To solve this problem, we'll use Kubernetes's services."),(0,a.kt)("p",null,"Really simple, create a file called ",(0,a.kt)("strong",{parentName:"p"},"hello-kube-service.yaml")," and insert the following code to it:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-yaml"},"apiVersion: v1\nkind: Service\nmetadata:\n name: hello-kube-service\nspec:\n ports:\n - port: 8080\n protocol: TCP\n targetPort: 12345\n selector:\n app: hello-kube-deployment\n type: ClusterIP\n")),(0,a.kt)("p",null,"In this file, we added the ",(0,a.kt)("strong",{parentName:"p"},"selector.app")," property on the service description, pointing to ",(0,a.kt)("strong",{parentName:"p"},"hello-kube-deployment"),". Kubernetes will use these properties to tie this service to the deployment's pods. And we're defining that this service will listen on ",(0,a.kt)("strong",{parentName:"p"},"port: 8080")," and that it will ",(0,a.kt)("strong",{parentName:"p"},"targetPort: 12345")," on pods. If recheck on our deployment file, we'll see that our containers will use correctly this port (",(0,a.kt)("strong",{parentName:"p"},"containerPort: 12345"),"). That really important, to make sure that our service will target the correct port when redirecting requests to our pods."),(0,a.kt)("p",null,"Then, we can use the following command to create this service in our Kubernetes cluster:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-console"},"$ kubectl apply -f hello-kube-service.yaml\nservice/hello-kube-service created\n")),(0,a.kt)("p",null,"After running above command, Kubernetes will create a service to represent our deployment in cluster. Finally, we need to define an ",(0,a.kt)("strong",{parentName:"p"},"ingress")," to expose this service to the outside world. Let's create a file called ",(0,a.kt)("strong",{parentName:"p"},"hello-kube-ingress.yaml")," with the following code:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-yaml"},"apiVersion: extensions/v1beta1\nkind: Ingress\nmetadata:\n name: hello-kube-ingress\nspec:\n rules:\n - http:\n paths:\n - path: /\n backend:\n serviceName: hello-kube-service\n servicePort: 8080\n")),(0,a.kt)("p",null,"In this file, we define an ",(0,a.kt)("a",{parentName:"p",href:"https://kubernetes.io/docs/concepts/services-networking/ingress"},"ingress resource with a single rule")," (",(0,a.kt)("strong",{parentName:"p"},"spec.rules"),"), tell with Kubernetes that we want requests pointing to the root path (",(0,a.kt)("strong",{parentName:"p"},"path: /"),") to redirect to the ",(0,a.kt)("strong",{parentName:"p"},"hello-kube-service")," on port (",(0,a.kt)("strong",{parentName:"p"},"servicePort: 8080"),")"),(0,a.kt)("p",null,"To deploy the new *ingress** in our cluster, we can follow the command line:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-console"},"$ kubectl apply -f hello-kube-ingress.yaml\ningress.extensions/hello-kube-ingress created\n")),(0,a.kt)("p",null,"Then, to see the result, we'll need to get the public IP address of our Kubernetes cluster, let's following the command below:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-console"},"$ minikube ip\n192.168.99.102\n")),(0,a.kt)("p",null,"This command will output an IP address that we can use in our browser to see the result. So, if we open the browser and navigate to this IP address, we'll see the sample Go application that we just deployed. Simply way with the terminal:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-console"},"$ curl http://192.168.99.102\nHello devexps from a docker container and Kubernetes\n")),(0,a.kt)("p",null,"That's it! we created a Kubernetes cluster on local machine and used it to spin up a sample Go application. While deploying this app, we learned basic Kubernetes concepts like ",(0,a.kt)("em",{parentName:"p"},"deployments"),", ",(0,a.kt)("em",{parentName:"p"},"pods"),", ",(0,a.kt)("em",{parentName:"p"},"containers"),", ",(0,a.kt)("em",{parentName:"p"},"services")," and ",(0,a.kt)("em",{parentName:"p"},"ingresses"),". With this knowledge, we are now ready to move on Kubernetes advanced concepts."),(0,a.kt)("p",null,"You can find the complete source code for the Go app and all YAML files in the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/devexps/devops/tree/master/hello_kube_with_go"},"Github Repository"),"."),(0,a.kt)("p",null,"Okay, I'll see you next article, see you soon!"))}m.isMDXComponent=!0}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.