<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Prabhu Jayakumar</title>
    <description>The latest articles on Forem by Prabhu Jayakumar (@prabhujayakumar).</description>
    <link>https://forem.com/prabhujayakumar</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F413775%2Ff84bfe9a-7e49-4bbd-aa31-f206b9081e63.jpeg</url>
      <title>Forem: Prabhu Jayakumar</title>
      <link>https://forem.com/prabhujayakumar</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/prabhujayakumar"/>
    <language>en</language>
    <item>
      <title>Firewall for Applications in Kubernetes</title>
      <dc:creator>Prabhu Jayakumar</dc:creator>
      <pubDate>Fri, 19 Feb 2021 20:13:45 +0000</pubDate>
      <link>https://forem.com/prabhujayakumar/firewall-for-applications-in-kubernetes-59bi</link>
      <guid>https://forem.com/prabhujayakumar/firewall-for-applications-in-kubernetes-59bi</guid>
      <description>&lt;p&gt;Originally published at &lt;a href="https://www.prabhujayakumar.dev"&gt;https://www.prabhujayakumar.dev&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;In this blog, we will look at a kubernetes feature which is intended to improve security for applications running in a cluster&lt;/p&gt;

&lt;p&gt;In a kubernetes cluster, we can run many applications with multiple replicas for each application. By default, any pods can talk to any other pods running in the same cluster. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AH0t240h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5ct8c2ijsooutlppmwmv.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AH0t240h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5ct8c2ijsooutlppmwmv.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But it is not recommended to allow such feature to be in place. In case an intruder get access to a pod, then he/she can access all pods from inside that compromised pod. So we need a firewall for applications using which it can decide if the traffic(both ingress and egress) should be allowed or denied inside the cluster.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2BgTCmsi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g23i43vtl65nea2lmw5z.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2BgTCmsi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g23i43vtl65nea2lmw5z.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There comes the saviour, &lt;code&gt;Network Policy&lt;/code&gt; that helps to create a firewall for applications running in kubernetes cluster.&lt;/p&gt;

&lt;p&gt;Let's understand the need for such firewall and how Network Policy helps for the same with some examples.&lt;/p&gt;

&lt;h3&gt;
  
  
  Guestbook
&lt;/h3&gt;

&lt;p&gt;Consider an application &lt;code&gt;Guestbook&lt;/code&gt; having 3 different components as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;guestbook-ui (frontend)&lt;/li&gt;
&lt;li&gt;guestbook-api (backend)&lt;/li&gt;
&lt;li&gt;guestbook-db (db)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Expected communication between these components are like ui communicates to api and api communicates to db.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WhIjyUVV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kwglz8f0pd3grdq6njwx.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WhIjyUVV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kwglz8f0pd3grdq6njwx.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But when all these components of guestbook application are running in a kubernetes cluster, technically ui component can communicate to db by default.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rvPeU2z_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xdag0szl8d1g1rx6z4hf.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rvPeU2z_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xdag0szl8d1g1rx6z4hf.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Use Network Policy to setup firewall for applications in cluster
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;As network policy is a feature that should be implemented by the network plugin, ensure that your network plugin supports NetworkPolicy resource. Creating NetworkPolicy resource without such plugin will have no effect. Calico, Cilium, Kube-router, Romana and Weave Net are some of the network plugins that support network policy&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As a first step, disable the default behaviour of allowing all communications between all pods running in a kubernetes cluster by creating a network policy as follows in all namespaces.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;networking.k8s.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NetworkPolicy&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deny-all&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;podSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
  &lt;span class="na"&gt;ingress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, none of the pods can communicate to any other pods running in the kubernetes cluster. Now based on requirements, allow the ingress/egress traffic for pods in the cluster.&lt;/p&gt;

&lt;p&gt;For the guestbook application, to allow ingress traffic to &lt;code&gt;guestbook-api&lt;/code&gt; pods but only from &lt;code&gt;guestbook-ui&lt;/code&gt; pods, create a network policy as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;networking.k8s.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NetworkPolicy&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;allow-ui-to-api&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;podSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;guestbook-api&lt;/span&gt;
      &lt;span class="na"&gt;tier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend&lt;/span&gt;   
  &lt;span class="na"&gt;ingress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;podSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;guestbook-ui&lt;/span&gt;
          &lt;span class="na"&gt;tier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;frontend&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And to allow ingress traffic to &lt;code&gt;guestbook-db&lt;/code&gt; pods but only from &lt;code&gt;guestbook-api&lt;/code&gt; pods, create a network policy as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;networking.k8s.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NetworkPolicy&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;allow-api-to-db&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;podSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;guestbook-db&lt;/span&gt;
      &lt;span class="na"&gt;tier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;db&lt;/span&gt;   
  &lt;span class="na"&gt;ingress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;podSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;guestbook-api&lt;/span&gt;
          &lt;span class="na"&gt;tier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Final setup with these network policies allows only the valid communications between the pods&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VFcGLkSx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/24tvvo7m39xdtvq2r4ft.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VFcGLkSx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/24tvvo7m39xdtvq2r4ft.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  More about network policy
&lt;/h3&gt;

&lt;h4&gt;
  
  
  NamespaceSelector
&lt;/h4&gt;

&lt;p&gt;In some scenarios, we have to allow ingress from any pods in a namespace. For example, all applications pods should allow ingress from all pods in &lt;code&gt;monitoring&lt;/code&gt; namespace. Namespace selector can be used to achieve this setup easily as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;networking.k8s.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NetworkPolicy&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;allow-monitoring-namespace&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;podSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt; &lt;span class="c1"&gt;## applies to all pods in the namespace&lt;/span&gt;
  &lt;span class="na"&gt;ingress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;namespaceSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;team&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;monitoring&lt;/span&gt; &lt;span class="c1"&gt;## labels of the monitoring namespace&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  IP Block
&lt;/h4&gt;

&lt;p&gt;Not just labels, network policy also allows configuration using IP blocks. Following network policy allows ingress from 10.72.X.X but blocks traffic from 10.72.10.X&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;networking.k8s.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NetworkPolicy&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;allow-using-ip&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;podSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
  &lt;span class="na"&gt;ingress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;ipBlock&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;cidr&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10.72.0.0/16&lt;/span&gt;
        &lt;span class="na"&gt;except&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10.72.10.0/8&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;It is good to have security at all levels in k8s cluster. Adding a firewall for the application pods in the kubernetes cluster increases level of security by reducing the attack surface and hence is highly recommended.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>security</category>
    </item>
    <item>
      <title>Save Your Kubernetes Cluster From DoS</title>
      <dc:creator>Prabhu Jayakumar</dc:creator>
      <pubDate>Mon, 06 Jul 2020 17:43:06 +0000</pubDate>
      <link>https://forem.com/prabhujayakumar/save-your-kubernetes-cluster-from-dos-4j8h</link>
      <guid>https://forem.com/prabhujayakumar/save-your-kubernetes-cluster-from-dos-4j8h</guid>
      <description>&lt;p&gt;Originally published at &lt;a href="https://www.prabhujayakumar.dev"&gt;https://www.prabhujayakumar.dev&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Kubernetes has become a market leader in container orchestration tools. According to the &lt;a href="https://www.cncf.io/wp-content/uploads/2020/03/CNCF_Survey_Report.pdf"&gt;2019 CNCF survey&lt;/a&gt;, "78% of respondents are using Kubernetes in production, a huge jump from 58% last year"&lt;/p&gt;

&lt;p&gt;While containers have become the norm for deploying applications, kubernetes has become the norm for container management. &lt;/p&gt;

&lt;h2&gt;
  
  
  DoS in Kubernetes cluster
&lt;/h2&gt;

&lt;p&gt;Consider a Kubernetes cluster with 3 worker nodes having a memory of 10GB each. Suppose the developers end up deploying some pods by mistake which consumes almost all the cpu and memory available in the node. Hence causing resource contention in the others application pods which serves traffic from consumers. This could also be caused when hackers inject high resource consuming pods intentionally into the system.&lt;/p&gt;

&lt;p&gt;To understand this situation better, assume a node having 10GB of allocatable memory for containers and there are 5 application pods sharing the available memory. Each application pod on an average consumes 1GB of memory which makes the node to run at 50% to 60% memory utilization. Now deploying a pod that consumes 10GB of memory in the same node will cause noisy neighbor problem. This results in resource contention in other application pods which in turn either increase the latency of those services or in the worse case make the services go unavailable.&lt;/p&gt;

&lt;p&gt;This might also happen when the developer commits a mistake in the code which leaks the memory and increase the memory usage steadily.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vI6hrlJh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/43x1sj346ezv3d917ujd.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vI6hrlJh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/43x1sj346ezv3d917ujd.jpg" alt="resource-contention"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Effective Resource Management in Kubernetes
&lt;/h2&gt;

&lt;p&gt;This is the reason why developers should be more conscious of the resources required for the services that they develop and configure the minimum required memory and cpu while deploying it in the Kubernetes cluster. Resource requests can be configured accordingly to schedule the pods in the node which guarantees the minimum resource.&lt;/p&gt;

&lt;p&gt;For example, if a service requires 2 cpu and 3GB of memory at minimum, then in the pod specification configure the resource request as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: v1
kind: Pod
metadata:
  name: demo-service
  namespace: demo
spec:
  containers:
  - name: demo-container
    image: demo-service-image
    resources:
      requests:
        cpu: "2"
        memory: "3G"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It is also important that the developers should also configure the maximum resources that their service could consume. This helps in avoiding noisy neighbor problem in other service pods.&lt;/p&gt;

&lt;p&gt;Let's say the same &lt;code&gt;demo-service&lt;/code&gt; should not consume more than 4 cpu and 5 GB of memory. In that case add the resource limit to the above pod specification.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: v1
kind: Pod
metadata:
  name: demo-service
  namespace: demo
spec:
  containers:
  - name: demo-container
    image: demo-service-image
    resources:
      requests:
        cpu: "2"
        memory: "3G"
      limits:
        cpu: "4"
        memory: "5G"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It is strongly recommended to configure the resource requests and limits in the pods deployed in the Kubernetes cluster as per the service needs.&lt;/p&gt;

&lt;p&gt;Having said that, just to be on the safer side, we need some policy to be added in the Kubernetes cluster to ensure the pods do not over utilize the resource causing noisy neighbor problem and hence save the apps deployed in cluster from Denial of Service.&lt;/p&gt;

&lt;h2&gt;
  
  
  Save your Kubernetes cluster from DoS
&lt;/h2&gt;

&lt;p&gt;One solution to the above problem is setting up some kind of a quota on the resources that will be configured as requests and limits in pods. This is to ensure that no one over configures the resource requests and limits and hence avoid the over utilization of resources in the node (beyond some threshold).&lt;/p&gt;

&lt;p&gt;Kubernetes provides ResourceQuota to achieve this as it injects an admission controller in validating phase. Most of the kubernetes distribution supports ResourceQuota by default. Even otherwise, it can be enabled by adding &lt;code&gt;ResourceQuota&lt;/code&gt; in &lt;code&gt;--enable-admission-plugins&lt;/code&gt; flag to kube-apiserver.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kube-apiserver --enable-admission-plugins=ResourceQuota,..
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After enabling the ResourceQuota admission plugin, add the quota for each namespace as per need. For example, to allocate only 10GB of memory that deploy their services in a namespace, create a resource quota as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: v1
kind: ResourceQuota
metadata:
  name: demo-resourcequota
spec:
  hard:
    limits.memory: 10G
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This resource quota ensures that the sum of memory in resource limits of all pods does not exceed 10GB of memory. Any create or modify request will be validated by the ResourceQuota admission controller in the validating phase. In case of non compliance of the existing ResourceQuota, the request will be rejected.&lt;/p&gt;

&lt;p&gt;Now deploy the pod with memory limit of 2GB as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
spec:
  containers:
  - name: myapp-container
    image: busybox:1.28
    command: ['sh', '-c', 'echo The app is running! &amp;amp;&amp;amp; sleep 3600']
    resources:
      limits:
        memory: 2G
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And by running &lt;code&gt;kubectl describe resourcequota demo-resourcequota&lt;/code&gt;, see that 2GB memory limit is used out of configured quota.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--b1AFiwP---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ewwnmx5l14tzh0wo2a5l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--b1AFiwP---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ewwnmx5l14tzh0wo2a5l.png" alt="used-resource-quota"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When another pod having memory limit of 9GB is deployed, it will fail as it will exceed the quota of 10GB. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FaSOetLb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/63vfdz35fuo45d42jf2f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FaSOetLb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/63vfdz35fuo45d42jf2f.png" alt="exceed-resource-quota"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cluster administrators should configure the values in ResourceQuota so that it does not overutilize the nodes.&lt;/p&gt;

&lt;p&gt;In kubernetes cluster, mentioning resource requests and limits in the pod spec is not mandatory and if its not mentioned, it means no limit for resources to be consumed by pod. It can consume resources as much as available in the node. Hence it is not recommended to skip the resource requests and limits in pod spec. &lt;/p&gt;

&lt;p&gt;Having ResourceQuota, any pod creation or updation will be rejected if the request or limit of resources that is required by resource quota is missing. For example, the above resource quota will not allow creation or updation of pods that does not have resource limit for memory configured.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--p7_bYQcZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/tke4wkzuklqiqrdgmt5b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--p7_bYQcZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/tke4wkzuklqiqrdgmt5b.png" alt="pod-with-no-memory-limits"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Simply to ensure that all the pods have some default resource request or limit, we can create LimitRanger in the namespace.&lt;/p&gt;

&lt;p&gt;LimitRanger is also an admission controller which will be involved in the mutating phase. If any of the pod spec does not have resource requests or limits, it will add the resource request and limit as mentioned in the LimitRanger of same namespace.&lt;/p&gt;

&lt;p&gt;Create a LimitRanger in a namespace  as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: v1
kind: LimitRange
metadata:
  name: default-requests-limits
  namespace: demo
spec:
  limits:
  - default:
      memory: 1Gi
    defaultRequest:
      memory: 500Mi
    type: Container
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And then apply the pod without resource requests and limits in the same namespace as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: v1
kind: Pod
metadata:
  name: myapp-no-resources-pod
  labels:
    app: myapp
spec:
  containers:
  - name: myapp-container
    image: busybox:1.28
    command: ['sh', '-c', 'echo The app is running! &amp;amp;&amp;amp; sleep 3600']
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now, get the yaml of the above pod that is running in the K8s cluster. Resource request and limits that is mentioned in the LimitRanger &lt;code&gt;default-requests-limits&lt;/code&gt; got added to &lt;code&gt;.spec.resources&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
spec:
  containers:
  - command:
    - sh
    - -c
    - echo The app is running! &amp;amp;&amp;amp; sleep 3600
    image: busybox:1.28
    imagePullPolicy: IfNotPresent
    name: myapp-container
    resources:
      limits:
        memory: 1G
      requests:
        memory: 500Mi
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Once again run &lt;code&gt;kubectl describe resourcequota demo-resourcequota&lt;/code&gt; and see that 3GB memory limit is used out of configured quota.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--F6LysnfR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/f5exbgph3111qvk5y446.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--F6LysnfR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/f5exbgph3111qvk5y446.png" alt="used-resource-quota"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Thus, configuring ResourceQuota and LimitRanger based on requirements, all the applications in the Kubernetes cluster can be saved from noisy neighbor problem and Denial of Service&lt;/p&gt;

</description>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Container From Scratch</title>
      <dc:creator>Prabhu Jayakumar</dc:creator>
      <pubDate>Tue, 23 Jun 2020 19:47:20 +0000</pubDate>
      <link>https://forem.com/prabhujayakumar/container-from-scratch-23c4</link>
      <guid>https://forem.com/prabhujayakumar/container-from-scratch-23c4</guid>
      <description>&lt;p&gt;Originally published at &lt;a href="https://www.prabhujayakumar.dev"&gt;https://www.prabhujayakumar.dev&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;This is my first blog and I want to share my learnings about containers&lt;/p&gt;

&lt;p&gt;Container adoption to run enterprise applications softwares in production has been increasing drastically nowadays. And most of the container deployments are using docker. Docker became the defacto technology for running containerised applications. But what is docker built on? How it is containerising the applications? I will try to answer these questions in this article.&lt;/p&gt;

&lt;h2&gt;
  
  
  Need for the container
&lt;/h2&gt;

&lt;p&gt;Before getting into containers, let's clearly understand what a process is?&lt;/p&gt;

&lt;p&gt;A process is created when a program is put into execution.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--svZ68I5P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/xok64id6qg9tn088eb6g.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--svZ68I5P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/xok64id6qg9tn088eb6g.jpg" alt="Process"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How can we execute a program? What are the requirements to execute a program?&lt;/p&gt;

&lt;p&gt;A program needs libs, envs and resources to be able to put into execution and thereby create a process. For example, to execute a python script, we need python binary and some python modules, python environments and resources like cpu, memory, disk.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--frTaL-Y4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/rr6nj64q4mgv2kxcd34x.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--frTaL-Y4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/rr6nj64q4mgv2kxcd34x.jpg" alt="Process Execution Requirements"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let us consider a Web Application which consists of many microservices running on various languages and various versions. These microservices are nothing but a process at the backend.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--F5doDMiM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/vf08hgemtw5zy515kpzb.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--F5doDMiM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/vf08hgemtw5zy515kpzb.jpg" alt="Web Application"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that being said, imagine running these services in a physical machine… Thats not an easy task, ITS MERELY POSSIBLE&lt;/p&gt;

&lt;p&gt;But Why? What is the challenge in running all these services of the same web application in a physical machine?&lt;/p&gt;

&lt;p&gt;The problem is, suppose if the application has 2 Java services using different Java versions what will be the value for JAVA_HOME? There can't be 2 JAVA_HOME set in a single physical machine.&lt;/p&gt;

&lt;p&gt;If we have N services to be run in a machine, we have to assign the port to each service such that no port collision occurs. Think about running 2 versions of postgres, pg10 on 5432 port and pg9.6 on 5433 port. So all the services should be aware of the port it is running on.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wUj9MzT---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/zx86daxfhvomlr974bp3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wUj9MzT---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/zx86daxfhvomlr974bp3.jpg" alt="Web Application in a host"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To sum up the above mentioned challenge in a single word, there is NO ISOLATION.&lt;/p&gt;

&lt;p&gt;Since there are different versions of libs and hence different envs are required, each and every service needs to be isolated from one another.&lt;/p&gt;

&lt;p&gt;In order to isolate the processes, people started using Virtual Machines. Let's see how Virtual Machines solve this problem.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8rHUabJS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/sagdqlf2d0eeod0xl5ke.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8rHUabJS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/sagdqlf2d0eeod0xl5ke.jpg" alt="Virtual Machine"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Virtual machine is a separate guest OS created by an hypervisor running on a host machine. This separate guest OS, helps to achieve isolated libs, envs and resources.&lt;/p&gt;

&lt;p&gt;But there are some challenges in using Virtual Machines in this case.&lt;/p&gt;

&lt;p&gt;Think about running all the above services(processes) in a physical machine by creating required virtual machines(1 VM for 1 service).&lt;/p&gt;

&lt;p&gt;You can evidently see the performance overhead in that physical machine which is running 10+ virtual machines. The reason being, the guest OS in each VM has its own memory management, network management and so on.&lt;/p&gt;

&lt;p&gt;Not just that, proper resource utilization becomes a tough task while using Virtual Machines.&lt;/p&gt;

&lt;p&gt;The main reason behind this overhead in Virtual machines approach is that the hypervisor virtualizes an hardware by creating guest OS for each VM.&lt;/p&gt;

&lt;p&gt;All that we want is something which can isolate the libs, envs and resources without having to create separate OS. Why can't we use the resource management of the Host OS itself instead of virtualizing the hardwares which results in overhead?&lt;/p&gt;

&lt;p&gt;Yes, we have something called “CONTAINER” which is capable of doing the same for us.&lt;/p&gt;

&lt;p&gt;A Container is nothing but an isolated process implemented by using some linux technologies like namespace and cgroup.&lt;/p&gt;

&lt;p&gt;Now let us dive deep into containers, how they provide isolation to a process, what are namespaces and cgroup and how are they used.&lt;/p&gt;

&lt;p&gt;Container is a group of process running on a host machine isolated by namespaces.&lt;/p&gt;

&lt;p&gt;It provides OS level virtualization. Hence we can call it as “Lightweight VM”&lt;/p&gt;

&lt;p&gt;We now have a basic understanding of what containers are. Next step would be how do we create it? I know many of us use docker to create containers using docker run command. But, is that the only option? No, there are few other tools like lxc, podman, etc. How the containers are created using these tools? What is the backend process?&lt;/p&gt;

&lt;p&gt;To understand that, let us see how to create a container from scratch using linux technologies like namespace and cgroup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Simple Container in Golang
&lt;/h2&gt;

&lt;p&gt;Let's create a simple go program which takes command as an argument and executes that command by creating a new process. Assume this go program as a docker. To execute a command in docker, we will use “docker run” command, similarly, here we use “go run container.go run”&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "fmt"
    "os"
    "os/exec"
)

// go run container.go run &amp;lt;cmd&amp;gt; &amp;lt;args&amp;gt;
// docker run &amp;lt;cmd&amp;gt; &amp;lt;args&amp;gt;
func main() {
    switch os.Args[1] {
    case "run":
        run()
    default:
        panic("invalid command!!")
    }
}

func run() {
    fmt.Printf("Running %v as PID %d \n", os.Args[2:], os.Getpid())

    cmd := exec.Command(os.Args[2], os.Args[3:]...)

    cmd.Stdin = os.Stdin
    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr

    cmd.Run()
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The above program executes the given arguments as a command. As you see below, “go run container run echo hello container” executes the command “echo hello container”. It executes the command by creating a new process which can be considered as a container.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aabvXsns--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/sq4xkq9sr69v0oc2jeiy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aabvXsns--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/sq4xkq9sr69v0oc2jeiy.gif" alt="container-run"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Similarly let's create a process using &lt;code&gt;/bin/bash&lt;/code&gt; and assign a dedicated hostname for that container. But changing the hostname inside the container, changed the hostname of the host machine as well.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NAxWjyae--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/c33mm0rvazeqxjo4k9mc.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NAxWjyae--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/c33mm0rvazeqxjo4k9mc.gif" alt="container-hostname"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This happens because there is no isolation of hostname for this container. So, to create isolation of hostname, we can assign new UTS namespace for the container. In golang, we can do this by using the &lt;code&gt;syscall&lt;/code&gt; package.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func run() {
    fmt.Printf("Running %v as PID %d \n", os.Args[2:], os.Getpid())

    cmd := exec.Command(os.Args[2], os.Args[3:]...)

    cmd.Stdin = os.Stdin
    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr

    cmd.SysProcAttr = &amp;amp;syscall.SysProcAttr{
        Cloneflags: syscall.CLONE_NEWUTS,
    }

    cmd.Run()
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now, if you change the hostname of the container, it will not affect the hostname of the host machine because the container has its own UTS namespace.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wopm8ifI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/szob7qvzfb92tqaqyo5z.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wopm8ifI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/szob7qvzfb92tqaqyo5z.gif" alt="container-hostname-fixed"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But I want to assign the hostname automatically to the container from golang program using syscall &lt;code&gt;syscall.Sethostname([]byte("container-demo"))&lt;/code&gt;. But where can I place this line in the above program, the process is created on &lt;code&gt;cmd.Run()&lt;/code&gt; and exited on the same line. Hence, let's fork a child process and set hostname inside that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "fmt"
    "os"
    "os/exec"
    "syscall"
)

// go run container.go run &amp;lt;cmd&amp;gt; &amp;lt;args&amp;gt;
// docker run &amp;lt;cmd&amp;gt; &amp;lt;args&amp;gt;
func main() {
    switch os.Args[1] {
    case "run":
        run()
    case "child":
        child()
    default:
        panic("invalid command!!")
    }
}

func run() {
    fmt.Printf("Running %v as PID %d \n", os.Args[2:], os.Getpid())

    args := append([]string{"child"}, os.Args[2:]...)
    cmd := exec.Command("/proc/self/exe", args...)

    cmd.Stdin = os.Stdin
    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr

    cmd.SysProcAttr = &amp;amp;syscall.SysProcAttr{
        Cloneflags: syscall.CLONE_NEWUTS,
    }

    cmd.Run()
}

func child() {
    fmt.Printf("Running %v as PID %d \n", os.Args[2:], os.Getpid())

    syscall.Sethostname([]byte("container-demo"))
    cmd := exec.Command(os.Args[2], os.Args[3:]...)

    cmd.Stdin = os.Stdin
    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr

    cmd.Run()
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gT1Nzf7o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/m4x1qws01yqay7ag8ghh.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gT1Nzf7o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/m4x1qws01yqay7ag8ghh.gif" alt="container-hostname-set"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another catch here is, the container is able to see all the processes running in the host machine.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--a0LoEnW5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/3hw227ph38gcgk0weepm.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--a0LoEnW5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/3hw227ph38gcgk0weepm.gif" alt="container-process-one"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A container should be able to see only the processes running in that container, which can be achieved by using PID namespace.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    cmd.SysProcAttr = &amp;amp;syscall.SysProcAttr{
        Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWPID,
    }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1TDQBoYI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/h4jgusde03y9gn7u4lww.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1TDQBoYI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/h4jgusde03y9gn7u4lww.gif" alt="container-process-two"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Even then, the container is able to see the processes of the host machine. The reason is &lt;code&gt;/proc&lt;/code&gt;; the container is using the same root filesystem as that of the host machine. Hence a different root file system is to be used for container and mount &lt;code&gt;/proc&lt;/code&gt; into it.&lt;br&gt;
&lt;code&gt;/containerfs&lt;/code&gt; directory contains files of an operating system which has few binaries like python and core linux utilities. So mounting this directory as a root file system for container makes it self sufficient for linux utilities and not depend on host machine for binaries. It also provides separate environment for this container.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func child() {
    fmt.Printf("Running %v as PID %d \n", os.Args[2:], os.Getpid())

    syscall.Sethostname([]byte("container-demo"))
    cmd := exec.Command(os.Args[2], os.Args[3:]...)

    cmd.Stdin = os.Stdin
    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr

    syscall.Chroot("/containerfs")
    os.Chdir("/")
    syscall.Mount("proc", "proc", "proc", 0, "")

    cmd.Run()
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ukn4jDWA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/9au9o8lk5m6xt0kz80ef.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ukn4jDWA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/9au9o8lk5m6xt0kz80ef.gif" alt="container-process-isolated"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we have achieved process id isolation using PID namespace. Similarly, we can provide isolation of network and users using network and user namespace.&lt;/p&gt;

&lt;p&gt;Basically, the namespace is about what you can see in the container. It allows us to create restricted views of systems like the process tree, network interfaces, and mounts and users. These are the various namespaces that are available to provide isolation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;UTS(Unix Time Sharing) namespace: hostname and domain name&lt;/li&gt;
&lt;li&gt;PID namespace: process number&lt;/li&gt;
&lt;li&gt;Mounts namespace: mount points&lt;/li&gt;
&lt;li&gt;IPC namespace: Inter Process Communication resources&lt;/li&gt;
&lt;li&gt;Network namespace: network resources&lt;/li&gt;
&lt;li&gt;User namespace: User and Group ID numbers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, let us see how resource management works in container. I have a python script &lt;code&gt;hungry.py&lt;/code&gt; which consumes 10mb of memory for each 0.5 seconds. Running this python script using the container.go program, allows the container process to consume all of the memory available in the host machine.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RMkrhAlt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/gz2nksa7vlmfp0awt823.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RMkrhAlt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/gz2nksa7vlmfp0awt823.gif" alt="container-memory-hungry"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To manage the resources like memory, cpu, disk blocks, we can use cgroups. &lt;br&gt;
Every system has control groups in &lt;code&gt;/sys/fs/cgroup/&lt;/code&gt; and memory uses the default values from &lt;code&gt;/sys/fs/cgroup/memory&lt;/code&gt;. You can see that the value in &lt;code&gt;/sys/fs/cgroup/memory/memory.limit_in_bytes&lt;/code&gt; is very huge, allowing a process to consume memory as much as available in the host machine.&lt;/p&gt;

&lt;p&gt;Here, in this go program, I am creating a control group &lt;code&gt;prabhu&lt;/code&gt; and giving 100mb as maximum limit of memory and disabling the swap memory. And also assigning the process id of the container to the tasks of cgroup &lt;code&gt;prabhu&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func child() {
    fmt.Printf("Running %v as PID %d \n", os.Args[2:], os.Getpid())

    syscall.Sethostname([]byte("container-demo"))
    controlgroup()

    cmd := exec.Command(os.Args[2], os.Args[3:]...)

    cmd.Stdin = os.Stdin
    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr

    syscall.Chroot("/containerfs")
    os.Chdir("/")
    syscall.Mount("proc", "proc", "proc", 0, "")

    cmd.Run()
}

func controlgroup() {

    cgPath := filepath.Join("/sys/fs/cgroup/memory", "prabhu")
    os.Mkdir(cgPath, 0755)

    ioutil.WriteFile(filepath.Join(cgPath, "memory.limit_in_bytes"), []byte("100000000"), 0700)

    ioutil.WriteFile(filepath.Join(cgPath, "memory.swappiness"), []byte("0"), 0700)

    ioutil.WriteFile(filepath.Join(cgPath, "tasks"), []byte(strconv.Itoa(os.Getpid())), 0700)
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nGzl68_z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/0tspf356bjp37r5b8pi9.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nGzl68_z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/0tspf356bjp37r5b8pi9.gif" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since, cgroup &lt;code&gt;prabhu&lt;/code&gt; assigned to the container process allows only 100mb of memory, the python process gets killed once it tries to exceed that memory limit.&lt;/p&gt;

&lt;p&gt;By using cgroups, system administrators gain fine-grained control over allocating, prioritizing, denying, managing, and monitoring system resources. The hardware resources can be appropriately divided up among tasks and users, increasing overall efficiency. And hence we can use the cgroups for resource management in container ecosystem.&lt;/p&gt;

&lt;p&gt;Here, I have created a simple container with isolation of hostname, mount(&lt;code&gt;/proc&lt;/code&gt;) and process tree using corresponding namespaces and also did memory management for the container using cgroups.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Containers are just isolated groups of processes running on a single host and that isolation leverages several underlying technologies built into the Linux kernel like namespaces, cgroups and chroots.&lt;/p&gt;

&lt;p&gt;This is how Docker is containerising the applications with many other features like storing and transferring the files in terms of docker images.&lt;/p&gt;

&lt;p&gt;And Docker is not the only technology that helps to run containers. There are other options like Podman from RedHat, LXC Linux Containers and rkt from CoreOS(project closed now).&lt;/p&gt;

&lt;p&gt;Inspired from &lt;a href="https://www.youtube.com/watch?v=Utf-A4rODH8"&gt;Building a container from scratch in Go - Liz Rice (Microscaling Systems)&lt;/a&gt;&lt;/p&gt;

</description>
      <category>containers</category>
      <category>docker</category>
      <category>devops</category>
      <category>go</category>
    </item>
  </channel>
</rss>
