<?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: Hitesh Pattanayak</title>
    <description>The latest articles on Forem by Hitesh Pattanayak (@hiteshrepo).</description>
    <link>https://forem.com/hiteshrepo</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%2F1008730%2F9b4d3cc5-0799-431e-a45f-551bb2dcf53d.jpeg</url>
      <title>Forem: Hitesh Pattanayak</title>
      <link>https://forem.com/hiteshrepo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/hiteshrepo"/>
    <language>en</language>
    <item>
      <title>gRPC dynamic loadbalancing</title>
      <dc:creator>Hitesh Pattanayak</dc:creator>
      <pubDate>Wed, 24 May 2023 16:34:26 +0000</pubDate>
      <link>https://forem.com/hiteshrepo/grpc-dynamic-loadbalancing-51jd</link>
      <guid>https://forem.com/hiteshrepo/grpc-dynamic-loadbalancing-51jd</guid>
      <description>&lt;h2&gt;
  
  
  gRPC
&lt;/h2&gt;

&lt;p&gt;gRPC has many benefits, like:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Multiplexes many requests using same connection.&lt;/li&gt;
&lt;li&gt;Support for typical client-server request-response as well as duplex streaming.&lt;/li&gt;
&lt;li&gt;Usage of a fast, very light, binary protocol with structured data as the communication medium among services.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://www.infracloud.io/blogs/understanding-grpc-concepts-best-practices/"&gt;More about gRPC&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All above make gRPC a very attractive deal but there is some consideration with gRPC particularly load balancing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The issue
&lt;/h2&gt;

&lt;p&gt;Lets delve deep into the issue.&lt;/p&gt;

&lt;p&gt;For this we will require a setup. The setup includes below:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a gRPC server, we call it &lt;code&gt;Greet Server&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;a client that acts as a REST gateway and internally it is a gRPC client as well. We call it &lt;code&gt;Greet Client&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We are also using kubernetes for the demonstration, hence there are a bunch of YAML manifest files. Let me explain them below:&lt;/p&gt;

&lt;p&gt;greetserver-deploy.yaml &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;apps/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;Deployment&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;greetserver-deploy&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;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
  &lt;span class="na"&gt;selector&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;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;greetserver&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&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;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;greetserver&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;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hiteshpattanayak/greet-server:1.0&lt;/span&gt;
          &lt;span class="na"&gt;imagePullPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;IfNotPresent&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;greetserver&lt;/span&gt;
          &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50051&lt;/span&gt;
          &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&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;POD_IP&lt;/span&gt;
              &lt;span class="na"&gt;valueFrom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;fieldRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="na"&gt;fieldPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;status.podIP&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;POD_NAME&lt;/span&gt;
              &lt;span class="na"&gt;valueFrom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;fieldRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="na"&gt;fieldPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;metadata.name&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;The above is a deployment mainfest of &lt;code&gt;Greet Server&lt;/code&gt;, that spins up 3 replicas of &lt;code&gt;Greet Server&lt;/code&gt;.&lt;br&gt;
The &lt;code&gt;Greet Server&lt;/code&gt; uses &lt;code&gt;hiteshpattanayak/greet-server:1.0&lt;/code&gt; image.&lt;br&gt;
Also each pod of the deployment exposes &lt;code&gt;50051&lt;/code&gt; port.&lt;br&gt;
Environment variables: POD_IP and POD_NAME are injected into the pods.&lt;/p&gt;

&lt;p&gt;What does each pod in the above server do?&lt;/p&gt;

&lt;p&gt;They expose an &lt;code&gt;rpc&lt;/code&gt; or service that expects a &lt;code&gt;first_name&lt;/code&gt; and a &lt;code&gt;last_name&lt;/code&gt;, in response they return a message in this format:&lt;br&gt;
&lt;code&gt;reponse from Greet rpc: Hello, &amp;lt;first_name&amp;gt; &amp;lt;last_name&amp;gt; from pod: name(&amp;lt;pod_name&amp;gt;), ip(&amp;lt;pod_ip&amp;gt;).&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;From the response, we can deduce which pod did our request land in.&lt;/p&gt;

&lt;p&gt;greet.svc.yaml&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;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;Service&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;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;greetserver&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;greetserver&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&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;ports&lt;/span&gt;&lt;span class="pi"&gt;:&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;grpc&lt;/span&gt;
      &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50051&lt;/span&gt;
      &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
      &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50051&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;greetserver&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above is a service manifest of &lt;code&gt;Greet server service&lt;/code&gt;. This basically acts as a proxy to above &lt;code&gt;Greet Server&lt;/code&gt; pods.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;selector&lt;/code&gt; section of the service matches with the &lt;code&gt;labels&lt;/code&gt; section of each pod.&lt;/p&gt;

&lt;p&gt;greetclient-deploy.yaml&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;apps/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;Deployment&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;greetclient-deploy&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;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;selector&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;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;greetclient&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&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;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;greetclient&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;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hiteshpattanayak/greet-client:4.0&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;greetclient&lt;/span&gt;
          &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;9091&lt;/span&gt;
          &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&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;GRPC_SERVER_HOST&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;greetserver.default.svc.cluster.local&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;GRPC_SVC&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;greetserver&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;POD_NAMESPACE&lt;/span&gt;
              &lt;span class="na"&gt;valueFrom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;fieldRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="na"&gt;fieldPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;metadata.namespace&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above is a deployment mainfest of &lt;code&gt;Greet Client&lt;/code&gt;, that spins up 1 replica of &lt;code&gt;Greet Client&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As mentioned above the pod runs an applications that acts as a rest gateway and reaches out to &lt;code&gt;Greet Server&lt;/code&gt; in order to process the request.&lt;/p&gt;

&lt;p&gt;This deployment is using &lt;code&gt;hiteshpattanayak/greet-client:4.0&lt;/code&gt; image.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;4.0&lt;/code&gt; tagged image has the load balancing issue.&lt;/p&gt;

&lt;p&gt;Also the pod(s) expose port &lt;code&gt;9091&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;greetclient-svc.yaml&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;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;Service&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;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;greetclient&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;greetclient&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&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;ports&lt;/span&gt;&lt;span class="pi"&gt;:&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;restgateway&lt;/span&gt;
      &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;9091&lt;/span&gt;
      &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
      &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;9091&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;greetclient&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;LoadBalancer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above service is just to redirect traffic to the &lt;code&gt;Greet Client&lt;/code&gt; pods.&lt;/p&gt;

&lt;p&gt;greet-ingress.yaml&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;Ingress&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;greet-ingress&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;
  &lt;span class="na"&gt;annotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;nginx.ingress.kubernetes.io/ssl-redirect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;false"&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;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;greet.com&lt;/span&gt;
      &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/&lt;/span&gt;
            &lt;span class="na"&gt;pathType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Prefix&lt;/span&gt;
            &lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;service&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;greetclient&lt;/span&gt;
                &lt;span class="na"&gt;port&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;restgateway&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above ingress is to expose &lt;code&gt;Greet Client Service&lt;/code&gt; to outside of the cluster.&lt;/p&gt;

&lt;p&gt;Note:&lt;br&gt;
&lt;code&gt;minikube&lt;/code&gt; by default does not have ingress enabled by default&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;check enabled or not: &lt;code&gt;minikube addons list&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;enable ingress addon: &lt;code&gt;minikube addons enable ingress&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;greet-clusterrole.yaml&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;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ClusterRole&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rbac.authorization.k8s.io/v1&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;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&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;service-reader&lt;/span&gt;
&lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;apiGroups&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;services"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;verbs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;get"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;watch"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;list"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;greet-clusterrolebinding.yaml&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;rbac.authorization.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;ClusterRoleBinding&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;service-reader-binding&lt;/span&gt;
&lt;span class="na"&gt;roleRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;apiGroup&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rbac.authorization.k8s.io&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;ClusterRole&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;service-reader&lt;/span&gt;
&lt;span class="na"&gt;subjects&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&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;ServiceAccount&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;default&lt;/span&gt;
    &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The cluster role and cluster role binding are required because the &lt;code&gt;default&lt;/code&gt; service account does not have permission to fetch service details.&lt;br&gt;
And the greet client pod internally tries to fetch service details, hence the binding is required.&lt;/p&gt;

&lt;p&gt;Create the setup in below sequence:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
kubectl create &lt;span class="nt"&gt;-f&lt;/span&gt; greet-clusterrole.yaml

kubectl create &lt;span class="nt"&gt;-f&lt;/span&gt; greet-clusterrolebinding.yaml

kubectl create &lt;span class="nt"&gt;-f&lt;/span&gt; greetserver-deploy.yaml

kubectl get po &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="s1"&gt;'run=greetserver'&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; wide
&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;com&lt;/span&gt;&lt;span class="sh"&gt;
NAME                                  READY   STATUS    RESTARTS   AGE   IP           NODE       NOMINATED NODE   READINESS GATES
greetserver-deploy-7595ccbdd5-67bmd   1/1     Running   0          91s   172.17.0.4   minikube   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;
greetserver-deploy-7595ccbdd5-k6zbl   1/1     Running   0          91s   172.17.0.3   minikube   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;
greetserver-deploy-7595ccbdd5-l8kmv   1/1     Running   0          91s   172.17.0.2   minikube   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;
&lt;/span&gt;&lt;span class="no"&gt;com

&lt;/span&gt;kubectl create &lt;span class="nt"&gt;-f&lt;/span&gt; greet.svc.yaml
kubectl get svc
&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;com&lt;/span&gt;&lt;span class="sh"&gt;
NAME          TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)     AGE
greetserver   ClusterIP   None         &amp;lt;none&amp;gt;        50051/TCP   77s
&lt;/span&gt;&lt;span class="no"&gt;com

&lt;/span&gt;kubectl create &lt;span class="nt"&gt;-f&lt;/span&gt; greetclient-deploy.yaml
kubectl get po &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="s1"&gt;'run=greetclient'&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; wide
&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;com&lt;/span&gt;&lt;span class="sh"&gt;
NAME                                 READY   STATUS    RESTARTS   AGE   IP           NODE       NOMINATED NODE   READINESS GATES
greetclient-deploy-6bddb94df-jwr25   1/1     Running   0          35s   172.17.0.6   minikube   &amp;lt;none&amp;gt;           &amp;lt;none&amp;gt;
&lt;/span&gt;&lt;span class="no"&gt;com

&lt;/span&gt;kubectl create &lt;span class="nt"&gt;-f&lt;/span&gt; greet-client.svc.yaml
kubectl get svc
&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;com&lt;/span&gt;&lt;span class="sh"&gt;
NAME          TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
greetclient   LoadBalancer   10.110.255.115   &amp;lt;pending&amp;gt;     9091:32713/TCP   22s
greetserver   ClusterIP      None             &amp;lt;none&amp;gt;        50051/TCP        5m14s
&lt;/span&gt;&lt;span class="no"&gt;com

&lt;/span&gt;kubectl create &lt;span class="nt"&gt;-f&lt;/span&gt; greet-ingress.yaml
kubectl get ingress
&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;com&lt;/span&gt;&lt;span class="sh"&gt;
NAME            CLASS   HOSTS       ADDRESS        PORTS   AGE
greet-ingress   nginx   greet.com   192.168.49.2   80      32s
&lt;/span&gt;&lt;span class="no"&gt;com
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;since we have exposed the &lt;code&gt;Greet Client&lt;/code&gt; to outside of cluster via &lt;code&gt;greet-ingress&lt;/code&gt;, the endpoint can be accessed on: &lt;code&gt;http://greet.com/greet&lt;/code&gt;.&lt;br&gt;
so when we make a curl request:&lt;/p&gt;

&lt;p&gt;Request#1&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--request&lt;/span&gt; POST &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--url&lt;/span&gt; http://greet.com/greet &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data&lt;/span&gt; &lt;span class="s1"&gt;'{
    "first_name": "Hitesh",
    "last_name": "Pattanayak"
}'&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;com&lt;/span&gt;&lt;span class="sh"&gt;
Response

reponse from Greet rpc: Hello, Hitesh Pattanayak from pod: name(greetserver-deploy-7595ccbdd5-l8kmv), ip(172.17.0.2).
&lt;/span&gt;&lt;span class="no"&gt;com
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Request#2&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--request&lt;/span&gt; POST &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--url&lt;/span&gt; http://greet.com/greet &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data&lt;/span&gt; &lt;span class="s1"&gt;'{
    "first_name": "Hitesh",
    "last_name": "Pattanayak"
}'&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;com&lt;/span&gt;&lt;span class="sh"&gt;
Response

reponse from Greet rpc: Hello, Hitesh Pattanayak from pod: name(greetserver-deploy-7595ccbdd5-l8kmv), ip(172.17.0.2).
&lt;/span&gt;&lt;span class="no"&gt;com
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Request#3&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--request&lt;/span&gt; POST &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--url&lt;/span&gt; http://greet.com/greet &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data&lt;/span&gt; &lt;span class="s1"&gt;'{
    "first_name": "Hitesh",
    "last_name": "Pattanayak"
}'&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;com&lt;/span&gt;&lt;span class="sh"&gt;
Response

reponse from Greet rpc: Hello, Hitesh Pattanayak from pod: name(greetserver-deploy-7595ccbdd5-l8kmv), ip(172.17.0.2).
&lt;/span&gt;&lt;span class="no"&gt;com
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So the ISSUE is no matter hw many request I make, the request lands up in the same server. This is happending because of sticky nature of HTTP/2.&lt;br&gt;
The advantage of gRPC becomes it own peril.&lt;/p&gt;

&lt;p&gt;The codebase to replicate the issue can be found &lt;a href="https://github.com/HiteshRepo/grpc-loadbalancing/commit/dd31d2628d4ee1e47b07b5737ff51cfc43c76d4e"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  gRPC Client side load balancing
&lt;/h2&gt;

&lt;p&gt;We have discussed earlier about one of the challenges with gRPC which is load balancing.&lt;/p&gt;

&lt;p&gt;That happens due to the sticky nature of gRPC connections.&lt;/p&gt;

&lt;p&gt;Now we shall discuss how to resolve the issue.&lt;/p&gt;

&lt;p&gt;This particular solution is quite simple.&lt;/p&gt;

&lt;p&gt;The onus to load balance falls on the client itself.&lt;/p&gt;

&lt;p&gt;To be particular, client does not mean end user. All gRPC servers have a REST gateway that is used by end users.&lt;/p&gt;

&lt;p&gt;This is because HTTP2, which is the protocol used by gRPC, is yet to have browser support.&lt;/p&gt;

&lt;p&gt;Hence the REST gateway acts as a gRPC client to gRPC servers. And thats why gRPC is mostly used for internal communications. &lt;/p&gt;

&lt;p&gt;Earlier we had used &lt;code&gt;hiteshpattanayak/greet-client:4.0&lt;/code&gt; image for &lt;code&gt;Greet Client&lt;/code&gt; which had the normal gRPC setup without client side load balancing.&lt;br&gt;
The code can be referred &lt;a href="https://github.com/HiteshRepo/grpc-loadbalancing/commit/dd31d2628d4ee1e47b07b5737ff51cfc43c76d4e"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Changes
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Code changes
&lt;/h3&gt;

&lt;p&gt;For this solution we use &lt;code&gt;hiteshpattanayak/greet-client:11.0&lt;/code&gt; image. The &lt;a href="https://github.com/HiteshRepo/grpc-loadbalancing/pull/1/files"&gt;codebase&lt;/a&gt; has below changes:&lt;/p&gt;

&lt;p&gt;Updated client deployment manifest:&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;apps/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;Deployment&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;greetclient-deploy&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;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;selector&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;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;greetclient&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&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;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;greetclient&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;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hiteshpattanayak/greet-client:11.0&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;greetclient&lt;/span&gt;
          &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;9091&lt;/span&gt;
          &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&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;GRPC_SVC&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;greetserver&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;POD_NAMESPACE&lt;/span&gt;
              &lt;span class="na"&gt;valueFrom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;fieldRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="na"&gt;fieldPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;metadata.namespace&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;configuring load balancing policy while making dialing to the server.&lt;/li&gt;
&lt;li&gt;configuring to terminate connection while dialing to the server.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;grpc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;servAddr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;grpc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithDefaultServiceConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`{"loadBalancingPolicy":"round_robin"}`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;grpc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithBlock&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;the server address used while dialing needs to the dns address of the server.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;serverHost&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;kubernetes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetServiceDnsName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GRPC_SVC"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"POD_NAMESPACE"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;serverHost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;servAddr&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%s:%s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;serverHost&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;serverPort&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Headless service
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;also earlier while replicating the issue the service (greetserver) we created for &lt;code&gt;Greet server pods&lt;/code&gt; was of normal &lt;code&gt;ClusterIP&lt;/code&gt; type. The headless ClusterIP service is required for this solution.
&lt;/li&gt;
&lt;/ul&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;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;Service&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;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;greetserver&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;greetserver&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&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;ports&lt;/span&gt;&lt;span class="pi"&gt;:&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;grpc&lt;/span&gt;
      &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50051&lt;/span&gt;
      &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
      &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50051&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;greetserver&lt;/span&gt;
  &lt;span class="na"&gt;clusterIP&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One significant thing to notice over here is that this is a special type of &lt;code&gt;ClusterIP&lt;/code&gt; service called &lt;code&gt;Headless&lt;/code&gt; service.&lt;/p&gt;

&lt;p&gt;In this &lt;code&gt;service&lt;/code&gt; kind, the type of service is not specified. By default the type becomes &lt;code&gt;ClusterIP&lt;/code&gt;. Which means the service becomes available within cluster.&lt;/p&gt;

&lt;p&gt;You can set &lt;code&gt;.spec.clusterIP&lt;/code&gt;, if you already have an existing DNS entry that you wish to reuse.&lt;/p&gt;

&lt;p&gt;In case you set &lt;code&gt;.spec.clusterIP&lt;/code&gt; to &lt;code&gt;None&lt;/code&gt;, it makes the service &lt;code&gt;headless&lt;/code&gt;, which means when a client sends a request to a headless Service, it will get back a list of all Pods that this Service represents (in this case, the ones with the label &lt;code&gt;run: greetserver&lt;/code&gt;). &lt;/p&gt;

&lt;p&gt;Kubernetes allows clients to discover pod IPs through DNS lookups. Usually, when you perform a DNS lookup for a service, the DNS server returns a single IP — the service’s cluster IP. But if you tell Kubernetes you don’t need a cluster IP for your service (you do this by setting the clusterIP field to None in the service specification ), the DNS server will return the pod IPs instead of the single service IP. Instead of returning a single DNS A record, the DNS server will return multiple A records for the service, each pointing to the IP of an individual pod backing the service at that moment. Clients can therefore do a simple DNS A record lookup and get the IPs of all the pods that are part of the service. The client can then use that information to connect to one, many, or all of them.&lt;/p&gt;

&lt;p&gt;Basically, the Service now lets the client decide on how it wants to connect to the Pods.&lt;/p&gt;

&lt;h4&gt;
  
  
  Verify headless service DNS lookup
&lt;/h4&gt;

&lt;p&gt;create the headless service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create &lt;span class="nt"&gt;-f&lt;/span&gt; greet.svc.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;create an utility pod:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl run dnsutils &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;tutum/dnsutils &lt;span class="nt"&gt;--command&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nb"&gt;sleep &lt;/span&gt;infinity
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;verify by running &lt;code&gt;nslookup&lt;/code&gt; command on the pod&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nb"&gt;exec &lt;/span&gt;dnsutils &lt;span class="nt"&gt;--&lt;/span&gt;  nslookup greetserver

&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;com&lt;/span&gt;&lt;span class="sh"&gt;
Result

Server:         10.96.0.10
Address:        10.96.0.10#53
Name:   greetserver.default.svc.cluster.local
Address: 172.17.0.4
Name:   greetserver.default.svc.cluster.local
Address: 172.17.0.3
Name:   greetserver.default.svc.cluster.local
Address: 172.17.0.2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see headless service resolves into the IP address of all pods connected through service. &lt;/p&gt;

&lt;p&gt;Contrast this with the output returned for non-headless service.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nb"&gt;exec &lt;/span&gt;dnsutils &lt;span class="nt"&gt;--&lt;/span&gt;  nslookup greetclient

&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;com&lt;/span&gt;&lt;span class="sh"&gt;
Server:     10.96.0.10
Address:    10.96.0.10#53

Name:   greetclient.default.svc.cluster.local
Address: 10.110.255.115
&lt;/span&gt;&lt;span class="no"&gt;com
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now lets test the changes by making curl requests to the exposed ingress.&lt;/p&gt;

&lt;p&gt;Request#1&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--request&lt;/span&gt; POST &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--url&lt;/span&gt; http://greet.com/greet &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data&lt;/span&gt; &lt;span class="s1"&gt;'{
    "first_name": "Hitesh",
    "last_name": "Pattanayak"
}'&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;com&lt;/span&gt;&lt;span class="sh"&gt;
Response

reponse from Greet rpc: Hello, Hitesh Pattanayak from pod: name(greetserver-deploy-7595ccbdd5-k6zbl), ip(172.17.0.3).
&lt;/span&gt;&lt;span class="no"&gt;com
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Request#2&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--request&lt;/span&gt; POST &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--url&lt;/span&gt; http://greet.com/greet &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data&lt;/span&gt; &lt;span class="s1"&gt;'{
    "first_name": "Hitesh",
    "last_name": "Pattanayak"
}'&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;com&lt;/span&gt;&lt;span class="sh"&gt;
Response

reponse from Greet rpc: Hello, Hitesh Pattanayak from pod: name(greetserver-deploy-7595ccbdd5-67bmd), ip(172.17.0.4).
&lt;/span&gt;&lt;span class="no"&gt;com
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Request#3&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--request&lt;/span&gt; POST &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--url&lt;/span&gt; http://greet.com/greet &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data&lt;/span&gt; &lt;span class="s1"&gt;'{
    "first_name": "Hitesh",
    "last_name": "Pattanayak"
}'&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;com&lt;/span&gt;&lt;span class="sh"&gt;
Response

reponse from Greet rpc: Hello, Hitesh Pattanayak from pod: name(greetserver-deploy-7595ccbdd5-l8kmv), ip(172.17.0.2).
&lt;/span&gt;&lt;span class="no"&gt;com
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The issue no longer exists.&lt;/p&gt;

&lt;p&gt;But what we are losing here is the capability of gRPC to retain connections for a longer period of time and multiplex several requests through them thereby reducing latency.&lt;/p&gt;

&lt;h2&gt;
  
  
  gRPC lookaside load balancing
&lt;/h2&gt;

&lt;p&gt;Earlier we discussed about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Load balancing challenge with gRPC&lt;/li&gt;
&lt;li&gt;How to address the above challenge via client side load balancing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even though we were able to resolve the load balancing issue but we traded off one of the major advantage of gRPC which is long duration connections.&lt;/p&gt;

&lt;p&gt;So in this post we would like the achive load balancing (still client side) but we are gonna not trade off the above mentionde gRPC's advantage.&lt;/p&gt;

&lt;p&gt;I would like to re-iterate when I say onus to load balance falls on &lt;code&gt;client side&lt;/code&gt;, client does not mean end user. All gRPC servers have a REST gateway that is used by end users. gRPC services are not directly exposed because of lack of browser support.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lookaside load balancer
&lt;/h2&gt;

&lt;p&gt;The purpose of this load balancer is to resolve which gRPC server to connect.&lt;/p&gt;

&lt;p&gt;At the moment this load balancer works in two ways: round robin and random.&lt;/p&gt;

&lt;p&gt;Load balancer itself is gRPC based and since the load is not going to be too much only one pod would suffice.&lt;/p&gt;

&lt;p&gt;It exposes a service called &lt;code&gt;lookaside&lt;/code&gt; and an rpc called &lt;code&gt;Resolve&lt;/code&gt; which expects the type of routing along with some details about the gRPC servers like kubernetes service name and namespace they exist in.&lt;/p&gt;

&lt;p&gt;Using the service name and namespace, it is going to fetch kubernetes endpoints object associated with it. From the endpoint object server IPs can be found.&lt;br&gt;
Those IPs are going to be stored in memory. Every now and then those IPs would be refreshed based on interval set. For every request to resolve IP, it is going to rotate the IPs based on the routing type in the request.&lt;/p&gt;

&lt;p&gt;Code for lookaside load balancer can be found &lt;a href="https://github.com/HiteshRepo/grpc-loadbalancing/tree/lookaside/internal/app/lookaside"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We are using the image &lt;code&gt;hiteshpattanayak/lookaside:9.0&lt;/code&gt; for lookaside pod.&lt;/p&gt;

&lt;p&gt;The pod manifest would be like this:&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;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;Pod&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;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lookaside&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;lookaside&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&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;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hiteshpattanayak/lookaside:9.0&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;lookaside&lt;/span&gt;
      &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50055&lt;/span&gt;
      &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&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;LB_PORT&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;50055"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;since it is too a gRPC server, the exposed port is &lt;code&gt;50055&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The service manifest that exposes the pod is as below:&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;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;Service&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;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lookaside-svc&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;lookaside-svc&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&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;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50055&lt;/span&gt;
      &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
      &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50055&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lookaside&lt;/span&gt;
  &lt;span class="na"&gt;clusterIP&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I chose &lt;code&gt;headless&lt;/code&gt; service for this as well but there is no such need for this.&lt;/p&gt;

&lt;p&gt;Updated the &lt;code&gt;ClusterRole&lt;/code&gt; to include ability to fetch &lt;code&gt;endpoints&lt;/code&gt; and &lt;code&gt;pod&lt;/code&gt; details&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;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ClusterRole&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rbac.authorization.k8s.io/v1&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;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&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;service-reader&lt;/span&gt;
&lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;apiGroups&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;services"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pods"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;endpoints"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;verbs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;get"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;watch"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;list"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Changes with Greet Client
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Greet Client&lt;/code&gt; is now &lt;a href="https://github.com/HiteshRepo/grpc-loadbalancing/blob/177c0fdccad06a76d7d6ce221ee267a47244dc43/internal/app/greetclient/app.go#L38"&gt;integrated&lt;/a&gt; with lookaside loadbalancer.&lt;/p&gt;

&lt;p&gt;The client is &lt;a href="https://github.com/HiteshRepo/grpc-loadbalancing/blob/177c0fdccad06a76d7d6ce221ee267a47244dc43/internal/app/greetclient/app.go#L131"&gt;set&lt;/a&gt; to use &lt;code&gt;RoundRobin&lt;/code&gt; routing type but can be made configurable via configmap or environment variables.&lt;/p&gt;

&lt;p&gt;Removed setting &lt;code&gt;load-balancing&lt;/code&gt; policy and forcefully terminating connection by setting &lt;code&gt;WithBlock&lt;/code&gt; option while dialing.&lt;/p&gt;

&lt;p&gt;from&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;grpc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;servAddr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;grpc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithDefaultServiceConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`{"loadBalancingPolicy":"round_robin"}`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;grpc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithBlock&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;grpc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;servAddr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So how does it solve the earlier load balancing problem where we traded off terminating long duration connections for the sake of load balancing.&lt;/p&gt;

&lt;p&gt;What we did was to store the previous connections to the server and reuse it but rotate for each request.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;greetClients&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;servAddr&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%s:%s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;serverPort&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"dialing greet server"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;servAddr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;grpc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;servAddr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"could not connect greet server: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;

    &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;currentGreetClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;proto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewGreetServiceClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;greetClients&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;currentGreetClient&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;currentGreetClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;gRPC is a great solution for microservice internal communication because of efficiency, speed and parity. But the long duration connections though an advantage results in tricky load balancing. With the help of this article we found ways to handle it.&lt;/p&gt;

&lt;p&gt;There are ways to handle via service meshes like Linkerd and Istio. But it would be handy to have solutions incase where service meshes are not setup.&lt;/p&gt;

&lt;p&gt;Folks, if you like my content, would you consider following me on &lt;a href="https://www.linkedin.com/in/hitesh-pattanayak-52290b160/"&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>go</category>
      <category>kubernetes</category>
      <category>grpc</category>
      <category>loadbalancing</category>
    </item>
    <item>
      <title>Blue Green Deployment with Kubernetes</title>
      <dc:creator>Hitesh Pattanayak</dc:creator>
      <pubDate>Sun, 02 Apr 2023 07:52:34 +0000</pubDate>
      <link>https://forem.com/hiteshrepo/blue-green-deployment-with-kubernetes-34a9</link>
      <guid>https://forem.com/hiteshrepo/blue-green-deployment-with-kubernetes-34a9</guid>
      <description>&lt;p&gt;Blue-green deployment is a software deployment strategy that allows the release of new features or updates without any downtime or service disruption. In this approach, two identical environments are created, one being the active or live environment (blue) and the other being the idle environment (green) where the new changes are deployed and tested before switching the traffic to the new environment.&lt;/p&gt;

&lt;p&gt;The process of blue-green deployment involves the following steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The initial production environment (blue) is running and actively serving customer traffic.&lt;/li&gt;
&lt;li&gt;A new environment (green) is created with the updated codebase or application version.&lt;/li&gt;
&lt;li&gt;The new environment is thoroughly tested to ensure that everything is working correctly and that the application is stable.&lt;/li&gt;
&lt;li&gt;Once the new environment is deemed stable, traffic is switched from the old environment to the new environment, and the old environment is decommissioned.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The main advantages of blue-green deployment are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Reduced downtime: Since the new environment is tested thoroughly before deploying to the live environment, there is minimal to no downtime during the actual deployment process.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Risk mitigation: In case of any issues or bugs that might have been missed during testing, the old environment can be quickly switched back to, reducing the risk of downtime or service disruption.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fast rollback: If any problems occur after the new environment is deployed, the switch back to the old environment can be done instantly, ensuring fast rollback with minimal impact to the end-users.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Increased reliability: Blue-green deployment enables a reliable and consistent approach to application updates, ensuring that there is minimal disruption to the end-users.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Testing in production: Blue-green deployment also allows for testing in production, which is an efficient way of testing new changes while avoiding any impact on the live environment.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Blue-Green vs Canary
&lt;/h3&gt;

&lt;p&gt;There is another popular deployment strategy called '&lt;a href="https://dev.to/hiteshrepo/canary-deployment-with-kubernetes-22c8"&gt;Canary Deployment&lt;/a&gt;'.&lt;/p&gt;

&lt;p&gt;Although they share some similarities, there are significant differences between the two.&lt;/p&gt;

&lt;p&gt;Canary deployment is a technique that allows you to deploy new changes to a small subset of users or servers, often referred to as the "canary group," and then gradually roll out the changes to the rest of the users or servers. This approach allows you to test the new changes on a small scale before making them available to the entire user base.&lt;/p&gt;

&lt;p&gt;One of the main differences between the two is that in blue-green deployment, both the old and new versions of the application are running at the same time, while in canary deployment, only one version of the application is running at a time. Another difference is that blue-green deployment typically involves switching the entire traffic from one environment to another, while canary deployment gradually increases the traffic to the new version.&lt;/p&gt;

&lt;p&gt;Both deployment strategies have their advantages and disadvantages, and the choice between the two depends on various factors such as the size of the user base, the criticality of the application, and the available resources. Blue-green deployment is preferred when there are a large number of users, and the application needs to be highly available, while canary deployment is a good option when you want to test new changes on a small scale before rolling them out to the entire user base.&lt;/p&gt;

&lt;h3&gt;
  
  
  Steps to demonstrate blue-green deployment
&lt;/h3&gt;

&lt;p&gt;** Create Blue deployment  **&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;with pod label &lt;code&gt;app: blue&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;with an busybox initContainer
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;initContainers:
    - name: &lt;span class="nb"&gt;install
    &lt;/span&gt;image: busybox:1.28
    &lt;span class="nb"&gt;command&lt;/span&gt;:
    - /bin/sh
    - &lt;span class="nt"&gt;-c&lt;/span&gt;
    - &lt;span class="s2"&gt;"echo blue &amp;gt; /work-dir/index.html"&lt;/span&gt;
    volumeMounts:
    - name: workdir
        mountPath: &lt;span class="s2"&gt;"/work-dir"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Final blue deployment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: blue-1.10
spec:
  replicas: 3
  selector:
    matchLabels:
      name: nginx
      app: blue
  template:
    metadata:
      labels:
        name: nginx
        app: blue
    spec:
      initContainers:
      - name: &lt;span class="nb"&gt;install
        &lt;/span&gt;image: busybox:1.28
        &lt;span class="nb"&gt;command&lt;/span&gt;:
        - /bin/sh
        - &lt;span class="nt"&gt;-c&lt;/span&gt;
        - &lt;span class="s2"&gt;"echo blue &amp;gt; /work-dir/index.html"&lt;/span&gt;
        volumeMounts:
        - name: workdir
          mountPath: &lt;span class="s2"&gt;"/work-dir"&lt;/span&gt;
      containers: 
        - name: nginx
          image: nginx:1.10
          ports:
          - name: http
            containerPort: 80
          volumeMounts:
          - name: workdir
            mountPath: /usr/share/nginx/html
      volumes:
      - name: workdir
        emptyDir: &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;** Create a service to interact with the blue deployment **&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apiVersion: v1
kind: Service
metadata: 
  name: nginx
  labels: 
    name: nginx
spec:
  ports:
    - name: http
      port: 80
      targetPort: 80
  selector: 
    name: nginx
    app: blue
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;** Create both deployment and service **&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create &lt;span class="nt"&gt;-f&lt;/span&gt; blue-deploy.yaml
kubectl create &lt;span class="nt"&gt;-f&lt;/span&gt; blue-green-svc.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;** Validate both the objects **&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get deploy

NAME         READY   UP-TO-DATE   AVAILABLE   AGE
blue-1.10   3/3     3            3           4m37s


kubectl get svc

NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT&lt;span class="o"&gt;(&lt;/span&gt;S&lt;span class="o"&gt;)&lt;/span&gt;   AGE
nginx        ClusterIP   10.109.140.77    &amp;lt;none&amp;gt;        80/TCP    57s

kubectl get po

NAME                          READY   STATUS    RESTARTS   AGE
blue-1.10-579857b89c-jvthn   1/1     Running   0          5m51s
blue-1.10-579857b89c-thq2z   1/1     Running   0          5m51s
blue-1.10-579857b89c-vhrvc   1/1     Running   0          5m51s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;** Test the deployment **&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;--restart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Never busybox &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;gcr.io/google-containers/busybox &lt;span class="nt"&gt;--command&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; wget &lt;span class="nt"&gt;-qO-&lt;/span&gt; nginx

&lt;span class="c"&gt;# o/p&lt;/span&gt;
blue
pod &lt;span class="s2"&gt;"busybox"&lt;/span&gt; deleted
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;** Create Green deployment **&lt;/p&gt;

&lt;p&gt;Green deployment is same as blue except for label &lt;code&gt;app=green&lt;/code&gt; and command echoing &lt;code&gt;green&lt;/code&gt; instead of &lt;code&gt;blue&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: green-1.10
spec:
  replicas: 3
  selector:
    matchLabels:
      name: nginx
      app: green
  template:
    metadata:
      labels:
        name: nginx
        app: green
    spec:
      initContainers:
      - name: &lt;span class="nb"&gt;install
        &lt;/span&gt;image: busybox:1.28
        &lt;span class="nb"&gt;command&lt;/span&gt;:
        - /bin/sh
        - &lt;span class="nt"&gt;-c&lt;/span&gt;
        - &lt;span class="s2"&gt;"echo green &amp;gt; /work-dir/index.html"&lt;/span&gt;
        volumeMounts:
        - name: workdir
          mountPath: &lt;span class="s2"&gt;"/work-dir"&lt;/span&gt;
      containers: 
        - name: nginx
          image: nginx:1.10
          ports:
          - name: http
            containerPort: 80
          volumeMounts:
          - name: workdir
            mountPath: /usr/share/nginx/html
      volumes:
      - name: workdir
        emptyDir: &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;** Create green deployment **&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create &lt;span class="nt"&gt;-f&lt;/span&gt; green-deploy.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;** Validate the green deployment **&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get deployments

NAME         READY   UP-TO-DATE   AVAILABLE   AGE
blue-1.10    3/3     3            3           3m33s
green-1.10   3/3     3            3           2m29s

kubectl get po

NAME                          READY   STATUS    RESTARTS   AGE
blue-1.10-6c6ff57655-9p5pf    1/1     Running   0          3m52s
blue-1.10-6c6ff57655-knpf5    1/1     Running   0          3m52s
blue-1.10-6c6ff57655-wpgqp    1/1     Running   0          3m52s
green-1.10-7f754b7675-kfj89   1/1     Running   0          2m48s
green-1.10-7f754b7675-nd749   1/1     Running   0          2m48s
green-1.10-7f754b7675-nrd9m   1/1     Running   0          2m48s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;** Update the selector of svc **&lt;/p&gt;

&lt;p&gt;Change selector of service &lt;code&gt;nginx&lt;/code&gt; from &lt;code&gt;app: blue&lt;/code&gt; to &lt;code&gt;app: green&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apiVersion: v1
kind: Service
metadata: 
  name: nginx
  labels: 
    name: nginx
spec:
  ports:
    - name: http
      port: 80
      targetPort: 80
  selector: 
    name: nginx
    app: green
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;** Re-Apply the service object ***&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; blue-green-svc.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;** Test the deployment **&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;--restart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Never busybox &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;gcr.io/google-containers/busybox &lt;span class="nt"&gt;--command&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; wget &lt;span class="nt"&gt;-qO-&lt;/span&gt; nginx

&lt;span class="c"&gt;# o/p&lt;/span&gt;
green
pod &lt;span class="s2"&gt;"busybox"&lt;/span&gt; deleted
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Simple bash script to automate blue to green switch
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="c"&gt;# bg-deploy.sh &amp;lt;service-name&amp;gt; &amp;lt;blue-deployment-name&amp;gt; &amp;lt;green-deployment-yaml-path&amp;gt; &amp;lt;green-deployment-name&amp;gt;&lt;/span&gt;

&lt;span class="nv"&gt;SERVICE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;
&lt;span class="nv"&gt;BLUEDEPLOYMENTNAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;
&lt;span class="nv"&gt;GREENDEPLOYMENTFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$3&lt;/span&gt;
&lt;span class="nv"&gt;GREENDEPLOYMENTNAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;

kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="nv"&gt;$GREENDEPLOYMENTFILE&lt;/span&gt;

&lt;span class="c"&gt;# Wait until the Green Deployment is ready by checking the MinimumReplicasAvailable condition.&lt;/span&gt;
&lt;span class="nv"&gt;READY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;kubectl get deploy &lt;span class="nv"&gt;$GREENDEPLOYMENTNAME&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; json | jq &lt;span class="s1"&gt;'.status.conditions[] | select(.reason == "MinimumReplicasAvailable") | .status'&lt;/span&gt; | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'"'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$READY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s2"&gt;"True"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    &lt;/span&gt;&lt;span class="nv"&gt;READY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;kubectl get deploy &lt;span class="nv"&gt;$GREENDEPLOYMENTNAME&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; json | jq &lt;span class="s1"&gt;'.status.conditions[] | select(.reason == "MinimumReplicasAvailable") | .status'&lt;/span&gt; | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'"'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;sleep &lt;/span&gt;5
&lt;span class="k"&gt;done&lt;/span&gt;

&lt;span class="c"&gt;# Update the service selector with the new version&lt;/span&gt;
kubectl patch svc &lt;span class="nv"&gt;$SERVICE&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"{&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;spec&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:{&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;selector&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: {&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;SERVICE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;app&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;green&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;}}}"&lt;/span&gt;

&lt;span class="c"&gt;# Delete blue deploy [optional]&lt;/span&gt;
kubectl delete deploy &lt;span class="nv"&gt;$BLUEDEPLOYMENTNAME&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Done."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In conclusion, blue-green deployment is an efficient and reliable approach to software deployment, allowing for the release of new features or updates with minimal to no downtime. With its ability to test in production, fast rollback, and reduced risk of service disruption, blue-green deployment is a preferred choice for applications that need to be highly available. While canary deployment shares some similarities with blue-green deployment, it differs in its approach to gradual rollout and testing on a small scale. The choice between the two deployment strategies depends on various factors, including the size of the user base, criticality of the application, and available resources. Overall, blue-green deployment is an excellent option for large applications that require high availability and reliability.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>bluegreendeployment</category>
      <category>deploymentstrategy</category>
      <category>deploy</category>
    </item>
    <item>
      <title>Canary Deployment with Kubernetes</title>
      <dc:creator>Hitesh Pattanayak</dc:creator>
      <pubDate>Sat, 01 Apr 2023 10:43:39 +0000</pubDate>
      <link>https://forem.com/hiteshrepo/canary-deployment-with-kubernetes-22c8</link>
      <guid>https://forem.com/hiteshrepo/canary-deployment-with-kubernetes-22c8</guid>
      <description>&lt;p&gt;In this post, we will learn how to do canary deployment using Kubernetes. In a canary deployment, a small set of users or requests are directed to a new version of the software while the majority of the traffic is still being handled by the old version. This allows us to test new versions of software in production without risking the entire system.&lt;/p&gt;

&lt;h3&gt;
  
  
  Advantage of Canary Deployment
&lt;/h3&gt;

&lt;p&gt;Canary deployment is a deployment strategy where a new version of an application is gradually rolled out to a small subset of users or servers before it is released to the entire user base. The advantages of canary deployment include:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Early detection of issues: Canary deployment allows you to test new features or changes on a small scale before rolling them out to your entire user base. This helps you to detect and fix any issues or bugs early on, minimizing the impact on your users.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Reduced risk: With canary deployment, you are reducing the risk of deploying new features or changes by limiting the scope of the rollout. This makes it easier to recover from any issues that may arise.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Better user experience: By gradually rolling out changes to a small subset of users, you can gather feedback and make adjustments before releasing the changes to your entire user base. This ensures a better user experience for your customers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Improved performance: Canary deployment can improve the performance of your application by allowing you to test and optimize new features or changes on a small scale before rolling them out to your entire user base.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Increased agility: Canary deployment enables you to be more agile in your development process by allowing you to release new features or changes more frequently and with less risk. This can help you to stay ahead of the competition and meet the changing needs of your users.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Steps to demontrate Canary Deployment
&lt;/h3&gt;

&lt;p&gt;Let’s start by creating two nginx deployments with labels version=v1 and version=v2 to differentiate. We will call our first deployment nginx-app-1 and use the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create deploy nginx-app-1 &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nginx &lt;span class="nt"&gt;--replicas&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3 &lt;span class="nt"&gt;--dry-run&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;client &lt;span class="nt"&gt;-o&lt;/span&gt; yaml &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; deploy-1.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we will edit the &lt;code&gt;deploy-1.yaml&lt;/code&gt; file and add a label &lt;code&gt;app=v1&lt;/code&gt; to the &lt;code&gt;metadata.labels&lt;/code&gt; section. We will also add an &lt;code&gt;initContainers&lt;/code&gt; section for the busybox pod:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;initContainers:
  - name: &lt;span class="nb"&gt;install
    &lt;/span&gt;image: busybox:1.28
    &lt;span class="nb"&gt;command&lt;/span&gt;:
      - /bin/sh
      - &lt;span class="nt"&gt;-c&lt;/span&gt;
      - &lt;span class="s2"&gt;"echo version-1 &amp;gt; /work-dir/index.html"&lt;/span&gt;
    volumeMounts:
      - name: workdir
        mountPath: &lt;span class="s2"&gt;"/work-dir"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let’s create a service for the deployment to be accessible:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apiVersion: v1
kind: Service
metadata:
  name: nginx-app-svc
  labels:
    app: nginx-app
spec:
  &lt;span class="nb"&gt;type&lt;/span&gt;: ClusterIP
  ports:
    - name: http
      port: 80
      targetPort: 80
  selector:
    app: nginx-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can test the deployment by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;--restart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Never busybox &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;gcr.io/google-containers/busybox &lt;span class="nt"&gt;--command&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; wget &lt;span class="nt"&gt;-qO-&lt;/span&gt; nginx-app-svc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let’s create another similar deployment with one replica, but with a label value of &lt;code&gt;app=v2&lt;/code&gt;. We will call this deployment &lt;code&gt;nginx-app-2&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create deploy nginx-app-2 &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nginx &lt;span class="nt"&gt;--replicas&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="nt"&gt;--dry-run&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;client &lt;span class="nt"&gt;-o&lt;/span&gt; yaml &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; deploy-2.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will also edit the &lt;code&gt;deploy-2.yaml&lt;/code&gt; file and add a label &lt;code&gt;app=v2&lt;/code&gt; to the &lt;code&gt;metadata.labels&lt;/code&gt; section. We will deploy this new version of the software by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; deploy-2.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can continuously call the service to see how the load balancer diverts the traffic between the two versions. To do this, we can run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;--restart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Never busybox &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;gcr.io/google-containers/busybox &lt;span class="nt"&gt;--&lt;/span&gt; /bin/sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'while sleep 1; do wget -qO- nginx-app-svc; done'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once we determine that &lt;code&gt;nginx-app-2&lt;/code&gt; is stable and we would like to deprecate &lt;code&gt;nginx-app-1&lt;/code&gt;, we can delete the old deployment by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl delete deploy nginx-app-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All traffic will then be directed to nginx-app-2. We can also scale nginx-app-2 to four replicas by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl scale &lt;span class="nt"&gt;--replicas&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;4 deploy nginx-app-2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To check the traffic, we can run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;sleep &lt;/span&gt;0.1&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do &lt;/span&gt;curl &lt;span class="si"&gt;$(&lt;/span&gt;kubectl get svc nginx-app-svc &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"{.spec.clusterIP}"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In summary, canary deployment is a powerful tool that can help you to deploy new features or changes with more confidence and less risk. By gradually rolling out changes and gathering feedback, you can improve the user experience, performance, and agility of your application.&lt;/p&gt;

</description>
      <category>canarydeployment</category>
      <category>deployment</category>
      <category>kubernetes</category>
      <category>k8s</category>
    </item>
    <item>
      <title>Managing Kubernetes Resources with Resource Quotas</title>
      <dc:creator>Hitesh Pattanayak</dc:creator>
      <pubDate>Fri, 31 Mar 2023 10:49:41 +0000</pubDate>
      <link>https://forem.com/hiteshrepo/managing-kubernetes-resources-with-resource-quotas-2pe4</link>
      <guid>https://forem.com/hiteshrepo/managing-kubernetes-resources-with-resource-quotas-2pe4</guid>
      <description>&lt;h2&gt;
  
  
  Resource quota
&lt;/h2&gt;

&lt;p&gt;When several users or teams share a cluster with a fixed number of nodes, there is a concern that one team could use more than its fair share of resources.&lt;/p&gt;

&lt;p&gt;Resource quotas are a tool for administrators to address this concern.&lt;/p&gt;

&lt;p&gt;A resource quota, defined by a ResourceQuota object, provides constraints that limit aggregate resource consumption per namespace. It can limit the quantity of objects that can be created in a namespace by type, as well as the total amount of compute resources that may be consumed by resources in that namespace.&lt;/p&gt;

&lt;p&gt;Resource quotas work like this:&lt;/p&gt;

&lt;p&gt;Different teams work in different namespaces. This can be enforced with RBAC.&lt;/p&gt;

&lt;p&gt;The administrator creates one ResourceQuota for each namespace.&lt;/p&gt;

&lt;p&gt;Users create resources (pods, services, etc.) in the namespace, and the quota system tracks usage to ensure it does not exceed hard resource limits defined in a ResourceQuota.&lt;/p&gt;

&lt;p&gt;If creating or updating a resource violates a quota constraint, the request will fail with HTTP status code 403 FORBIDDEN with a message explaining the constraint that would have been violated.&lt;/p&gt;

&lt;p&gt;If quota is enabled in a namespace for compute resources like cpu and memory, users must specify requests or limits for those values; otherwise, the quota system may reject pod creation. Hint: Use the LimitRanger admission controller to force defaults for pods that make no compute resource requirements.&lt;/p&gt;

&lt;h3&gt;
  
  
  Explanation of resource_quota.yaml file
&lt;/h3&gt;

&lt;p&gt;This is a YAML file containing two Kubernetes objects.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apiVersion: v1
kind: Namespace
metadata:
  name: mynamespace

&lt;span class="nt"&gt;---&lt;/span&gt;
apiVersion: v1
kind: List
items:
  - apiVersion: v1
    kind: ResourceQuota
    metadata:
      name: user-compute-quota
      namespace: mynamespace
    spec:
      hard:
        requests.cpu: &lt;span class="s2"&gt;"1"&lt;/span&gt;
        requests.memory: 1Gi
        limits.cpu: &lt;span class="s2"&gt;"2"&lt;/span&gt;
        limits.memory: 2Gi
  - apiVersion: v1
    kind: ResourceQuota
    metadata:
      name: user-object-quota
      namespace: mynamespace
    spec:
      hard:
        configmaps: &lt;span class="s2"&gt;"10"&lt;/span&gt;
        persistentvolumeclaims: &lt;span class="s2"&gt;"4"&lt;/span&gt;
        replicationcontrollers: &lt;span class="s2"&gt;"20"&lt;/span&gt;
        secrets: &lt;span class="s2"&gt;"10"&lt;/span&gt;
        services: &lt;span class="s2"&gt;"10"&lt;/span&gt;
        services.loadbalancers: &lt;span class="s2"&gt;"2"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first object is of kind "Namespace" and has a metadata field with the name "mynamespace". This is creating a namespace named "mynamespace" in Kubernetes.&lt;/p&gt;

&lt;p&gt;The second object is of kind "List" and contains a list of two "ResourceQuota" objects. The first "ResourceQuota" object has a metadata field with the name "user-compute-quota" and namespace set to "mynamespace". The "spec" field defines resource usage limits for the namespace, such as CPU and memory requests and limits. Specifically, this quota allows for a maximum of 1 CPU and 1Gi of memory for requests and a maximum of 2 CPUs and 2Gi of memory for limits.&lt;/p&gt;

&lt;p&gt;The second "ResourceQuota" object has a metadata field with the name "user-object-quota" and namespace set to "mynamespace". The "spec" field defines limits on the number of objects of different types that can be created in the namespace. Specifically, this quota allows for a maximum of 10 configmaps, 4 persistentvolumeclaims, 20 replicationcontrollers, 10 secrets, 10 services, and 2 load balancer services.&lt;/p&gt;

&lt;h3&gt;
  
  
  Steps to create ‘Resource Quota’ objects and observe their working
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Create resource quota objects:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; resource_quota.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Verify created resource quota objects:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; kubectl get quota &lt;span class="nt"&gt;-n&lt;/span&gt; mynamespace 

NAME                 AGE   REQUEST                                                                                                                                   LIMIT
user-compute-quota   79s   requests.cpu: 0/1, requests.memory: 0/1Gi                                                                                                 limits.cpu: 0/2, limits.memory: 0/2Gi
user-object-quota    44s   configmaps: 1/10, persistentvolumeclaims: 0/4, replicationcontrollers: 0/20, secrets: 0/10, services: 0/10, services.loadbalancers: 0/2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Create deployment (dep_without_quota.yaml)
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  namespace: mynamespace
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: k8s-demo
          image: nginx
          ports:
            - name: nginx-port
              containerPort: 8080

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create &lt;span class="nt"&gt;-f&lt;/span&gt; dep_without_quota.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Verify deployment
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get deploy &lt;span class="nt"&gt;-n&lt;/span&gt; mynamespace

NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   0/3     0            0           31s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;nothing in ready state.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Explore reason
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get rs &lt;span class="nt"&gt;-n&lt;/span&gt; mynamespace 

NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-64ff9dbcdf   3         0         0       2m51s


kubectl describe rs nginx-deployment-64ff9dbcdf

...
Events:
  Type     Reason        Age                 From                   Message
  &lt;span class="nt"&gt;----&lt;/span&gt;     &lt;span class="nt"&gt;------&lt;/span&gt;        &lt;span class="nt"&gt;----&lt;/span&gt;                &lt;span class="nt"&gt;----&lt;/span&gt;                   &lt;span class="nt"&gt;-------&lt;/span&gt;
  Warning  FailedCreate  3m9s                replicaset-controller  Error creating: pods &lt;span class="s2"&gt;"nginx-deployment-64ff9dbcdf-wkr8s"&lt;/span&gt; is forbidden: failed quota: user-compute-quota: must specify limits.cpu &lt;span class="k"&gt;for&lt;/span&gt;: k8s-demo&lt;span class="p"&gt;;&lt;/span&gt; limits.memory &lt;span class="k"&gt;for&lt;/span&gt;: k8s-demo&lt;span class="p"&gt;;&lt;/span&gt; requests.cpu &lt;span class="k"&gt;for&lt;/span&gt;: k8s-demo&lt;span class="p"&gt;;&lt;/span&gt; requests.memory &lt;span class="k"&gt;for&lt;/span&gt;: k8s-demo
  Warning  FailedCreate  3m9s                replicaset-controller  Error creating: pods &lt;span class="s2"&gt;"nginx-deployment-64ff9dbcdf-mhn6c"&lt;/span&gt; is forbidden: failed quota: user-compute-quota: must specify limits.cpu &lt;span class="k"&gt;for&lt;/span&gt;: k8s-demo&lt;span class="p"&gt;;&lt;/span&gt; limits.memory &lt;span class="k"&gt;for&lt;/span&gt;: k8s-demo&lt;span class="p"&gt;;&lt;/span&gt; requests.cpu &lt;span class="k"&gt;for&lt;/span&gt;: k8s-demo&lt;span class="p"&gt;;&lt;/span&gt; requests.memory &lt;span class="k"&gt;for&lt;/span&gt;: k8s-demo
  Warning  FailedCreate  3m9s                replicaset-controller  Error creating: pods &lt;span class="s2"&gt;"nginx-deployment-64ff9dbcdf-77n7m"&lt;/span&gt; is forbidden: failed quota: user-compute-quota: must specify limits.cpu &lt;span class="k"&gt;for&lt;/span&gt;: k8s-demo&lt;span class="p"&gt;;&lt;/span&gt; limits.memory &lt;span class="k"&gt;for&lt;/span&gt;: k8s-demo&lt;span class="p"&gt;;&lt;/span&gt; requests.cpu &lt;span class="k"&gt;for&lt;/span&gt;: k8s-demo&lt;span class="p"&gt;;&lt;/span&gt; requests.memory &lt;span class="k"&gt;for&lt;/span&gt;: k8s-demo
  Warning  FailedCreate  3m9s                replicaset-controller  Error creating: pods &lt;span class="s2"&gt;"nginx-deployment-64ff9dbcdf-t5m7q"&lt;/span&gt; is forbidden: failed quota: user-compute-quota: must specify limits.cpu &lt;span class="k"&gt;for&lt;/span&gt;: k8s-demo&lt;span class="p"&gt;;&lt;/span&gt; limits.memory &lt;span class="k"&gt;for&lt;/span&gt;: k8s-demo&lt;span class="p"&gt;;&lt;/span&gt; requests.cpu &lt;span class="k"&gt;for&lt;/span&gt;: k8s-demo&lt;span class="p"&gt;;&lt;/span&gt; requests.memory &lt;span class="k"&gt;for&lt;/span&gt;: k8s-demo
  Warning  FailedCreate  3m9s                replicaset-controller  Error creating: pods &lt;span class="s2"&gt;"nginx-deployment-64ff9dbcdf-j6974"&lt;/span&gt; is forbidden: failed quota: user-compute-quota: must specify limits.cpu &lt;span class="k"&gt;for&lt;/span&gt;: k8s-demo&lt;span class="p"&gt;;&lt;/span&gt; limits.memory &lt;span class="k"&gt;for&lt;/span&gt;: k8s-demo&lt;span class="p"&gt;;&lt;/span&gt; requests.cpu &lt;span class="k"&gt;for&lt;/span&gt;: k8s-demo&lt;span class="p"&gt;;&lt;/span&gt; requests.memory &lt;span class="k"&gt;for&lt;/span&gt;: k8s-demo
  Warning  FailedCreate  3m9s                replicaset-controller  Error creating: pods &lt;span class="s2"&gt;"nginx-deployment-64ff9dbcdf-ldtx8"&lt;/span&gt; is forbidden: failed quota: user-compute-quota: must specify limits.cpu &lt;span class="k"&gt;for&lt;/span&gt;: k8s-demo&lt;span class="p"&gt;;&lt;/span&gt; limits.memory &lt;span class="k"&gt;for&lt;/span&gt;: k8s-demo&lt;span class="p"&gt;;&lt;/span&gt; requests.cpu &lt;span class="k"&gt;for&lt;/span&gt;: k8s-demo&lt;span class="p"&gt;;&lt;/span&gt; requests.memory &lt;span class="k"&gt;for&lt;/span&gt;: k8s-demo
  Warning  FailedCreate  3m9s                replicaset-controller  Error creating: pods &lt;span class="s2"&gt;"nginx-deployment-64ff9dbcdf-jzfqg"&lt;/span&gt; is forbidden: failed quota: user-compute-quota: must specify limits.cpu &lt;span class="k"&gt;for&lt;/span&gt;: k8s-demo&lt;span class="p"&gt;;&lt;/span&gt; limits.memory &lt;span class="k"&gt;for&lt;/span&gt;: k8s-demo&lt;span class="p"&gt;;&lt;/span&gt; requests.cpu &lt;span class="k"&gt;for&lt;/span&gt;: k8s-demo&lt;span class="p"&gt;;&lt;/span&gt; requests.memory &lt;span class="k"&gt;for&lt;/span&gt;: k8s-demo
  Warning  FailedCreate  3m8s                replicaset-controller  Error creating: pods &lt;span class="s2"&gt;"nginx-deployment-64ff9dbcdf-xrp62"&lt;/span&gt; is forbidden: failed quota: user-compute-quota: must specify limits.cpu &lt;span class="k"&gt;for&lt;/span&gt;: k8s-demo&lt;span class="p"&gt;;&lt;/span&gt; limits.memory &lt;span class="k"&gt;for&lt;/span&gt;: k8s-demo&lt;span class="p"&gt;;&lt;/span&gt; requests.cpu &lt;span class="k"&gt;for&lt;/span&gt;: k8s-demo&lt;span class="p"&gt;;&lt;/span&gt; requests.memory &lt;span class="k"&gt;for&lt;/span&gt;: k8s-demo
  Warning  FailedCreate  3m8s                replicaset-controller  Error creating: pods &lt;span class="s2"&gt;"nginx-deployment-64ff9dbcdf-s29ht"&lt;/span&gt; is forbidden: failed quota: user-compute-quota: must specify limits.cpu &lt;span class="k"&gt;for&lt;/span&gt;: k8s-demo&lt;span class="p"&gt;;&lt;/span&gt; limits.memory &lt;span class="k"&gt;for&lt;/span&gt;: k8s-demo&lt;span class="p"&gt;;&lt;/span&gt; requests.cpu &lt;span class="k"&gt;for&lt;/span&gt;: k8s-demo&lt;span class="p"&gt;;&lt;/span&gt; requests.memory &lt;span class="k"&gt;for&lt;/span&gt;: k8s-demo
  Warning  FailedCreate  25s &lt;span class="o"&gt;(&lt;/span&gt;x7 over 3m6s&lt;span class="o"&gt;)&lt;/span&gt;  replicaset-controller  &lt;span class="o"&gt;(&lt;/span&gt;combined from similar events&lt;span class="o"&gt;)&lt;/span&gt;: Error creating: pods &lt;span class="s2"&gt;"nginx-deployment-64ff9dbcdf-9gxvc"&lt;/span&gt; is forbidden: failed quota: user-compute-quota: must specify limits.cpu &lt;span class="k"&gt;for&lt;/span&gt;: k8s-demo&lt;span class="p"&gt;;&lt;/span&gt; limits.memory &lt;span class="k"&gt;for&lt;/span&gt;: k8s-demo&lt;span class="p"&gt;;&lt;/span&gt; requests.cpu &lt;span class="k"&gt;for&lt;/span&gt;: k8s-demo&lt;span class="p"&gt;;&lt;/span&gt; requests.memory &lt;span class="k"&gt;for&lt;/span&gt;: k8s-demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;since quota is not specified in the deployment file, it fails to provision the pods.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create deployment (dep_with_quota.yaml)
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: helloworld-deployment
  namespace: mynamespace
  labels:
    app: nginx-ssl
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx-ssl
  template:
    metadata:
      labels:
        app: nginx-ssl
    spec:
      containers:
        - name: k8s-demo
          image: nginx:1.16
          ports:
            - name: nginxssl-port
              containerPort: 8081
          resources:
            requests:
              cpu: 200m
              memory: 0.5Gi
            limits:
              cpu: 400m
              memory: 1Gi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create &lt;span class="nt"&gt;-f&lt;/span&gt; dep_with_quota.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Verify deployment
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get rs &lt;span class="nt"&gt;-n&lt;/span&gt; mynamespace 

NAME                               DESIRED   CURRENT   READY   AGE
helloworld-deployment-7986cbf64d   3         2         2       45s
nginx-deployment-64ff9dbcdf        3         0         0       8m52s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;only 2 out of 3 are in ready state.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Explore reason
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get rs &lt;span class="nt"&gt;-n&lt;/span&gt; mynamespace 

NAME                               DESIRED   CURRENT   READY   AGE
helloworld-deployment-7986cbf64d   3         2         2       45s
nginx-deployment-64ff9dbcdf        3         0         0       8m52s

kubectl describe rs helloworld-deployment-7986cbf64d &lt;span class="nt"&gt;-n&lt;/span&gt; mynamespace

Events:
  Type     Reason            Age                From                   Message
  &lt;span class="nt"&gt;----&lt;/span&gt;     &lt;span class="nt"&gt;------&lt;/span&gt;            &lt;span class="nt"&gt;----&lt;/span&gt;               &lt;span class="nt"&gt;----&lt;/span&gt;                   &lt;span class="nt"&gt;-------&lt;/span&gt;
  Normal   SuccessfulCreate  59s                replicaset-controller  Created pod: helloworld-deployment-7986cbf64d-k46hw
  Warning  FailedCreate      59s                replicaset-controller  Error creating: pods &lt;span class="s2"&gt;"helloworld-deployment-7986cbf64d-cxjqx"&lt;/span&gt; is forbidden: exceeded quota: user-compute-quota, requested: limits.memory&lt;span class="o"&gt;=&lt;/span&gt;1Gi,requests.memory&lt;span class="o"&gt;=&lt;/span&gt;512Mi, used: limits.memory&lt;span class="o"&gt;=&lt;/span&gt;2Gi,requests.memory&lt;span class="o"&gt;=&lt;/span&gt;1Gi, limited: limits.memory&lt;span class="o"&gt;=&lt;/span&gt;2Gi,requests.memory&lt;span class="o"&gt;=&lt;/span&gt;1Gi
  Normal   SuccessfulCreate  59s                replicaset-controller  Created pod: helloworld-deployment-7986cbf64d-r68vf
  Warning  FailedCreate      59s                replicaset-controller  Error creating: pods &lt;span class="s2"&gt;"helloworld-deployment-7986cbf64d-sx2vj"&lt;/span&gt; is forbidden: exceeded quota: user-compute-quota, requested: limits.memory&lt;span class="o"&gt;=&lt;/span&gt;1Gi,requests.memory&lt;span class="o"&gt;=&lt;/span&gt;512Mi, used: limits.memory&lt;span class="o"&gt;=&lt;/span&gt;2Gi,requests.memory&lt;span class="o"&gt;=&lt;/span&gt;1Gi, limited: limits.memory&lt;span class="o"&gt;=&lt;/span&gt;2Gi,requests.memory&lt;span class="o"&gt;=&lt;/span&gt;1Gi
  Warning  FailedCreate      59s                replicaset-controller  Error creating: pods &lt;span class="s2"&gt;"helloworld-deployment-7986cbf64d-zx6pq"&lt;/span&gt; is forbidden: exceeded quota: user-compute-quota, requested: limits.memory&lt;span class="o"&gt;=&lt;/span&gt;1Gi,requests.memory&lt;span class="o"&gt;=&lt;/span&gt;512Mi, used: limits.memory&lt;span class="o"&gt;=&lt;/span&gt;2Gi,requests.memory&lt;span class="o"&gt;=&lt;/span&gt;1Gi, limited: limits.memory&lt;span class="o"&gt;=&lt;/span&gt;2Gi,requests.memory&lt;span class="o"&gt;=&lt;/span&gt;1Gi
  Warning  FailedCreate      59s                replicaset-controller  Error creating: pods &lt;span class="s2"&gt;"helloworld-deployment-7986cbf64d-khchm"&lt;/span&gt; is forbidden: exceeded quota: user-compute-quota, requested: limits.memory&lt;span class="o"&gt;=&lt;/span&gt;1Gi,requests.memory&lt;span class="o"&gt;=&lt;/span&gt;512Mi, used: limits.memory&lt;span class="o"&gt;=&lt;/span&gt;2Gi,requests.memory&lt;span class="o"&gt;=&lt;/span&gt;1Gi, limited: limits.memory&lt;span class="o"&gt;=&lt;/span&gt;2Gi,requests.memory&lt;span class="o"&gt;=&lt;/span&gt;1Gi
  Warning  FailedCreate      59s                replicaset-controller  Error creating: pods &lt;span class="s2"&gt;"helloworld-deployment-7986cbf64d-z8j4s"&lt;/span&gt; is forbidden: exceeded quota: user-compute-quota, requested: limits.memory&lt;span class="o"&gt;=&lt;/span&gt;1Gi,requests.memory&lt;span class="o"&gt;=&lt;/span&gt;512Mi, used: limits.memory&lt;span class="o"&gt;=&lt;/span&gt;2Gi,requests.memory&lt;span class="o"&gt;=&lt;/span&gt;1Gi, limited: limits.memory&lt;span class="o"&gt;=&lt;/span&gt;2Gi,requests.memory&lt;span class="o"&gt;=&lt;/span&gt;1Gi
  Warning  FailedCreate      59s                replicaset-controller  Error creating: pods &lt;span class="s2"&gt;"helloworld-deployment-7986cbf64d-7rqj4"&lt;/span&gt; is forbidden: exceeded quota: user-compute-quota, requested: limits.memory&lt;span class="o"&gt;=&lt;/span&gt;1Gi,requests.memory&lt;span class="o"&gt;=&lt;/span&gt;512Mi, used: limits.memory&lt;span class="o"&gt;=&lt;/span&gt;2Gi,requests.memory&lt;span class="o"&gt;=&lt;/span&gt;1Gi, limited: limits.memory&lt;span class="o"&gt;=&lt;/span&gt;2Gi,requests.memory&lt;span class="o"&gt;=&lt;/span&gt;1Gi
  Warning  FailedCreate      59s                replicaset-controller  Error creating: pods &lt;span class="s2"&gt;"helloworld-deployment-7986cbf64d-sb8ml"&lt;/span&gt; is forbidden: exceeded quota: user-compute-quota, requested: limits.memory&lt;span class="o"&gt;=&lt;/span&gt;1Gi,requests.memory&lt;span class="o"&gt;=&lt;/span&gt;512Mi, used: limits.memory&lt;span class="o"&gt;=&lt;/span&gt;2Gi,requests.memory&lt;span class="o"&gt;=&lt;/span&gt;1Gi, limited: limits.memory&lt;span class="o"&gt;=&lt;/span&gt;2Gi,requests.memory&lt;span class="o"&gt;=&lt;/span&gt;1Gi
  Warning  FailedCreate      59s                replicaset-controller  Error creating: pods &lt;span class="s2"&gt;"helloworld-deployment-7986cbf64d-pxsdv"&lt;/span&gt; is forbidden: exceeded quota: user-compute-quota, requested: limits.memory&lt;span class="o"&gt;=&lt;/span&gt;1Gi,requests.memory&lt;span class="o"&gt;=&lt;/span&gt;512Mi, used: limits.memory&lt;span class="o"&gt;=&lt;/span&gt;2Gi,requests.memory&lt;span class="o"&gt;=&lt;/span&gt;1Gi, limited: limits.memory&lt;span class="o"&gt;=&lt;/span&gt;2Gi,requests.memory&lt;span class="o"&gt;=&lt;/span&gt;1Gi
  Warning  FailedCreate      58s                replicaset-controller  Error creating: pods &lt;span class="s2"&gt;"helloworld-deployment-7986cbf64d-jdnfp"&lt;/span&gt; is forbidden: exceeded quota: user-compute-quota, requested: limits.memory&lt;span class="o"&gt;=&lt;/span&gt;1Gi,requests.memory&lt;span class="o"&gt;=&lt;/span&gt;512Mi, used: limits.memory&lt;span class="o"&gt;=&lt;/span&gt;2Gi,requests.memory&lt;span class="o"&gt;=&lt;/span&gt;1Gi, limited: limits.memory&lt;span class="o"&gt;=&lt;/span&gt;2Gi,requests.memory&lt;span class="o"&gt;=&lt;/span&gt;1Gi
  Warning  FailedCreate      39s &lt;span class="o"&gt;(&lt;/span&gt;x8 over 57s&lt;span class="o"&gt;)&lt;/span&gt;  replicaset-controller  &lt;span class="o"&gt;(&lt;/span&gt;combined from similar events&lt;span class="o"&gt;)&lt;/span&gt;: Error creating: pods &lt;span class="s2"&gt;"helloworld-deployment-7986cbf64d-pjms2"&lt;/span&gt; is forbidden: exceeded quota: user-compute-quota, requested: limits.memory&lt;span class="o"&gt;=&lt;/span&gt;1Gi,requests.memory&lt;span class="o"&gt;=&lt;/span&gt;512Mi, used: limits.memory&lt;span class="o"&gt;=&lt;/span&gt;2Gi,requests.memory&lt;span class="o"&gt;=&lt;/span&gt;1Gi, limited: limits.memory&lt;span class="o"&gt;=&lt;/span&gt;2Gi,requests.memory&lt;span class="o"&gt;=&lt;/span&gt;1Gi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;failed to provision 3rd pod as it exceeded quota&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How much quota exhausted:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl describe quota user-compute-quota &lt;span class="nt"&gt;-n&lt;/span&gt; mynamespace 

Name:            user-compute-quota
Namespace:       mynamespace
Resource         Used  Hard
&lt;span class="nt"&gt;--------&lt;/span&gt;         &lt;span class="nt"&gt;----&lt;/span&gt;  &lt;span class="nt"&gt;----&lt;/span&gt;
limits.cpu       800m  2
limits.memory    2Gi   2Gi
requests.cpu     400m  1
requests.memory  1Gi   1Gi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And they consumed resources as specified in resources specs of the helloworld deployment.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a limit ranger object:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apiVersion: v1
kind: LimitRange
metadata:
  name: limits-quota
  namespace: mynamespace
spec:
  limits:
    - default:
        cpu: 200m
        memory: 512Mi
      defaultRequest:
        cpu: 100m
        memory: 256Mi
      &lt;span class="nb"&gt;type&lt;/span&gt;: Container
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create &lt;span class="nt"&gt;-f&lt;/span&gt; limit_range.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Now retry dep_without_quota.yaml
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create &lt;span class="nt"&gt;-f&lt;/span&gt; dep_without_quota.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Verify again dep_without_quota replicas/pods:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get deploy &lt;span class="nt"&gt;-n&lt;/span&gt; mynamespace 

NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   3/3     3            3           13s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All 3 are in ready states&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Finally check the consumption of quota
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl describe quota user-compute-quota &lt;span class="nt"&gt;-n&lt;/span&gt; mynamespace 

Name:            user-compute-quota
Namespace:       mynamespace
Resource         Used  Hard
&lt;span class="nt"&gt;--------&lt;/span&gt;         &lt;span class="nt"&gt;----&lt;/span&gt;  &lt;span class="nt"&gt;----&lt;/span&gt;
limits.cpu       600m    2
limits.memory    1536Mi  2Gi
requests.cpu     300m    1
requests.memory  768Mi   1Gi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All 3 pods got scheduled using default limits specified in limit_range.yaml This is because the deployment ‘nginx-deployment’ does not have resources spec specified hence the pods created out of it use default specs from LimitRange object.&lt;/p&gt;

&lt;p&gt;Folks, if you like my content, would you consider following me on linked in at: &lt;a href="https://www.linkedin.com/in/hitesh-pattanayak-52290b160/"&gt;https://www.linkedin.com/in/hitesh-pattanayak-52290b160/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>k8s</category>
      <category>resourcequota</category>
      <category>deployment</category>
    </item>
    <item>
      <title>Understanding gRPC Concepts, Use Cases &amp; Best Practices</title>
      <dc:creator>Hitesh Pattanayak</dc:creator>
      <pubDate>Sun, 15 Jan 2023 17:03:40 +0000</pubDate>
      <link>https://forem.com/hiteshrepo/understanding-grpc-concepts-use-cases-best-practices-2npk</link>
      <guid>https://forem.com/hiteshrepo/understanding-grpc-concepts-use-cases-best-practices-2npk</guid>
      <description>&lt;p&gt;&lt;a href="https://www.infracloud.io/blogs/understanding-grpc-concepts-best-practices/" rel="noopener noreferrer"&gt;Original blog post&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As we progress with application development, among various things, there is one primary thing we are less worried about i.e. computing power. With the advent of cloud providers, we are less worried about managing data centers. Everything is available within seconds, and that too on-demand. This leads&lt;br&gt;
With the increase in the size of data, we have activities like serializing, deserializing and transportation costs added to it. Though we are not worried about computing resources, the latency becomes an overhead. We need to cut down on transportation. A lot of messaging protocols have been developed in the past to address this. SOAP was bulky, and REST is a trimmed-down version, but we need an even more efficient framework. That’s where Remote Procedure Calls (RPC) comes in.&lt;/p&gt;

&lt;p&gt;In this blog post, we will understand what RPC is and the various implementations of RPC with a focus on gRPC, which is Google's implementation of RPC. We'll also compare REST with RPC and understand various aspects of gRPC, including security, tooling, and much more. So, let's get started!&lt;/p&gt;
&lt;h2&gt;
  
  
  What is RPC?
&lt;/h2&gt;

&lt;p&gt;RPC stands for ‘Remote Procedure Calls’. The definition is in the name itself. Procedure calls simply mean function/method calls; it's the ‘Remote’ word that makes all the difference. What if we can make a function call remotely? &lt;/p&gt;

&lt;p&gt;Simply put, if a function resides on a ‘server’ and in order to be invoked from the ‘client’ side, could we make it as simple as a method/function call? Essentially what an RPC does is it gives the ‘illusion’ to the client that it is invoking a local method, but in reality, it invokes a method in a remote machine that abstracts the network layer tasks. The beauty of this is that the contract is kept very strict and transparent (we will discuss this later in the article).&lt;/p&gt;

&lt;p&gt;Steps involved in an RPC call:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7cf1yt5yrwi5ekc03c2y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7cf1yt5yrwi5ekc03c2y.png" alt="RPC Sequence Flow" width="800" height="484"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is how a typical REST process looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fceou7lcpooap5o2q09t7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fceou7lcpooap5o2q09t7.png" alt="Rest Flow" width="750" height="987"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;RPCs boil down the process to below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flbq0ife51x44n180n3cb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flbq0ife51x44n180n3cb.png" alt="GRPC Flow" width="780" height="681"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is because all the complications associated with making a request are now abstracted from us (we will discuss this in code-generation). All we need to worry about is the data and logic.&lt;/p&gt;
&lt;h2&gt;
  
  
  gRPC - what, why, and how of it
&lt;/h2&gt;

&lt;p&gt;So far, we discussed RPC, which essentially means making function/method calls remotely. Thereby giving us the benefits like ‘strict contract definition’, ‘abstracting transmission and conversion of data’, ‘reducing latency’, etc. Which we will be discussing as we proceed with this post. What we would really like to dive deep into is one of the implementations of RPC. RPC is a concept, and gRPC is a framework based on it.&lt;/p&gt;

&lt;p&gt;There are various implementations of RPCs. They are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;gRPC (Google)&lt;/li&gt;
&lt;li&gt;Thrift (Facebook)&lt;/li&gt;
&lt;li&gt;Finagle (Twitter)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Google’s version of RPC is referred to as gRPC which was introduced in 2015 and has been gaining traction since. It is one of the most chosen communication mechanisms in a microservice architecture.&lt;/p&gt;

&lt;p&gt;gRPC uses &lt;a href="https://developers.google.com/protocol-buffers" rel="noopener noreferrer"&gt;protocol buffers&lt;/a&gt; (it is an open source message format) as the default method of communication between client and server. Also, gRPC uses HTTP/ 2 as the default protocol. &lt;/p&gt;

&lt;p&gt;There are again four types of communication that gRPC supports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://grpc.io/docs/what-is-grpc/core-concepts/#unary-rpc" rel="noopener noreferrer"&gt;Unary&lt;/a&gt; (typical client and server communication)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://grpc.io/docs/what-is-grpc/core-concepts/#client-streaming-rpc" rel="noopener noreferrer"&gt;Client side streaming&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://grpc.io/docs/what-is-grpc/core-concepts/#server-streaming-rpc" rel="noopener noreferrer"&gt;Server side streaming&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://grpc.io/docs/what-is-grpc/core-concepts/#bidirectional-streaming-rpc" rel="noopener noreferrer"&gt;Bidirectional streaming&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Coming on to the message format that is being used widely in gRPC - protocol buffers a.k.a protobufs. A protobuf message looks something like below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight protobuf"&gt;&lt;code&gt;&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;Person&lt;/code&gt; is the message we would like to transfer (as a part of request/response), which has fields &lt;code&gt;name&lt;/code&gt; (string type), &lt;code&gt;id&lt;/code&gt; (string type) and &lt;code&gt;email&lt;/code&gt; (string type). The numbers 1, 2, 3 represent the position of the data (as in &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;id&lt;/code&gt;, and &lt;code&gt;has_ponycopter&lt;/code&gt;) when it is serialized to binary format. &lt;/p&gt;

&lt;p&gt;Once the developer has created the Protocol Buffer file(s) with all messages, we can use a ‘protocol buffer compiler’ (a binary) to compile the written protocol buffer file, which will generate all the utility classes and methods which are needed to work with the message. For example, as shown in the above &lt;code&gt;Person&lt;/code&gt; message, depending on the chosen language, the &lt;a href="https://github.com/infracloudio/grpc-blog/blob/master/proto/example/person.pb.go" rel="noopener noreferrer"&gt;generated code will look like this&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do we define services?
&lt;/h3&gt;

&lt;p&gt;We need to define services that use the above messages to be sent/received.&lt;/p&gt;

&lt;p&gt;After writing the necessary request and response message types, the next step is to write the service itself.&lt;br&gt;
gRPC services are also defined in Protocol Buffers and they use the ‘service’ and ‘rpc’ keywords to define a service.&lt;/p&gt;

&lt;p&gt;Take a look at the content of the below proto file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight protobuf"&gt;&lt;code&gt;&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;HelloRequest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;int32&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;HelloResponse&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;processedMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;service&lt;/span&gt; &lt;span class="n"&gt;HelloService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;rpc&lt;/span&gt; &lt;span class="n"&gt;SayHello&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HelloRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HelloResponse&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;HelloRequest&lt;/code&gt; and &lt;code&gt;HelloResponse&lt;/code&gt; are the messages and &lt;code&gt;HelloService&lt;/code&gt; is exposing one unary RPC called &lt;code&gt;SayHello&lt;/code&gt; which takes &lt;code&gt;HelloRequest&lt;/code&gt; as input and gives &lt;code&gt;HelloResponse&lt;/code&gt; as output.&lt;/p&gt;

&lt;p&gt;As mentioned, &lt;code&gt;HelloService&lt;/code&gt; at the moment contains a single unary RPC. But it could contain more than one RPC. Also, it can contain a variety of RPCs (unary/client-side streaming/server-side streaming/Bidirectional).&lt;/p&gt;

&lt;p&gt;In order to define a streaming RPC, all you have to do is prefix ‘stream’ before the request/response argument, &lt;a href="https://github.com/infracloudio/grpc-blog/tree/master/proto/streaming" rel="noopener noreferrer"&gt;Streaming RPCs proto definitions, and generated code&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the above code-base link:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/infracloudio/grpc-blog/blob/master/proto/streaming/streaming.proto" rel="noopener noreferrer"&gt;streaming.proto&lt;/a&gt;: this file is user defined&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/infracloudio/grpc-blog/blob/master/proto/streaming/streaming.pb.go" rel="noopener noreferrer"&gt;streaming.pb.go&lt;/a&gt; &amp;amp; &lt;a href="https://github.com/infracloudio/grpc-blog/blob/master/proto/streaming/streaming_grpc.pb.go" rel="noopener noreferrer"&gt;streaming_grpc.pb.go&lt;/a&gt;: these files are auto-generated on running &lt;a href="https://github.com/infracloudio/grpc-blog/blob/883e25e207b8e7d3fdf8384b98fb0828a982d5b3/proto/Taskfile.yaml#L18" rel="noopener noreferrer"&gt;proto compiler command&lt;/a&gt; command.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  gRPC vs REST
&lt;/h2&gt;

&lt;p&gt;We did talk about gRPC a fair bit. Also, there was a mention of REST. What we missed was discussing the difference. I mean when we have a well-established, lightweight communication framework in the form of REST, why was there a need to look for another communication framework? Let us understand more about gRPC with respect to REST along with the pros and cons of each of it.&lt;/p&gt;

&lt;p&gt;In order to compare what we require are parameters. So let’s break down the comparison into the below parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Message format: protocol buffers vs JSON&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Serialization and deserialization speed is way better in the case of protocol buffers across all data sizes (small/medium/large). &lt;a href="https://github.com/infracloudio/grpc-blog/blob/master/proto/test.out" rel="noopener noreferrer"&gt;Benchmark-Test-Results&lt;/a&gt;. &lt;/li&gt;
&lt;li&gt;Post serialization JSON is human readable while protobufs (in binary format) are not. Not sure if this is a disadvantage or not because sometimes you would like to see the request details in the Google developers tool or Kafka topics and in the case of protobufs you can't make out anything. &lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Communication protocol: HTTP 1.1 vs HTTP/2&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;REST is based on HTTP 1.1; communication between a REST  client and server would require an established TCP connection which in turn has a 3-way handshake involved. When we get a response from the server upon sending a request from the client, the TCP connection does not exist after that. A new TCP connection needs to be spun up in order to process another request. This establishment of a TCP connection on each and every request adds up to the latency.&lt;/li&gt;
&lt;li&gt;So gRPC which is based on HTTP 2 has encountered this challenge by having a persistent connection. We must remember that persistent connections in HTTP 2 are different from that in web sockets where a TCP connection is hijacked and the data transfer is unmonitored. In a gRPC connection, once a TCP connection is established, it is reused for several requests. All requests from the same client and server pair are multiplexed onto the same TCP connection.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Just worrying about data and logic: Code generation being a first-class citizen&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Code generation features are native to gRPC via its in-built protoc compiler. With REST APIs, it’s necessary to use a third-party tool such as Swagger to auto-generate the code for API calls in various languages.&lt;/li&gt;
&lt;li&gt;In the case of gRPC, it abstracts the process of marshaling/unmarshalling, setting up a connection, and sending/receiving messages; what we all need to worry about is the data that we want to send or receive and the logic.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Transmission speed&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Since the binary format is much lighter than JSON format, the transmission speed in the case of gRPC is 7 to 10 times faster than that of REST.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Feature&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;REST&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;gRPC&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Communication Protocol&lt;/td&gt;
&lt;td&gt;Follows request-response model. It can work with either HTTP version but is typically used with HTTP 1.1&lt;/td&gt;
&lt;td&gt;Follows client-response model and is based on HTTP 2. Some servers have workarounds to make it work with HTTP 1.1 (via rest gateways)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Browser support&lt;/td&gt;
&lt;td&gt;Works everywhere&lt;/td&gt;
&lt;td&gt;Limited support. Need to use &lt;a href="https://github.com/grpc/grpc-web" rel="noopener noreferrer"&gt;gRPC-Web&lt;/a&gt;, which is an extension for the web and is based on HTTP 1.1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Payload data structure&lt;/td&gt;
&lt;td&gt;Mostly uses JSON and XML-based payloads to transmit data&lt;/td&gt;
&lt;td&gt;Uses protocol buffers by default to transmit payloads&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Code generation&lt;/td&gt;
&lt;td&gt;Need to use third-party tools like Swagger to generate client code&lt;/td&gt;
&lt;td&gt;gRPC has native support for code generation for various &lt;a href="https://grpc.io/docs/languages/" rel="noopener noreferrer"&gt;languages&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Request caching&lt;/td&gt;
&lt;td&gt;Easy to cache requests on the client and server sides. Most clients/servers natively support it (for example via cookies)&lt;/td&gt;
&lt;td&gt;Does not support request/response caching by default&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Again for the time being gRPC does not have browser support since most of the UI frameworks still have limited or no support for gRPC. Although gRPC is an automatic choice in most cases when it comes to internal microservices communication, it is not the same for external communication that requires UI integration.&lt;/p&gt;

&lt;p&gt;Now that we have done a comparison of both the frameworks: gRPC and REST. Which one to use and when?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In a microservice architecture with multiple lightweight microservices, where the efficiency of data transmission is paramount, gRPC would be an ideal choice.&lt;/li&gt;
&lt;li&gt;If code generation with multiple language support is a requirement, gRPC should be the go-to framework.&lt;/li&gt;
&lt;li&gt;With gRPC’s streaming capabilities, real-time apps like trading or OTT would benefit from it rather than polling using REST.&lt;/li&gt;
&lt;li&gt;If bandwidth is a constraint, gRPC would provide much lower latency and throughput.&lt;/li&gt;
&lt;li&gt;If quicker development and high-speed iteration is a requirement, REST should be a go-to option.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  gRPC Concepts
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Load balancing
&lt;/h3&gt;

&lt;p&gt;Even though the persistent connection solves the latency issue, it props up another challenge in the form of load balancing. Since gRPC (or HTTP2) creates persistent connections, even with the presence of a load balancer, the client forms a persistent connection with the server which is behind the load balancer. This is analogous to a sticky session.&lt;/p&gt;

&lt;p&gt;We can understand the challenge via a demo &amp;amp; the code and deployment files for the same are present &lt;a href="https://github.com/infracloudio/grpc-blog/tree/master/grpc-loadbalancing" rel="noopener noreferrer"&gt;in this repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;From the above demo code base, we can find out that the onus of load balancing falls on the client. This leads to the fact that the advantage of gRPC i.e. persistent connection does not exist with this change. But gRPC can still be used for its other benefits.&lt;/p&gt;

&lt;p&gt;Read more about &lt;a href="https://grpc.io/blog/grpc-load-balancing/" rel="noopener noreferrer"&gt;load balancing in gRPC&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the above demo code-base, only a ‘round-robin’ load balancing strategy is used/showcased. But gRPC does support another client-based load balancing strategy OOB called ‘pick-first’.&lt;/p&gt;

&lt;p&gt;Furthermore, &lt;a href="https://learn.microsoft.com/en-us/aspnet/core/grpc/loadbalancing?view=aspnetcore-6.0" rel="noopener noreferrer"&gt;custom client-side&lt;/a&gt; load balancing is also supported.&lt;/p&gt;

&lt;h3&gt;
  
  
  Clean contract
&lt;/h3&gt;

&lt;p&gt;In REST, the contract between the client and server is documented but not strict. If we go back even further to SOAP, contracts were exposed via wsdl files. In REST we expose contracts via Swagger and other provisions. But the strictness is lacking, we cannot for sure know if the contract has changed on the server's side while the client code is being developed.&lt;/p&gt;

&lt;p&gt;With gRPC, the contract is shared with both the client and server either directly via proto files or generated stub from proto files. This is like making a function call but remotely. And since we are making a function call we exactly know what we need to send and what we are expecting as a response. The complexity of making connections with the client, taking care of security, serialization-deserialization, etc are abstracted. All we care about is the data.&lt;/p&gt;

&lt;p&gt;Lets consider the code base for &lt;a href="https://github.com/infracloudio/grpc-blog/tree/master/greet_app" rel="noopener noreferrer"&gt;Greet App&lt;/a&gt;.   &lt;/p&gt;

&lt;p&gt;The client uses the &lt;a href="https://github.com/infracloudio/grpc-blog/blob/883e25e207b8e7d3fdf8384b98fb0828a982d5b3/greet_app/internal/app/client/client.go#L6" rel="noopener noreferrer"&gt;stub&lt;/a&gt; (generated code from proto file) to create a client object and invoke remote function call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="n"&gt;greetpb&lt;/span&gt; &lt;span class="s"&gt;"github.com/infracloudio/grpc-blog/greet_app/internal/pkg/proto"&lt;/span&gt;
&lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;grpc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;lt;server-address&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"could not connect: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;greetpb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewGreetServiceClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Background&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"error while calling greet rpc : %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Similarly, the server too uses the same &lt;a href="https://github.com/infracloudio/grpc-blog/blob/883e25e207b8e7d3fdf8384b98fb0828a982d5b3/greet_app/internal/app/server/server.go#L6" rel="noopener noreferrer"&gt;stub&lt;/a&gt; (generated code from proto file) to receive request object and create response object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="n"&gt;greetpb&lt;/span&gt; &lt;span class="s"&gt;"github.com/infracloudio/grpc-blog/greet_app/internal/pkg/proto"&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Greet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;greetpb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GreetingRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;greetpb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GreetingResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="c"&gt;// do something with 'req'&lt;/span&gt;

   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;greetpb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GreetingResponse&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both of them are using the same stub generated from the proto file &lt;a href="https://github.com/infracloudio/grpc-blog/blob/master/greet_app/internal/pkg/proto/greet.proto" rel="noopener noreferrer"&gt;greet.proto&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And the stub was generated using ‘proto’ compiler and the command to generate is &lt;a href="https://github.com/infracloudio/grpc-blog/blob/883e25e207b8e7d3fdf8384b98fb0828a982d5b3/greet_app/Taskfile.yaml#L10" rel="noopener noreferrer"&gt;this&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;protoc &lt;span class="nt"&gt;--go_out&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--go_opt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;paths&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;source_relative &lt;span class="nt"&gt;--go-grpc_out&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--go-grpc_opt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;paths&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;source_relative internal/pkg/proto/&lt;span class="k"&gt;*&lt;/span&gt;.proto
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Security
&lt;/h3&gt;

&lt;p&gt;gRPC authentication and authorization works on two levels:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Call-level authentication/authorization is usually handled through tokens that are applied in metadata when the call is made. &lt;a href="https://github.com/infracloudio/grpc-blog/compare/master...secure_token" rel="noopener noreferrer"&gt;Token based authentication example&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Channel-level authentication uses a client certificate that's applied at the connection level. It can also include call-level authentication/authorization credentials to be applied to every call on the channel automatically. &lt;a href="https://github.com/infracloudio/grpc-blog/compare/secure_grpc" rel="noopener noreferrer"&gt;Certificate based authentication example&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Either or both of these mechanisms can be used to help secure services.&lt;/p&gt;

&lt;h3&gt;
  
  
  Middlewares
&lt;/h3&gt;

&lt;p&gt;In REST, we use middlewares for various purposes like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rate limiting&lt;/li&gt;
&lt;li&gt;Pre/Post request/response validation&lt;/li&gt;
&lt;li&gt;Address security threats&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can achieve the same with gRPC as well. The verbiage is different in gRPC, they are referred as ‘interceptors’ but they do similar activities.&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://github.com/infracloudio/grpc-blog/tree/middlewares/greet_app/internal/app" rel="noopener noreferrer"&gt;the middlewares branch&lt;/a&gt; of the &lt;code&gt;greet_app&lt;/code&gt; code base, we have integrated logger and Prometheus interceptors. &lt;/p&gt;

&lt;p&gt;Look how the interceptors are configured to use Prometheus and logging packages in &lt;a href="https://github.com/infracloudio/grpc-blog/blob/7700323e1e488eb8777a06ca762e4d29602d2424/greet_app/internal/pkg/middleware/middleware.go#L29" rel="noopener noreferrer"&gt;middleware.go&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;    &lt;span class="c"&gt;// add middleware&lt;/span&gt;
    &lt;span class="n"&gt;AddLogging&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;zap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;uInterceptors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;sInterceptors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;AddPrometheus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;uInterceptors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;sInterceptors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But we can integrate other packages to interceptors for purposes like preventing panic and recovery (to handle exceptions), tracing, even authentication, etc.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/grpc-ecosystem/go-grpc-middleware" rel="noopener noreferrer"&gt;Supported middlewares by gRPC framework&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Packaging, versioning and code practices of proto files
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Packaging
&lt;/h4&gt;

&lt;p&gt;Let's follow &lt;a href="https://github.com/infracloudio/grpc-blog/blob/packaging/proto/packaging/processor.proto" rel="noopener noreferrer"&gt;the packaging branch&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;First start with &lt;code&gt;Taskfile.yaml&lt;/code&gt;, the task &lt;code&gt;gen-pkg&lt;/code&gt; says &lt;code&gt;protoc --proto_path=packaging packaging/*.proto --go_out=packaging&lt;/code&gt;. This means &lt;code&gt;protoc&lt;/code&gt; (the compiler) will convert all files in &lt;code&gt;packaging/*.proto&lt;/code&gt; into its equivalent Go files as denoted by flag &lt;code&gt;--go_out=packaging&lt;/code&gt; in the &lt;code&gt;packaging&lt;/code&gt; directory itself.&lt;/p&gt;

&lt;p&gt;Secondly in the ‘processor.proto’ file, 2 messages have been defined namely ‘CPU’ and ‘GPU’. While CPU is a simple message with 3 fields of in-built data types, GPU message on the other hand has an additional custom data type called ‘Memory’ along with in-built data types same as CPU message. ‘Memory’ is a separate message and is defined in a different file altogether.&lt;br&gt;
So how do you use the ‘Memory’ message in the ‘processor.proto’ file? By using &lt;a href="https://github.com/infracloudio/grpc-blog/blob/436d84358868f463ea7929eb14120eb80801fde1/proto/packaging/processor.proto#L6" rel="noopener noreferrer"&gt;import&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight protobuf"&gt;&lt;code&gt;&lt;span class="na"&gt;syntax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"proto3"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;laptop_pkg&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;option&lt;/span&gt; &lt;span class="na"&gt;go_package&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"/pb"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"memory.proto"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;CPU&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;brand&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;uint32&lt;/span&gt; &lt;span class="na"&gt;cores&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;GPU&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;brand&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;uint32&lt;/span&gt; &lt;span class="na"&gt;cores&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;Memory&lt;/span&gt; &lt;span class="na"&gt;memory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight protobuf"&gt;&lt;code&gt;&lt;span class="na"&gt;syntax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"proto3"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;laptop_pkg&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;option&lt;/span&gt; &lt;span class="na"&gt;go_package&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"/pb"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;Memory&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;Unit&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;UNKNOWN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="na"&gt;BIT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="na"&gt;BYTE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="na"&gt;KILOBYTE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="na"&gt;MEGABYTE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="na"&gt;GIGABYTE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="kt"&gt;uint64&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;Unit&lt;/span&gt; &lt;span class="na"&gt;unit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even if you try to generate a proto file by running task &lt;code&gt;gen-pkg&lt;/code&gt; after mentioning import, it will throw an error. As by default &lt;code&gt;protoc&lt;/code&gt; assumes both files &lt;code&gt;memory.proto&lt;/code&gt; and &lt;code&gt;processor.proto&lt;/code&gt; to be in different packages. So you need to mention the same package name in both files.&lt;br&gt;
The optional &lt;code&gt;go_package&lt;/code&gt; indicates the compiler to create a package name as &lt;code&gt;pb&lt;/code&gt; for Go files. If any other language-d proto files were to be created, the package name would be &lt;code&gt;laptop_pkg&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Versioning
&lt;/h4&gt;

&lt;p&gt;There can be two kinds of changes in gRPC breaking and non-breaking changes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Non-breaking changes include adding a new service, adding a new method to a service, adding a field to request or response proto, and adding a value to enum&lt;/li&gt;
&lt;li&gt;Breaking changes like renaming a field, changing field data type, field number, renaming or removing a package, service or methods require versioning of services&lt;/li&gt;
&lt;li&gt;In order to distinguish between same name messages or services across proto files, &lt;a href="https://developers.google.com/protocol-buffers/docs/proto#packages" rel="noopener noreferrer"&gt;optional packaging&lt;/a&gt; can be implemented.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Code practices
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Request message must suffix with request &lt;code&gt;CreateUserRequest&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Response message must suffix with request &lt;code&gt;CreateUserResponse&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;In case the response message is empty, you can either use an empty object &lt;code&gt;CreateUserResponse&lt;/code&gt; or use the &lt;code&gt;google.protobuf.Empty&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Package name must make sense and must be versioned, for example: package &lt;code&gt;com.ic.internal_api.service1.v1&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Tooling
&lt;/h3&gt;

&lt;p&gt;gRPC ecosystem supports an array of tools to make life easier in non-developmental tasks like documentation, rest gateway for a gRPC server, integrating custom validators, linting, etc. Here are some tools that can help us achieve the same:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/grpc-ecosystem/grpc-gateway" rel="noopener noreferrer"&gt;protoc-gen-grpc-gateway&lt;/a&gt; — plugin for creating a gRPC REST API gateway. It allows gRPC endpoints as REST API endpoints and performs the translation from JSON to proto. Basically, you define a gRPC service with some custom annotations and it makes those gRPC methods accessible via REST using JSON requests.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/grpc-ecosystem/grpc-gateway" rel="noopener noreferrer"&gt;protoc-gen-swagger&lt;/a&gt; — a companion plugin for grpc-gateway. It is able to generate swagger.json based on the custom annotations required for gRPC gateway. You can then import that file into your REST client of choice (such as &lt;a href="https://www.postman.com/" rel="noopener noreferrer"&gt;Postman&lt;/a&gt;) and perform REST API calls to the methods you exposed.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/grpc/grpc-web" rel="noopener noreferrer"&gt;protoc-gen-grpc-web&lt;/a&gt; — a plugin that allows our front end to communicate with the backend using gRPC calls. A separate blog post on this coming up in the future.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/mwitkow/go-proto-validators" rel="noopener noreferrer"&gt;protoc-gen-go-validators&lt;/a&gt; — a plugin that allows to define validation rules for proto message fields. It generates a &lt;code&gt;Validate() error&lt;/code&gt; method for proto messages you can call in Go to validate if the message matches your predefined expectations.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/yoheimuta/protolint" rel="noopener noreferrer"&gt;protolint&lt;/a&gt; - a plugin to add lint rules to proto files.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Testing using Postman
&lt;/h2&gt;

&lt;p&gt;Unlike testing REST APIs with Postman or any equivalent tools like Insomnia, it is not quite comfortable to test gRPC services.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; gRPC services can also be tested from CLI using tools like &lt;a href="https://github.com/ktr0731/evans" rel="noopener noreferrer"&gt;evans-cli&lt;/a&gt;. But for that reflection needs (if not enabled the path to the proto file is &lt;a href="https://github.com/infracloudio/grpc-blog/blob/ed390485e12ce6b63fd9fd53f867cf6e818a5407/greet_app/Taskfile.yaml#L82" rel="noopener noreferrer"&gt;required&lt;/a&gt;) to be enabled in gRPC servers. This &lt;a href="https://github.com/infracloudio/grpc-blog/compare/evans" rel="noopener noreferrer"&gt;compare link&lt;/a&gt; shows the way to enable reflection and how to enter into evans-cli repl mode. Post entering repl mode of evans-cli, gRPC services can be tested from CLI itself and the process is described in &lt;a href="https://github.com/ktr0731/evans" rel="noopener noreferrer"&gt;evans-cli GitHub page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Postman has a &lt;a href="https://blog.postman.com/postman-now-supports-grpc/" rel="noopener noreferrer"&gt;beta version&lt;/a&gt; of testing gRPC services.&lt;/p&gt;

&lt;p&gt;Here are the steps of how you can do it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open Postman, goto ‘APIs’ in the left sidebar and click on ‘+’ sign to create new api. In the popup window, enter ‘Name’, ‘Version’, and ‘Schema Details’ and click on create [unless you need to import from some sources like GitHub, Bitbucket].&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv1fivej52t94m1i8cnww.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv1fivej52t94m1i8cnww.png" alt="Create new API" width="800" height="489"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Once Your API gets created then go to definition and enter your proto contract.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhte5kxleam6imok9yk9k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhte5kxleam6imok9yk9k.png" alt="Enter proto contract" width="800" height="236"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Remember importing does not work here, so it would be better to keep all dependent protos at one place.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The above steps will help to retain contracts for future use.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Then click on ‘New’ and select ‘gRPC request', enter the URI and choose the proto from the list of saved ‘APIs’ and finally enter your request message and hit ‘Invoke’&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5g5ujonnug1f8kjv4o89.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5g5ujonnug1f8kjv4o89.png" alt="Create gRPC request" width="800" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the above steps we figured out the process to test our gRPC APIs via Postman. The process to test gRPC endpoints is different from that of REST endpoints using Postman. One thing to remember is that while creating and saving proto contract as in 5, all proto message and service definitions need to be in the same place. As there is no provision to access proto messages across versions in Postman.&lt;/p&gt;

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

&lt;p&gt;In this post, we developed an idea about RPC, drew parallels with REST as well as discussed their differences, then we went on to discuss an implementation of RPC i.e. gRPC developed by Google. &lt;/p&gt;

&lt;p&gt;gRPC as a framework can be crucial, especially for microservice-based architecture for internal communication. It can be used for external communication as well but will require a REST gateway. gRPC is a must for streaming and real-time apps. &lt;/p&gt;

&lt;p&gt;The way Go is proving itself as a server-side scripting language, gRPC is proving itself as a de-facto communication framework.&lt;/p&gt;

&lt;p&gt;That's it folks! Feel free to reach out to &lt;a href="https://www.linkedin.com/in/hitesh-pattanayak-52290b160/" rel="noopener noreferrer"&gt;Hitesh&lt;/a&gt;/&lt;a href="https://www.linkedin.com/in/pranoy-kundu-74b179167" rel="noopener noreferrer"&gt;Pranoy&lt;/a&gt; for any feedback and thoughts on this topic.&lt;/p&gt;

&lt;p&gt;Looking for help with building your DevOps strategy or want to outsource DevOps to the experts? Learn why so many startups &amp;amp; enterprises consider us as one of the &lt;a href="https://www.infracloud.io/devops-consulting-services/" rel="noopener noreferrer"&gt;best DevOps consulting &amp;amp; services companies&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Further reads&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://grpc.io/docs/" rel="noopener noreferrer"&gt;gRPC official documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.google.com/protocol-buffers/docs/gotutorial" rel="noopener noreferrer"&gt;Protobuff golang documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/grpc-ecosystem" rel="noopener noreferrer"&gt;gRPC ecosystem&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.baeldung.com/rest-vs-grpc" rel="noopener noreferrer"&gt;REST vs gRPC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.ibm.com/docs/en/aix/7.1?topic=concepts-remote-procedure-call" rel="noopener noreferrer"&gt;RPC concepts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>career</category>
      <category>java</category>
      <category>community</category>
      <category>welcome</category>
    </item>
  </channel>
</rss>
