<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Taha Mashhadi on Medium]]></title>
        <description><![CDATA[Stories by Taha Mashhadi on Medium]]></description>
        <link>https://medium.com/@taha_mashhadi?source=rss-a5378da94957------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*UhJhGXmmDd7g1OD_SZVknA.jpeg</url>
            <title>Stories by Taha Mashhadi on Medium</title>
            <link>https://medium.com/@taha_mashhadi?source=rss-a5378da94957------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 00:48:48 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@taha_mashhadi/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Kubernetes (Manual Scheduling, Taints and Tolerations, Node Affinity, Node Selector)]]></title>
            <link>https://medium.com/@taha_mashhadi/kubernetes-manual-scheduling-taints-and-tolerations-node-affinity-node-selector-cca193b9efa6?source=rss-a5378da94957------2</link>
            <guid isPermaLink="false">https://medium.com/p/cca193b9efa6</guid>
            <category><![CDATA[pod-scheduling]]></category>
            <category><![CDATA[deployment]]></category>
            <category><![CDATA[devops]]></category>
            <category><![CDATA[taints-and-toleration]]></category>
            <category><![CDATA[kubernetes]]></category>
            <dc:creator><![CDATA[Taha Mashhadi]]></dc:creator>
            <pubDate>Thu, 22 Feb 2024 15:54:21 GMT</pubDate>
            <atom:updated>2024-02-22T15:54:21.811Z</atom:updated>
            <content:encoded><![CDATA[<p><strong>Introduction: </strong>In Kubernetes pods are scheduled on nodes based on the internal algorithm of <strong>scheduler</strong> which picks the best node available at that time but sometime there are scenarios we want to restrict pods to be put on specific node or we want to put the pods on specific node, in this blog we we will discuss all the possibilities of how we can achieve pod scheduling according to our needs and how we can restricts nodes to be picked by scheduler to put pod on it</p><p>Following are the topics which are covered in this blog</p><ul><li><strong>Manual Scheduling</strong></li><li><strong>Taints and Toleration</strong></li><li><strong>Node Selector</strong></li><li><strong>Node Affinity</strong></li></ul><p><strong>Manual Scheduling: </strong>in manual scheduling we schedule pod manually on node, to understand this concept we have to understand how kube-scheduler work, whenever we create a pod through definition file scheduler looks for the pod which have no “nodeName” property attached to them and ignored the pod which have on it, “<strong>nodeName</strong>” property is assigned under pod.spec section when we create our pod , if there is no nodeName specified then scheduler pick the pod and placed it on a best available node available at that time in k8-cluster. What if we specified nodeName while creating our pod the pod is ignored by the scheduler and it is directly placed on that node which is specified on it, by specifying nodeName we directly scheduled our pod on node of our choice. We can use manual scheduling when there is no scheduler available on k8-cluster in this situation pod will goes into pending state until and unless we specify the nodeName in pod definition file while we create it. Below is the example of definition file where we select node2 to put the pod on</p><pre>apiVersion: v1<br>kind: Pod<br>metadata:<br>  name: nginx<br>  labels:<br>    name: nginx<br>spec:<br>  containers:<br>  - name: nginx<br>    image: nginx:alpine<br>    ports:<br>    - containerPort: 8080<br>  nodeName: node2</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/945/1*i0H1Kxx698VSdlDRPfJAnA.png" /><figcaption><strong>Manually scheduling pod to k8-worker1</strong></figcaption></figure><p>What if we want to schedule the pod on specific node and we forget to mention that nodeName while creation and it’s already created, kubernetes wont allow us to edit the pod file and add nodeName property to it but we can achieve this by creating a <strong>binding object</strong> and then sending object data by a <strong>POST</strong> request to binding api through this way it mimics what actual scheduler do. Below is the example of binding object and the api request</p><pre>apiVersion: v1<br>kind: Binding<br>metadata:<br>  name: nginx<br>target:<br>  apiVersion: v1<br>  kind: Node<br>  name: node2</pre><pre>##binding api requestrequest<br>$ curl --header &quot;Content-Type:application/json&quot; --request POST \<br>  --data &#39;{&quot;apiVersion&quot;:&quot;v1&quot;, &quot;kind&quot;:&quot;Binding&quot; ...}&#39; \<br>  http://$SERVER/api/v1/namespace/default/pods/$PODNAME/binding</pre><p><strong>Taint and Toleration: </strong>is one of the main concept through which we can understand and learn about how nodes are restricted to deploy POD’s on it. To understand Taint and Toleration we draw an analogy by which it become easy to grasp the concept</p><p><strong>Analogy: </strong>Suppose we went for camping and there are lot of bugs and mosquitos the first thing we will do we apply bug/mosquito repellent on ourself now all the species of bug and mosquito will not come on our body and bite us but some specie of bug and mosquito have toleration against that repellent it means that species of bug/mosquito can come on our body and bite us. As you can see i use the word a bug/mosquito who are tolerated to that repellent <strong>can</strong> come because there is a possibility that those species of bug and mosquito not come on our body and goes to some other person.</p><p>In Kubernetes we will replace ourself as a <strong>node</strong>, mosquito/bug as a <strong>pod</strong>, repellent as a <strong>Taint. </strong>If there is a taint apply on the node only the pod which have <strong>Toleration</strong> against that Taint can be deployed on that node. Having a Toleration against the Taint does not guarantee that scheduler will put the tolerated pod on that specific node which have Taint, but there is a possibility that it can be deployed tolerated pod on node which have same taint as the pod have toleration for.</p><p><strong>Taint</strong>: Taint can only be applied on node, by default master-node in k8-cluster is tainted, this is the reason scheduler does not put any pod on it.</p><p><strong>Taint Effect: </strong>a taint effect defines the action of scheduler in the case if the pod does not tolerate the node taint. There are 3 effects or ways of Pod scheduling which are applied with Taint on nodes. Following are the effects</p><ul><li><strong>NoSchedule: </strong>In NoSchedule un-tolerated pods which cant tolerate the Taint which are applied on node are not scheduled by the scheduler. Existing pod will continue to run on the node regardless of the toleration exist on the pod or not</li><li><strong>PreferNoSchedule: </strong>The scheduler will avoid this node until and unless there is no node left to shceduled pod on. Existing pods which are running on that pod are un-effected</li><li><strong>NoExecute: </strong>In NoExecute not only the future pods effected but also the current pod will be evicted if they dont have the Toleration for that node, if it have a toleration it will continue to run. We can specify the eviction time on pod name by <strong>tolerationSeconds </strong>it will continue to run on node until the seconds not finished</li></ul><p>Below is the command to Taint a node</p><pre>##kubectl taint node node-name key=value:taint-effect<br>$ kubectl taint node k8-worker1 black-taint=black:NoSchedule</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/965/1*LDnpT_QvnlHbfgwzOXNqVw.png" /><figcaption><strong>Tainting node k8-worker1, our pod is deployed on k8-worker2 which is not tainted</strong></figcaption></figure><p><strong>Toleration: </strong>Toleration can only be applied on pod, putting Toleration for any Tainted node does not guarantee that the pod will put on that node, it is only guaranteed if the pod is part of the daemonset. To create a toleration on pod we specify the Tolerations under pod.spec section in definition file. Below is the example of pod definition file which have toleration against the node2 on which we created Taint above</p><pre>apiVersion: v1<br>kind: Pod<br>metadata:<br>  name: tolerated-nginx<br>  labels:<br>    name: nginx<br>spec:<br>  containers:<br>  - name: nginx<br>    image: nginx:alpine<br>    ports:<br>    - containerPort: 8080<br>  tolerations:<br>  - key: black-taint<br>    operator: Equal<br>    value: black<br>    effect: NoSchedule</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*BzgrIEzbr_3I0thZTv3XvQ.png" /><figcaption><strong>Our k8-worker1 is Tainted and by creating toleration on our tolerated-nginx pod scheduler deployed it to our tainted node which k8-worker1</strong></figcaption></figure><p><strong>Node Selector: </strong>Node Selector are used to select node for pod scheduling based on certain criteria which are defined inside pod definition file under spec section with the property name <strong>nodeSelector</strong>. We can select node based on the <strong>labels </strong>of node, then the scheduler search for these labels of node and match with those mentioned under nodeSelector if any node with same label found the scheduler deploy the pod on that specific node if not then pod is deployed on any node. If multiple node found with same label then scheduler can choose the best one based on it’s algorithm.</p><p>Prior to define the nodeSelector in pod definition file we must ensure that the node with same <strong>label</strong> node exist in our cluster, to <strong>label the node</strong> we can use the below commands. We can define multiple labels on single node</p><pre>## choose one of your node and labeled it<br>$ kubectl label nodes k8-worker1 disktype=ssd<br><br>##overwrite the label of same node with different value<br>$ kubectl label --overwrite nodes k8-worker1 disktype=hdd<br><br>##comfirm if the label is applied on your node, getting all node in default namespace with lables<br>$ kubectl get nodes k8-worker1 --show-labels<br><br>##to check if the node with the label exist in our cluster<br>$ kubectl get nodes --show-lables | grep -i hdd<br><br>##To remove the label from a node, provide the key without any value<br>$ kubectl label --overwrite nodes k8-worker1 disktype-</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*A-lA-wtRKd-GK08q6_DnKA.png" /></figure><p>Below is pod definition file with <strong>nodeSelector</strong>, we have label k8-worker2 node as disktype=hhd</p><pre>apiVersion: v1<br>kind: Pod<br>metadata:<br>  name: nginx<br>  labels:<br>    name: nginx<br>spec:<br>  containers:<br>  - name: nginx<br>    image: nginx:alpine<br>    ports:<br>    - containerPort: 8080<br>  nodeSelector:<br>    disktype: hhd</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*gpku18RbR259cTUYJrKZKQ.png" /><figcaption><strong>nginx pod with node-selector “disktype=hhd” deployed on k8-worker2 which have same label</strong></figcaption></figure><p><strong>PS:</strong> Node selector have some limitation like we cant instruct scheduler to place pod on one of the node based on multiple selector, like selecting node which have cpu=8 or cpu=10</p><p><strong>Node Affinity: </strong>Node Affinity is same as the node selector but with overcoming the limitation which are in the node selector, <strong>nodeAffinity</strong> provides advanced capabilities to select node based on there labels and can defined multiple labels, scheduler search for the node labels and place pod on the node which have matched labels. It is defined in the pod definition under spec.affinity there are multiple keys defined under it, to understand we will see the the structure of file then dig into each key</p><pre>apiVersion: v1<br>kind: Pod<br>metadata:<br>  name: nginx<br>  labels:<br>    name: nginx<br>spec:<br>  containers:<br>  - name: nginx<br>    image: nginx:alpine<br>    ports:<br>    - containerPort: 8080<br>  affinity:<br>    nodeAffinity:<br>      requiredDuringSchedulingIgnoredDuringExecution:<br>        nodeSelectorTerms:<br>        - matchExpressions:<br>          - key: disktype<br>            operator: In<br>            values:<br>            - hhd<br>            </pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Bw8l8bzOgDE-2sJ5DoEuvg.png" /><figcaption><strong>nginx pod with node-affinity “disktype=hhd” deployed on k8-worker2 which have same label</strong></figcaption></figure><p><strong>requiredDuringSchedulingIgnoredDuringExecution: </strong>This is the type of nodeAffinity, it is not so difficult to understand this key, this key instruct the scheduler that matched node label is required when pod is scheduling and if after matched node label is removed after the pod is scheduled then ignore it and don&#39;t evict the pod it will continue to run on that node</p><p><strong>preferredDuringSchedulingIgnoredDuringExecution: </strong>This is the second type of nodeAffinity, as the key is self explanatory it instruct the scheduler that matched node label are preferred not mandatory during scheduling of pod and once it scheduled on pod later if the node label is removed it will ignore it and countinue to run pod on that same node. We use this type where the pod placement is more important then the node which is it being placed on</p><p><strong>matchExpression: </strong>it is used to instruct scheduler to check the node labels against the match expression which are combination of key, operator and values. The matchExpression can be one or multiple</p><p><strong>key: </strong>key of the node selector</p><p><strong>operator: </strong>operator is the criteria of matching nodes label with defined key value, following are the operators(<strong>In</strong>, <strong>NotIn</strong>, <strong>Exists</strong>, <strong>DoesNotExist</strong>)</p><p><strong>values: </strong>values of the node selector, it can be one or multiple</p><p><strong>Conclusion: </strong>In this article we have built a good understanding of pod scheduling and different technique to scheduled pod in Kubernetes.</p><p><strong>See you in the next topic, until then keep hustling and keep learning!</strong></p><p>Follow me on<br><a href="https://www.linkedin.com/in/taha-mashhadi/">https://www.linkedin.com/in/taha-mashhadi</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=cca193b9efa6" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Understanding Terraform Core Concepts -Part 1]]></title>
            <link>https://medium.com/@taha_mashhadi/understanding-terraform-core-concepts-part-1-5afaa8c02541?source=rss-a5378da94957------2</link>
            <guid isPermaLink="false">https://medium.com/p/5afaa8c02541</guid>
            <category><![CDATA[devops]]></category>
            <category><![CDATA[infrastructure-as-code]]></category>
            <category><![CDATA[terraform]]></category>
            <category><![CDATA[aws]]></category>
            <category><![CDATA[iac]]></category>
            <dc:creator><![CDATA[Taha Mashhadi]]></dc:creator>
            <pubDate>Wed, 21 Feb 2024 18:08:54 GMT</pubDate>
            <atom:updated>2024-02-21T18:08:54.145Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/480/1*gk2qgVB1UoGKxSyQAmcN6Q.png" /></figure><p><strong>Introduction : </strong>In modern tech infrastructure provisioning and managing it have become easy this can be done through writing some instruction in a specific format and then executing those configuration files, there are multiple tools which can be used for provisioning infrastructure but so far <strong>Terraform by Hashicorp </strong>is one of the best tool for<strong> IAC(Infrastructure As Code). </strong>In this article we will understand the core concepts of terraform from basics then we advanced our concepts in 2 separate article in which we will discuss more advance topics</p><p>Following are the topics which will be covered in this article</p><ul><li><strong>What is IAC and it’s types</strong></li><li><strong>What is Terraform and it’s 3 phases</strong></li><li><strong>Mutable vs Immutable Infrastructure</strong></li><li><strong>Installing Terraform on your local machine</strong></li><li><strong>HashiCorp Configuration Language (HCL) and Configuration Directory</strong></li><li><strong>Terraform Providers</strong></li><li><strong>Write → Initialize → Plan → Apply → Update → Destroy Infrastructure</strong></li><li><strong>Terraform State and it’s purpose</strong></li><li><strong>Terraform State Commands</strong></li></ul><h4><strong>What is IAC:</strong></h4><p><strong>Background: </strong>Before cloud computing traditional infrastructure is provisioned by setting up physical hardware resources in their <strong>on premises data center</strong>, the main drawback in managing physical on premises data center is that if we have to provisioned some computational or hardware resources it will take a good amount of time which became a bottleneck for the organization who need to scale up and down rapidly.</p><p>Then comes the cloud provider’s organization which need to scale fast shift from on premises data center to cloud providers like<strong>(AWS, GCP, AZURE etc..</strong>) cloud providers give flexibility to orchestrate resources whenever they want these resources will be provisioned in few minutes with some click on their dashboard which saves lot of time and managing cost.</p><p>Till now seems like cloud providers solves our problems related to saving time and managing cost but let give it a second thought what if these organization have large infrastructure spans around multiple cloud provider including on premises resources and they have to update or orchestrate their infrastructure often according to their needs, by going on to the dashboard of each cloud provider and changing resources will become cumbersome and time consuming too.</p><p><strong>IAC: </strong>What if all the resources are provisioned and scaled by executing a file which contain all the instruction for creating and updating infrastructure in it and these instruction write in specific format is called <strong>Infrastructure As Code (IAC). </strong>Using IAC we can manage any infrastructure components as code such as (<strong>Database, Computation, Storage, Network e.tc</strong>) and also the <strong>application configuration</strong>.</p><p>There are multiple tools to address <strong>IAC</strong> which can be broadly divided into 3 main type based on their functionality</p><p><strong>Configuration Management: </strong>The purpose of configuration management tool is to configure application and services on existing infrastructure and also to monitor resources on these, it can be run on multiple remote resources at once. These tools are idempotent means once anything is configure on a resource it will not configure once it run again. Tools which are fall into this category are (<strong>Ansible, Chef, Puppet, Saltstack</strong>).</p><p><strong>Server Templating: </strong>The purpose of sever templating tool to spinup servers which are identically configured to a defined standard, it is used to create custom images of a machine which contains pre installed application and services in it. Infrastructure which is orchestrated using server templating are immutable unlike configuration management tool. Tools which fall into this category are (<strong>Docker, Vagrant and Packer</strong>)</p><p><strong>Provisioning : </strong>These tool are used for provisioning infrastructure and it component on cloud such as (<strong>Database, Computation, Storage, Network e.tc</strong>) multiple resources can be provisioned in one go using these tools. Tools which fall into this category are (<strong>Terraform, CloudFormation</strong>), in this article we will discuss one of the provisioning tool Terraform in detail.</p><h4><strong>What is Terraform</strong></h4><p>With <strong>terraform</strong> we can write our infrastructure using dedicated configuration language called <strong>HCL </strong>and then saved it in a <strong>.ts</strong> file once we execute these file our infrastructure is provisioned exactly as defined in configuration file. Terraform allows us to <strong>build</strong>, <strong>manage</strong> and <strong>destroy</strong> infrastructure in matter of minutes, these infrastructure component can be on private-public cloud or on prem, it can also manage low level component like compute, storage, and networking resources, as well as high-level components like DNS entries and SaaS features.</p><p>Every object which terraform can manages is called <strong>resource</strong> and terraform manages it resource using <strong>providers</strong> through it’s API, providers helps terraform to work with any platform or services using it’s API, we have discuss providers in detail in different section below.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/746/1*DoATGMZQx9-MFgg6qvMhMQ.png" /></figure><p><strong>3 Phases: </strong>The core terraform workflow consist of 3 phases <strong>Write, Plan </strong>and<strong> Apply. </strong>First we write our infrastructure in <strong>Hashicorp Configuration Language </strong>then we plan our infrastructure in which terraform creates an execution plan of how resources are created or updated based on the configuration file and finally we apply our plan in this stage terraform execute the plan which is created earlier by performing each operation in correct order.</p><h4><strong>Mutable Infrastructure:</strong></h4><p>In mutable infrastructure the component or the services running on it can be me modified without recreating the resource again. For instance if we have to update nginx version on 4 of our server we can do it by only updating the nginx version without recreating server with newer nginx version. By this approach a configuration drift can happen if one of the servers fail to update the nginx software then it leave infrastructure in unstable state</p><h4>Immutable Infrastructure:</h4><p>In immutable infrastructure service or software can’t be updated or changed in any form until and unless it’s underline component is also recreated with the updated changes. For instance if we have to update new version of nginx on to our 4 servers with immutable infrastructure the server will be recreated with new version of nginx, by this approach it minimizes the configuration drift and become easy to manage underline infrastructure resources.</p><h4><strong>Installing Terraform on your local machine:</strong></h4><p>Installing terraform on your machine is an straight process where we download the official binaries from terraform and then install it using package manager of our system, below is the command and result snippet of installing terraform in our Ubuntu machine<br>You can also refer to official guide to install terraform on your machine<br><a href="https://developer.hashicorp.com/terraform/install">https://developer.hashicorp.com/terraform/install</a></p><pre>wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg<br>echo &quot;deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main&quot; | sudo tee /etc/apt/sources.list.d/hashicorp.list<br>sudo apt update &amp;&amp; sudo apt install terraform</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*CtvhRew8R01T6CTjvyPqsA.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/827/1*AAREpiVwcJ-hZO3rRA3g7g.png" /></figure><h4><strong>HashiCorp Configuration Language (HCL):</strong></h4><p><strong>HCL</strong> is an language format of Terraform in which we write instructions for creating, updating and removing <strong>resources</strong> of our infrastructure, file in which these instruction are written is called <strong>configuration file</strong> and have a <strong>.ts </strong>extension. We can name these file with any valid string but the default configuration file is called <strong>main.ts</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/875/1*R9a82dgJtal1M30qVByrJg.png" /></figure><p>HCL file mainly contain <strong>resource block</strong> these blocks defined what attributes our resource will have and these attributes can be vary between different resources provided by the <strong>providers(plugins)</strong> but syntax of resource block are mainly the same, resource block is used to create and update different resources on our infrastructure these resource can be from creating or updating <strong>EC2 instance</strong> on amazon to creating or updating <strong>local_file</strong> on the server instance. Below is the syntax of a resource block</p><h4><strong>Configuration Directory</strong></h4><p>The directory where configuration file are located is called terraform configuration directory, all the commands should be run within the <strong>configuration directory</strong>. Configuration directory can contain multiple <strong>configuration</strong>, <strong>variable </strong>files<strong> </strong>but it contain only single <strong>terraform.tfstate</strong> and <strong>plan </strong>file. Configuration Directory is the main directory where all the configuration file repleted to our architecture is located.</p><h4><strong>Terraform Providers :</strong></h4><p>In order to manages resources terraform uses <strong>plugins called provider</strong> which interact with the terraform API in order to create, update and delete resources and services on it. A resources manages by terraform can be on cloud, on prem or locally in order to manage these resources terraform uses different providers which are responsible for interacting with specific resource or service like <strong>aws </strong>plugin interact with resources on <strong>AWS cloud </strong>whereas <strong>local </strong>plugin allows us to interact with local resources like <strong>files </strong>on local system.</p><p>There are<strong> 3 tiers of providers</strong>, below are the details</p><p><strong>Official Provider: </strong>These are the providers which are officially maintain by hashicorp itself</p><p><strong>Partner: </strong>These are the partner of hashicorp and participates in <strong>Hashicorp Technology Program</strong>, plugins are maintained, managed, validated and publish by partner themself</p><p><strong>Community: </strong>Providers which are maintain and publish by individuals maintainers or by the group of maintainers into <strong>terraform registry</strong></p><p>To check all the providers and their documentation go to official website of <strong>terraform registry</strong> [<a href="https://registry.terraform.io/">https://registry.terraform.io/</a>]</p><h4><strong>Write → Initialize → Plan → Apply → Update → Destroy Infrastructure</strong></h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/792/1*T8DXmimNM6SiwDq6Hl32hQ.png" /></figure><p><strong>Write: </strong>We start by writing infrastructure in a defined <strong>hcl </strong>format in a <strong>.ts </strong>extension file, hcl file mainly contains the <strong>resource blocks</strong> which instruct how to create or update resources in our infrastructure other block may include <strong>data source block</strong> or <strong>provisioner block</strong> in our hcl file. Below is the example of hcl file name <strong>main.tf</strong> we have used <strong>local_file</strong> provider</p><pre>resource &quot;local_file&quot; &quot;rand_new_pet&quot;{<br>  filename = &quot;/root/my-files/my-pet.txt&quot;,<br>  content= &quot;My new pet name is max&quot;<br>}</pre><p><strong>Initialize: </strong>In order to orchestrate or manage any resource in our infrastructure we first required the respective providers into our configuration directory. When we run the initialize command terraform creates a new secret directory name <strong>.terraform </strong>in this secret directory all our required plugins are placed, below are the command and snippet</p><pre>## initializing terraform config directory by downloading required provider<br>$ terraform init</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/876/1*rsimHYowDzqxv5oA7Ou4ZQ.png" /><figcaption><strong>In sippet we can see local provider is downloaded into our config directory</strong></figcaption></figure><p><strong>Plan: </strong>After initializing the configuration directory we creates plan by running the blow command, when the command is run terraform creates an execution plan of how to execute instruction which are specified in configuration file(<strong>hcl</strong>), below are the command and snippets</p><pre>## creating plan for creating resources defined in our config file, <br>## the -out options is used to store the execution plan in a file, its optional<br>$ terraform plan -out local-infra-plan</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*uZSXb1zeGpc_3DNx-2sKgw.png" /></figure><p><strong>Apply: </strong>Once we plan our infrastructure now we can apply changes in real world by executing our plan with <em>apply </em>command, through this command our changes will be reflected in matters of minutes, below are the command and snippets</p><pre>## applying plan which we just saved in a file, <br>## if we have saved plan we can pass it if not then apply can be executed without it<br>$ terraform apply local-infra-plan</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/944/1*NEXMh5kzgVXLiNSeAKx8Qg.png" /><figcaption><strong>resource id is highlighted in yellow</strong></figcaption></figure><p><strong>PS: </strong>Every resources created by terraform have a unique id which helps terraform to manage them, we can see those id when resource is created or we can check it later in terraform.tfstate file</p><p><strong>Update: </strong>If in future we need to update any resource in our infrastructure this can be easily done by following the core work flow of terraform again which is <strong>changing</strong> the configuration file then <strong>plan</strong> it and finally <strong>apply</strong> it (<strong>Change → Plan → Apply</strong>), below are the snippets</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ivxiFtURMeq9SBHlSTHN_A.png" /><figcaption><strong>editing configuration file and then creating plan</strong></figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/892/1*EuHWfsBwFv3Ty_hj2CKdDw.png" /><figcaption><strong>applying new changes, terraform creates new file instead of changing content within it because of it immutable infrastructure. We can notice resource id is changed</strong></figcaption></figure><p>Whenever new changes are being done the resource is recreated because of terraform immutable infrastructure, we can verify it by seeing the difference in <strong>resource id</strong> which terraform assign for every new resources</p><p><strong>Destroy: </strong>If we want to destroy our whole infrastructure define in configuration file located at configuration directory we can do so by using one simple command <em>destroy</em>, keep in mind this command will remove all our infrastructure resources in one go so it’s better to create destroy plan first and then execute this plan, below are the command and snippets</p><pre>## we can destroy our infrastructure by using simple destroy command, <br>## but it&#39;s better to create a destruction plan save it in a file and then apply that plan<br>$ terraform plan -destroy -out local-infra-plan <br><br>$ terraform apply local-infra-plan</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*j0RHdIdblGRRaFNrsUg3RA.png" /><figcaption><strong>creating destruction plan and saving it in a file</strong></figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/792/1*WnEBAnAIlG1_xL5YcirU7A.png" /><figcaption><strong>destroying resources which we created earlier using destruction plan</strong></figcaption></figure><h4><strong>Terraform State and it’s purpose</strong></h4><p>Terraform maintain a local state of infrastructure which hold all the details of every resources which are in real world, the state is created when we run apply command first time and stored it in a file name “<strong>terraform.tfstate</strong>”. The state files is in json format which maps every detail of real world resources in it, this state file is consider as a single source of truth, once terraform.tfstate file created by default it refreshes every time whenever plan or apply command run and matches the changes in configuration file with the current refresh state this procedure helps terraform to identifies the changes which are being done on our infrastructure and once new configuration apply then terraform changes it state file with the updated changes.</p><p>A state file is considered as a blue print of our real world infrastructure, it eliminates the configuration drift between the real world resources and configuration file if any drift exist terraform state helps to create an execution plan based on the difference which eliminates the configuration drift. State file not only maps the resources itself but also maps the metadate of it like resource dependencies, we will learn more about resource dependency in chapter2</p><p>We can use terraform state for increasing the performance as well like whenever we apply new resources or create plan terraform refresh the state by reconciling it local state from the real world infrastructure if our infrastructure is large having ton of resources then it can take lot of time to get the updated state from our infrastructure instead reconciling every time from real world infrastructure we can use terraform.tfstate file for reconciliation. By using — refresh false option with every commands, we can skip refresh and local state is used for reconciliation</p><p><strong>PS: </strong>Every user who are working on same infrastructure should have latest terraform.tfstate file on their machines, we should never share these file through version control system such as git or bitbucket instead it should be posted on remote data storage like s3 or terraform cloud because state file is sensitive in nature and holds secrets of our infrastructure</p><h4><strong>Terraform State Commands:</strong></h4><p>Terraform state file is in json format and should not be edited manually instead terraform provides sets of command to interact or edit with it’s state file. Command which is used is terraform state state followed by sub command which are described below with result snippet</p><pre>## it will only print the resource address in current state <br>$ terraform state list<br><br>## it will show the detail of specific resource by providing resource id<br>$ terraform state show local_file.rand_new_pet<br><br>## moving item within same state file or moving resources from one state file to another state file<br>## one usecase of this command is to renaming the resource, below is the commnad. <br>## After state file change we have to reanme resource name manually in config file too<br>$ terraform state mv local_file.rand_new_pet local_file.rand_old_pet<br><br>## it used to download and display the current remote state of our infrastrucuture<br>$ terraform state pull<br><br>## it is used to delete item from state, this command is used if we dont want to mannage the resource through terraform<br>## the resource itself will not be removed by this command<br>$ terraform state rm local_file.rand_new_pet</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*LnL--iZVMw_Jg83anjJ8Mg.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*wm01sxBtXXXDbds7lLaq1A.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/858/1*5tmfda6VwxVFl1NSZg8IGA.png" /></figure><p><strong>Conclusion: </strong>In this article we have discuss core concepts of terraform, so far we understand how terraform works and what is the workflow of terraform by implementing basic infrastructure on local machine in par2 and advance topic we will create infrastructure on cloud and discuss more advance topics until the stay tuned…</p><p><strong>See you in the next topic, until then keep hustling and keep learning!</strong></p><p>Follow me on<br><a href="https://www.linkedin.com/in/taha-mashhadi/">https://www.linkedin.com/in/taha-mashhadi</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5afaa8c02541" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[End To End DevSecOps (Kubernetes & Ansible)]]></title>
            <link>https://medium.com/@taha_mashhadi/end-to-end-devsecops-kubernetes-ansible-9f4776c2599c?source=rss-a5378da94957------2</link>
            <guid isPermaLink="false">https://medium.com/p/9f4776c2599c</guid>
            <category><![CDATA[aws]]></category>
            <category><![CDATA[ci-cd-pipeline]]></category>
            <category><![CDATA[projects]]></category>
            <category><![CDATA[ansibe]]></category>
            <category><![CDATA[kubernetes]]></category>
            <dc:creator><![CDATA[Taha Mashhadi]]></dc:creator>
            <pubDate>Sat, 17 Feb 2024 20:50:37 GMT</pubDate>
            <atom:updated>2025-11-30T23:32:16.266Z</atom:updated>
            <content:encoded><![CDATA[<h3><strong>End To End DevSecOps Project (Kubernetes &amp; Ansible)</strong></h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*WfPKWt9xHkeEN9RAqdG_Yw.png" /></figure><p><strong>Introduction </strong>This project is an actual depiction of setting up the production pipeline and architecture by following the best DevSecOps practices and tools, we have used Kubernetes to deploy our application, Ansible to configure our k8-cluster and configure many other tools. In this project we have cover a wide array of topics and concept which are essentials for setting up and configuring tools for production. This project perfectly covers all the aspect of modern DevSecOps practices.</p><p><strong>Prerequisites: </strong>There is no compulsory prerequisites concept in this project, but a basic understanding of CI/CD pipeline including Kubernetes and Ansible is compulsory. We will use <strong>AWS</strong> for provisioning our servers but you can use any cloud provider. <strong>Dockerhub</strong> and <strong>Gmail</strong> account is required</p><p>Following are the topics which are covered in this article<br><strong>1.</strong> <strong>Setting up EC2 instance</strong><br><strong>2.</strong> <strong>Installing and Configuring</strong> <strong>Jenkins on Jenkins/Ansible server<br></strong>3.<strong> Installing Docker<br>4. Installing Sonarqube<br>5. Installing Trivy<br>6. Installing and configuring Ansible Control node<br>7. Configuring Kubernetes Cluster through Ansible<br>8. Setting up monitoring-server using Prometheus and Grafana<br>9. Configuring node exporter on jenkins server<br>10. Configuring node exporter as a daemonset on k8-cluster<br>11. Setting up CI/CD Pipeline</strong></p><p><strong>Lets Dive into Building</strong></p><p>First we need to orchestrate our ec2 instances, we will spin up 4 instance with following configurations</p><ul><li><strong>Jenkins Server/Ansible Control Node(t2.large, 35Gb):</strong> On this server we will install and configure multiple tools like jenkins, ansible, sonarqube, docker, kubectl and trivy</li><li><strong>Monitoring Server(t2.medium, 15Gb): </strong>This server is solely responsible for monitoring, we will install and configure Prometheus, Grafana and node exporter</li><li><strong>Kubernetes Master Server(t2.mdeium, 8Gb): </strong>On this server we will configure k8 master node through ansible playbook, it will act as an ansible managed node and the k8-master-controlplane</li><li><strong>Kubernetes Worker Server(t2.medium, 8Gb): </strong>This server will act as an k8 worker and the managed ansible node, we will install and configure k8 worker node through ansible playbook</li></ul><p>Before we start orchestrating the instances on AWS we will select the nearest region from the “<strong>region selector</strong>” located at top right corner, In my case “Canada Central” is the nearest one, select according to yours</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6zM7bTLiRxmLMkMu1WOvUQ.png" /></figure><p><strong>Create Security Group: </strong>Next we will create security group for our server, to control <strong>inbound and outbound traffic</strong>. All 4 instance will share same security group all inbound TCP traffic is allowed and the SSH access will only be allowed to our home ip address</p><p>Go to search bar and search EC2 and then from ec2 dashboard select Security Group</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Vvr7SRWah2mYrp0FCaHzGw.png" /></figure><p>Next add basic details like name and description of security group “plg1-sg”</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*CcdGYODKVaLrcX_C-DVZ_Q.png" /></figure><p>After creating security group edit inbound rules, allow all inbound TCP traffic and allow SSH to only your ip</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*N0cYLEWQYHJLlqwJccD98Q.png" /></figure><p><strong>Setting up EC2 instance: </strong>Now we will start creating our ec2 instance, i have show steps to spin up 1 instance “<strong>jenkins-server</strong>”, all other 3 ec2 instance can be orchestrated following exactly same steps with their own instance name, type and storage</p><p>From the ec2 Dashboard select “Launch Instance”</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*O9hxUhJMUB1IWN-3l5L7Vg.png" /></figure><p>Then add the instance detail like instance name “jenkins-server”, os “ubuntu 22.04”, instance type “t2.large”</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*9ZwU3j8XmmcmdPfb2CLPgg.png" /></figure><p>Then from key pair section, we will create a new key pair and name it “plg1-ec2” then select the key format i have selected .ppk key format you can select either<strong> .pem</strong> or <strong>.ppk</strong>. Now we will create the key and save it on our local machine, it will be showed once so keep it safely. This key is used for connecting to our server, i will use this same key for all our instances</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/751/1*a8XKItLDXLMJ7daBh6Hbrg.png" /></figure><p>Now from the network settings section, “Select existing security group” and from drop down select the one which we created earlier named “plg1-sg”</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/756/1*botWrbIjUgcixCsgIEqYbg.png" /></figure><p>Finally edit storage for our jenkins server we need atleast 35Gb storage and the click on launch instance</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*3D70pKGgwKsRJXDL6MrZwQ.png" /></figure><p>Now spin-up 3 more ec2 instances named <strong>“monitoring-server”,</strong> <strong>“k8-master”</strong> and <strong>“k8-worker”</strong> . At final all the 4 server will look like below</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*vXx8iZCnt9aYXDBalvjfnQ.png" /></figure><p>After orchestrating all 4 servers, we have to configured our server and install all the required tools and packages on each of them. First we will start from <strong>jenkins server</strong></p><p>Login into jenkins server using the .ppk key, from “<strong>putty</strong>” software on your local machine, open it specify public ip in our case it is 3.96.135.216 then from left pane select <strong>Connection-&gt;SSH-&gt;Auth-&gt;Credentials</strong> and specify private key which we generated earlier and then select open button</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/592/1*B77bgdwaaAK5ZupmuBiOBw.png" /></figure><p><strong>Installing and Configuring</strong> <strong>Jenkins: </strong>On jenkins server we will start by changing <strong>hostname</strong> and then <strong>installing jenkins</strong> on it, write following command on the shell as root user</p><pre>##changing hostname<br>hostnamectl hostname jenkins-server<br><br>##Installing JDK<br>sudo apt update -y<br>sudo apt install openjdk-11-jre -y<br>##check JDK version<br>java --version<br><br>##Installing Jenkins<br>curl -fsSL https://pkg.jenkins.io/debian/jenkins.io-2023.key | sudo tee \<br>  /usr/share/keyrings/jenkins-keyring.asc &gt; /dev/null<br>echo deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc] \<br>  https://pkg.jenkins.io/debian binary/ | sudo tee \<br>  /etc/apt/sources.list.d/jenkins.list &gt; /dev/null<br>sudo apt-get update -y<br>sudo apt-get install jenkins -y</pre><p>After installing, we can see jenkins service is running</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*XaVueMxepZFMKDir6MqHOg.png" /></figure><p>Now we have to configure jenkins admin user and plugins on it, in order to do so we need to “Unlock Jenkins”, to unlock it we need to get the “<strong>initialAdminPassword</strong>” it’s located at <strong>/var/lib/jenkins/secrets/initialAdminPassword</strong> to get the pswd type below command</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/753/1*WFmwMoZPJRo3NuPComJVKA.png" /></figure><p>Now open the jenkins UI on web-browser by typing jenkins url which will be your server ip followed by the port 8080, in my case it is “<strong>3.96.135.216:8080</strong>” and then pass the initial-admin-pswd</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*23ROTPCQ97Ouor77fME9FQ.png" /></figure><p>Now Click on <strong>Install Suggested Plugin</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*MYwBOrfg42Z7ecCH6ZgOZg.png" /></figure><p>After suggested plugin installed, create your first admin account and click <strong>Save and Continue</strong></p><p>At last add your jenkins url and click <strong>Save and Finish</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*IWc1nshITB-q9BzjqlqFtg.png" /></figure><p><strong>Installing Docker </strong>on jenkins-server, write below command on shell</p><pre>##Installing Docker<br>sudo apt update<br>sudo apt install docker.io -y<br><br>##Adding jenkins and ubuntu user into docker group<br>sudo usermod -aG docker jenkins<br>sudo usermod -aG docker ubuntu<br><br>##Restarting docker service and changing docker.sock file privilege<br>sudo systemctl restart docker<br>sudo chmod 777 /var/run/docker.sock</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/721/1*9WscitAxZdGPP-JtCJEBHg.png" /></figure><p><strong>Installing Sonarqube</strong> we will run sonarqube as an <strong>docker container </strong>on jenkins-server, as we already installed and configure docker on our jenkins server now we can write below command to spin-up our sonarqube docker container</p><pre>##-d is for running container in detached mode and -p is for defining port<br>docker run -d --name sonar -p 9000:9000 sonarqube:lts-community<br><br>##checking docker runing<br>docker ps</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*cGMF4RW_H2wqPz_DcXpvVg.png" /></figure><p>Now we will open the sonarqube ui on web-browser by putting <strong>&lt;jenkins-server-public-ip&gt;:9000</strong>, then login into default account. Below are the default credentials<br><strong>username: admin</strong><br><strong>pswd: admin</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fzwIphlCKNibgSx178Tl1w.png" /></figure><p>On next screen reset the pswd and click update</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/612/1*kC-eXQCie-KuyZkUreHUmw.png" /></figure><p>After resetting the paswd we can see our sonarqube dashboard</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*dNoXnzGaO3IrtyUNCQIhcg.png" /></figure><p><strong>Installing Trivy</strong> on jenkins-server, we will use it to scan the <strong>vulnerabilities</strong> in our docker image. Below are the commands</p><pre>##installing pre-requisite packages<br>sudo apt-get install wget apt-transport-https gnupg lsb-release<br><br>##getting aquasecurity, adding key and listing the package in source list<br>wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo apt-key add -<br>echo deb https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main | sudo tee -a /etc/apt/sources.list.d/trivy.list<br><br>##installling trivy<br>sudo apt-get update<br>sudo apt-get install trivy</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1006/1*9aj9h8FRpZYGzltoKf16-A.png" /></figure><p><strong>Installing and configuring Ansible Control node: </strong>we will use jenkins server as an controlled ansible node which is used to managed and installing services on k8-master and k8-worker node</p><p>To install ansible on control-node(jenkins-server) we only required 2 packages <strong>python</strong> and <strong>ansible-core</strong>, ansible is not required to installed on managed node just python is required on all node in order to work with ansible, so we just have to make sure python is installed on k8-master and k8-worker node</p><pre>##install python package<br>sudo apt install python3.6<br><br>##install ansible-core<br>sudo apt install ansible-core<br><br>##check ansible version<br>ansible --version<br><br>##creating ansible user, with the shell access<br>sudo i<br>useradd -m -s /bin/bash ansible<br>passwd ansible</pre><p>Ansible connect to other nodes with the help of <strong>ssh</strong>, to do so we have to make sure we are able to ssh on our both <strong>k8-master </strong>and <strong>k8-worker</strong> node from jenkins server. We will create a <strong>private</strong>, <strong>public key pair</strong> in our jenkins server(ansible user) at location <strong>~ dir</strong> and then put the public key inside both managed server at location <strong>/home/$USER/.ssh/authorized_keys</strong></p><p>First create pub, private key pair at ansible user home dir by following command<br><strong>Note:</strong> while generating key don’t enter any passphrase, let everything be default</p><pre>## switch to ansible user<br>$ sudo su ansible<br>$ cd<br>$ mkdir .ssh<br>$ cd .ssh<br><br>## generating key with the name aws_ec2 at location ~/.ssh<br>$ ssh-keygen -t rsa -b 4096 ~/.ssh/aws_ec2<br>$ ls .ssh</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/841/1*ghGwWjs1PSRTKwtjgxcs5w.png" /></figure><p>Now change the private key <strong>file permission</strong> to read and write and give this access to ansible user only, below is the command</p><pre>##changing and viewing file permission<br>chmod 600 .ssh/aws_ec2<br>ls -l .ssh</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/718/1*K4KcM_T8RtjRvHTx6DPg_w.png" /></figure><p>We will update <strong>ansible.cfg</strong> file to include the default private key path, by this we don&#39;t have to specify the path in-order to ssh into managed nodes, below are the command</p><pre>##adding privates ssh key path to ansible cfg file<br>echo private_key_file=/home/ansible/.ssh/aws_ec2 &gt; /etc/ansible/ansible.cfg<br><br>##viewing edited file<br>cat /etc/ansible/ansible.cfg</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*b6c8r1bAFoAUuaPtLiTZIg.png" /></figure><p>Now we copy our public key and place it into both k8-master and k8-worker server at location <strong>/home/k8/.ssh/authorized_keys<br>Login into k8-master server</strong>, first change the hostname to “k8-master” and create a “k8” user, below are the commands</p><pre>##changing hostname<br>hostnamectl hostname k8-master<br><br>##verifying hostname change<br>hostnamectl <br><br>##creating k8 user, with the shell access<br>sudo -i<br>useradd -m -s /bin/bash k8<br>passwd k8<br><br>##adding k8 user to sudo group<br>sudo usermod -aG sudo k8<br>sudo su k8</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/737/1*0NHzahww5bjquKV9TVke8w.png" /></figure><p>Now we will make <strong>.ssh dir</strong> at k8 user and paste the public key inside authorized_keys file which we have copied from the jenkins-server , after that we will exit from the server. Below are the command</p><pre>##creating .ssh if dir not exist<br>mkdir -p .ssh<br><br>##creating authorized_keys file with the public key in it<br>echo &lt;public-key&gt; &gt;&gt; ~/.ssh/authorized_keys<br>cat ~/.ssh/authorized_keys<br><br>##logging out from the k8-master server <br>exit<br>exit</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/810/1*tE3Np0eNlRsnt1bxAtchTw.png" /></figure><p>We will repeat the step for copying public key to k8-worker server. First we will login into the k8-worker server change the hostname to “k8-worker1” and then create “k8&quot; user and at final paste the public key at k8 user ~/.ssh/authorized_keys and then exit from the server</p><pre>##changing hostname<br>hostnamectl hostname k8-worker1<br><br>##verifying hostname change<br>hostnamectl<br><br>##creating k8 user, with the shell access<br>sudo -i<br>useradd -m -s /bin/bash k8<br>passwd k8<br><br>##adding k8 user to sudo group<br>sudo usermod -aG sudo k8<br>sudo su k8<br><br>##creating .ssh if dir not exist<br>mkdir -p .ssh<br><br>##creating authorized_keys file with the public key in it<br>echo &lt;public-key&gt; &gt;&gt; ~/.ssh/authorized_keys<br>cat ~/.ssh/authorized_keys<br><br>##logging out from the k8-master server <br>exit<br>exit</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/638/1*sF_AAaEbv3VnaX9PIZL9QQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/707/1*zJ6jtD99muOPwiQgt0MUvw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/807/1*zzwcMVEuAvm1OD9DTEQWgw.png" /></figure><p>Now after placing public key at both the k8-master and k8-worker server we will test if our ansible control node(jenkins-server) able to connect to both the server</p><p><strong>Login in</strong> into jenkins-server then switch to ansible user. First we have to create a dir name “ansible_k8_mannaged_nodes” in that dir we will create our ansible file structure, below is the command</p><pre>sudo su ansible<br><br>## making our ansible dir ansible_k8_mannaged_nodes and changing working dir<br>mkdir ansible_k8_mannaged_nodes<br>cd ansible_k8_mannaged_nodes</pre><p>In “ansible_k8_mannaged_nodes” dir we will create “inventory” file our managed node host information will be placed in it, below is the command</p><pre>sudo vi inventory<br>###########file content below this line#################<br>[k8-master-node]<br>k8-master<br><br>[k8-worker-node]<br>k8-worker1<br>###########file content above this line#################</pre><p>After creating inventory file we will create “host_var” dir and inside the created dir we create host-variable files, the host variable file name will be the same as the host name we specified in our inventory file in our case it will be “k8-master.yaml” and “k8-worker1.yaml”. Inside both the variable files we will specify the all the variables which related to that host including the connection method and credentials, below is the command</p><pre>mkdir host_vars<br>cd host_vars<br><br>sudo vi k8-master.yaml<br>###########file content below this line#################<br>ansible_connection: ssh<br>ansible_host: k8@35.183.181.173<br>###########file content above this line#################<br><br>sudo vi k8-worker1.yaml<br>###########file content below this line#################<br>ansible_connection: ssh<br>ansible_host: k8@3.98.97.29<br>###########file content above this line#################<br><br>##get to home dir<br>cd</pre><p>Now it’s time to test our connection to both the managed nodes, to test it we will use ansible ping command, below is the command</p><pre>cd ansible_k8_mannaged_nodes<br><br>##ping k8-master node<br>ansible k8-master -m ping -i inventory <br><br>##ping k8-worker node<br>ansible k8-worker1 -m ping -i inventory</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Jme-p34uqZ_urarVhPBs8w.png" /></figure><p><strong>Configuring Kubernetes Cluster through Ansible: </strong>Now we will start configuring Kubernetes cluster through ansible, in this step we will create roles, ansible role help us to automatically loads the artifacts of our respective host. <br>First create a dir name “roles” inside “ansible_k8_mannaged_nodes” dir , below is the command and the snippet of file structure so far</p><pre>mkdir roles</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/928/1*L1RnKTUKcQEJ3GWfD0pRCA.png" /></figure><p>Now we have to create our roles according to the tasks which have to be performed on our nodes, we have separated our whole task into 2 main roles. The first role task named “cluster-setup” will setup all the configuration and packages required both on k8-master and k8-worker node. The second role task name “master-setup”, these are the task which are only run on the k8-master-node after the first batch of task performed(cluster-setup)</p><p>Creating directory</p><pre>cd &amp;&amp; cd ansible_k8_mannaged_nodes/roles<br>mkdir -p cluster-setup master-setup<br>mkdir cluster-setup/tasks &amp;&amp; mkdir master-setup/tasks<br>tocuh cluster-setup/tasks/main.yaml &amp;&amp; tocuh cluster-setup/tasks/main.yaml</pre><p>The file structure for “role” will look like below snippet</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/932/1*Foc48xXcLoOCIBpRuvjJkg.png" /></figure><p>Now we have to edit the file content of our role “cluster-setup”, below is the content of the file “ansible_k8_mannaged_nodes/roles/cluster-setup/tasks/main.yaml”</p><pre><br>    - name: &quot;updating package initially&quot;<br>      apt:<br>        update_cache: yes<br>      become: true<br><br>    - name: &quot;swap-off&quot;<br>      shell: <br>        cmd: swapoff -a; sed -i &#39;/swap/d&#39; /etc/fstab<br>      become: true<br><br>    - name: &quot;install pre-requisite module&quot;<br>      apt: name={{ item }} state=present<br>      with_items: &quot;{{ pre_dependencies }}&quot;<br>      become: true<br><br>    - name: &quot;Getting apt-key for k8&quot;<br>      shell:<br>        cmd: curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -<br>      become: true<br><br>    - name: &quot;adding k8 packege in apt sorce list&quot;<br>      shell: <br>        cmd: echo deb https://apt.kubernetes.io/ kubernetes-xenial main | sudo tee -a /etc/apt/sources.list.d/kubernetes.list<br>      become: true<br>        <br>    - name: &quot;updating package after adding k8 in sorce list&quot;<br>      apt:<br>        update_cache: yes<br>      become: true<br><br>    - name: &quot;install module&quot;<br>      apt: name={{ item }} state=present<br>      with_items: &quot;{{ dependencies }}&quot;<br>      become: true<br><br>    - name: &quot;start docker&quot;<br>      shell:<br>        cmd: sudo systemctl start docker<br>      become: true<br><br>    - name: &quot;enable docker&quot;<br>      shell:<br>        cmd: sudo systemctl enable docker<br>      become: true<br>    <br>    - name: &quot;adding current user to docker group&quot;<br>      shell:<br>        cmd: sudo usermod -aG docker $USER<br>      become: true<br><br>    - name: &quot;update the iptables&quot;<br>      shell:<br>        cmd: |<br>          cat &lt;&lt; EOF | sudo tee /etc/sysctl.d/k8s.conf<br>          net.bridge.bridge-nf-call-ip6tables = 1<br>          net.bridge.bridge-nf-call-iptables = 1<br>          EOF<br>      become: true<br><br>    - name: &quot;applying systemctl param&quot;<br>      shell:<br>        cmd: sudo sysctl --system<br>      become: true<br><br>    - name: &quot;changing docker c-groupc config file&quot;<br>      shell:<br>        cmd: echo &#39;{&quot;exec-opts&quot;:[&quot;native.cgroupdriver=systemd&quot;]}&#39; | sudo tee /etc/docker/daemon.json<br>      become: true<br><br>    - name: &quot;reloading systemd&quot;<br>      shell:<br>        cmd: sudo systemctl daemon-reload<br>      become: true<br><br>    - name: &quot;restart docker&quot;<br>      shell:<br>        cmd: sudo systemctl restart docker<br>      become: true</pre><p>Now we have to edit the master-setup.yaml, below is the content of the file “ansible_k8_mannaged_nodes/roles/master-setup/tasks/main.yaml”</p><pre>    - name: &quot;pulling packages from kubeadm&quot;<br>      shell:<br>        cmd: sudo kubeadm config images pull<br>      become: true<br><br>    - name: &quot;restart kubelet&quot;<br>      shell:<br>        cmd: sudo systemctl restart kubelet<br>      become: true<br><br>    - name: &quot;assigning private ip&quot;<br>      shell:<br>        cmd: sudo kubeadm init &gt;&gt; k8-conection-string<br>      become: true<br><br>    - name: &quot;mkdir .kube at $HOME&quot;<br>      shell:<br>        cmd: mkdir -p $HOME/.kube<br>      become: true<br><br>    - name: &quot;copying k8/admin.conf to /home/$USER/.kube/config&quot;<br>      shell:<br>        cmd: sudo cp /etc/kubernetes/admin.conf $HOME/.kube/config<br>      become: true<br><br>    - name: &quot;changing user and group ownership recursively of /home/$USER/.kube/config&quot;<br>      shell:<br>        cmd: sudo chown $(id -u):$(id -g) $HOME/.kube/config<br>      become: true<br><br>    - name: &quot;activating calico pod networking&quot;<br>      shell:<br>        cmd: kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.25.0/manifests/calico.yaml<br>      become: true</pre><p>After adding the roles task of both cluster-setup and master-setup, now we will add our variable for both the host, these variables are required in the role task file</p><p>Edit the “ansible_k8_mannaged_nodes/host_vars/k8-master.yaml” file with below host variables for k8-master</p><pre>pre_dependencies:<br>  - apt-transport-https<br>  - ca-certificates<br>  - curl<br>  - gpg<br>dependencies:<br>  - kubectl <br>  - kubeadm <br>  - kubelet <br>  - kubernetes-cni <br>  - docker.io</pre><p>Edit the “ansible_k8_mannaged_nodes/host_vars/k8-worker1.yaml” file with below host variables for k8-worker1 host</p><pre>pre_dependencies:<br>  - apt-transport-https<br>  - ca-certificates<br>  - curl<br>  - gpg<br>dependencies:<br>  - kubectl <br>  - kubeadm <br>  - kubelet <br>  - kubernetes-cni <br>  - docker.io</pre><p>After editing both the files our final file content will look like below snippet . As from the below snippet we can see our variables for both the host are almost same</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/905/1*vwn6HgL9eI_4eA9LpkR5vQ.png" /></figure><p>Now we are almost ready to spin-up our k8-cluster through ansible control node, but to run these tasks on our role we need a playbook which can play our role tasks</p><p>Create a playbook named “<strong>k8-playbook.yaml</strong>”, below is the file content, as you can notice i have written “<strong>any_errors_fatal: true</strong>” for both our plays this is because if on any step error occur we have to exit from the ansible immediately without going on to the next task as most of the steps are critical</p><pre>-<br> name: Deploying k8-cluster<br> hosts: k8-master-node k8-worker-node<br> any_errors_fatal: true<br> roles:<br>  - cluster-setup<br><br><br>- <br>  name: Setting up k8-master<br>  hosts: k8-master<br>  any_errors_fatal: true<br>  roles:<br>    - master-setup</pre><p>Now we are ready to run our playbook we will use below command, make sure you are on “ansible” user and in the “<strong>ansible_k8_mannaged_nodes</strong>” directory</p><pre>ansible-playbook -i inventory k8-playbook.yaml </pre><p>If everything goes well every task will be executed smoothly and K8-cluster will be setup, this comes in hand when in real enterprise environment we have 100 of worker node, we can’t manually go into each worker-node and setup k8-cluster. Below are the result snippet</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*hLJhrjXtR276LiOyu8t8pQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*QeTvFYDAxcDDTywjokNbNA.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*F_LV4RcMzwL0czh77pSEZw.png" /></figure><p>Now we have to connect our worker-nodes to our k8-cluster, in order to do so we have to run the<strong> join command</strong> on every worker node on cluster through playbook, we already save the join command which we get from the otuput of the command <strong>kubeadm init</strong> and its located in the file “k8-conection-string”<br>Login into the k8-master(k8-user) server to get the join command, and copy it and then exit from k8-master server</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*tpm3LjqNhRglqBCqWwWIhA.png" /></figure><p>Now logged back into our jenkins-server(ansible-user) which is our ansible control node and create a ansible play to join the worker node to our clusters, below are the commands</p><pre>cd ansible_k8_mannaged_nodes<br>vi k8-joining-node-playbook.yaml</pre><p>Below is the content of the file “k8-joining-node-playbook.yaml”</p><pre>-<br>  name: Joining Worker Nodes<br>  hosts: k8-worker-node<br>  tasks:<br>    - name: kubeadm join<br>      shell:<br>        cmd: kubeadm join 172.31.1.118:6443 --token mwrjxo.3se77rnljzb8lggh --discovery-token-ca-cert-hash swqha256:76546e1bec5c5dd52ec205904930822ec8eeeb1abcc40a925fd4d95c5a6f800c<br>      become: true</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*yfmWltrI_HZ5fKCjHTPm-A.png" /></figure><p>After editing the “k8-joining-node-playbook.yaml” file, we will now run the playbook by below command</p><pre>ansible-playbook -i inventory k8-joining-node-playbook.yaml</pre><p>By joining worker nodes now we can check our nodes, by logging into the worker node and running below command</p><pre>kubectl get nodes -o wide</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ujlpqsM7Y7QXN6reTwESlA.png" /></figure><p>Finally we have completely setup our Kubernetes cluster and its fully functional, now we will exit from k8-master server</p><p><strong>Setting up monitoring-server,</strong> in monitoring server we will first create the Prometheus user, below are the commands</p><pre>##creating prometheus user with no shell and home<br>sudo useradd --system --no-create-home --shell /bin/false prometheus<br><br>##to verify if the user created or not<br>cat /etc/passwd | grep prometheus</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/831/1*-ghYJozp3t3-VqajSYuT3A.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/696/1*WR9p-5rFssIgNOTLTLg3Ig.png" /></figure><p>In this step we will download the prometheus file and then untar the file below is the command</p><pre>##dowloading prometheus <br>wget https://github.com/prometheus/prometheus/releases/download/v2.49.0-rc.1/prometheus-2.49.0-rc.1.linux-amd64.tar.gz<br><br>##untaring the prometheus file<br>tar -xvf prometheus-2.49.0-rc.1.linux-amd64.tar.gz</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*pgVFkwVFybxjT8YnfZGH7Q.png" /></figure><p>After un-taring we will we move files from “prometheus-2.49.0-rc.1.linux-amd64”, below are the command</p><pre>##changing dir<br>cd prometheus-2.49.0-rc.1.linux-amd64<br><br>##moving files<br>sudo mv prometheus promtool /usr/local/bin/<br>sudo mkdir -p /data /etc/prometheus<br>sudo mv consoles console_libraries/ prometheus.yml /etc/prometheus/<br><br>##changing permision to prometheus user<br>sudo chown -R prometheus:prometheus /etc/prometheus/ /data/<br><br>##verifying the permision of file if changed or not<br>stat /etc/prometheus<br>stat /data</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ZUrxOHQc8L_iENlyiWL4jA.png" /></figure><p>checking prometheus version</p><pre>prometheus --version</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1015/1*QPVx2eeMroEVId3cAvDfoQ.png" /></figure><p>Now we will create the systemd file of prometheus in order for it to run as an service, edit the “/etc/systemd/system/prometheus.service” file and update it with the below content</p><pre>sudo vi /etc/systemd/system/prometheus.service</pre><pre>[Unit]<br>Description=Prometheus<br>Wants=network-online.target<br>After=network-online.target<br>StartLimitIntervalSec=500<br>StartLimitBurst=5<br>[Service]<br>User=prometheus<br>Group=prometheus<br>Type=simple<br>Restart=on-failure<br>RestartSec=5s<br>ExecStart=/usr/local/bin/prometheus \<br> - config.file=/etc/prometheus/prometheus.yml \<br> - storage.tsdb.path=/data \<br> - web.console.templates=/etc/prometheus/consoles \<br> - web.console.libraries=/etc/prometheus/console_libraries \<br> - web.listen-address=0.0.0.0:9090 \<br> - web.enable-lifecycle<br>[Install]<br>WantedBy=multi-user.target</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/725/1*-3xiiRQeoqprPDWvFpocFw.png" /></figure><p>After editing the file we will enable it and start the prometheus service, below is the command</p><pre>sudo systemctl enable prometheus.service<br>sudo systemctl start prometheus.service<br>systemctl status prometheus.service</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1018/1*JuWEsDN9_pVOGJZLZtWYDQ.png" /></figure><p>we will check the default port of prometheus by below command, and then open it in web browser by using following url &lt;monitoring-server-public-ip&gt;:&lt;prometheus-port&gt;, in our case it is 35.183.234.130:9090</p><pre>sudo lsof -i -P -n | grep LISTEN</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/882/1*9FORyGTX9k-ZjY8NrmIWMw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*xXF8oOEgMv7G55DpRK_HfQ.png" /></figure><p>Once prometheus is up and running now we want node_exporter to export machine resources data like(CPU,RAM etc), then tese data will be showed on Grafana dashboard used as a “<strong>Data Source</strong>” for <strong>Grafana</strong></p><p>First we will create node_exporter user then downloading node_exporter package and extract it and at last moving the <strong>node_exporter</strong> dir to <strong>/usr/local/bin/</strong>, below is the command</p><pre>##creating node_exporter user with no shell and home<br>sudo useradd --system --no-create-home --shell /bin/false node_exporter<br><br>##to verify if the user created or not<br>cat /etc/passwd | grep node_exporter<br><br>##downloading the node exporter package<br>wget https://github.com/prometheus/node_exporter/releases/download/v1.7.0/node_exporter-1.7.0.linux-amd64.tar.gz<br><br>##untar the node_exporter package and moving the node_exporter<br>tar -xvf node_exporter-1.7.0.linux-amd64.tar.gz<br>sudo mv node_exporter-1.7.0.linux-amd64/node_exporter /usr/local/bin/</pre><p>check <strong>node_exporter</strong> version, below is the command</p><pre>node_exporter --version</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/997/1*d6i97kW-IM_LRFnoUxwpRw.png" /></figure><p>Now we will create the systemd file of node_exporter in order for it to run as an service, edit the “<strong>/etc/systemd/system/node_exporter.service</strong>” file and update it with the below content</p><pre>sudo vi /etc/systemd/system/node_exporter.service</pre><pre>[Unit]<br>Description=Node Exporter<br>Wants=network-online.target<br>After=network-online.target<br>StartLimitIntervalSec=500<br>StartLimitBurst=5<br>[Service]<br>User=node_exporter<br>Group=node_exporter<br>Type=simple<br>Restart=on-failure<br>RestartSec=5s<br>ExecStart=/usr/local/bin/node_exporter \<br> - collector.logind<br>[Install]<br>WantedBy=multi-user.target</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/645/1*Fqf8u699eyqhxtn7aTJxGA.png" /></figure><p>After editing the file we will enable it and start the node_exporter service, below is the command</p><pre>sudo systemctl enable node_exporter<br>sudo systemctl enable node_exporter<br>systemctl status node_exporter.service</pre><p>we will now add the node exporter to prometheus<strong> target file</strong> “<strong>/etc/prometheus/prometheus.yml</strong>”, inorder to get the metrics send by the node_exporter</p><pre>sudo vim /etc/prometheus/prometheus.yml</pre><p>edit the file with the below content</p><pre>  - job_name: &quot;node_exporter&quot;<br>    static_configs:<br>      - targets: [&quot;localhost:9100&quot;]</pre><p>now our file will look like this in the below snippet</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/1*z5yx5KKbK6k40v9tjPai6A.png" /></figure><p><strong>promtool</strong> is used to validate our changes in our promethus configuration, we use it to validate our changes which just made, below is the command</p><pre>promtool check config /etc/prometheus/prometheus.yml</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/892/1*fGuPtun4mswsCo35mswE1A.png" /></figure><p>once the changes is confirmed and validated, now we can push our changes to prometheus server by using curl post command to our server, below is the command</p><pre>curl -X POST http://localhost:9090/-/reload</pre><p>The changes can be verified by going on to /target path on our prometheus server, in our case the url is “<a href="http://35.183.234.130:9090/targets?search="><strong>http://35.183.234.130:9090/target</strong></a><strong>s</strong>”</p><p>Now we will install Grafana tool in our monitoring server in order to visualize our metrics data, coming from our prometheus target paths, below are the commands</p><pre>sudo apt-get install -y apt-transport-https software-properties-common wget<br>sudo mkdir -p /etc/apt/keyrings/<br>wget -q -O - https://apt.grafana.com/gpg.key | gpg - dearmor | sudo tee /etc/apt/keyrings/grafana.gpg &gt; /dev/null<br>echo &quot;deb [signed-by=/etc/apt/keyrings/grafana.gpg] https://apt.grafana.com stable main&quot; | sudo tee -a /etc/apt/sources.list.d/grafana.list<br>echo &quot;deb [signed-by=/etc/apt/keyrings/grafana.gpg] https://apt.grafana.com beta main&quot; | sudo tee -a /etc/apt/sources.list.d/grafana.list<br>sudo apt-get update</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*n1PbnZdFciWCr0VbRhohuA.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4Vow8WLGEBBzNuukGyQ_8w.png" /></figure><p>now install grafana</p><pre>sudo apt-get install grafana</pre><p>after installing grafana we will enable the grafana service, below are the commands</p><pre>sudo systemctl enable grafana-server.service<br>sudo systemctl start grafana-server.service<br>sudo systemctl status grafana-server.service</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Rj9vlYn1AZpeM2AKI4cNxQ.png" /></figure><p>in order to login into grafana on web we required the port, to get port we will use below commands</p><pre>sudo lsof -i -P -n | grep LISTEN</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/912/1*GjhlaovfsWNRKjt6ZgSLYw.png" /></figure><p>copy your grafana url &lt;monitoring-server-public-ip&gt;:&lt;grafana-port&gt; on web browser, in our case it will be “35.183.234.130:3000”. At first time we have to reset the pswd, the default username and pswd is “<strong>admin</strong>”</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Tdj9MrPKbpTduGqktFqKGw.png" /></figure><p>After login into grafana, we first add a data source by clicking on “Add your first data source” then select prometheus then giving it a name and the prometheus url which is in our case is the mointoring-server-public-ip:9090 “<a href="http://35.183.234.130:9090/"><strong>http://35.183.234.130:9090</strong></a>”</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Uonrr153pXOHSQ-o4B8qww.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*UBkgy5lyDvbMDeeuD-cg-g.png" /></figure><p>Now click “Save &amp; test”</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*9RN46Nx-4I_6EVDznMb2iQ.png" /></figure><p>Now we will configure the dashboard for our data source, going to the dashboard section and importing a dashboard by its dashboard id and click “Load”</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*qt96H-btUG3zGFGlhWbsIg.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ArV8mlfDeifL9OiBhbm-PA.png" /></figure><p>Below is the dashboard snippet</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*j56xWkNu3sZLPzme2iUPhQ.png" /></figure><p><strong>Configuring node exporter on jenkins server, </strong>in order to monitor the jenkins-server we need an agent which export the server resource data like node_exporter and then add it to prometheus target then finally create an dashboard on grafana</p><p>First installing prometheus plugin on jenkins, below is the snippet</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*WO6SqmA7lmIpCbe0PbJ21Q.png" /></figure><p>Now we will edit “/etc/prometheus/prometheus.yml” to add in our jenkins-server target, below is the commad to edit the content</p><pre>sudo vim /etc/prometheus/prometheus.yml</pre><pre>- job_name: &quot;jenkins&quot;<br>    static_configs:<br>      - targets: [&quot;&lt;jenkins-server-public-ip&gt;:8080&quot;]</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/691/1*rh86_ruXBTt4Ggm5Cn8I4Q.png" /></figure><p>now testing the config file which we have just edited through promtool, below is the command</p><pre>promtool check config /etc/prometheus/prometheus.yml</pre><p>if its validated then we will push our changes to prometheus server, below is the command</p><pre>curl -X POST http://localhost:9090/-/reload</pre><p>We now check if our jenkins metrics appears on our prometheus /target or not, to do so we will open our prometheus url with /target path in it. In our case it is “<a href="http://35.183.234.130:9090/target">http://35.183.234.130:9090/target</a>”</p><p>In this step we will create the dashboard on grafana for our jenkins metrics, to do so we will first import jenkins dashboard clicking on<br> New-&gt;Import and then providing the jenkins dashboard id and Load it</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*YCSzJ0lA4UX_M9_4I7lceg.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/875/1*6Qb7SrLFB6LZwH3JAlaA9g.png" /></figure><p>After that we will select the default prometheus from drop-down menu and click import it</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*w97Ab0kSFbGZ_Gx_KpDqag.png" /></figure><p>Below is the jenkins-server grafana dashbaord snippet</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*aScH4lPeIDKTywf2IK2khw.png" /></figure><p><strong>Configuring node exporter as a daemonset on k8-cluster: </strong>Till now we have configured our grafana dashboard for the 2 servers jenkins-server and the monitoring-server itself, now we will configure grafana dashboard for our k8-worker and k8-master server. On both the server we will take leverage of kubernetes and deploying a daemonset of node_exporter service and not installing node_exporter directly on the server</p><p>First login into k8-mater server and create a namespace named “monitoring”, below is the command</p><pre>kubectl create ns monitoring<br>kubectl get ns </pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/682/1*TVvu7hz02vjL2P_NkISMiQ.png" /></figure><p>In this step we create daemonset, we will create it by creating definition file. For creating definition file we create a pod definition file using imperative command as it mostly match to it and then edit this file accordingly</p><pre>##creating definition folder, all the definition file will be placed here<br>mkdir k8-definitions<br><br>##generating a definition and then saving it<br>kubectl run node-exporter --image=prom/node-exporter \<br>  --port=9100 \<br>  -n monitoring \<br>  --dry-run=client -o yaml &gt; k8-definitions/node-exporter-ds.yaml<br>  <br>##now we will edit the file to make it a daemonset as our requirement<br>vi k8-definitions/node-exporter-ds.yaml<br><br>##after editing file create daemonset<br>kubectl apply -f k8-definitions/node-exporter-ds.yaml</pre><p>Below is the final content of daemonset definition which will goes into the “k8-definitions/node-exporter-ds.yaml” file.</p><pre>kind: DaemonSet<br>metadata:<br>  labels:<br>    app.kubernetes.io/name: node-exporter<br>  name: node-exporter<br>  namespace: monitoring<br>spec:<br>  selector:<br>    matchLabels:<br>      app.kubernetes.io/name: node-exporter<br>  template:<br>    metadata:<br>      labels:<br>        app.kubernetes.io/name: node-exporter<br>    spec:<br>      tolerations: <br>      - key: node-role.kubernetes.io/control-plane<br>        effect: NoSchedule<br>      containers:<br>      - args:<br>        - --path.sysfs=/host/sys<br>        - --path.rootfs=/host/root<br>        - --no-collector.wifi<br>        - --no-collector.hwmon<br>        - --collector.filesystem.ignored-mount-points=^/(dev|proc|sys|var/lib/docker/.+|var/lib/kubelet/pods/.+)($|/)<br>        - --collector.netclass.ignored-devices=^(veth.*)$<br>        name: node-exporter<br>        image: prom/node-exporter<br>        ports:<br>          - containerPort: 9100<br>            protocol: TCP<br>        resources:<br>          limits:<br>            cpu: 250m<br>            memory: 180Mi<br>          requests:<br>            cpu: 102m<br>            memory: 180Mi<br>        volumeMounts:<br>        - mountPath: /host/sys<br>          mountPropagation: HostToContainer<br>          name: sys<br>          readOnly: true<br>        - mountPath: /host/root<br>          mountPropagation: HostToContainer<br>          name: root<br>          readOnly: true<br>      volumes:<br>      - hostPath:<br>          path: /sys<br>        name: sys<br>      - hostPath:<br>          path: /<br>        name: root</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*aPtz2N5zAhrhxMw7-vdCKg.png" /></figure><p><strong>NOTE: </strong>If we see our “<strong>node-exporter-ds.yaml</strong>” definition file i have added a tolerations in it of type “<strong>NoSchedule</strong>” with the key “<strong>node-role.kubernetes.io/control-plane</strong>”. This is because by default master node is <strong>tainted</strong>, the purpose of taint is to make sure no other pod is deployed on node except only the one’s which have toleration for that specific taint. We can find the taint on node by checking the config, below is the command and snippet</p><pre>##it will check Taints key if exist in node config<br>kubectl describe node k8-master | grep Taint</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/803/1*sXexV1wUwDOm1WQe0p4_5w.png" /></figure><p>From the below snippet we can see our daemonset pod is deployed on both the k8-node “k8-master” and “k8-worker1”</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*C8XnId66mOjxoOFQzt26eA.png" /></figure><p>After creating the daemonset now we will create the service of node-exporter through definition file named “node-exporter-sv.yaml” for our daemonsets, below is the command</p><pre>kubectl create service nodeport node-exporter --tcp=9100 \<br>  -n monitoring \<br>  --dry-run=client -o yaml &gt; k8-definitions/node-exporter-sv.yaml<br><br>##editing the file<br>vi k8-definitions/node-exporter-sv.yaml<br><br>##after editing file create service<br>kubectl apply -f k8-definitions/node-exporter-sv.yaml<br><br>##listing services in monitoring namespace<br>kubectl get svc -n monitoring</pre><p>Below is the final content of service definition which will goes into the “k8-definitions/node-exporter-sv.yaml” file</p><pre>kind: Service<br>apiVersion: v1<br>metadata:<br>  name: node-exporter<br>  namespace: monitoring<br>  annotations:<br>      prometheus.io/scrape: &#39;true&#39;<br>      prometheus.io/port:   &#39;9100&#39;<br>spec:<br>  selector:<br>      app.kubernetes.io/name: node-exporter<br>  type: NodePort<br>  ports:<br>  - name: node-exporter<br>    protocol: TCP<br>    port: 9100<br>    targetPort: 9100</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/882/1*2A9uVDOJ0tunEMSDN4TOpw.png" /></figure><p>As we can see from the above snippet, k8 have assigned us random valid nodeport for our service, this is the port “32025” which we will use with our public ip for the node_exporter url, in our case it is “35.183.181.173:32025” and “3.98.97.29:32025”, below are the snippets</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/912/1*oEUA55QN1FWYMizbY01Y4w.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*oW1WG7B6ekpgXMy9fWnbqQ.png" /></figure><p>Exit from the k8-worker host machine and then logged back in to the “monitoing-server”</p><p>Now we will add these node_exporter url for the metrics at prometheus target file “/etc/prometheus/prometheus.yml”, below is the content</p><pre>sudo vim /etc/prometheus/prometheus.yml</pre><pre>  - job_name: &quot;k8-master&quot;<br>    metrics_path: &quot;/metrics&quot;<br>    static_configs:<br>      - targets: [&quot;35.183.181.173:32025&quot;]<br><br>  - job_name: &quot;k8-worker1&quot;<br>    metrics_path: &quot;/metrics&quot;<br>    static_configs:<br>      - targets: [&quot;3.98.97.29:32025&quot;]</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*a3BgqrzVwPNF8IFY58Lrvg.png" /></figure><p>After making change in file we will validate the changes and push the changes to prometheus server if its validated</p><pre>##validating the changes<br>promtool check config /etc/prometheus/prometheus.yml<br><br>##pushing the changes to prometheus server<br>curl -X POST http://localhost:9090/-/reload</pre><p>Now we can see our node_exporter metrics url at prometheus /target path</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*adyW-z5E8OhitUIhwQQAIQ.png" /></figure><p>Now we can check the metrics of k8 hardware resources on grafana, go the the grafana dashboard and select Node Exporter, we can see the the kuberentes metrics there</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*s97Dr862t-YIvjTe9xgutg.png" /></figure><p><strong>Setting up CI/CD Pipeline: </strong>in last we have to configure our build pipeline on jenkins, we have to install multiple plugins and configure them. we will start with the below plugins Download following plugins <strong>Eclipse Temurin installer</strong> , <strong>SonarQube Scanner, NodeJS</strong></p><p>Login into your jenkins account, in our case the jenkins url is “3.96.135.216:8080”, click “Manage Jenkins” from left pane then click “Plugins” then click on “Available Plugins” from left pane, type the listed plugins then select all the listed plugins and then click on Install</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Y6GNV4lW0n-5CeUXxVwVBQ.png" /></figure><p>Once Installed now we have to configure NodeJS and JDK tools, Goto <strong>Dashbaord-&gt;Manage Jenkins-&gt;Tools</strong><br>Then go-to Jdk section and add following details below in snippet</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/878/1*Ln5ryZkiZKkUu6VxSSaEfA.png" /></figure><p>Go to NodeJs section and add below details, i’ve selected “16.0.0” version because my “resume-app” is not comaptible with latest version</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4rtqn9MbsnFdte4U7v_zcQ.png" /></figure><p>Now we will setup sonarqube which we install earlier, to include this in our pipeline, open sonarqube url &lt;jenkins-server-public-ip&gt;:9000 in our case it is “<a href="http://3.96.135.216:9000/projects">3.96.135.216:9000</a>”</p><p>First we have to get the user authentication token for this we have to go to Administration-&gt;Security-&gt;Users then click on the small list icon under token column</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ZrP4IO7aRWKQFvNfacFfZQ.png" /></figure><p>Now we will provide the token name as in our case it is “plg1” and then click on generate, we will copy the generated token and keep it somewhere</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*750GMfewLhrHXuAHucWjxQ.png" /></figure><p>We will add this token to Jenkins Credentials, go to Dashbaord-&gt;Manage Jenkins-&gt;Credentials-&gt;System-&gt;Global credentials, then click on “Add Credentials” and paste the token we just created, the id i have give is “sonarqube-token”, below are the details in snippet</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_yyt56GavEElyc7iSb3goQ.png" /></figure><p>Now we will add sonarqube to jenkins system, go to Manage Jenkins-&gt;System then on “Sonarqube servers” section we will add the name and sonarqube server url, below is the snippet</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ENdikNwQWlHxwdP3bSybYA.png" /></figure><p>Then we will add sonarqube-scanner into tools, go to <br>Manage Jenkins-&gt;Tools and scroll to “SonarQube Scanner” section add it with below details in snippet</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Jzg3cGsgTojNd8OV7xEJqg.png" /></figure><p>Now we have to create a webhook for jenkins on sonarqube, go to sonarqube url click on Administration-&gt;Configuration<strong> </strong>and then select Webhooks. Click on create and create the webhook with below details in snippet</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_wEyyGdCn0HliQ34-vkRHg.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/607/1*2TEyO-FJhiEHF7SesMglQQ.png" /></figure><p>Below is the created webhook for jenkins on sonarqube</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Jnw5q6USKP81OB0o5xVHXQ.png" /></figure><p>After creating webhook, now we will create sonarqube project Manually</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jbE96MEhdqCkVVtdYecakA.png" /></figure><p>Below are the details in snippet</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/651/1*4vzWFT6F8gCWEMtjOP3qzQ.png" /></figure><p>Click on setup, then on next screen provide existing token then continue</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*1qsRBkOQWDZLR9vEEaveTw.png" /></figure><p>On 2nd step select other as your build step and Linux as OS</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*laECVEI0Gg-AKOHDtYqjyA.png" /></figure><p>Now we will add a post-build alert in our pipeline, we will send email in as an post-build alert with the information about the build. For this we need an sender email address we are using gmail for this</p><p>First add an Email extension plugin</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*nYjOmzkmwNmHfqLQ-lH-NQ.png" /></figure><p>Then generate an app password from the gmail, we will use this app password in our credentials, put App name “Jenkins” Click on Create</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*IiPtGk2IO095XON4sCusUg.png" /></figure><p>Below is the snippet of generated App password</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/855/1*13zxcoiOcNL2CkWeMP4t5A.png" /></figure><p>Now we will add this “app-password” in our jenkins credentials, go to Manage Jenkins-&gt;Credentials-&gt;System-&gt;Global credentials then click on “Add Credentials”</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*hHoMVU1xQg0EqWqlIapIzg.png" /></figure><p>Below are the email credentials detail in snippet</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/951/1*-f0iCjK2Xi1iBmGBCtbFLQ.png" /></figure><p>Once added it will look like below</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*cIAv-k9t68sbmgmWdWGYYw.png" /></figure><p>Once the credentilas setup for email, we will move to the “<strong>SMTP server</strong>” in our Jenkins System settings, go to Manage Jenkins-&gt;System and scroll down to “<strong>E-mail Notification</strong>” and the below details shown in snippet. Provide SMTP server-name, server-port and email credentials</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/915/1*VMXGpf7dCR83IAfiklc_3w.png" /></figure><p>We can test if email is sending or not by clicking on test check-box</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/538/1*d3j8ZGLqLwG8xkAqYqOspw.png" /></figure><p>We are almost ready to make our initial build with sonarqube and postbuild alert but we need a code repo(an node.js application). For the demo purpose i have get the react-resume-app from the github and named it “<a href="https://github.com/syedtahamashhadi/plg1-resume.git"><strong>plg1-resume</strong></a>” you can use this repo or any node-js appliaction<br><strong>Note: </strong>If you get the dependencies issue you can change the node.js version from Dashboard-&gt;Manage Jenkins-&gt;Tools Node.js section, as i am using version “16.0.0&quot;</p><p>This repo is private, in order to pull from this repo we need credentials. We will setup ssh access to our github account from our jenkins server, first we will create private-public key put the public-key on github and then we will provide this private key in jenkins-credentials</p><p>Login into jenkins server switch user to jenkins then generate ssh key , below is the code</p><pre>su jenkins<br><br>##generating key leave everything as default<br>ssh-keygen<br><br>##copy public key &quot;id_rsa.pub&quot;<br>cat .ssh/id_rsa.pub</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*eB-WwKh6YaNvZKbIhQxVpw.png" /></figure><p>Copy the public key and paste it into “SSH and GPG keys” section under profile settings, in our case we named it “plg1-jenkins-server”, below is the snippet</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*2utOtCsvQ5kniYdXVNs8EA.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*HKM5AulVk__4OF7f9R5q8w.png" /></figure><p>Now verify if the ssh connection is established to our github from jenkins-server, below is the command</p><pre>ssh -T git@github.com</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1007/1*UNBboF96Ze1lt4eHDWYrNA.png" /></figure><p>Now copy the private ssh key(“<strong>id_rsa</strong>”) which we have just created located at jenkin user in the jenkins-server and then create a jenkins credentials with it. Go to Manage Jenkins-&gt;Credentials-&gt;System-&gt;Global Credentials, add new credentials with the details below in the snippet, use your git email and private key which you just copied</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*YqgqiTNBqzfsWmIx0rpxcg.png" /></figure><p>We are done with setting up git credential, now we can easily pull the code from our private repo using the “git ssh url”</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*CtVt7M-ZntMeqle0kc5wGg.png" /></figure><p>Now we will setup the initial pipeline, go to the Jenkins dashboard select “New item” from left pane select the “Pipeline” project and named it “Resume” and click “OK”</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*hopcz1pwrG0PR-jTwV9eug.png" /></figure><p>In next screen scroll-down to the Pipeline section and add script, below is the initial pipeline stage script</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*NXst6y_2-JQ25Wk7e4s_QA.png" /></figure><pre>pipeline{<br>    agent any<br>    tools{<br>        jdk &#39;jdk&#39;<br>        nodejs &#39;nodejs&#39;<br>    }<br>    environment {<br>        SCANNER_HOME=tool &#39;sonarqube-server&#39;<br>    }<br>    stages {<br>        stage(&#39;Workspace Cleaning&#39;){<br>            steps{<br>                cleanWs()<br>            }<br>        }<br>        stage(&#39;Checkout from Git&#39;){<br>            steps{<br>                git branch: &#39;master&#39;, credentialsId: &#39;git_ssh_key&#39;, url: &#39;git@github.com:syedtahamashhadi/plg1-resume.git&#39;<br>            }<br>        }<br>        stage(&quot;Sonarqube Analysis&quot;){<br>            steps{<br>                 withSonarQubeEnv(&#39;sonarqube-server&#39;) {<br>                    sh &#39;&#39;&#39; $SCANNER_HOME/bin/sonar-scanner -Dsonar.projectName=Resume \<br>                    -Dsonar.projectKey=Resume \<br>                    &#39;&#39;&#39;<br>                }<br>            }<br>        }<br>        stage(&quot;Quality Gate&quot;){<br>           steps {<br>                script {<br>                    waitForQualityGate abortPipeline: false, credentialsId: &#39;sonar-token&#39; <br>                }<br>            } <br>        }<br>        stage(&#39;Install Dependencies&#39;) {<br>            steps {<br>                sh &quot;npm install&quot;<br>            }<br>        }  <br>    }<br>    post {<br>     always {<br>        emailext attachLog: true,<br>            subject: &quot;&#39;${currentBuild.result}&#39;&quot;,<br>            body: &quot;Project: ${env.JOB_NAME}&lt;br/&gt;&quot; +<br>                &quot;Build Number: ${env.BUILD_NUMBER}&lt;br/&gt;&quot; +<br>                &quot;URL: ${env.BUILD_URL}&lt;br/&gt;&quot;,<br>            to: &#39;syedtaha2016@gmail.com&#39;,<br>            attachmentsPattern: &#39;trivyfs.txt,trivyimage.txt&#39;<br>        }<br>    }<br>}</pre><p>Now click on Apply and then Save, after saving the script we will create the build by clicking on “Build Now” on left pane, once build is sucessfully completed we can check our sonarqube code analysis on our sonarqube server under project section</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bSVAwUTelNcv02MDKxVHoQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*J8ynP3Fb_mF2x5rPh063yA.png" /></figure><p>Now we will setup OWASP build step, first we will install required plugins<br>“OWASP Dependency-Check Plugin” an then add it in <br>Tools-&gt;”Dependency-Check installations”</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6wjhFvv4fFrtK8Jidqhvxg.png" /></figure><p>Below is the details to put in Dependency-Check</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*CBbxrhLi_eGGsdEP0arecA.png" /></figure><p>Now we will add the build step for OWASP in our “Resume” pipeline, below is the build step for it</p><pre>stage(&#39;OWASP DP SCAN&#39;) {<br>  steps {<br>      dependencyCheck additionalArguments: &#39;--scan ./ --disableYarnAudit --disableNodeAudit&#39;, odcInstallation: &#39;OWASP-DP-CHECK&#39;<br>      dependencyCheckPublisher pattern: &#39;**/dependency-check-report.xml&#39;<br>  }<br>}<br>stage(&#39;TRIVY FS SCAN&#39;) {<br>    steps {<br>        sh &quot;trivy fs . &gt; trivyfs.txt&quot;<br>    }<br>}</pre><p>Click on save and make build of it, once build is sucessfull we see the dependency check report on the left pane, as shown in below snippet</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*NgDVxFXWlufMlWw1ux7BLQ.png" /></figure><p>Now we have to setup docker build step, in order to do so we need docker-hub account then we push the docker image to our private docker repo, create one at <a href="https://hub.docker.com/">https://hub.docker.com/</a>. Once we have our docker hub account we need to pass our docker hub credentials in our jenkins credentials management</p><p>First add required docker plugins into jenkins, below are the required plugin<br>Docker, Docker Commons, Docker Pipeline, Docker API, docker-build-step</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*xIJ3CNnDfj0OykJiLqtdWA.png" /></figure><p>Adding docker credentials, as shown in below snippet</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*z3bolWZuv5ncNkUMzzV7Qw.png" /></figure><p>After adding credentials we can add the build step in it, below is the build step</p><pre> stage(&#39;Docker Build and Push to Docker Hub&#39;) {<br>    steps{<br>        script{<br>            withDockerRegistry(credentialsId: &#39;docker_hub_cred&#39;, toolName: &#39;docker&#39;){<br>                sh &quot;docker build -t resume .&quot;<br>                sh &quot;docker tag resume spawn328/resume:latest&quot;<br>                sh &quot;docker push spawn328/resume:latest&quot;<br>            }<br>        }<br>    }<br>}<br>stage(&#39;TRIVY&#39;){<br>    steps{<br>        sh &#39;trivy image spawn328/resume:latest &gt; trivyimage.txt&#39;<br>    }<br>}</pre><p>In-order to make a docker image we required <strong>Dockerfile</strong> of our code, this file must be placed at root dir of our project folder. Below is the Dockerfile for our react-resume app. If your application is different it can differ slightly</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/622/1*iceYU9qteIfDiPqEWmToww.png" /></figure><p>Now we will create the build, from the below snippet we can see its successful</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Ti9oY4DuXI5IlRKEdy0qzg.png" /></figure><p>Once build is successful our docker image is pushed to our docker hub repo</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bKMhlnKkY_lMIaQ0hE0LMw.png" /></figure><p>Now we have to configure and add last step in our build process which is to deploy the docker image as pod on to our Kubernetes cluster. To do so we first need to install all required plugin into Jenkins. Below are the plugins</p><p>Kubernetes, Kubernetes Credentials, Kubernetes Client API, Kubernetes CLI, Kubernetes Credential Provider</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*U83prr9uV4plyjwCkwbmtA.png" /></figure><p>Now in-order to deploy our image on K8 cluster, we need jenkins able to access k8-cluster , we can do so by getting the .kube/config details and adding it to jenkins credentials as a secret file</p><p>Login into k8-master server et the config details from .kube/config located at home dir of k8 user, below is the code</p><pre>su k8<br><br>##copy the output and save it in a file name &quot;k8-config.txt&quot; at local machine<br>cat .kube/config</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ELtOTObRQgT1r4S2WSSbPw.png" /></figure><p>Now add this file as a credentials on jenkins, below is the snippet</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8dDnHLKZVS6CDLGJ87zQVQ.png" /></figure><p>Now we are ready to include our last build step which is to deploy application on kubernetes cluster, below is the build step<br><strong>Note: </strong>deployment.yaml and service.yaml file is included into our code repo, also i will mention both the definition file here too, place both the file inside k8 dir located at root of the project folder</p><p><strong>deolyment.yaml</strong></p><pre>apiVersion: apps/v1<br>kind: Deployment<br>metadata:<br>  labels:<br>    app: resume-fe<br>  name: resume-fe<br>  namespace: webapp<br>spec:<br>  replicas: 2<br>  selector:<br>    matchLabels:<br>      app: resume-fe<br>  template:<br>    metadata:<br>      labels:<br>        app: resume-fe<br>    spec:<br>      containers:<br>      - image: spawn328/resume:latest<br>        name: resume<br>        ports:<br>        - containerPort: 80</pre><p><strong>service.yaml</strong></p><pre>apiVersion: v1<br>kind: Service<br>metadata:<br>  creationTimestamp: null<br>  labels:<br>    app: resume-fe<br>  name: resume-fe<br>  namespace: webapp<br>spec:<br>  ports:<br>  - name: 80-80<br>    port: 80<br>    protocol: TCP<br>    targetPort: 80<br>    nodePort: 31000<br>  selector:<br>    app: resume-fe<br>  type: NodePort</pre><p><strong>Note: To save time and resources, I have not implemented a full Ingress controller for our Kubernetes services.</strong></p><p>Build step for deploying application on kubernetes</p><pre>stage(&#39;Deploy to Kubernetes&#39;){<br>  steps{<br>      script{<br>          dir(&#39;k8&#39;) {<br>              withKubeConfig(caCertificate: &#39;&#39;, clusterName: &#39;&#39;, contextName: &#39;&#39;, credentialsId: &#39;k8s&#39;, namespace: &#39;webapp&#39;, restrictKubeConfigAccess: false, serverUrl: &#39;&#39;) {<br>                      sh &#39;kubectl apply -f deployment.yaml&#39;<br>                      sh &#39;kubectl apply -f service.yaml&#39;<br>                      sh &#39;kubectl get svc -n webapp&#39;<br>                      sh &#39;kubectl get all -n webapp&#39;<br>              }   <br>          }<br>      }<br>  }<br>}</pre><p>Our final build script will look like below</p><pre>pipeline{<br>    agent any<br>    tools{<br>        jdk &#39;jdk&#39;<br>        nodejs &#39;nodejs&#39;<br>    }<br>    environment {<br>        SCANNER_HOME=tool &#39;sonarqube-server&#39;<br>    }<br>    stages {<br>        stage(&#39;Workspace Cleaning&#39;){<br>            steps{<br>                cleanWs()<br>            }<br>        }<br>        stage(&#39;Checkout from Git&#39;){<br>            steps{<br>                git branch: &#39;master&#39;, credentialsId: &#39;git_ssh_key&#39;, url: &#39;git@github.com:syedtahamashhadi/plg1-resume.git&#39;<br>            }<br>        }<br>        stage(&quot;Sonarqube Analysis&quot;){<br>            steps{<br>                withSonarQubeEnv(&#39;sonarqube-server&#39;) {<br>                    sh &#39;&#39;&#39; $SCANNER_HOME/bin/sonar-scanner -Dsonar.projectName=Resume \<br>                    -Dsonar.projectKey=Resume \<br>                    &#39;&#39;&#39;<br>                }<br>            }<br>        }<br>        stage(&quot;Quality Gate&quot;){<br>           steps {<br>                script {<br>                    waitForQualityGate abortPipeline: false, credentialsId: &#39;sonarqube-token&#39; <br>                }<br>            } <br>        }<br>        stage(&#39;Install Dependencies&#39;) {<br>            steps {<br>                sh &quot;npm install&quot;<br>            }<br>        }<br>        stage(&#39;OWASP DP SCAN&#39;) {<br>            steps {<br>                dependencyCheck additionalArguments: &#39;--scan ./ --disableYarnAudit --disableNodeAudit&#39;, odcInstallation: &#39;OWASP-DP-CHECK&#39;<br>                dependencyCheckPublisher pattern: &#39;**/dependency-check-report.xml&#39;<br>            }<br>        }<br>        stage(&#39;TRIVY FS SCAN&#39;) {<br>            steps {<br>                sh &quot;trivy fs . &gt; trivyfs.txt&quot;<br>            }<br>        }<br>        stage(&#39;Docker Build and Push to Docker Hub&#39;) {<br>            steps{<br>                script{<br>                    withDockerRegistry(credentialsId: &#39;docker_hub_cred&#39;, toolName: &#39;docker&#39;){<br>                        sh &quot;docker build -t resume .&quot;<br>                        sh &quot;docker tag resume spawn328/resume:latest&quot;<br>                        sh &quot;docker push spawn328/resume:latest&quot;<br>                    }<br>                }<br>            }<br>        }<br>        stage(&#39;TRIVY&#39;){<br>            steps{<br>                sh &#39;trivy image spawn328/resume:latest &gt; trivyimage.txt&#39;<br>            }<br>        }<br>        stage(&#39;Deploy to Kubernetes&#39;){<br>            steps{<br>                script{<br>                    dir(&#39;k8&#39;) {<br>                        withKubeConfig(caCertificate: &#39;&#39;, clusterName: &#39;&#39;, contextName: &#39;&#39;, credentialsId: &#39;k8s&#39;, namespace: &#39;webapp&#39;, restrictKubeConfigAccess: false, serverUrl: &#39;&#39;) {<br>                                sh &#39;kubectl apply -f deployment.yaml&#39;<br>                                sh &#39;kubectl apply -f service.yaml&#39;<br>                                sh &#39;kubectl get svc&#39;<br>                                sh &#39;kubectl get all&#39;<br>                        }   <br>                    }<br>                }<br>            }<br>        }<br>    }<br>    post {<br>     always {<br>        emailext attachLog: true,<br>            subject: &quot;&#39;${currentBuild.result}&#39;&quot;,<br>            body: &quot;Project: ${env.JOB_NAME}&lt;br/&gt;&quot; +<br>                &quot;Build Number: ${env.BUILD_NUMBER}&lt;br/&gt;&quot; +<br>                &quot;URL: ${env.BUILD_URL}&lt;br/&gt;&quot;,<br>            to: &#39;syedtaha2016@gmail.com&#39;,<br>            attachmentsPattern: &#39;trivyfs.txt,trivyimage.txt&#39;<br>        }<br>    }<br>}</pre><p><strong>Note: In our Jenkins pipeline script at “Deploy to Kubernetes stage” once our deployment is done we dont need to do deploy our application again and again for same application intead set it with the new image by using following command “kubectl set image deployment/resume-fe resume=spawn328/resume:latest”</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/855/1*3U19EVWt7yDx7lZcrJhnXw.png" /></figure><p>Now hit the Build Now button, once build is successful to view the application we use public ip of any k8 worker node and use the nodeport, in our case it is “3.98.97.29:31000”. below is the deployed react-resume app snippet</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Q9gXowZAYL2bFXDLHtVd2w.png" /></figure><p><strong>Conclusion:<br></strong>If you come this far and set things on your end too it means you have covered lot of topics and tools, by completing this project and understanding each step it will make you confident enough to use these tools in your actual environment. Having said that the technology space changes too fast new things come and go but the topics which are covered in this project will be here to stay for a long time.</p><p><strong>See you in the next topic, until then keep hustling and keep learning!</strong></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=9f4776c2599c" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Linux Process Management and Monitoring]]></title>
            <link>https://medium.com/@taha_mashhadi/linux-process-management-and-monitoring-0760e31b9947?source=rss-a5378da94957------2</link>
            <guid isPermaLink="false">https://medium.com/p/0760e31b9947</guid>
            <category><![CDATA[linux-process-management]]></category>
            <category><![CDATA[linux-monitoring]]></category>
            <category><![CDATA[linux-process]]></category>
            <category><![CDATA[linux]]></category>
            <dc:creator><![CDATA[Taha Mashhadi]]></dc:creator>
            <pubDate>Thu, 15 Feb 2024 16:20:34 GMT</pubDate>
            <atom:updated>2024-02-15T16:20:34.485Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/892/1*EjhfhC9VcihC-_xW4mEblw.png" /></figure><p><strong>Introduction: </strong>To understand how process work and how we can diagnose and manage it is an big asset for any linux user. In this blog we will deep dive into understanding how process work and if some issue arise with the processes then how we can diagnose it and then based on our diagnosis and understanding we can take best actions to resolve it</p><p>Following are the topics which we will cover in this blog</p><ul><li><strong>Process</strong></li><li><strong>Foreground and Background Process</strong></li><li><strong>Process States</strong></li><li><strong>Process niceness</strong></li><li><strong>Controlling Process</strong></li><li><strong>Daemons</strong></li><li><strong>Process Signals</strong></li></ul><p><strong>Process: </strong>A process is sometime mistakenly taken as an program where it is not true the actual definition can be said as “<strong><em>process is the running instance of any program in our machine which have unique id named PID assigned by the kernel</em>”. </strong>Linux creates process for every program that executes or run for instance if we type <strong><em>ls </em></strong>on command line it creates a short live process for the program <strong><em>ls</em></strong>, some process are longer like process of a node js application or some process closed when system goes off like <strong>daemon processes.</strong></p><p>Whenever system boots up the first process which runs is <strong>init </strong>process and it gets the <strong>PID 1</strong> every other process are derived from this first process and init become parent or grandparent of every other process, init is a daemon process which runs until system shutdown. We can use the below command to see all the processes of current user.</p><pre>## displaying all process of current user in user readable format<br>## the ax combination is for listing all process and the u option is for human readable format<br>$ ps -aux | grep<br><br>## we can customize the ouptput by passing -o option<br>$ ps -aux <br><br>## to check process runing by specific user, if we want output in user oriented format pass u<br>$ ps -U osboxes<br><br>## if we want to check specific process, we can do it by passing the pid of it<br>$ ps u 1<br><br>## if we know the process name we can use below command, a option is for listing command<br>$ pgrep -a containerd<br></pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/761/1*X7CJQ9A0dhJE5drCUxCF1w.png" /><figcaption>In COMMAND column the wrap processes [] are the kernel process, it runs inside the privilege area of linux</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/722/1*V1C5XABuCfUs6VyyRNL0RA.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/480/1*3s5AIupF8kZxs1o9xBmYzQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/762/1*fJRu3qqRGBtTJlzQbBWFOg.png" /></figure><p>To continuously monitor the logs we use <strong><em>htop </em></strong>command it is the newer version of <strong><em>top </em></strong>command, htop continuously shows the process sorted by highest cpu usage it gives detailed information of each process along with the usage of overall resources. Below is the output snippet</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/902/1*4I82HGVeGRCvJ54s3BzN9w.png" /></figure><p>At any given time a single program can have multiple instance of its process running and a program can have multiple threads running simultaneously (<strong>multithreading</strong>) each of it considered as a separate process of a running program, every process has a <strong>pid</strong>(Process ID)<strong>, ppid</strong>(Parent Process ID) and <strong>pgid</strong>(Group Process ID), the max number of pid is mention in file <strong>/proc/sys/kernel/pid_max </strong>we can edit this number and if the pid reach to it max number then the process restart again at PID <strong>300</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/497/1*aQzXai9OclNUZyVyCfO8cw.png" /></figure><p>Processes are run in isolation it only runs in the user space, other user can not have control or any type of access on process running on other user space this enhance the security of the system. Process cant access hardware directly in order to access the hardware it indirectly access hardware through <strong>system calls</strong>, hardware can only be accessed by <strong>kernel </strong>directly</p><p><strong>Forgeround and Backgorund Process: </strong>A process can run in <strong>background</strong> like a daemon process or in <strong>foreground</strong> like an <strong><em>htop</em></strong> command on shell, a background process will not interrupt user or holds shell whereas foreground process holds the shell but we can put foreground process into background and free up the shell for further operations, the background process runs at lower priority which allow user to interact with other tasks smoothly</p><p>Adding <strong>ampersand</strong> (<strong>&amp;</strong>) after a command will run the command in the background, like putting &amp; after htop command</p><p>By pressing <strong>CTRL+Z</strong> suspend foreground processes and <strong>CTRL+C </strong>terminates a foreground process, for running process in background type <strong>bg </strong>and for running it in foreground type <strong>fg</strong></p><p><strong><em>jobs </em></strong>command is used to list all the background and stopped process of current user</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/331/1*3D49XiZV3kWGfxRjsRsQwQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/357/1*VVxGLlPpqKSNGRW-Yy25cA.png" /><figcaption>running htop process in background and then terminating it, the fg command will take htop background process into foreground</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/485/1*kpfvpKcLOp-D2VsxmiGz9g.png" /><figcaption>job command for listing background process</figcaption></figure><p><strong>Process States: </strong>A process can be in different state in its lifetime, we have discuss all the process state below</p><ul><li><strong>Running : </strong>A process is in running state when it’s consuming resources like cpu or memory, a process can be in queue before going into running state a queued process goes into running state when the priority elevated it</li><li><strong>Waiting: </strong>A process is in waiting state when its wait for some response from task or required I/O operation to be complete in order to run again</li><li><strong>Stopped : </strong>A stopped process is the process which goes into the temporary stop state instructed by the user or from other process, in this state process is in hold and can be resumed again</li><li><strong>Zombie: </strong>A process which is completely terminated and releases all it resources except it’s entry in process table is called Zombie process</li></ul><p><strong>Process niceness: </strong>process niceness refer to how nice process is to other processes we can measure the niceness from (<strong>-20 lowest</strong>) to (<strong>+19 highest</strong>), the niceness value set the priority of process execution (<strong>lowest the value highest the priority</strong>) or (<strong>highest the value lowest the priority</strong>). The default value of niceness of any process is inherited from the process which rans them. We can change these value of any process but it can only be raised by normal user and only root user can lower the niceness value, every process have the niceness value which effect the execution of process and it can be controlled by <strong><em>nice </em></strong>and<strong><em> renice </em></strong>commands difference between both of them is nice allow user to set the value during execution of process and renice allow user to change it later, below are the examples.</p><pre>## to se the process of current user with nice value we use l option, nice value is under NI cloumn<br>##we can include ax option to list all process<br>$ ps -l<br><br>## to set the nice value at time of the launch, nice command will append the value<br>$ nice -n 4 bash<br><br>## to check which process is parent to other processes in a tree format, f option is for tree format output<br>$ ps -fax<br><br>## using renice to change the nice value by specfying the PID<br>$ renice 7 8617</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Y4W67Bd96v94Q43DctpXiQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/595/1*hUUBpRIAjN2JUP8_kYQwMA.png" /><figcaption>In above example we can see while lowering the nice value of bash process it return permission denied</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/767/1*jAilJ-L1SdeZN9RZlPaMyQ.png" /><figcaption>renice command</figcaption></figure><p><strong>Controlling Process: </strong>It is better to limit resources of each user process consumption, this is the responsibility of system admin to put a restriction and limitation for every user resource consumption by there processes, an admin can put <strong>restriction</strong> so the server does not get exhausted or can expand it limitation so task can easily be performed, this can be done through <strong><em>ulimit </em></strong>command it is an built-in command which is used for displaying and limiting resource used by processes for each user.</p><p>Through ulimit we can restrict resource like memory, cpu time or max number of process on the system, ulimit can only limit user process for current session for permanently setting values we have to edit <strong><em>/etc/security/limits.conf </em></strong>file. Limit is classified into two types</p><ul><li>An “<strong>hard limit”</strong> can’t be override by regular user for instance if hard limit says a user cant create more then 12 process then user can not run more then 12 process, its the max value of resources used by a user.</li><li>An “<strong>soft limit</strong>” is the initial limit of a user to create and after if needed it can be manually increase by user but they cant go above the hard limit. <strong>“-” </strong>a dash identifies both the hard and soft limit, which mean if a user have 16 process limit of <strong>dash </strong>“<strong>-</strong>” then they can use all the 16 process anytime they want</li></ul><pre><br>## viewing detail ulimit report<br>$ ulimit -a <br><br>##viewing detailed soft limit<br>$ ulimit -Sa<br><br>##viewing detailed hard limit<br>$ ulimit -Ha<br><br>##setting max file size a user can make<br>$ ulimit -f 10<br><br>## limit number of open file<br>$ ulimit -n 1200<br><br>## hard limit number of open file<br>$ ulimit -H -n 1200<br><br>## soft limit number of open file<br>$ ulimit -H -n 1000</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/518/1*VgO6pOt9wWLItC7Opq6K2A.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/516/1*Oro5MaPcwWjShLyB_x4DLQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/516/1*rpp5QSzwSkqG4_mOOutjHQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/536/1*yI_aGCqzZIUpWTN4lrImQg.png" /><figcaption><strong>ulimit -f 10</strong></figcaption></figure><p><strong>Daemons: </strong>daemon process is an background process which runs continuously in background until the system shutdown, daemon process usually starts with the system bootup and unlike other process it does not respond to signals from the keyboard. Daemon process handle all request in background and ensure everything runs smoothly, many process in linux system are daemon process and they usually ends with “d” like <strong>httpd</strong>, <strong>crond</strong>, <strong>lpd</strong> and <strong>vsftpd</strong>. Daemon process provides better security and control compared to other processes as it only operate when needed and does not required any controlling terminal or any I/O device.</p><p><em>We can list daemons process by following the command instructed in this stackexchange question<br></em><a href="https://unix.stackexchange.com/questions/175380/how-to-list-all-running-daemons"><em>https://unix.stackexchange.com/questions/175380/how-to-list-all-running-daemons</em></a></p><p><strong>Process Signals: </strong>process signals is a kind of interruption for the process and once signal received by process it will act accordingly, these are kind of asynchronous event for process which tell process to do specific action synchronously. Process signal can be triggered by other process or by user, every process signal <strong>starts</strong> with <strong>SIG. SIGSTOP and SIGKILL </strong>are the only 2 signal which cant be ignored else for other signal it depends upon on how application is programmed to act on these signal or not. We can only send signal to process which are owned by current user</p><pre>## to list all signals, l option is for listing<br>$ kill -l<br><br>## we can use signal with thier whole name like SIGTERM followed by PID<br>## or we can use with thier signal name like TERM followed by PID<br>## or we can use the signal id only like SIGTERM have an ID 15 followed by PID<br>## terminating sshd process<br>$ kill -SIGTERM 7941<br><br>## same as the above command, if no signal defined it sends SIGTERM signal by default<br>$ kill 7941<br><br>## killing process by its name, if we only know the name of the process we use pkil command<br>$ pkill -TERM sshd</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/713/1*agwzdgs2TtzB0n-LOZuTaw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/792/1*GyYm5X5LQDuez0DYpOoO3Q.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/782/1*gQzg3lZwKZdOKjDZp9WE1A.png" /></figure><p><strong>PS:</strong> Both <strong>SIGTERM </strong>and <strong>SIGKILL </strong>do same job but the main difference is SIGKILL kills the process in abrupt fashion where SIGTERM tries to kill the process in a polite fashion and it can be handled by the program unlike SIGKILL</p><p><strong>Conclusion: </strong>In this article we have learned about processes in linux system and how we can list or manage these process by using commands, we can take advantage of these command in diagnosing the issue related to process execution or failure.</p><p><strong>See you in the next topic, until then keep hustling and keep learning!</strong></p><p>Follow me on<br><a href="https://www.linkedin.com/in/taha-mashhadi/">https://www.linkedin.com/in/taha-mashhadi</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=0760e31b9947" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Kubernetes Pods orchestration techniques (ReplicaSets, DaemonSets, Deployments)]]></title>
            <link>https://medium.com/@taha_mashhadi/kubernetes-replicasets-daemonsets-deployments-b30ad6cf1cba?source=rss-a5378da94957------2</link>
            <guid isPermaLink="false">https://medium.com/p/b30ad6cf1cba</guid>
            <category><![CDATA[kubernetes-cluster]]></category>
            <category><![CDATA[kubernetes]]></category>
            <category><![CDATA[deployment]]></category>
            <category><![CDATA[daemonset]]></category>
            <category><![CDATA[kubernetes-replicaset]]></category>
            <dc:creator><![CDATA[Taha Mashhadi]]></dc:creator>
            <pubDate>Tue, 13 Feb 2024 16:54:43 GMT</pubDate>
            <atom:updated>2024-02-13T19:49:46.253Z</atom:updated>
            <content:encoded><![CDATA[<p><strong>Introduction: </strong>In Kubernetes all application are deployed as a pod which is also refer as an smallest object in kubernetes. In this topic we will discuss about what are the ways to orchestrate the pods and how it can be created. The three main way to create pod’s are by creating Replicasets, Daemonsets and Deployment. There are other ways to create pods like (creating Static Pod or scheduling a Single Pod) but in this topic we will focus on these 3 resource type</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*MRU2_GXa4a-bBD4yOv9y5w.png" /></figure><h3>Replicasets<strong>:</strong></h3><p>The literal meaning of replication is to create an exact copy of same thing and these same copies together can be refer as an replicasets. In kubernetes context creating multiple replicas of same exact pods are called the replicasets, but why we create it and what purpose it serves, to understand this we have to understand following scenarios</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/787/1*26eWHdu7TatKK4JUdMSJxQ.png" /></figure><p><strong>High Availability:</strong> Suppose our application is running as a single pod and for any reason our pod crashed or our node failed, in this situation our user faces the downtime to counter this situation we need high availability which can be guaranteed by replica set it ensures that specified number of pod replicas are running all the time across our k8 cluster</p><p><strong>Load Balancing: </strong>Load to our application can be increased anytime and if there is only one node there is high chances that it can be crashed, replicaset helps in this situation by distributing loads evenly on our pods. These pods can be on same server or distributed on different server node, by this way load is distributed to different server machines. Replicasets can spans around on different worker node or on single worker node and it ensures the balance of traffic load to each pod.</p><p><strong>PS: Replicaset</strong> is early known as the <strong>Replication Controller</strong> which is exactly the same thing but an older technology there is no major difference except that replica set required selector definition and Replication Controller does not, now we refer <strong>Replication Controller</strong> as <strong>Replicaset</strong></p><p><strong>Replicaset Definition File: </strong>To create any object/resource in kuberenetes we need a definition file for it, which describe how the object will look like in YAML format. In Replicaset definition file we use following main keys</p><p>- <strong>apiVersion: </strong>api version of the object which “apps/v1”<br>- <strong>kind: </strong>kind of the definition file which is “ReplicaSet”<br><strong>-</strong> <strong>template:</strong> a pod definition under the spec section<br><strong>- selector: </strong>we use selector to select the pods which is included in replicaset selected based on their name tag, however it is not the required field<br>- <strong>replicas: </strong>number of pods defined which includes in the replicaset</p><p>Below is the example of <strong>replicaset definition</strong> file named <br>“my-webapp-rs.yaml”</p><pre>apiVersion: apps/v1 <br>kind: ReplicaSet<br>metadata:<br>  name: my-webapp-rs<br>  labels:<br>    app: my-webapp<br>    type: frontend<br>spec:<br>  template:<br>    metadata:<br>      name: my-webapp-pod<br>      labels: <br>        app: my-webapp<br>        type: frontend<br>    spec:<br>      containers:<br>      - name: nginx-container<br>        image: nginx  <br>  replicas: 3<br>  selector:<br>    matchLabels:<br>      type: frontend</pre><p><strong>Creating Replica Set and Managing it: </strong>In this section we will see and understand some commands use to create and manage replicaset, with example on actual K8-cluster(1 worker and 1 controlplane node)</p><pre>## creating rs by definition file<br>kubectl apply -f my-webapp-rs.yaml <br><br>##geting rs in default namespace<br>kubectl get rs<br><br>## scaling replicas in rs<br>kubectl scale --replicas=4 rs/my-webapp-rs<br><br>## deleting replicaset<br>kubectl delete rs </pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*nbKqXGwvBAv4TiLqB3le_Q.png" /><figcaption>Creating and Getting Replica Set in default namespace</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/663/1*l_g0PmJw74Ns1G6Acv5vsg.png" /><figcaption>Scaling Up an Scaling Down Replica Set</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/525/1*s9rI60RILAGytsEWWAIhTg.png" /><figcaption>Deleting rs</figcaption></figure><p><strong>Note</strong>: replicaset assign a random hash id to its pods, the hash id is added after the rs name</p><h3><strong>DaemonSets:</strong></h3><p>Daemonsets are like replicasets as it helps us to deploy multiple instances of the pods span around the worker-nodes, but the main difference is that daemonsets guaranteed the deployment of single pod on every worker-node in kubernetes cluster and it ensures a pod is present every time on a each node. It runs one copy of pod on every worker node, if in future new node is added it automatically adds new pod on it or similarly if node is removed it automatically removes it.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/682/1*jiWmTXB6f9kiZRa96tEpIg.png" /></figure><p>Earlier daemonset uses the node-name approach to bypass scheduler and put pod one every node but from v1.12 kubernetes uses <strong>Node Affinity</strong> and <strong>default scheduler</strong> to schedule pods on each node. Below are some use-cases where we can take leverage of daemonsets</p><p><strong>Monitoring and Logging Agent: </strong>Now in every production architecture we need ways to get the monitoring and logs data which can provide us the detail information about the resource utilization and logs of the application that are running, to do so we have to deploy some sort of monitoring and logging agent like(Prometheus and Grafana) on our instances(which are mostly server running in cloud or in premises). The best way is to deploy these agents as a daemonset on k8 cluster, by this way our logging and monitoring agent can be deployed on each worker node and if new node is added or removed theses agent can be added or removed automatically. Deploying these agents as an daemonset ensures we get monitoring and logging data seamlessly without any interruption.</p><p>Below are the 2 other use cases other then monitoring and logging agent where we can deploy pods as daemonsets</p><p><strong>Kube-proxy: </strong>kube-proxy is one of the main component of k8-cluster which is required on every worker node, to make sure kube-proxy is present on every worker node we can deploy it as a daemonsets</p><p><strong>Networking: </strong>Some networking solution required some agent to be deployed on every worker node, we can use daemonset to deployed it on every worker node</p><p><strong>PS: Daemonsets </strong>ensures the deployment of pod on every single node in k8-cluster but not on the <strong>Tainted node</strong> like the master-node as it is tainted by default. To deploy pod on tainted nodes too we have to create <strong>Toleration</strong> for that node by specifying the taint name and type under toleration key in definition file</p><p><strong>Daemonset Definition File: </strong>Creating ds definition file is almost same as the replicaset we have to specify type as <strong>Daemonset </strong>except we don&#39;t use replicas in it</p><p>Below is the example of <strong>daemonset definition</strong> file named “my-webapp-ds.yaml”, but first as we have only 2 nodes in our k8-cluster so in order to deploy pods on master node along with worker node we have to create <strong>Tolerations </strong>for the <strong>Taints</strong> which is on master-node</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/702/1*jBsM9XDpoQxMImyk1j6VNQ.png" /><figcaption>Finding the taint of master node by above command and using it in definition file below</figcaption></figure><pre>apiVersion: apps/v1 <br>kind: DaemonSet<br>metadata:<br>  name: my-monitoring-agent-ds<br>  labels:<br>    app: my-montioring-agent<br>    type: monitoring-agent<br>spec:<br>  selector:<br>    matchLabels:<br>      app: my-montioring-agent<br>      type: monitoring-agent<br>  template:<br>    metadata:<br>      name: my-montioring-agent-pod<br>      labels: <br>        app: my-montioring-agent<br>        type: monitoring-agent<br>    spec:<br>      tolerations: <br>      - key: node-role.kubernetes.io/control-plane<br>        effect: NoSchedule<br>      containers:<br>      - name: nginx-container<br>        image: nginx</pre><p><strong>Creating Daemonsets and Managing it: </strong>In this section we will see and understand some commands use to create and manage daemonsets, with example on actual K8-cluster(1 worker and 1 controlplane node)</p><pre>##creating daemonset<br>kubectl create -f my-webapp-ds.yaml<br><br>##getting ds<br>kubectl get ds<br><br>##deleting ds<br>kubectl delete ds</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*90lgthlfHrBs3MbaUA7Zgw.png" /><figcaption>Creating DaemonSet</figcaption></figure><h3>Deployments:</h3><p>Deployment are used to deploy our containerized application on pods in actual development/production env and it caters all the underline process which are required in deploying the application and controls it behavior, it come’s after the replicaset in hierarchy of kubernetes object. It give the capabilities of deployment like rolling-updates, saclling-up, undo-changes, pausing pod instances and resuming it. If we want to deploy any application on kubernetes we use deployment due to its underline capacity to handle deployment of application on kubernetes cluster seamlessly</p><p><strong>Deployment Definition File: </strong>Creating deployment definition file is almost same as the replicaset, we have to specify type as <strong>Deployment</strong></p><p>Below is the example of <strong>deployment definition</strong> file named “my-webapp-dp.yaml”</p><pre>apiVersion: apps/v1 <br>kind: Deployment<br>metadata:<br>  name: my-webapp-dp<br>  labels:<br>    app: my-webapp<br>    type: frontend<br>spec:<br>  template:<br>    metadata:<br>      name: my-webapp-pod<br>      labels: <br>        app: my-webapp<br>        type: frontend<br>    spec:<br>      containers:<br>      - name: nginx-container<br>        image: nginx  <br>  replicas: 2<br>  selector:<br>    matchLabels:<br>      type: frontend</pre><p><strong>Creating Deployment and Managing it: </strong>In this section we will see and understand some commands use to create and manage ds, with example on actual K8-cluster(1 worker and 1 control plane node)</p><pre>##creating deployment by my-webapp-dp<br>kubectl apply -f my-webapp-dp.yaml<br><br>##setting new image to deployment<br>kubectl set image deployment/my-webapp-dp nginx-container=redis-alpine<br><br>##checking rollout status of current change on deployment<br>kubectl rollout status deployment/my-webapp-dp<br><br>##checking rollout history of mentioned deployment<br>kubectl rollout history deployment/my-webapp-dp<br><br>##rolling back to previous deployment state<br>kubectl rollout undo deployment/my-webapp-dp<br><br>##scale rs of deployment<br>kubectl scale deployment/my-webapp-dp --replicas=3<br><br>##pause rollouts for new changes<br>kubectl rollout pause deployment/nginx-deployment<br><br>##resume rollouts for new changes<br>kubectl rollout resume deployment/nginx-deployment</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/972/1*WZWbOm67xKSQE2eI4cWMcg.png" /><figcaption>Creating new deployment and also setting new deployment image</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/772/1*7Ebx0DkVlTM0LyN-aZEYKQ.png" /><figcaption>A new rs has been created for new image</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/886/1*S2w_4iLWPSJ4GRjJuaVTWA.png" /><figcaption>Undo recent image changing rolling it back to previous one</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/637/1*gb6zGUKej7pgNNTrNfMMGA.png" /><figcaption>scaling up or scaling down the deployment</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/923/1*N21k_aEVhyO6q_yhKe88fA.png" /><figcaption>setting new image on deployment is paused until we resumed</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/921/1*a4QVIKAdeLe9vZ_7GsQ8qA.png" /><figcaption>Once resumed rollout we can see changes are being rolled out smoothly</figcaption></figure><p><strong>Conclusion: </strong>In this blog we have cover main topics of kubernetes which is related to pod orchestrations by using different methods and techniques, as in kuberentes it is important to understand how pods are scheduled using these main techniques most of the time we use one of the methods which we discuss in this blog to scheduled pods. Other then these method pod can also be scheduled as a single pod using definition file or scheduling it as a static pod by putting pod definition file in manifest folder.</p><p><strong>See you in the next topic, until then keep hustling and keep learning!</strong></p><p>Follow me on<br><a href="https://www.linkedin.com/in/taha-mashhadi/">https://www.linkedin.com/in/taha-mashhadi/</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b30ad6cf1cba" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Linux (Mastering Bash Shell Scripting Part-1)]]></title>
            <link>https://medium.com/@taha_mashhadi/linux-mastering-bash-shell-scripting-part-1-da38698c910e?source=rss-a5378da94957------2</link>
            <guid isPermaLink="false">https://medium.com/p/da38698c910e</guid>
            <category><![CDATA[linux-command-line]]></category>
            <category><![CDATA[automation]]></category>
            <category><![CDATA[shell-script]]></category>
            <category><![CDATA[linux-commands]]></category>
            <category><![CDATA[bash-script]]></category>
            <dc:creator><![CDATA[Taha Mashhadi]]></dc:creator>
            <pubDate>Sun, 11 Feb 2024 02:11:49 GMT</pubDate>
            <atom:updated>2024-02-11T03:27:38.499Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/558/1*LJaXr8uj1ExOHGw-tuVZLA.png" /></figure><p><strong>Introduction: </strong>In linux system in order to automate some processes which usually need to perform repeatedly from command line, we bundle those set of command instruction in a file known as <strong>shell script</strong> and then these scripts is parsed by an interpreter like bash and executed on the fly is called <strong>bash shell scripting</strong>. We used <strong>bash</strong> for scripting because it is simple and powerful language which is widely used by all unix based operating systems and also an default shell of most distribution. In this blog we will only discuss the prerequisite commands and techniques which comes handy and need to be known before moving to the actual bash slanguage syntax which we will cover in <strong>Part-2</strong>.</p><p><strong>First line of script (#!/bin/bash): </strong>whenever we start writing our script we have to specify a line which consist of “<strong>#!</strong>” also known as <strong>shebang</strong> followed by full path of the command interpreter which is “<strong>/bin/bash</strong>” with no space between them, we have to make sure it will always present in start of our bash script if it’s not there our script will not work and after first line we can start writing our script.</p><p><strong>PS: </strong>As we are using bash script the above explanation is applicable for other command shells like <strong>csh </strong>or <strong>ksh</strong></p><p><strong>Return value: </strong>In linux every program or script returns a value when they exit, not only programs or script but also methods which are used in script generate these value after they complete there execution. These return value are stored in special variable “<strong>$</strong>” the value in it indicates if the program, script or method exit successfully or not which helps parent process to monitor the exit state. These variable “$” holds numeric value where <strong>0 </strong>indicates successful exit other then 0 it mean error or other issue.</p><p>Below is the example of exit code of “rm” command if file remove successfully it return 0 if not then it returns 1.The return value of unsuccessful exit code can vary between different programs, similarly if we try to list directory which is not exist by “ls” command it will return 2. To check return value on command line we use “<strong><em>echo $?</em></strong>”</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/517/1*Zg7RauvpvrOXLgNUVJYsiw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/491/1*Gw30H6ZH2zHb9pMnXvMcsQ.png" /></figure><p><strong>Script parameters: </strong>we can pass arguments to bash script from the command line while we run the script, these parameters(argument) can be any number or a string character in order to access these parameter value inside a script we use <strong>$ </strong>sign followed by a number each parameter got its variable name dynamically which is the numeric number from <strong>$1</strong> to the <strong>$nth </strong>number, the variable is assigned according to their passing order where <strong>$0</strong> variable holds the script name itself and <strong>$* </strong>holds all the parameter values in it.</p><p>In below example we have written a script name <strong>var_name.sh</strong> which prints the parameter that are passed from the command line</p><pre>#!/bin/bash<br>echo script name : $0<br>echo first perameter : $1<br>echo second perameter : $2<br>echo third perameter : $2<br>echo All perameters : $*</pre><p>Now we will run script but first make script executable with below commands</p><pre>$ chmod +x ./var_name.sh<br>$ ./var_name.sh first second third</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/482/1*Z8Asa9aaLK6qhCLSrhfDIg.png" /><figcaption><strong>output of the script</strong></figcaption></figure><p><strong>Comments: </strong>Like other scripting languages we can follow the same syntax as Python to comment a single line which is <strong>#</strong>, comments are ignored by bash interpreter and it moves to the next line. Comments are useful in defining what operation is being performed next, in large script where multiple things are done it become essential to add comments</p><pre>#!/bin/bash<br>#echo This line will be ignored<br>echo This line will be executed</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/488/1*_ffA0cmcrbx5pzqiyixOSA.png" /><figcaption><strong>output of comment_script.sh</strong></figcaption></figure><p><strong>Output redirection: </strong>every commands create an output stream which is shown on the terminal, in order to redirect the output to specific location we use output redirection. Following are the 2 pattern of output redirection</p><p>first one is using <strong>&gt;(greater then sign) </strong>after the command and then followed by the location of file where generated output need to be saved. The single greater then sign(&gt;) will completely removes the content of the file and add the current output</p><p>second one is using <strong>&gt;&gt;</strong>(<strong>doble greater then sign</strong>)<strong> </strong>it will work as same as the above one but the difference is the (<strong>&gt;&gt;</strong>) sign will append the content of file and not removing old content of file. Below is the pattern and example snippet</p><pre>$ date &gt; /home/osboxes/current_date_1<br>$ date &gt;&gt; /home/osboxes/current_date_2</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/552/1*zgXuOmCThSNBc2m8SYauFg.png" /></figure><p><strong>/dev/null and /dev/zero: </strong>consider these 2 as your rescuer for dumping all your unnecessary data both are special file tag as c type but both are slightly different from each other how they process data. /<strong>dev/null </strong>is also known as black-hole of linux galaxy anything goes in will disappear and <strong>/dev/zero </strong>act same where all write request to it are discarder but it generates infinite stream of zeros.</p><p>We can redirect logs and output generated by any command to these location, it’s come’s handy when there is some command in our script which generate output that is not useful for us then we can redirect them to <strong>/dev/null</strong>.</p><p>Below is the snippet where we have redirect the output of “<strong>find /etc</strong>” command to /dev/null, the only output which is showed is from the <strong>stderrr </strong>stream. If we want to ignore the <strong>stderr</strong> stream we can use this command <br>“<strong>find /etc &gt;&amp; /dev/null</strong>”</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/501/1*U5Dh2Saordl5HtrFWEp-xA.png" /></figure><p><strong>Logging error outputs: </strong>A output can be generated from two type of stream <strong>stdout </strong>and<strong> stderr, </strong>there can be scenarios where we want to log the error generated by any command for the purpose of investigating the issue this can be achieve by error redirection. Syntax of error redirection is same as normal redirection the only change is we add <strong>2 before &gt;&gt;</strong>. Below is the example of code and snippet</p><pre># redirecting error to err_log file, it will only show stdout on screen<br>$ find /etc 2&gt;&gt; ./err_logfile<br><br># it will show nothing on screen, redirect the stdout stream to /dev/null and stderr to ./error_log file<br>$ find /etc &gt;&gt; /dev/null 2&gt;&gt; ./err_log</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/527/1*LYquQZOCKZVveH70OlMNqw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/527/1*hmMzCV2F_4iC0OIHpZvy3A.png" /></figure><p><strong>Special characters: </strong>Following are some special characters which can be used in a bash script</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6Fr5lTUaXDamXuAG8t0ytg.png" /></figure><p><strong>Command substitution: </strong>command substitution is a way of substituting commands with other command which allow commands to create dynamically, it become so much useful when our command output depends upon the result of other command. The output of one command is an input for other command through command nesting commands</p><p>There are 2 ways to substitute commands both have different syntax but the result generated by both of them are same, the first syntax is substitute command written in <strong>$(your command) </strong>and the second syntax is a substitute code written inside `<strong>your command`</strong>.</p><p>For instance i have to change the user and group ownership of file to current login user but i don&#39;t know what my user id and group id is? instead of first checking my user id and group id I can directly substitute these commands with “chown” command in one line, below is the example code where i used both syntaxes and result snippet.</p><pre>sudo chown $(id -u):`id -g` /home/osboxes/error_log</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/657/1*7hPsvVVCBrst2KhRCbIPXQ.png" /></figure><p><strong>Generating random data: </strong>random characters and numbers are very useful in shell scripting especially when we want to assign some unique name to a file or to a directory with unique characters in their name or it can be useful in generating a file with random character for payload testing. There are few ways to generate random character or number, the popular one is to generate random number by using default <strong>RANDOM </strong>variable of shell other way is to use <strong>openssl</strong> to get the random characters, below are the example code and snippet</p><pre># getting random number each time<br>$ echo $RANDOM<br><br># generating random character of 18 bytes in base64 format, we can also use different option with openssl rand command<br>$ openssl rand -base64 18<br><br># generating random character of 128 bytes in base64 format and saving it in a file<br>$ openssl rand -base64 -out random-data 128</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/583/1*QZWzbSpoSlQJhWVD1_k0aA.png" /></figure><p><strong>Temporary files and directories: </strong>we can create temporary files and directories which are only available until the end of user current session and these file/directories only accessible to user who created it, these temporary files/dir are located in “<strong>/tmp</strong>” directory. Temporary files and directories come handy when we need to create files and folder which only needed by current user for placing some temporary information or file that are only useful until script completely executes itself or until current login session</p><p>To create temp file or dir we use command name “<strong>mktemp</strong>” followed by the location of file which is <strong>“/tmp” </strong>and then finally random file/dir name, following is the syntax for naming random file/dir “<strong>temp.XXXX</strong>” where <strong>XXXX</strong> is the random char which will be automatically changed into character when file is created</p><p>For creating random directory the syntax is almost same as for creating random file the only difference is we have to provide <strong>“-d” </strong>option to “<strong>mktemp</strong>” command. Below is the example code of creating both random file &amp; directory with result snippet attached</p><pre>$ mktemp /tmp/temp.XXXX<br><br>$ mktemp -d /tmp/temp.XXXX</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/542/1*QISJnwRiaXFCR8j-K-u0zA.png" /></figure><p><strong>Debugging script: </strong>we can run script in debug mode by specifying <strong>-x </strong>while we run the script or can debug specific part of our script by combining it to <strong>+x </strong>with the <strong>set </strong>keyword. When we run script in debug mode it prints each line of command in script which it executes. Below is the example of both the ways and snippet</p><pre># this command will run scipt in debug mode<br>$ bash -x debug_script.sh</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/452/1*LZ1jWc9BFha-Mxs1Q0EaLA.png" /></figure><p>In below snippet we have set debug mode for the specific set of lines in out shell script file.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/437/1*Ff772hJR7C3smZNzrtcJog.png" /></figure><p><strong>Conclusion: </strong>Till now we have cover all the essentials command and techniques which create advance possibilities of doing things particularly in bash shell, now in part2 we will cover all the syntax of bash shell scripting, until then keep practice and stay tuned.</p><p><strong>See you in the next topic, until then keep hustling and keep learning!</strong></p><p>Follow me on<br><a href="https://www.linkedin.com/in/taha-mashhadi/">https://www.linkedin.com/in/taha-mashhadi/</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=da38698c910e" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Kubernetes (Automating etcd backup and restore using AWS s3)]]></title>
            <link>https://medium.com/@taha_mashhadi/kubernetes-automating-etcd-backup-and-restore-using-aws-s3-aaba7f9f338f?source=rss-a5378da94957------2</link>
            <guid isPermaLink="false">https://medium.com/p/aaba7f9f338f</guid>
            <category><![CDATA[kubernetes]]></category>
            <category><![CDATA[etcd-backup]]></category>
            <category><![CDATA[iam-roles]]></category>
            <category><![CDATA[etcd-restore]]></category>
            <category><![CDATA[s3-backup]]></category>
            <dc:creator><![CDATA[Taha Mashhadi]]></dc:creator>
            <pubDate>Thu, 08 Feb 2024 18:03:23 GMT</pubDate>
            <atom:updated>2024-02-11T00:02:26.685Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/952/1*GsVVn7ZUeTQnhy8RyQhgWA.png" /></figure><p><strong>Introduction: </strong>In kuberentes etcd-database holds the current state of our cluster, in order to be vigilant with our infrastructure on kubernetes we should always have a recent backup of etcd either on cloud or on different backup machine, by taking backup we make sure that if something went wrong with our kuberentes cluster we can restore it to previous working state through our recent backup of etcd database. In this project we will cover each step of how we can automate our process of taking backup of etcd on cloud(amazon s3) which include setting up an IAM user then configuring s3 bucket and aws-cli on control plane machine followed by writing a bash shell script for taking backup and restoring it and in the end we will use crontab to schedule our backup.</p><p>Following are the topics which will be covered in this project</p><ul><li><strong>what is etcd</strong></li><li><strong>etcdctl</strong></li><li><strong>Configuring AWS IAM</strong></li><li><strong>Configuring AWS S3</strong></li><li><strong>Configuring AWS CLI</strong></li><li><strong>etcd backup through bash shell script</strong></li><li><strong>etcd restore through bash shell script</strong></li><li><strong>scheduling backup (crontab)</strong></li></ul><p><strong>what is etcd : </strong>etcd is an key value persistent storage in which we can store our data, in kuberentes etcd plays an vital role as it holds the current state of complete k8 cluster any changes made to the cluster are reflected into the etcd database no change is complete in k8 cluster until and unless it is recorded into the etcd, it is the component of control-plane node and kube-apiserver is responsible to communicate and update information into the etcd database directly.</p><p>It is important for us to make sure that we always have a backup of current working state of etcd database because any issue with our controlplane machine or any misconfiguration can effect our applications or services running on kuberentes cluster, for instance if we have to perform some maintenance task in our k8-cluster and unfortunately after the maintenance resources which are previously running fine are now missing or not performing as expected in this situation the backup of etcd database which we take before the maintenance or at any time comes to rescue as we can now restore our previous working state from the recent etcd backup.</p><p><strong>etcdctl: <em>etcdctl</em></strong> is a default command line client for etcd database through which we can interact with our etcd db, by using it we can perform multiple actions like taking snapshot of our etcd db then restoring from that snapshot or getting status of snapshot. In this project we will use etcdctl to interact with etcd database and we will use version 3 of it, in order to work with v3 we have to use ETCDCTL_API=3 in start of every etcdctl command or if you are an root user you can set the env variable by exporting it.</p><p>To install etcdctl on ububtu machine type below command</p><pre>$ sudo apt update<br>$ sudo apt install etcd-client</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*IAxIz_yuyxBkVb6dsrQIYg.png" /><figcaption><strong>installing etcd-client</strong></figcaption></figure><p><strong>AWS IAM: </strong>AWS IAM also known as (Amazon Web Service Identity Access Management), it is an popular aws service to manage workforce and workload across multiple teams and groups and the primary purpose of it to securely control access to our infrastructure and service which are on aws. On AWS IAM dashboard we as an admin create Roles which have certain parameter and specific access to our services on aws then these <strong>Roles</strong> are attached to specific <strong>User</strong> or <strong>Group, </strong>we can attached different policies to our user by creating new one or selecting from the aws pre configured policies</p><p>We will create IAM role for our user which have access for <strong><em>s3</em></strong> service then we will create access key these access keys are then used to configure aws cli</p><p>Step1 : Login into aws-console account and then go to s3 dashboard to create user and leave everything as default</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Hlt-0JRLEudkYTFdGY8mXw.png" /><figcaption><strong>creating IAM user</strong></figcaption></figure><p>Step2: Then on next page attach policy name (AmazonS3FullAccess) to our user and leave everything as default</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*-ZMJUULSYqpLIXQTxONtNg.png" /><figcaption><strong>attaching S3 policy</strong></figcaption></figure><p>Step3: Then on next page create user, tags are optional</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4h7wqFVVrvoa5Qkl86FOPw.png" /><figcaption><strong>creating IAM user</strong></figcaption></figure><p>Step4: Click on <strong><em>User</em></strong> then <strong><em>Security Credentials</em></strong> Tab and then in access key section click on <strong><em>Create access key</em></strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*KxO4a7axVCbRmO9m_WX0Sg.png" /></figure><p>Step5: On Access Key page select <strong><em>Application running outside AWS</em></strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*JLUwDLiGgu8L-PY1_s5tHw.png" /></figure><p>Step6: On next page Add description and then click on <strong><em>Create access key</em></strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*MhF3pOP26FnxlamOIYobIw.png" /><figcaption><strong>creating access of IAM user</strong></figcaption></figure><p>Step7: Securely copy <strong><em>Access</em></strong> <strong><em>Key </em></strong>and <strong><em>Secret Access Key </em></strong>it will be only shown once</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8MoDglzOKWIiIlJ9ksfTHA.png" /></figure><p><strong>AWS S3: </strong>We will take our etcd backup on cloud, aws have a popular service name <strong><em>s3 </em></strong>it is used to store large amount of data on cloud which act as an simple storage service, there are lot of other purpose of s3 but for our project we will only use it for storing our etcd backup.</p><p>Step1: Go to <strong><em>s3 </em></strong>dashboard and select <strong><em>Create bucket, </em></strong>on first page select your region and give it a unique global name</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*VYJGEXyjApsItk_5AZCNew.png" /></figure><p>Step2: Scroll Down and select <strong><em>Enable </em></strong>radio button in Default encryption section and finally click on C<strong><em>reate bucket</em></strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*VOTYyvMf5ikOxOs-Qd4ULQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*pWgMZbCPMooN2ETYAjQLLQ.png" /></figure><p><strong>PS:</strong> While configuring s3 you can use <strong><em>Amazon S3 Lifecycle Rule</em></strong>, it helps to set expiry on your saved object and auto remove it which is effective in cleaning up outdated backups which saves our cost too</p><p><strong>Configuring AWS CLI: </strong>We will interact with s3 through <strong><em>aws cli </em></strong>from our control plane machine, in order to interact with it we need to install aws-cli into our control-plane machine and then after we will configure access key and region for aws-cli</p><p>Step1: Install official package from aws through curl request, it will be downloaded as zip file we have to unzip it’s content. Below are the command and result snippet</p><pre>curl &quot;https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip&quot; -o &quot;awscliv2.zip&quot;<br>unzip awscliv2.zip<br>sudo ./aws/install</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/860/1*Xdr6JaB1nuIORPrQPhHsjg.png" /><figcaption><strong>downloading official cli binary installer</strong></figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/687/1*NtG-ZZyBqhlyKY3RzrVcsQ.png" /><figcaption><strong>unzipping awscliv2.zip</strong></figcaption></figure><p>Step2: File will be extracted with the name <strong><em>aws, </em></strong>run the installer located in that dir</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/777/1*rIr4QLaSDCCHmesr4kcPYg.png" /><figcaption><strong>installing aws-cli</strong></figcaption></figure><p>Step3: configure aws using <strong><em>aws configure </em></strong>command and then passing access key, access secret key and region. These configuration will be saved in home inside the <strong><em>.aws </em></strong>dir</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/638/1*-rceOw-5y32y6ZFm_wgWaw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/598/1*iD8goPmaWBNCTKkvANQ9-g.png" /><figcaption><strong>aws configure</strong></figcaption></figure><p>Step4: Verifying the connection to aws services by listing content of s3 bucket</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/530/1*ZHQVF6cd1OkLQZCai12M7Q.png" /></figure><p><strong>etcd backup through shell script: </strong>Now we will take backup of our etcd database from the control-plane where it is located, we can do so by typing each command 1 by 1 but in order to take backup at every day at specific time we have to automate this process for this purpose we will use the bash scripting and then add this script file as a cronjob into crontab</p><p>Step1: Change etcd-data directory from <strong><em>etcd</em></strong> object definition file located at <strong><em>/etc/kubernetes/manifest/etcd.yml, </em></strong>open this file with your favorite editor and change mounted data dir to “<strong><em>/opt/etcd-restore</em></strong>” under the key “<strong><em>spec.volumes[1].hostpath.path</em></strong>”</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/595/1*Y415IOmYNaT4VJjy_q7bRw.png" /></figure><p>Step2: Create bash shell script file where we write our script to take backup and named it “<strong><em>backup-script.sh</em></strong>” and then make compressed archive file of our backup with tar and finally upload it to your s3 bucket. Below is the content of backup-script.sh, I have added comment on each step in order to understand what each step do</p><pre>#!/bin/sh<br><br># create /opt/etcd-backup dir, in this directory daily etcd-database backup will be stored<br>mkdir -p /opt/etcd-backup<br><br># creating file name variable which have value of filename with current datetime<br>FILE_NAME=etcd-$(date +&quot;%F%T&quot;).db<br><br># creting etcd path variable where full path for current backup file is defined<br>ETCD_PATH=/opt/etcd-backup/$FILE_NAME<br><br># taking etcd database snapshot with etcdctl and saving it into /opt/etcd-backup dir, we have to specify 4 keys in order to interact with etcd server<br># --endpoints it is the url of etcd server<br># --cacert it is the full path where ca.crt file located<br># --cert it is the full path where server.crt file located<br># --key it is the full path where server.key file located<br>ETCDCTL_API=3 etcdctl \<br>        --endpoints=https://127.0.0.1:2379 \<br>        --cacert=/etc/kubernetes/pki/etcd/ca.crt \<br>        --cert=/etc/kubernetes/pki/etcd/server.crt \<br>        --key=/etc/kubernetes/pki/etcd/server.key \<br>        snapshot save $ETCD_PATH<br><br># we will delete backup file if it is older then 7 days from etcd-backup directory<br># value under [] is an test statement followed by actual statement<br># if /opt/etcd-backup dir exist then delete files from it which are 7 days older<br>[ -d /opt/etcd-backup ] &amp;&amp; find /opt/etcd-backup -cmin +10080 -delete<br><br># archiving and compressing using tar with .gz utility of etcd-backup folder,<br># after compression etcd-backup.tar.gz file will be located at current dir where this script is located<br>tar czfp etcd-backup.tar.gz --absolute-names /opt/etcd-backup/<br><br># finally uploading our tar compressed backup to s3 buket<br># quiet option will run command in quiet mode<br># storage-class option is for defining which storage class to used for storing object<br>aws s3 cp ./etcd-backup.tar.gz s3://taha-k8-etcd-backup --storage-class STANDARD</pre><p>Step3: change permission of backup-script.sh file to 744 which mean only owner have full read, write, execute access where group and other user have only read access. Below is the command and result snippet</p><pre>$ chmod 744 ./backup-script.sh</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/511/1*xlxMeWyOGfCs4YfzG9Ohyw.png" /></figure><p>Step4: now we will run script using below command</p><pre>$ ./backup-script.sh</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/752/1*wIaOi2mVepRXF18mguRe0w.png" /></figure><p>Step5: after running backup-script successfully we will verify each step by looking for backup file at each location by below commands. For verification check time of each file</p><pre>## verifying if compressed backup file uploaded to s3 bucket<br>$ aws s3 ls s3://taha-k8-etcd-backup<br><br>## verifying if new backup compressed file created<br>$ls -l etcd-backup.tar.gz<br><br>## verifying if new backup file created at /opt/etcd-backup folder<br>$ls /opt/etcd-backup</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/627/1*1sDsS01CG-e6ZWi_OeDE5g.png" /></figure><p><strong>etcd restore through shell script: </strong>at some point due to some technical reason our kubernetes cluster resources are not present or not performing as expected and now we have to restore our last backup of etcd-database from cloud(s3-bucket), this task can be done manually by writing each command step by step but i have written bash shell script for restoring backup too, the script for restoring backup name as “<strong><em>restore-backup.sh</em></strong>” and it’s located at root home dir. Below are the steps to restore our backup and run our applications again on k8-cluster :-)</p><p>Step1: Create file name restore-backup.sh with your favorite editor and then open it to add step for restoration of etcd-database with the last backup file from cloud(s3-bucket), I have added comment on each step in order to understand what each step do</p><pre>#!/bin/sh<br># removing /opt/etcd-restore folder if it exist, <br># if we dont remove our data dir then etcd will throw err &quot;Error: data-dir path exists&quot; <br>[ -d /opt/etcd-restore ] &amp;&amp; rm -r /opt/etcd-restore<br><br># creating aws-etcd-restore directory where we will put our backup file downloaded from s3<br>mkdir -p aws-etcd-restore<br><br># syncing our local folder with s3 bucket, it only download content which are not in sync and vice versa<br>aws s3 sync s3://taha-k8-etcd-backup ./aws-etcd-restore<br><br># extracting compressed tar file to our backup-dir whcih is /opt/etcd-backup<br>[ -f ./aws-etcd-restore/etcd-backup.tar.gz ] &amp;&amp; tar -xf ./aws-etcd-restore/etcd-backup.tar.gz -C /<br><br># picking the last updated file whcih is the most recent one and assign it to RECENT_BACKUP variable<br>RECENT_BACKUP=/opt/etcd-backup/$(ls -Art /opt/etcd-backup/ | tail -n 1)<br><br># printing out the RECENT_BACKUP variable which holds full path to most recent etcd-backup file<br>echo $RECENT_BACKUP<br><br># restoring most recent backup using etcdctl <br># by specifying --data-dir restoration will goes into the specified dir which is in our case is /opt/etcd-restore<br>ETCDCTL_API=3 etcdctl snapshot restore --data-dir /opt/etcd-restore $RECENT_BACKUP</pre><p>Step2: change permission of backup-script.sh file to 744 which mean only owner have full read, write, execute access where group and other user have only read access. Below is the command and result snippet</p><pre>$ chmod 744 ./restore-script.sh</pre><p>Step3: now we will run script using below command</p><pre>$ ./restore-script.sh</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*VVq-XeZZa8PtA088plWqEQ.png" /><figcaption><strong>restore is successful, for verification match the backup file name which we take in previous backup section</strong></figcaption></figure><p><strong>scheduling backup (crontab): </strong>we will use crontab to register our cronjob entry for running our backup script at every night 12 AM, use full path to your backup-script.sh. Following are the step to schedule our job with crontab</p><p>Step1: run <strong><em>“sudo crontab -e” </em></strong>without quotes command to open crontab file, it will then ask you to select editor. Use sudo for root user and and if you are normal user then no need to use sudo</p><p>Step2 : add cronjob entry in end of file, our will be<br> “<strong><em>0 0,12 * * * /root/backup-script.sh</em></strong>” without quotes, always use full path.</p><p>Step3: after adding cronjob verify our entry by using following command “<strong><em>sudo crontab -l</em></strong>” without quotes</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/623/1*6PvhKUgBpXzLsNY51pPeTg.png" /><figcaption><strong>our cronjob for running backup script at every 12 AM successfully register in crontab, now our script will run at 12 AM every night</strong></figcaption></figure><p><strong>Conclusion: </strong>In this project we have cover vast array of topic which directly or indirectly help you in task automation. Our primary purpose in this project is to automate etcd-dabase backup with uploading backups to cloud(s3-bucket), further more if you want to challenge yourself create backups of High Availability cluster which have multiple control plane node.</p><p><strong>See you in the next topic, until then keep hustling and keep learning!</strong></p><p>Follow me on<br><a href="https://www.linkedin.com/in/taha-mashhadi/">https://www.linkedin.com/in/taha-mashhadi/</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=aaba7f9f338f" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Kubernetes Control-Plane Components]]></title>
            <link>https://medium.com/@taha_mashhadi/kubernetes-control-plane-components-c2295bb2a87b?source=rss-a5378da94957------2</link>
            <guid isPermaLink="false">https://medium.com/p/c2295bb2a87b</guid>
            <category><![CDATA[kubernetes]]></category>
            <category><![CDATA[kubernetes-controller]]></category>
            <category><![CDATA[kubernetes-controlplane]]></category>
            <category><![CDATA[kubernetes-cluster]]></category>
            <category><![CDATA[kubernetes-components]]></category>
            <dc:creator><![CDATA[Taha Mashhadi]]></dc:creator>
            <pubDate>Sun, 04 Feb 2024 18:30:11 GMT</pubDate>
            <atom:updated>2024-02-05T04:30:16.248Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1002/1*gYKZ3BMuDRSpAwy3SxrHAA.png" /></figure><p><strong>Introduction: </strong>A kubernetes cluster is consist of one or more control nodes and worker nodes, these control plane node have multiple component which works all together to make kubernetes cluster functional in proper way. In this blog we will understand each component in control-plane node and how these component works and communicate with each other. In k8-cluster master/controlplane node is like the brain of the cluster which is responsible for running all the components which are required for running our application, before doing hands-on with kubernetes like deploying application on the k8-cluster it is better to understand what are it’s components and how they function together.</p><p>Following are the topics which we discuss in this blog</p><ul><li><strong>kube-apiserver</strong></li><li><strong>kube-controller-manager</strong></li><li><strong>node-controller</strong></li><li><strong>replication controller</strong></li><li><strong>etcd</strong></li><li><strong>kube-scheduler</strong></li></ul><p><strong>kube-apiserver: </strong>kube-api-server is central point of communication in Kubernetes it handles all internal and and external api-calls and then forward it to other components after authentication and validation of the request, it is an single point of contact to “<strong>etcd database” </strong>which directly interact with it<strong>. </strong>kube-apiserver provides sophisticated REST api’s through which we can interact with other components in the cluster, all our “kubectl” commands are passed through the kube-api-server after validation and authentication the request then passed to respective components like if we want to get pods in default ns (kubectl get pods -n default) this request will first go for authentication and validation of request and of the user once its done the request will finally pass to <strong>etcd database </strong>for retrieving the current pods state in default namespace. kube-api-server is used for updating and passing information within the cluster components in other words it is an center point of communication between all the components whenever any request is initiated or any information need to be passed within the cluster components.</p><p>kube-apiserver is installed as a binary on the system and run as a service when we setup our cluster through the <strong>hard-way. </strong>When we setup cluster through <strong>kubeadm</strong> it’s automatically run as a pod in <strong>kube-system </strong>namespace on the control-plane node(master-node).</p><p><strong>kube-controller-manager: </strong>it is used to manages different controller within kuberenetes and it consist of multiple controller like(node-controller, replication controller, namespace controller) we will discuss the main one below. The primary purpose of kube-controller-manager is to verify the current state of cluster by communicating through <strong>kube-api-server </strong>if the current state of cluster does not matched it will instruct necessary controller to act accordingly in-order to match the state of the cluster.</p><p>kube-controller-manager can be downloaded from the official kubernetes website and run as a service or when we setup cluster through <strong>kubeadm </strong>it automatically run as a pod in <strong>kube-system </strong>namespace on the control-plane node(master-node). We can define different options to customize kube-controller-manager by editing <strong>kube-controller-manager.service</strong> file if it is installed as a service or we can edit the <strong>kube-controller-manager</strong> definition file in <strong>/etc/kubernetes/manifests</strong> folder if it’s running as a pod. We can enable and disable different controller or can edit the grace-period, monitoring-period and eviction period by editing service or definition file. We can also checks the option of running kube-controller-manager through process command</p><pre>## getting kube-controller-manager pod, if it&#39;s running through kubeadm<br>kubectl get pod -n kube-system | grep kube-controller-manager<br><br>## for editing pod definition file of kube-controller-manager, if running through kubeadm<br>sudo vi /etc/kubernetes/manifest/kube-controller-manager.yml<br><br>##checking current option of kube-controller-manager<br>ps -aux | grep kube-controller-manager</pre><p><strong>node-controller: </strong>node controller is one of the main controller in kube-controller-manager it continuously monitors the status of the node in cluster through kube-api-server if any node not responding or not working correctly the node-controller will act accordingly by shifting the resources from unfunctional node to functional node. By default it checks status of node at every 5 sec if it doesn&#39;t get the response from the node for 40 sec it marks as <strong>Unreachable-Node/NotReady</strong> once node is marked unreachable the node-controller will give time of 5 min to node for coming back if the node doesn&#39;t respond within 5 min it removes the pod which are running on that node and assign them to different functional node</p><p><strong>replication-controller: </strong>replication controller is responsible to monitor the replica-set, it make sure the desired number of pod in replica-set are always up , if any pod goes down replication-controller will create another pod to match the number of pod defined in replicaset definition file</p><p><strong>etcd: </strong>if we define etcd in a nutshell we can say that it is a persistent storage where cluster information and current state of the kubernetes-cluster are stored in an key:value format and the only component which can directly interact with the etcd is an kube-apiserver any change in our k8-cluster are updated in etcd db through kube-apiserver. As kubernetes is designed in the way that all it’s component are decoupled but the only exception is with the etcd we cant remove it as if we do all the information of our cluster will be removed too, we have to make sure our etcd data is protected and should not be exploit or lost by any mean. Before we do any maintenance on k8-cluster we have to make sure that we have taken backup of our etcd db which hold the current state of our kubernetes cluster, this backup can be done through a default client name “<strong><em>etcdctl”</em></strong></p><p>An <strong>etcd database</strong> can be installed through the package-manager and run as a service or if we setup it through kubeadm it will run as a pod in the kube-system. The default port of etcd is <strong>2379 </strong>and the default client is <strong>etcdctl </strong>we can use it to store or retrieve data from our etcd db.</p><p><strong>Note: </strong>In High-Availability Cluster there can be multiple master nodes and it will have corresponding etcd database, in this scenario we have to make sure that each etcd should know each other this can be done by editing the service or definition file on each master node and add url of each etcd db in the “<strong>- -initial-cluster</strong>” parameter like below<br><strong><em>- -initial-cluster controller-0=https://{master-node1-ip}:2380,controller-1=https://{master-node2-ip}:2380,n..</em></strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/912/1*PnZa7hsFF62IbEvzkG1WMA.png" /></figure><p><strong>PS: </strong>We will cover an important topic of how to take etcd backup and then restoring it in detail, in a different blog</p><p><strong>kube-scheduler: </strong>kube-scheduler is used to schedule pods on the node in kubernetes cluster, the pods are not scheduled randomly in fact kubernetes have an dedicated algorithm which runs to check the best fit node available to deploy pod and once find it deploy the pod immediately on it or we can use our custom scheduler instead of default scheduler of kubernetes . The kube-scheduler algorithm checks different factor for deploying pod like what are the resources required for pod we can instruct kube-scheduler to select pod based on the parameter like min/max computation and memory resources required by a pod these resources parameter are defined in the pod definition file, once the requested resource node found then kube-scheduler will deploy or re-deploy pods. Pods can be in pending state until the requested parameter are met, several factors derive in the placement of pod on node along with the kube-scheduler algorithm like we can also used node binding or Taint and Toleration to deploy pods on the specific node of our choice.<br>We can download kube-scheduler binaries from the official kubernetes website and run as a service on machine or if the cluster is setup through kubeadm then scheduler will run as a pod on master node in kube-system namespace</p><p><strong>Conclusion: </strong>So far we have cover all the component which are required in kubernetes cluster on controlplane/master node and also understand what purpose each component serve in kubernetes cluster. These components are setup differently in our cluster based on how we are setting things up like we can do it by <strong>hardway </strong>by installing each component and run them as a service on our machine or we can initiate our cluster through <strong>kubeadm </strong>where all our components are deploy as a pod on master node in the kube-system namespace and then join our worker node to master node through <strong>kubeadm join</strong> command, kubeadm is the easiest and fastest way to setting things up. <br><strong>PS: </strong>In this blog we haven’t cover 2 component (<strong>kubelet </strong>and<strong> kube-proxy</strong>) as these components are not the main components of controlplane-node and it is common to worker node also, so we will discuss these component in detail in different blog</p><p><strong>See you in the next topic, until then keep hustling and keep learning!</strong></p><p>Follow me on<br><a href="https://www.linkedin.com/in/taha-mashhadi/">https://www.linkedin.com/in/taha-mashhadi/</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c2295bb2a87b" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>