{"componentChunkName":"component---src-templates-blog-list-template-js","path":"/engineering/34","result":{"data":{"allMarkdownRemark":{"edges":[{"node":{"excerpt":"Cloud Cost Optimization is the method of reducing the total cloud spending by finding mismanaged capital and scale-up of Right Sizing…","fields":{"slug":"/engineering/cloud-cost-optimization/"},"html":"<p>Cloud Cost Optimization is the method of reducing the total cloud spending by finding mismanaged capital and scale-up of Right Sizing computing services. CCO only charge for the services you use, the cloud gives companies infinite scalability and lower IT costs.</p>\n<ol>\n<li>As per Gartner <a href=\"https://www.gartner.com/smarterwithgartner/4-trends-impacting-cloud-adoption-in-2020/\">report</a> cloud cost optimization is the first factor that will impact cloud adoption in 2020. Also Gartner predicts <em>\"75% of midsize and large organizations will have adopted a multi-cloud and/or hybrid IT strategy in 2021.\"</em></li>\n<li>As <a href=\"https://research.g2.com/insights/2020-trends/it-cloud-computing-trends-2020\">per G2</a> <em>\"General necessity for a broad hardware stack will fade away as solutions become increasingly cloud-driven, virtualized, and software-defined. “Appliance-attached” solutions will decline in favor of dedicated, pure software solutions performing similar functions.</em></li>\n</ol>\n<h2 id=\"infrastructure-journey\" style=\"position:relative;\"><a href=\"#infrastructure-journey\" aria-label=\"infrastructure journey permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Infrastructure Journey</h2>\n<h3 id=\"on-premise\" style=\"position:relative;\"><a href=\"#on-premise\" aria-label=\"on premise permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>On-Premise</h3>\n<p>On-Premise Infrastructure was only option around 10 years ago but managing On-premise Infrastructure include the extra cost with other challenges, Challenges are Network, Hardware, Cooling, Power, Space also needed technical staff for taking care all infrastructure</p>\n<h3 id=\"colocation\" style=\"position:relative;\"><a href=\"#colocation\" aria-label=\"colocation permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Colocation</h3>\n<p>The Colocation is when a business places its own server in a third-party data center and uses its infrastructure services. Colocation takes responsibility for Network, Hardware, Cooling, Space also business not need to worry about technical man force for managing servers</p>\n<p>Still business have more challenges OS software, Application security, Data storage   </p>\n<h3 id=\"cloud\" style=\"position:relative;\"><a href=\"#cloud\" aria-label=\"cloud permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Cloud</h3>\n<p>The Cloud service provider is providing solutions for all the challenges. The cloud service provider takes total responsibility for hardware, network, space, power, maintaining, and security also they are managing all technical workforce for the whole infrastructure </p>\n<p>  <span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 44.30769230769231%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAIAAAC9o5sfAAAACXBIWXMAABibAAAYmwFJdYOUAAABsklEQVQoz3VRW0/bMBTO79zEL4BRXsbTkAaISWjSEBqMgoQAFdSXoV2A0hSqce0tlAYSSlLSpWqD1pA6hSZ1brUzux2T9rDPn46Pj8/nYx8z4b/we57eaRAatqZbjYeOhhAK/wMGPQNjmtR8rK8L49FCZOHkVbQ4uilOuK5L4jQBBSH2e4GLsR/igIpt24YQdruw1pTVpnTT4FJS7Lu49PX6U6K8ypY3pDp/pwlGGwS2gtrpVo2FeiqEJSr2PI9MpOrG5ZvZo6FoYSxZXlvKjX3MDn/m57aFD9OJF+8OX0oGR+vjHrFd28KIOozv++RC0HZ59Sxb2S8oB6LK5SpsppIoVU+v1PO8cpBXdsCvlHV/AerZ4JGDlo7pkzHjB2Sg/M/k4V3sRzXO14/Pa1/SSiyjfrvSTtJVGhQap8fy/C4/mRLfG3rJ6T7hvpqKkY9ZeX0xN7LMRfaklbg4tZAb3rp+m5RXl4sRQlZe2xSmV4qv47cz94bmOt6guwzpFuknAMBsm6YJTLMNTOpTS9fgjwNafdPqdJ4sy8L90lTsDABdSqdPciB1noPQcZ2/uxSDf/4NQFnX10FOuqYAAAAASUVORK5CYII='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"infra 1\"\n        title=\"infra 1\"\n        src=\"/static/64703cac970eff2098f5a2c2b2caf53d/e5715/infra1.png\"\n        srcset=\"/static/64703cac970eff2098f5a2c2b2caf53d/a6d36/infra1.png 650w,\n/static/64703cac970eff2098f5a2c2b2caf53d/e5715/infra1.png 768w,\n/static/64703cac970eff2098f5a2c2b2caf53d/1ff84/infra1.png 1040w\"\n        sizes=\"(max-width: 768px) 100vw, 768px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></p>\n<h2 id=\"how-to-reduce-cloud-cost\" style=\"position:relative;\"><a href=\"#how-to-reduce-cloud-cost\" aria-label=\"how to reduce cloud cost permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>How to Reduce Cloud Cost</h2>\n<p>Reducing Cloud cost is not a one time task. it is a recurring process. We need to identify underutilized resources, Right size machine, reserving capacity for higher discounts also need to optimization Application for reducing hardware cost. Let's start </p>\n<h3 id=\"choose-the-right-cloud-provider\" style=\"position:relative;\"><a href=\"#choose-the-right-cloud-provider\" aria-label=\"choose the right cloud provider permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Choose the Right Cloud Provider</h3>\n<p>Cloud infrastructure is increasing day by day. Choosing the right cloud provider is the most important decision for long term success. The big three cloud providers are  Amazon Web Services (AWS), Microsoft Azure, and Google Cloud Platform (GCP). These three cloud providers are providing mostly services so they might be confused about choosing the right cloud provider. We can easily evaluate the right cloud provider from the following steps</p>\n<ul>\n<li>Compliance</li>\n<li>Security </li>\n<li>Downtime</li>\n<li>Support</li>\n<li>Pricing structure</li>\n<li>Location wise availability </li>\n</ul>\n<h3 id=\"discounted-instances\" style=\"position:relative;\"><a href=\"#discounted-instances\" aria-label=\"discounted instances permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Discounted Instances</h3>\n<p>All Big Cloud Providers are providing discounted Instances or spot instances. Spot instances are unused instances. Cloud Providers offered up to 90% discount on these instances compared to on-demand or reserved instances. The majority of organizations have some workloads that are not critical, We can reduce the cost for not critical workload by using spot instances. AWS, Azure, and Google (GCP) all provide the option to use Spot Instances.</p>\n<ul>\n<li>AWS Spot Instances </li>\n<li>Azure Low Priority VMS</li>\n<li>GCP Preemptible VMS</li>\n</ul>\n<h3 id=\"identify-instance-right-size\" style=\"position:relative;\"><a href=\"#identify-instance-right-size\" aria-label=\"identify instance right size permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Identify Instance Right Size</h3>\n<p>Identify the right size for the Instance, not an easy task. We need to configure multiple matrices in our cloud service provider. Key metrics to look for are CPU and memory usage. Identify instances with a maximum CPU usage and memory usage of the month.</p>\n<h2 id=\"how-to-check-metrics\" style=\"position:relative;\"><a href=\"#how-to-check-metrics\" aria-label=\"how to check metrics permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>How to Check Metrics</h2>\n<p>Generally, people make mistakes during checking metrics. Most of the people prefer averages in monitoring but averages mislead the measurement. Let understand this by example </p>\n<p>You are running an online technology tutorial site. Suppose 1million active users on your website in normal days. Now you are hosting weekly technology webinars in your platform. During webinars time your platform traffic should increase. At that time CPU usages and memory usages should be high compared to the rest of the time. Now suppose you have checked the 24 hours average CPU usages and memory usages. It was around 40% and you have decided this is underutilized and scale down the lower size instance. It can impact you 5% - 10% traffic Let’s look at a real-world example. This chart shows the overall CPU usages </p>\n<p>  <span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 25.23076923076923%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAFCAYAAABFA8wzAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAjUlEQVQY032PWQpDIQxF3f/uuoN+FTq9ah3iEL1Vn1JaeAYOIebmgIKIUEpZ0upox8w/CO/9UsQ5I3JeSlt05kWzHpW0AZoiQjrO/Jdo5phyP5rEinYBp/OjI41H4rGPDB9Tz8y8H2+p/kTcNoXL9d4FT6WhDGFTpkqozq27MTtIPTDf/npbKLvfUEj4ALRNiMJUPswSAAAAAElFTkSuQmCC'); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"image 1\"\n        title=\"image 1\"\n        src=\"/static/d94c819d0bac9ae9587065340e2696ae/e5715/image1.png\"\n        srcset=\"/static/d94c819d0bac9ae9587065340e2696ae/a6d36/image1.png 650w,\n/static/d94c819d0bac9ae9587065340e2696ae/e5715/image1.png 768w,\n/static/d94c819d0bac9ae9587065340e2696ae/1df5b/image1.png 1999w\"\n        sizes=\"(max-width: 768px) 100vw, 768px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></p>\n<p>First Image showing Average CPU utilization. You can see Maximum CPU was 18.6 %</p>\n<p>Now, let’s check the CPU 99th percentile:\n<span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 25.538461538461537%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAFCAYAAABFA8wzAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAjklEQVQY042OSw7DIAwFuf/teoOuKvWXhkKCsU1egYCqLoJqaWQZP48wRIRt24aUOtqp6g+GmYciTQmsaSgt0Z43IoKjmpcIFxhRFP+WSdlcflCOOpxxa8Tp/KjMniDa9qwglprpeWpvkj3mNllcrvcqeFoH6wMm67Mk5Ln0tc0rZtfw3/56L7DLfhOi4AO9uojIjcQZggAAAABJRU5ErkJggg=='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"image 2\"\n        title=\"image 2\"\n        src=\"/static/fd4ef501e6650dd11aac920e390596b8/e5715/image2.png\"\n        srcset=\"/static/fd4ef501e6650dd11aac920e390596b8/a6d36/image2.png 650w,\n/static/fd4ef501e6650dd11aac920e390596b8/e5715/image2.png 768w,\n/static/fd4ef501e6650dd11aac920e390596b8/1df5b/image2.png 1999w\"\n        sizes=\"(max-width: 768px) 100vw, 768px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></p>\n<p>As expected, the 99th percentile is higher than the average. 99th percentile is around 93% </p>\n<p>The conclusion is We need to always check the 99th percentile. The average can mislead and it can impact your users.</p>\n<h3 id=\"creating-underutilization-alarm\" style=\"position:relative;\"><a href=\"#creating-underutilization-alarm\" aria-label=\"creating underutilization alarm permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Creating Underutilization Alarm</h3>\n<p>We can create different types of resources and applications utilization monitoring matrix and based on the data we can configure multiple alarms. You can configure notification or alarms on email, SMS from the Cloud provider dashboard. you can also configure alarms that automatically stop or terminate EC2 instances or VM when instance unused or underutilized according to the configured threshold. During the development or some POC as a developer or devops person we have to create some instances or resources but sometimes we forgot to terminate the instances or resources. You can minimize the this extra cost by creating a group of alarms that sends an email notification to developers whose instances have been underutilized or ideal for some hours, then terminates an instance. It will save the overall infra cost. different cloud providers provide different ways for creating these type alarms</p>\n<ul>\n<li><a href=\"https://aws.amazon.com/cloudwatch/features/\">Amazone (Aws)</a></li>\n<li><a href=\"https://azure.microsoft.com/en-in/blog/announcing-azure-advisor-azure-monitor-and-resource-health/\">Azure</a> </li>\n<li><a href=\"https://cloud.google.com/compute/docs/instances/viewing-and-applying-idle-vm-recommendations\">Google Cloud</a></li>\n</ul>\n<h3 id=\"creating-time-based--actions\" style=\"position:relative;\"><a href=\"#creating-time-based--actions\" aria-label=\"creating time based  actions permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Creating time based  actions</h3>\n<p>You can save around 75% cost for your Non - Production Development, Staging, and QA environment. Non - Production environment generally needed during working days. You can turn off these servers during off-hours. Cost-saving depends on the infrastructure size, it can be hundred, thousands of dollars</p>\n<p>You can create automation scripts for infrastructure deployment. Schedule the script in your cloud provider         </p>\n<h3 id=\"in-memory-cache-storage\" style=\"position:relative;\"><a href=\"#in-memory-cache-storage\" aria-label=\"in memory cache storage permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>In-memory cache Storage</h3>\n<p>Application in-memory cache reduces the cost of transferring data in the network and overall application performance because reduce the traffic between the database servers or any other external application reduce the network level cost in the cloud also caching improves  the efficiency and accessibility of data that used repeatedly or frequently accessed. Suppose your application is fetching user configuration or settings in every request from the database server. You can keep this type of configuration, which is not changing frequently in the in-memory cache. it will save a lot network-level cost </p>\n<h3 id=\"data-transfer-cost-optimization\" style=\"position:relative;\"><a href=\"#data-transfer-cost-optimization\" aria-label=\"data transfer cost optimization permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Data Transfer Cost Optimization</h3>\n<p>Data Transfer cost mostly hidden or Some time we don't take care of it. Generally, data transfer is free in the same region between different services Storage, Compute service, etc.\nIf you do a lot of cross-region transfer, it will increase your network data transfer cost also if you will deploy multiple services in the same region it will improve application performance </p>\n<h3 id=\"cost-visibility\" style=\"position:relative;\"><a href=\"#cost-visibility\" aria-label=\"cost visibility permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Cost visibility</h3>\n<p>This includes knowing what you spend in detail, how specific services are billed, and the ability to display how (or why) you spent a specific amount Here, keep in mind key capabilities such as the ability to create shared accountability, hold frequent cost reviews, analyze trends, and visualize the impact of your actions on a near-real-time basis. You can also use cost controls like budget alerts and quotas to keep your costs in check over time. </p>\n<h3 id=\"consider-a-multi-cloud-architecture\" style=\"position:relative;\"><a href=\"#consider-a-multi-cloud-architecture\" aria-label=\"consider a multi cloud architecture permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Consider a Multi-Cloud Architecture</h3>\n<p>Enterprises or Mid Level companies are adopting multi-cloud infrastructure. Consider this recent prediction from IDC: “By 2020, over 90% of enterprises will use multiple cloud services and platforms.” Or this one from 451 Research: “The future of IT is multi-cloud and hybrid with 69% of respondents planning to have some type of multi-cloud environment by 2019.”  </p>\n<h3 id=\"benefits-of-multi-cloud-architecture\" style=\"position:relative;\"><a href=\"#benefits-of-multi-cloud-architecture\" aria-label=\"benefits of multi cloud architecture permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Benefits of multi-cloud Architecture</h3>\n<ul>\n<li>Low latency</li>\n<li>Competitive Pricing</li>\n<li>more compliance options</li>\n<li>Enhanced Security </li>\n</ul>\n<h2 id=\"conclusion\" style=\"position:relative;\"><a href=\"#conclusion\" aria-label=\"conclusion permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Conclusion</h2>\n<p>Organizations need to develop a cost optimization culture and awareness. Cost optimization is an ongoing activity in the organization. Need to decide someone responsible for the cost optimization it can be an Engineering team or DevOps team. Most cloud providers provide billing alarm’s they can alert you in case of cost increment also we can configure budget in the Cloud provider dashboard.</p>\n<style class=\"grvsc-styles\">\n  .grvsc-container {\n    overflow: auto;\n    -webkit-overflow-scrolling: touch;\n    padding-top: 1rem;\n    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));\n    padding-bottom: 1rem;\n    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));\n    border-radius: 8px;\n    border-radius: var(--grvsc-border-radius, 8px);\n    font-feature-settings: normal;\n  }\n  \n  .grvsc-code {\n    display: inline-block;\n    min-width: 100%;\n  }\n  \n  .grvsc-line {\n    display: inline-block;\n    box-sizing: border-box;\n    width: 100%;\n    padding-left: 1.5rem;\n    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));\n    padding-right: 1.5rem;\n    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));\n  }\n  \n  .grvsc-line-highlighted {\n    background-color: var(--grvsc-line-highlighted-background-color, transparent);\n    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, transparent);\n  }\n  \n</style>","frontmatter":{"date":"July 09, 2020","updated_date":null,"description":"Optimization of cloud costs lowers spending by recognizing mismanaged capital, reserving higher discount space, and proper sizing.","title":"Cloud Cost Optimization in 2021","tags":["Cloud","Optmization"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1.408450704225352,"src":"/static/2300b46e98d3db0ddac0decdc33cf57e/ee604/cloud.png","srcSet":"/static/2300b46e98d3db0ddac0decdc33cf57e/69585/cloud.png 200w,\n/static/2300b46e98d3db0ddac0decdc33cf57e/497c6/cloud.png 400w,\n/static/2300b46e98d3db0ddac0decdc33cf57e/ee604/cloud.png 800w,\n/static/2300b46e98d3db0ddac0decdc33cf57e/f3583/cloud.png 1200w,\n/static/2300b46e98d3db0ddac0decdc33cf57e/5707d/cloud.png 1600w,\n/static/2300b46e98d3db0ddac0decdc33cf57e/c1526/cloud.png 1747w","sizes":"(max-width: 800px) 100vw, 800px"}}},"author":{"id":"Vijay Singh Shekhawat","github":"code-vj","avatar":null}}}},{"node":{"excerpt":"This post will cover a demo working setup of a service mesh architecture using Envoy using a demo application. In this service mesh…","fields":{"slug":"/engineering/service-mesh-with-envoy/"},"html":"<p>This post will cover a demo working setup of a service mesh architecture using Envoy using a demo application. In this service mesh architecture, we will be using Envoy proxy for both control and data plane. The setup is deployed in a Kubernetes cluster using Amazon EKS.</p>\n<h1 id=\"pre-requisites\" style=\"position:relative;\"><a href=\"#pre-requisites\" aria-label=\"pre requisites permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Pre-requisites</h1>\n<p>We will be deploying an echo-grpc test application provided by Google in their article related to gRPC load balancing and was used as a reference to test the service mesh setup with Envoy. The article covers setting up Envoy as an edge proxy only.\nThis is a simple gRPC application that exposes a unary method that takes a string in the content request field and responds with the content unaltered.\nRepo: <a href=\"https://github.com/GoogleCloudPlatform/grpc-gke-nlb-tutorial\">grpc-gke-nlb-tutorial</a></p>\n<ul>\n<li>Clone this repo.</li>\n<li>Go to the echo-grpc directory.</li>\n<li>Using the Dockerfile provided in the folder, we would have to build the image and push it to the Docker registry of choice. Since we are not using GCP, Docker Hub is used as the registry.</li>\n<li>Run docker login and login with your hub credentials.</li>\n<li>Build the image docker build -t echo-grpc .</li>\n<li>Tag the image docker tag echo-grpc <hub-username>/echo-grpc</li>\n<li>Push the image docker push <hub-username>/echo-grpc</li>\n<li>Create a separate folder to put all the YAML files.</li>\n<li>Create namespace in k8s:\n<code>kubectl create namespace envoy</code></li>\n<li>Install grpcurl tool which is similar to curl but for gRPC for testing:\n<code>go get github.com/fullstorydev/grpcurl</code></li>\n</ul>\n<h1 id=\"sidecar-deployment\" style=\"position:relative;\"><a href=\"#sidecar-deployment\" aria-label=\"sidecar deployment permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Sidecar Deployment</h1>\n<p>Configuration of envoy for the sidecar deployment:</p>\n<p><strong>envoy-echo.yaml:</strong></p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"0\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">apiVersion: v1</span>\n<span class=\"grvsc-line\">kind: ConfigMap</span>\n<span class=\"grvsc-line\">metadata:</span>\n<span class=\"grvsc-line\">  name: envoy-echo</span>\n<span class=\"grvsc-line\">data:</span>\n<span class=\"grvsc-line\">  envoy.yaml: |</span>\n<span class=\"grvsc-line\">    static_resources:</span>\n<span class=\"grvsc-line\">      listeners:</span>\n<span class=\"grvsc-line\">      - address:</span>\n<span class=\"grvsc-line\">          socket_address:</span>\n<span class=\"grvsc-line\">            address: 0.0.0.0</span>\n<span class=\"grvsc-line\">            port_value: 8786</span>\n<span class=\"grvsc-line\">        filter_chains:</span>\n<span class=\"grvsc-line\">        - filters:</span>\n<span class=\"grvsc-line\">          - name: envoy.http_connection_manager</span>\n<span class=\"grvsc-line\">            config:</span>\n<span class=\"grvsc-line\">              access_log:</span>\n<span class=\"grvsc-line\">              - name: envoy.file_access_log</span>\n<span class=\"grvsc-line\">                config:</span>\n<span class=\"grvsc-line\">                  path: &quot;/dev/stdout&quot;</span>\n<span class=\"grvsc-line\">              codec_type: AUTO</span>\n<span class=\"grvsc-line\">              stat_prefix: ingress_https</span>\n<span class=\"grvsc-line\">              route_config:</span>\n<span class=\"grvsc-line\">                name: local_route</span>\n<span class=\"grvsc-line\">                virtual_hosts:</span>\n<span class=\"grvsc-line\">                - name: https</span>\n<span class=\"grvsc-line\">                  domains:</span>\n<span class=\"grvsc-line\">                  - &quot;*&quot;</span>\n<span class=\"grvsc-line\">                  routes:</span>\n<span class=\"grvsc-line\">                  - match:</span>\n<span class=\"grvsc-line\">                      prefix: &quot;/api.Echo/&quot;</span>\n<span class=\"grvsc-line\">                    route:</span>\n<span class=\"grvsc-line\">                      cluster: echo-grpc</span>\n<span class=\"grvsc-line\">              http_filters:</span>\n<span class=\"grvsc-line\">              - name: envoy.health_check</span>\n<span class=\"grvsc-line\">                config:</span>\n<span class=\"grvsc-line\">                  pass_through_mode: false</span>\n<span class=\"grvsc-line\">                  headers:</span>\n<span class=\"grvsc-line\">                  - name: &quot;:path&quot;</span>\n<span class=\"grvsc-line\">                    exact_match: &quot;/healthz&quot;</span>\n<span class=\"grvsc-line\">                  - name: &quot;x-envoy-livenessprobe&quot;</span>\n<span class=\"grvsc-line\">                    exact_match: &quot;healthz&quot;</span>\n<span class=\"grvsc-line\">              - name: envoy.router</span>\n<span class=\"grvsc-line\">                config: {}</span>\n<span class=\"grvsc-line\">      clusters:</span>\n<span class=\"grvsc-line\">      - name: echo-grpc</span>\n<span class=\"grvsc-line\">        connect_timeout: 0.5s</span>\n<span class=\"grvsc-line\">        type: STATIC</span>\n<span class=\"grvsc-line\">        lb_policy: ROUND_ROBIN</span>\n<span class=\"grvsc-line\">        http2_protocol_options: {}</span>\n<span class=\"grvsc-line\">        load_assignment:</span>\n<span class=\"grvsc-line\">          cluster_name: echo-grpc</span>\n<span class=\"grvsc-line\">          endpoints:</span>\n<span class=\"grvsc-line\">          - lb_endpoints:</span>\n<span class=\"grvsc-line\">            - endpoint:</span>\n<span class=\"grvsc-line\">                address:</span>\n<span class=\"grvsc-line\">                  socket_address:</span>\n<span class=\"grvsc-line\">                    address: &quot;127.0.0.1&quot;</span>\n<span class=\"grvsc-line\">                    port_value: 8081</span>\n<span class=\"grvsc-line\">        health_checks:</span>\n<span class=\"grvsc-line\">          timeout: 1s</span>\n<span class=\"grvsc-line\">          interval: 10s</span>\n<span class=\"grvsc-line\">          unhealthy_threshold: 2</span>\n<span class=\"grvsc-line\">          healthy_threshold: 2</span>\n<span class=\"grvsc-line\">          grpc_health_check: {}</span>\n<span class=\"grvsc-line\">    admin:</span>\n<span class=\"grvsc-line\">      access_log_path: &quot;/dev/stdout&quot;</span>\n<span class=\"grvsc-line\">      address:</span>\n<span class=\"grvsc-line\">        socket_address:</span>\n<span class=\"grvsc-line\">          address: 127.0.0.1</span>\n<span class=\"grvsc-line\">          port_value: 8090</span></code></pre>\n<p>A couple things to note here. </p>\n<ul>\n<li>We are exposing sidecar on 8786 port on the container. </li>\n<li>Filter <strong>envoy.http<em>connection</em>manager</strong> handles the HTTP traffic. </li>\n<li><strong>route_config</strong> is used to define the routes for each domain to their respective clusters. Here we are keeping the domain as <code>*</code>, allowing all domains to pass-through.</li>\n<li>A cluster is envoy defines the services that will be called based on the route.</li>\n<li>In the cluster, the <strong>lb_policy</strong> defines the algorithm for load balancing, keeping as ROUND<em>ROBIN, with type STATIC because it is a sidecar and needs to communicate to only one pod always which leads to the reason for keeping the address in socket</em>address as localhost while port_value is what will be exposed by that particular service’s deployment.</li>\n</ul>\n<p>Run:\n<code>kubectl apply -f envoy-echo.yaml -n envoy</code></p>\n<p>Deployment of echo-grpc application with 3 replicas. The config contains two containers, one for application and another being the Envoy image.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"1\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">apiVersion: apps/v1</span>\n<span class=\"grvsc-line\">kind: Deployment</span>\n<span class=\"grvsc-line\">metadata:</span>\n<span class=\"grvsc-line\">  name: echo-grpc</span>\n<span class=\"grvsc-line\">spec:</span>\n<span class=\"grvsc-line\">  replicas: 3</span>\n<span class=\"grvsc-line\">  selector:</span>\n<span class=\"grvsc-line\">    matchLabels:</span>\n<span class=\"grvsc-line\">      app: echo-grpc</span>\n<span class=\"grvsc-line\">  template:</span>\n<span class=\"grvsc-line\">    metadata:</span>\n<span class=\"grvsc-line\">      labels:</span>\n<span class=\"grvsc-line\">        app: echo-grpc</span>\n<span class=\"grvsc-line\">    spec:</span>\n<span class=\"grvsc-line\">      containers:</span>\n<span class=\"grvsc-line\">      - name: echo-grpc</span>\n<span class=\"grvsc-line\">        image: &lt;hub-username&gt;/echo-grpc</span>\n<span class=\"grvsc-line\">        imagePullPolicy: Always</span>\n<span class=\"grvsc-line\">        resources: {}</span>\n<span class=\"grvsc-line\">        env:</span>\n<span class=\"grvsc-line\">        - name: &quot;PORT&quot;</span>\n<span class=\"grvsc-line\">          value: &quot;8081&quot;</span>\n<span class=\"grvsc-line\">        ports:</span>\n<span class=\"grvsc-line\">        - containerPort: 8081</span>\n<span class=\"grvsc-line\">        readinessProbe:</span>\n<span class=\"grvsc-line\">          exec:</span>\n<span class=\"grvsc-line\">            command: [&quot;/bin/grpc_health_probe&quot;, &quot;-addr=:8081&quot;]</span>\n<span class=\"grvsc-line\">          initialDelaySeconds: 1</span>\n<span class=\"grvsc-line\">        livenessProbe:</span>\n<span class=\"grvsc-line\">          exec:</span>\n<span class=\"grvsc-line\">            command: [&quot;/bin/grpc_health_probe&quot;, &quot;-addr=:8081&quot;]</span>\n<span class=\"grvsc-line\">          initialDelaySeconds: 1</span>\n<span class=\"grvsc-line\">      - name: envoy</span>\n<span class=\"grvsc-line\">        image: envoyproxy/envoy:v1.9.1</span>\n<span class=\"grvsc-line\">        resources: {}</span>\n<span class=\"grvsc-line\">        ports:</span>\n<span class=\"grvsc-line\">        - name: https</span>\n<span class=\"grvsc-line\">          containerPort: 443</span>\n<span class=\"grvsc-line\">        volumeMounts:</span>\n<span class=\"grvsc-line\">        - name: config</span>\n<span class=\"grvsc-line\">          mountPath: /etc/envoy</span>\n<span class=\"grvsc-line\">      volumes:</span>\n<span class=\"grvsc-line\">        - name: config</span>\n<span class=\"grvsc-line\">          configMap:</span>\n<span class=\"grvsc-line\">            name: envoy-echo</span></code></pre>\n<p>Here, echo-grpc is test application and envoy is being deployed in the same pod. Config volumes are mounted so that the envoy can read the configmaps.</p>\n<p>Run:\n<code>kubectl apply -f echo-deployment.yaml -n envoy</code></p>\n<h1 id=\"headless-service-configuration\" style=\"position:relative;\"><a href=\"#headless-service-configuration\" aria-label=\"headless service configuration permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Headless Service Configuration</h1>\n<p>We are using headless service for echo-grpc. Using service as headless will expose the Pods IP to the DNS server of kubernetes which will be used by Envoy to do service discovery for the pods.</p>\n<p><strong>echo-service.yaml</strong></p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"2\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">apiVersion: v1</span>\n<span class=\"grvsc-line\">kind: Service</span>\n<span class=\"grvsc-line\">metadata:</span>\n<span class=\"grvsc-line\">  name: echo-grpc</span>\n<span class=\"grvsc-line\">spec:</span>\n<span class=\"grvsc-line\">  type: ClusterIP</span>\n<span class=\"grvsc-line\">  clusterIP: None</span>\n<span class=\"grvsc-line\">  selector:</span>\n<span class=\"grvsc-line\">    app: echo-grpc</span>\n<span class=\"grvsc-line\">  ports:</span>\n<span class=\"grvsc-line\">  - name: http2-echo</span>\n<span class=\"grvsc-line\">    protocol: TCP</span>\n<span class=\"grvsc-line\">    port: 8786</span>\n<span class=\"grvsc-line\">  - name: http2-service</span>\n<span class=\"grvsc-line\">    protocol: TCP</span>\n<span class=\"grvsc-line\">    port: 8081</span></code></pre>\n<p>In the above config file, we are exposing two ports, one for envoy sidecar (this is the same port we mentioned in the config map of sidecar envoy) and one for the service itself.</p>\n<p>Run:\n<code>kubectl apply -f echo-service.yaml -n envoy</code></p>\n<h1 id=\"front-envoy-configuration\" style=\"position:relative;\"><a href=\"#front-envoy-configuration\" aria-label=\"front envoy configuration permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Front Envoy Configuration</h1>\n<p>Creating a service of type LoadBalancer so that client can access the backend service.</p>\n<p><strong>envoy-service.yaml:</strong></p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"3\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">apiVersion: v1</span>\n<span class=\"grvsc-line\">kind: Service</span>\n<span class=\"grvsc-line\">metadata:</span>\n<span class=\"grvsc-line\">  name: envoy</span>\n<span class=\"grvsc-line\">spec:</span>\n<span class=\"grvsc-line\">  type: LoadBalancer</span>\n<span class=\"grvsc-line\">  selector:</span>\n<span class=\"grvsc-line\">    app: envoy</span>\n<span class=\"grvsc-line\">  ports:</span>\n<span class=\"grvsc-line\">  - name: https</span>\n<span class=\"grvsc-line\">    protocol: TCP</span>\n<span class=\"grvsc-line\">    port: 443</span>\n<span class=\"grvsc-line\">    targetPort: 443</span></code></pre>\n<h3 id=\"creating-self-signed-certificates\" style=\"position:relative;\"><a href=\"#creating-self-signed-certificates\" aria-label=\"creating self signed certificates permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Creating self-signed certificates</h3>\n<p>Run:\n<code>kubectl apply -f envoy-service.yaml -n envoy</code></p>\n<p>Since we are deploying front envoy LoadBalancer on port 443, we have to create a self-signed certificate to make it terminate SSL/TLS connection.</p>\n<ul>\n<li>Get the external IP:\n<code>kubectl describe svc/envoy -n envoy</code></li>\n<li>Copy the LoadBalancer address in the EXTERNAL-IP section and do a nslookup and copy the IP address:\n<code>nslookup &#x3C;your load balancer aadess></code></li>\n<li>Create a self-signed cert and key:\n<code>openssl req -x509 -nodes -newkey rsa:2048 -days 365 -keyout privkey.pem -out cert.pem -subj \"/CN=&#x3C;ip-address>\"</code></li>\n<li>Create a Kubernetes TLS Secret called envoy-certs that contains the self-signed SSL/TLS certificate and key:\n<code>kubectl create secret tls envoy-certs --key privkey.pem --cert cert.pem --dry-run -o yaml</code></li>\n</ul>\n<h3 id=\"edge-envoy-configuration\" style=\"position:relative;\"><a href=\"#edge-envoy-configuration\" aria-label=\"edge envoy configuration permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Edge Envoy configuration</h3>\n<p>Configuration for the edge Envoy:</p>\n<p><strong>envoy-configmap.yaml</strong></p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"4\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">apiVersion: v1</span>\n<span class=\"grvsc-line\">kind: ConfigMap</span>\n<span class=\"grvsc-line\">metadata:</span>\n<span class=\"grvsc-line\">  name: envoy-conf</span>\n<span class=\"grvsc-line\">data:</span>\n<span class=\"grvsc-line\">  envoy.yaml: |</span>\n<span class=\"grvsc-line\">    static_resources:</span>\n<span class=\"grvsc-line\">      listeners:</span>\n<span class=\"grvsc-line\">      - address:</span>\n<span class=\"grvsc-line\">          socket_address:</span>\n<span class=\"grvsc-line\">            address: 0.0.0.0</span>\n<span class=\"grvsc-line\">            port_value: 443</span>\n<span class=\"grvsc-line\">        filter_chains:</span>\n<span class=\"grvsc-line\">        - filters:</span>\n<span class=\"grvsc-line\">          - name: envoy.http_connection_manager</span>\n<span class=\"grvsc-line\">            config:</span>\n<span class=\"grvsc-line\">              access_log:</span>\n<span class=\"grvsc-line\">              - name: envoy.file_access_log</span>\n<span class=\"grvsc-line\">                config:</span>\n<span class=\"grvsc-line\">                  path: &quot;/dev/stdout&quot;</span>\n<span class=\"grvsc-line\">              codec_type: AUTO</span>\n<span class=\"grvsc-line\">              stat_prefix: ingress_https</span>\n<span class=\"grvsc-line\">              route_config:</span>\n<span class=\"grvsc-line\">                name: local_route</span>\n<span class=\"grvsc-line\">                virtual_hosts:</span>\n<span class=\"grvsc-line\">                - name: https</span>\n<span class=\"grvsc-line\">                  domains:</span>\n<span class=\"grvsc-line\">                  - &quot;*&quot;</span>\n<span class=\"grvsc-line\">                  routes:</span>\n<span class=\"grvsc-line\">                  - match:</span>\n<span class=\"grvsc-line\">                      prefix: &quot;/api.Echo/&quot;</span>\n<span class=\"grvsc-line\">                    route:</span>\n<span class=\"grvsc-line\">                      cluster: echo-grpc</span>\n<span class=\"grvsc-line\">              http_filters:</span>\n<span class=\"grvsc-line\">              - name: envoy.health_check</span>\n<span class=\"grvsc-line\">                config:</span>\n<span class=\"grvsc-line\">                  pass_through_mode: false</span>\n<span class=\"grvsc-line\">                  headers:</span>\n<span class=\"grvsc-line\">                  - name: &quot;:path&quot;</span>\n<span class=\"grvsc-line\">                    exact_match: &quot;/healthz&quot;</span>\n<span class=\"grvsc-line\">                  - name: &quot;x-envoy-livenessprobe&quot;</span>\n<span class=\"grvsc-line\">                    exact_match: &quot;healthz&quot;</span>\n<span class=\"grvsc-line\">              - name: envoy.router</span>\n<span class=\"grvsc-line\">                config: {}</span>\n<span class=\"grvsc-line\">          tls_context:</span>\n<span class=\"grvsc-line\">            common_tls_context:</span>\n<span class=\"grvsc-line\">              tls_certificates:</span>\n<span class=\"grvsc-line\">              - certificate_chain:</span>\n<span class=\"grvsc-line\">                  filename: &quot;/etc/ssl/envoy/tls.crt&quot;</span>\n<span class=\"grvsc-line\">                private_key:</span>\n<span class=\"grvsc-line\">                  filename: &quot;/etc/ssl/envoy/tls.key&quot;</span>\n<span class=\"grvsc-line\">      clusters:</span>\n<span class=\"grvsc-line\">      - name: echo-grpc</span>\n<span class=\"grvsc-line\">        connect_timeout: 0.5s</span>\n<span class=\"grvsc-line\">        type: STRICT_DNS</span>\n<span class=\"grvsc-line\">        lb_policy: ROUND_ROBIN</span>\n<span class=\"grvsc-line\">        http2_protocol_options: {}</span>\n<span class=\"grvsc-line\">        load_assignment:</span>\n<span class=\"grvsc-line\">          cluster_name: echo-grpc</span>\n<span class=\"grvsc-line\">          endpoints:</span>\n<span class=\"grvsc-line\">          - lb_endpoints:</span>\n<span class=\"grvsc-line\">            - endpoint:</span>\n<span class=\"grvsc-line\">                address:</span>\n<span class=\"grvsc-line\">                  socket_address:</span>\n<span class=\"grvsc-line\">                    address: echo-grpc.envoy.svc.cluster.local</span>\n<span class=\"grvsc-line\">                    port_value: 8786</span>\n<span class=\"grvsc-line\">        health_checks:</span>\n<span class=\"grvsc-line\">          timeout: 1s</span>\n<span class=\"grvsc-line\">          interval: 10s</span>\n<span class=\"grvsc-line\">          unhealthy_threshold: 2</span>\n<span class=\"grvsc-line\">          healthy_threshold: 2</span>\n<span class=\"grvsc-line\">          grpc_health_check: {}</span>\n<span class=\"grvsc-line\">    admin:</span>\n<span class=\"grvsc-line\">      access_log_path: &quot;/dev/stdout&quot;</span>\n<span class=\"grvsc-line\">      address:</span>\n<span class=\"grvsc-line\">        socket_address:</span>\n<span class=\"grvsc-line\">          address: 127.0.0.1</span>\n<span class=\"grvsc-line\">          port_value: 8090</span></code></pre>\n<p>Since we will be offloading HTTPS, we are using port_value of 443. Most of the configurations are same as of sidecar envoy except for three things:</p>\n<ul>\n<li>A <strong>tls_context</strong> config is required to mention the tls certifications needed for authentication purposes.</li>\n<li>In clusters, the type has been to STATIC to STRICT_DNS which is a kind of service discovery mechanism making use of Headless service we deployed earlier.</li>\n<li>The socket_address’s address value has been changed to the FQDN of the service.</li>\n</ul>\n<p>Run:\n<code>kubectl apply -f envoy-configmap.yaml -n envoy</code></p>\n<h3 id=\"deployment-configuration\" style=\"position:relative;\"><a href=\"#deployment-configuration\" aria-label=\"deployment configuration permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Deployment Configuration</h3>\n<p><strong>envoy-deployment.yaml</strong></p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"5\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">apiVersion: apps/v1</span>\n<span class=\"grvsc-line\">kind: Deployment</span>\n<span class=\"grvsc-line\">metadata:</span>\n<span class=\"grvsc-line\">  name: envoy</span>\n<span class=\"grvsc-line\">spec:</span>\n<span class=\"grvsc-line\">  replicas: 2</span>\n<span class=\"grvsc-line\">  selector:</span>\n<span class=\"grvsc-line\">    matchLabels:</span>\n<span class=\"grvsc-line\">      app: envoy</span>\n<span class=\"grvsc-line\">  template:</span>\n<span class=\"grvsc-line\">    metadata:</span>\n<span class=\"grvsc-line\">      labels:</span>\n<span class=\"grvsc-line\">        app: envoy</span>\n<span class=\"grvsc-line\">    spec:</span>\n<span class=\"grvsc-line\">      containers:</span>\n<span class=\"grvsc-line\">      - name: envoy</span>\n<span class=\"grvsc-line\">        image: envoyproxy/envoy:v1.9.1</span>\n<span class=\"grvsc-line\">        resources: {}</span>\n<span class=\"grvsc-line\">        ports:</span>\n<span class=\"grvsc-line\">        - name: https</span>\n<span class=\"grvsc-line\">          containerPort: 443</span>\n<span class=\"grvsc-line\">        volumeMounts:</span>\n<span class=\"grvsc-line\">        - name: config</span>\n<span class=\"grvsc-line\">          mountPath: /etc/envoy</span>\n<span class=\"grvsc-line\">        - name: certs</span>\n<span class=\"grvsc-line\">          mountPath: /etc/ssl/envoy</span>\n<span class=\"grvsc-line\">        readinessProbe:</span>\n<span class=\"grvsc-line\">          httpGet:</span>\n<span class=\"grvsc-line\">            scheme: HTTPS</span>\n<span class=\"grvsc-line\">            path: /healthz</span>\n<span class=\"grvsc-line\">            httpHeaders:</span>\n<span class=\"grvsc-line\">            - name: x-envoy-livenessprobe</span>\n<span class=\"grvsc-line\">              value: healthz</span>\n<span class=\"grvsc-line\">            port: 443</span>\n<span class=\"grvsc-line\">          initialDelaySeconds: 3</span>\n<span class=\"grvsc-line\">        livenessProbe:</span>\n<span class=\"grvsc-line\">          httpGet:</span>\n<span class=\"grvsc-line\">            scheme: HTTPS</span>\n<span class=\"grvsc-line\">            path: /healthz</span>\n<span class=\"grvsc-line\">            httpHeaders:</span>\n<span class=\"grvsc-line\">            - name: x-envoy-livenessprobe</span>\n<span class=\"grvsc-line\">              value: healthz</span>\n<span class=\"grvsc-line\">            port: 443</span>\n<span class=\"grvsc-line\">          initialDelaySeconds: 10</span>\n<span class=\"grvsc-line\">      volumes:</span>\n<span class=\"grvsc-line\">      - name: config</span>\n<span class=\"grvsc-line\">        configMap:</span>\n<span class=\"grvsc-line\">          name: envoy-conf</span>\n<span class=\"grvsc-line\">      - name: certs</span>\n<span class=\"grvsc-line\">        secret:</span>\n<span class=\"grvsc-line\">          secretName: envoy-certs</span></code></pre>\n<p>Run:\n<code>kubectl apply -f envoy-deployment.yaml -n envoy</code></p>\n<h1 id=\"testing\" style=\"position:relative;\"><a href=\"#testing\" aria-label=\"testing permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Testing</h1>\n<p>Proto file for the echo-grpc service:</p>\n<p><strong>ccho.proto:</strong></p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"6\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">syntax = &quot;proto3&quot;;</span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\">package api;</span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\">service Echo {</span>\n<span class=\"grvsc-line\">  rpc Echo (EchoRequest) returns (EchoResponse) {}</span>\n<span class=\"grvsc-line\">}</span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\">message EchoRequest {</span>\n<span class=\"grvsc-line\">  string content = 1;</span>\n<span class=\"grvsc-line\">}</span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\">message EchoResponse {</span>\n<span class=\"grvsc-line\">  string content = 1;</span>\n<span class=\"grvsc-line\">}</span></code></pre>\n<p>Run the following command to call the server:\n<code>grpcurl -d '{\"content\": \"echo\"}' -proto echo.proto -insecure -v &#x3C;load_balancer_or_external_ip>:443 api.Echo/Echo</code></p>\n<p>The output will be similar to something like this:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"7\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">Resolved method descriptor:</span>\n<span class=\"grvsc-line\">rpc Echo ( .api.EchoRequest ) returns ( .api.EchoResponse );</span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\">Request metadata to send:</span>\n<span class=\"grvsc-line\">(empty)</span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\">Response headers received:</span>\n<span class=\"grvsc-line\">content-type: application/grpc</span>\n<span class=\"grvsc-line\">date: Wed, 27 Feb 2019 04:40:19 GMT</span>\n<span class=\"grvsc-line\">hostname: echo-grpc-5c4f59c578-wcsvr</span>\n<span class=\"grvsc-line\">server: envoy</span>\n<span class=\"grvsc-line\">x-envoy-upstream-service-time: 0</span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\">Response contents:</span>\n<span class=\"grvsc-line\">{</span>\n<span class=\"grvsc-line\">  &quot;content&quot;: &quot;echo&quot;</span>\n<span class=\"grvsc-line\">}</span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\">Response trailers received:</span>\n<span class=\"grvsc-line\">(empty)</span>\n<span class=\"grvsc-line\">Sent 1 request and received 1 response</span></code></pre>\n<p>Run the above command multiple times and check the value of the hostname field every time which will contain the pod name of one of the 3 pods deployed. </p>\n<h1 id=\"references\" style=\"position:relative;\"><a href=\"#references\" aria-label=\"references permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>References</h1>\n<ul>\n<li>Article: <a href=\"https://cloud.google.com/solutions/exposing-grpc-services-on-gke-using-envoy-proxy\">Using Envoy Proxy to load-balance gRPC services on GKE</a></li>\n<li><a href=\"https://kubernetes.io/docs/concepts/services-networking/service/#headless-services\">Headless service</a></li>\n</ul>\n<style class=\"grvsc-styles\">\n  .grvsc-container {\n    overflow: auto;\n    -webkit-overflow-scrolling: touch;\n    padding-top: 1rem;\n    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));\n    padding-bottom: 1rem;\n    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));\n    border-radius: 8px;\n    border-radius: var(--grvsc-border-radius, 8px);\n    font-feature-settings: normal;\n  }\n  \n  .grvsc-code {\n    display: inline-block;\n    min-width: 100%;\n  }\n  \n  .grvsc-line {\n    display: inline-block;\n    box-sizing: border-box;\n    width: 100%;\n    padding-left: 1.5rem;\n    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));\n    padding-right: 1.5rem;\n    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));\n  }\n  \n  .grvsc-line-highlighted {\n    background-color: var(--grvsc-line-highlighted-background-color, transparent);\n    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, transparent);\n  }\n  \n  .dark-default-dark {\n    background-color: #1E1E1E;\n    color: #D4D4D4;\n  }\n</style>","frontmatter":{"date":"July 06, 2020","updated_date":null,"description":null,"title":"Service Mesh with Envoy","tags":["Service Mesh","Envoy","Microservices"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1.834862385321101,"src":"/static/f5fbebaefd091eb3f33c225fa71b0814/14b42/front-image.jpg","srcSet":"/static/f5fbebaefd091eb3f33c225fa71b0814/f836f/front-image.jpg 200w,\n/static/f5fbebaefd091eb3f33c225fa71b0814/2244e/front-image.jpg 400w,\n/static/f5fbebaefd091eb3f33c225fa71b0814/14b42/front-image.jpg 800w,\n/static/f5fbebaefd091eb3f33c225fa71b0814/47498/front-image.jpg 1200w,\n/static/f5fbebaefd091eb3f33c225fa71b0814/0e329/front-image.jpg 1600w,\n/static/f5fbebaefd091eb3f33c225fa71b0814/6ed45/front-image.jpg 2100w","sizes":"(max-width: 800px) 100vw, 800px"}}},"author":{"id":"Piyush Kumar","github":"kpiyush17","avatar":null}}}},{"node":{"excerpt":"Kafka Streams is a Java library developed to help applications that do stream processing built on Kafka. To learn about Kafka Streams, you…","fields":{"slug":"/engineering/stream-processing-using-kafka/"},"html":"<p>Kafka Streams is a Java library developed to help applications that do stream processing built on Kafka. To learn about Kafka Streams, you need to have a basic idea about Kafka to understand better.  If you’ve worked with Kafka before, Kafka Streams is going to be easy to understand.</p>\n<h2 id=\"what-are-kafka-streams\" style=\"position:relative;\"><a href=\"#what-are-kafka-streams\" aria-label=\"what are kafka streams permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>What are Kafka Streams?</h2>\n<p>Kafka Streams is a streaming application building library, specifically applications that turn Kafka input topics into Kafka output topics. Kafka Streams enables you to do this in a way that is distributed and fault-tolerant, with succinct code.</p>\n<h2 id=\"what-is-stream-processing\" style=\"position:relative;\"><a href=\"#what-is-stream-processing\" aria-label=\"what is stream processing permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>What is Stream processing?</h2>\n<p>Stream processing is the ongoing, concurrent, and record-by-record real-time processing of data.</p>\n<p><strong>Let us get started with some highlights of Kafka Streams:</strong></p>\n<ul>\n<li>Low Barrier to Entry:  Quickly write and run a small-scale POC on a single instance. You only need to run multiple instances of the application on various machines to scale up to high-volume production workloads.</li>\n<li>Lightweight and straightforward client library:  Can be easily embedded in any Java application and integrated with any existing packaging, deployment, and operational tools.</li>\n<li>No external dependencies on systems other than <a href=\"https://en.wikipedia.org/wiki/Apache_Kafka\">Apache Kafka</a> itself</li>\n<li>Fault-tolerant local state: Enables fast and efficient stateful operations like windowed joins and aggregations</li>\n<li>Supports exactly-once processing: Each record will be processed once and only once, even when there is a failure.</li>\n<li>One-record-at-a-time processing to achieve millisecond processing latency supports event-time-based windowing operations with out-of-order arrival of records.</li>\n</ul>\n<h2 id=\"kafka-streams-concepts\" style=\"position:relative;\"><a href=\"#kafka-streams-concepts\" aria-label=\"kafka streams concepts permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Kafka Streams Concepts:</h2>\n<ul>\n<li><strong>Stream</strong>:  An ordered, replayable, and fault-tolerant sequence of immutable data records, where each data record is defined as a key-value pair.</li>\n<li><strong>Stream Processor</strong>:  A node in the processor topology represents a processing step to transform data in streams by receiving one input record at a time from its source in the topology, applying any operation to it, and may subsequently produce one or more output records to its sinks.</li>\n</ul>\n<p>There are two individual processors in the topology:</p>\n<ul>\n<li><strong>Source Processor</strong>: A source processor is a special type of stream processor that does not have any upstream processors. It produces an input stream to its topology from one or multiple Kafka topics by consuming records from these topics and forwarding them to its down-stream processors.</li>\n<li><strong>Sink Processor</strong>: A sink processor is a special type of stream processor that does not have down-stream processors. It sends any received records from its up-stream processors to a specified Kafka topic.</li>\n</ul>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 119.53846153846155%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAYABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAIF/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAH/2gAMAwEAAhADEAAAAd1UlASS0LP/xAAYEAACAwAAAAAAAAAAAAAAAAAAECAhMf/aAAgBAQABBQIt7H//xAAVEQEBAAAAAAAAAAAAAAAAAAAQEf/aAAgBAwEBPwEh/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAgEBPwEf/8QAFBABAAAAAAAAAAAAAAAAAAAAMP/aAAgBAQAGPwIf/8QAGhAAAgMBAQAAAAAAAAAAAAAAAAEQEVFxof/aAAgBAQABPyGtZ1DVmGobovfBH//aAAwDAQACAAMAAAAQ08BB/8QAGBEAAgMAAAAAAAAAAAAAAAAAAAEQETH/2gAIAQMBAT8QuEHp/8QAFhEBAQEAAAAAAAAAAAAAAAAAAQAQ/9oACAECAQE/EMWL/8QAHBABAQEBAAIDAAAAAAAAAAAAAREhABAxQVGB/9oACAEBAAE/EHTfXIzoLSFyngIp6adpYAZvzx60nAijv0XhbqLkPRMv73//2Q=='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Toplogy Example\"\n        title=\"Toplogy Example\"\n        src=\"/static/b27b1b16e63c3b3ac479a43ba7c12482/212bf/streams-architecture-topology.jpg\"\n        srcset=\"/static/b27b1b16e63c3b3ac479a43ba7c12482/6aca1/streams-architecture-topology.jpg 650w,\n/static/b27b1b16e63c3b3ac479a43ba7c12482/212bf/streams-architecture-topology.jpg 768w,\n/static/b27b1b16e63c3b3ac479a43ba7c12482/47311/streams-architecture-topology.jpg 1080w\"\n        sizes=\"(max-width: 768px) 100vw, 768px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></p>\n<ul>\n<li><strong>Kstream</strong>: KStream is nothing but that, a Kafka Stream. It’s a never-ending flow of data in a stream. Each piece of data — a record or a fact — is a collection of key-value pairs. Data records in a record stream are always interpreted as an \"INSERT\".</li>\n<li><strong>KTable</strong>: A KTable is just an abstraction of the stream, where only the latest value is kept. Data records in a record stream are always interpreted as an \"UPDATE\".</li>\n</ul>\n<p>There is actually a close relationship between streams and tables, the so-called stream-table duality</p>\n<h2 id=\"implementing-kafka-streams\" style=\"position:relative;\"><a href=\"#implementing-kafka-streams\" aria-label=\"implementing kafka streams permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Implementing Kafka Streams</h2>\n<p>Let's Start with the Setup using Scala instead of Java. The Kafka Streams DSL for Scala library is a wrapper over the existing Java APIs for Kafka Streams DSL.</p>\n<p>To Setup things, we need to create a <code>KafkaStreams</code> Instance. It needs a topology and configuration (<code>java.util.Properties</code>). We also need a input topic and output topic. Let's look through a simple example of sending data from an input topic to an output topic using the Streams API</p>\n<p>You can create a topic using the below commands (need to have Kafka pre installed)</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"shell\" data-index=\"0\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">kafka-topics --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic inputTopic</span>\n<span class=\"grvsc-line\">kafka-topics --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic outputTopic</span></code></pre>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"scala\" data-index=\"1\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">val config: Properties = {</span>\n<span class=\"grvsc-line\">    val properties = new Properties()</span>\n<span class=\"grvsc-line\">    properties.put(StreamsConfig.APPLICATION_ID_CONFIG, &quot;your-application&quot;)</span>\n<span class=\"grvsc-line\">    properties.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, &quot;localhost:9092&quot;)</span>\n<span class=\"grvsc-line\">    properties.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, &quot;latest&quot;)</span>\n<span class=\"grvsc-line\">    properties.put(StreamsConfig.PROCESSING_GUARANTEE_CONFIG, StreamsConfig.EXACTLY_ONCE)</span>\n<span class=\"grvsc-line\">    properties.put(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG, Serdes.String())</span>\n<span class=\"grvsc-line\">    properties.put(StreamsConfig.DEFAULT_VALUE_SERDE_CLASS_CONFIG, Serdes.String())</span>\n<span class=\"grvsc-line\">    properties</span>\n<span class=\"grvsc-line\">    }</span></code></pre>\n<p>StreamsBuilder provide the high-level Kafka Streams DSL to specify a Kafka Streams topology.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"scala\" data-index=\"2\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">val builder: StreamsBuilder = new StreamsBuilder</span></code></pre>\n<p>Creates a KStream from the specified topics.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"scala\" data-index=\"3\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">val inputStream: KStream[String,String] = builder.stream(inputTopic, Consumed.`with`(Serdes.String(), Serdes.String()))</span></code></pre>\n<p>Store the input stream to the output topic.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"scala\" data-index=\"4\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">inputStream.to(outputTopic)(producedFromSerde(Serdes.String(),Serdes.String())</span></code></pre>\n<p>Starts the Streams Application</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"scala\" data-index=\"5\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">val kEventStream = new KafkaStreams(builder.build(), config)</span>\n<span class=\"grvsc-line\">kEventStream.start()</span>\n<span class=\"grvsc-line\">sys.ShutdownHookThread {</span>\n<span class=\"grvsc-line\">      kEventStream.close(10, TimeUnit.SECONDS)</span>\n<span class=\"grvsc-line\">    }</span></code></pre>\n<p>You can send data to the input topic using </p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"shell\" data-index=\"6\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">kafka-console-producer --broker-list localhost:9092 --topic inputTopic</span></code></pre>\n<p>And can fetch the data from the output topic using</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"shell\" data-index=\"7\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">kafka-console-consumer --bootstrap-server localhost:9092 --topic outputTopic --from-beginning</span></code></pre>\n<p>You can add the necessary dependencies in your build file for sbt or pom file for maven. Below is an example for build.sbt.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"sbt\" data-index=\"8\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">// Kafka</span>\n<span class=\"grvsc-line\">libraryDependencies += &quot;org.apache.kafka&quot; %% &quot;kafka-streams-scala&quot; % &quot;2.0.0&quot;</span>\n<span class=\"grvsc-line\">libraryDependencies += &quot;javax.ws.rs&quot; % &quot;javax.ws.rs-api&quot; % &quot;2.1&quot; artifacts( Artifact(&quot;javax.ws.rs-api&quot;, &quot;jar&quot;, &quot;jar&quot;)) // this is a workaround. There is an upstream dependency that causes trouble in SBT builds.</span></code></pre>\n<p>Let us modify the code a little bit to try out a WordCount example:\nThe code splits the sentences into words and groups by word as a key and the number of occurences or count as value and is being sent to the output topic by converting the KTable to KStream.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"scala\" data-index=\"9\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">val textLines: KStream[String, String] = builder.stream[String, String](inputTopic)</span>\n<span class=\"grvsc-line\">val wordCounts: KTable[String, Long] = textLines</span>\n<span class=\"grvsc-line\">\t\t.flatMapValues(textLine =&gt; textLine.toLowerCase.split(&quot;\\\\W+&quot;))</span>\n<span class=\"grvsc-line\">\t\t.groupBy((_, word) =&gt; word)</span>\n<span class=\"grvsc-line\">\t\t.count()(materializedFromSerde(Serdes.String(),Serdes.Long()))</span>\n<span class=\"grvsc-line\">\twordCounts.toStream.to(outputTopic)(producedFromSerde(Serdes.String(),Serdes.Long())</span></code></pre>\n<p>With the above process, we can now implement a simple streaming application or a word count application using Kafka Streams in Scala. If you want to set up kafka on Windows, here is a quick guide to implement apache <a href=\"/quick-kafka-installation/\">kafka on windows OS</a>. </p>\n<style class=\"grvsc-styles\">\n  .grvsc-container {\n    overflow: auto;\n    -webkit-overflow-scrolling: touch;\n    padding-top: 1rem;\n    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));\n    padding-bottom: 1rem;\n    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));\n    border-radius: 8px;\n    border-radius: var(--grvsc-border-radius, 8px);\n    font-feature-settings: normal;\n  }\n  \n  .grvsc-code {\n    display: inline-block;\n    min-width: 100%;\n  }\n  \n  .grvsc-line {\n    display: inline-block;\n    box-sizing: border-box;\n    width: 100%;\n    padding-left: 1.5rem;\n    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));\n    padding-right: 1.5rem;\n    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));\n  }\n  \n  .grvsc-line-highlighted {\n    background-color: var(--grvsc-line-highlighted-background-color, transparent);\n    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, transparent);\n  }\n  \n  .dark-default-dark {\n    background-color: #1E1E1E;\n    color: #D4D4D4;\n  }\n</style>","frontmatter":{"date":"July 01, 2020","updated_date":null,"description":"Learn about Kafka Streams, key concepts and highlights with simple streaming or a word count application using Kafka Streams in Scala","title":"Kafka Streams: A stream processing guide","tags":["Scala","Kafka","Kafka Streams"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1.5037593984962405,"src":"/static/b42ed1fb037f4d27ff3e60a004298488/ee604/header.png","srcSet":"/static/b42ed1fb037f4d27ff3e60a004298488/69585/header.png 200w,\n/static/b42ed1fb037f4d27ff3e60a004298488/497c6/header.png 400w,\n/static/b42ed1fb037f4d27ff3e60a004298488/ee604/header.png 800w,\n/static/b42ed1fb037f4d27ff3e60a004298488/f3583/header.png 1200w","sizes":"(max-width: 800px) 100vw, 800px"}}},"author":{"id":"Priyadarshan Mohanty","github":"priyadarshan1995","avatar":null}}}},{"node":{"excerpt":"You’re probably hosting your MongoDB on a reliable cloud service provider say Atlas for instance because you really want to focus on your…","fields":{"slug":"/engineering/self-hosted-mongo/"},"html":"<p>You’re probably hosting your MongoDB on a reliable cloud service provider say <a href=\"https://cloud.mongodb.com\">Atlas</a> for instance because you really want to focus on your idea and delegate all the subtle key management areas such as networking, storage, access, etc.</p>\n<p>It all looks good initially until your small idea starts turning into a business and the cost starts skyrocketing. Even if that is not the case, this post will still give you a general overview of the technical complexities involved (and bucks saved!) if you were to migrate to a self-hosted solution.</p>\n<p>BTW, how much savings are we talking about? Let’s do a quick comparison between an <strong>Atlas</strong> instance and a self-hosted MongoDB on <strong>AWS</strong>.</p>\n<p><strong>Atlas (~$166/month)</strong></p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 42%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAIAAAB2/0i6AAAACXBIWXMAAAsTAAALEwEAmpwYAAABDUlEQVQY031Qy24DIQzM//9YL1VvVXto02y0kdhHAAMGzLPejdJDGxWNMBiPPcPhWR9f3TjQ9cWcLqQwExAuSlJJvtIMUqjVF4LoxkVINAKu78ORcVbzQRjpQlDGfAwnqSGnjNZNej0r4RxSpFrqjpJT6r23WjkZfdDeHiYmozeIYK3znp9jjF9GPIm3EEMkChQ3xICIrfdaKxcYDatR22QMQSzLMI7aGIeotebaXDpSibn2P6vtu01+l+09y5YA3AUcTtOMPqTaKNdc2n/km2zLfAAWz95SSq094DyebNmzx4sQq1IsGwDanc3hp1Hr7Td5tkpq/TkMN892W44D7P75opTm8w2c5w/rd/I3OuXMieG2KrwAAAAASUVORK5CYII='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"&quot;Atlas Pricing&quot;\"\n        title=\"Atlas Pricing\"\n        src=\"/static/37ae695d63da0d8e11b315ac53da7162/e5715/atlas.png\"\n        srcset=\"/static/37ae695d63da0d8e11b315ac53da7162/a6d36/atlas.png 650w,\n/static/37ae695d63da0d8e11b315ac53da7162/e5715/atlas.png 768w,\n/static/37ae695d63da0d8e11b315ac53da7162/cc8d6/atlas.png 791w\"\n        sizes=\"(max-width: 768px) 100vw, 768px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span>\n$0.23/hour based on the above-selected requirements (~ <a href=\"https://cloud.mongodb.com\">cloud.mongodb.com</a>)</p>\n<p><br><br><strong>AWS (~$36/month)</strong>\n<span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 27.846153846153847%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAIAAABM9SnKAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAu0lEQVQY021QywqDMBDM//9Sv6HnXgo9VMGoZPMg72g6RhRpO2yGIQmzs8sez1c/cEGktNbGgKVSX4XLcZqPmmZBYuTqfmMpxlxKrdU51/U9SQldSlmW5WQhKISQck4p4bMgqZWqemZo50Pw3ltriQjt/QHYbew9HHcNwAVRlDE2RPbuOmtdaIgxhgtOl6v27Qkt4cgkyYIo/4DM9QdIvq4rBF7ZwDn2sW2rsWwLw4pwMEhuc16B9LtA/w8AoVktzOpq7wAAAABJRU5ErkJggg=='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"&quot;AWS Pricing&quot;\"\n        title=\"AWS Pricing\"\n        src=\"/static/919463e3199f2098ff4d7388991b988f/e5715/aws.png\"\n        srcset=\"/static/919463e3199f2098ff4d7388991b988f/a6d36/aws.png 650w,\n/static/919463e3199f2098ff4d7388991b988f/e5715/aws.png 768w,\n/static/919463e3199f2098ff4d7388991b988f/2cefc/aws.png 1400w\"\n        sizes=\"(max-width: 768px) 100vw, 768px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></p>\n<p>$0.0416/hour for the instance and additional pricing based on the EBS type and storage (~ <a href=\"https://calculator.aws/\">calculator.aws</a>)</p>\n<blockquote>\n<p>It is almost 4.5x savings just in terms of the infrastructure!</p>\n</blockquote>\n<p>Now that you know the major why(s) and are still reading this post, without further ado, let’s dive into the tech.</p>\n<hr />\n<h1 id=\"outline\" style=\"position:relative;\"><a href=\"#outline\" aria-label=\"outline permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Outline</h1>\n<ol>\n<li>Setting up the infrastructure</li>\n<li>Setting up MongoDB</li>\n<li>Bulk migration</li>\n<li>Delta-sync to bridge the connection switch latency (not applicable to stale clusters)</li>\n</ol>\n<p>Since the entire content can be a bit exhausting in one place, I’m going to divide this into 2 related posts.</p>\n<h1 id=\"1-setting-up-the-infrastructure\" style=\"position:relative;\"><a href=\"#1-setting-up-the-infrastructure\" aria-label=\"1 setting up the infrastructure permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>1. Setting up the Infrastructure</h1>\n<p>I’m going to mention below the guide for setting up an instance running <strong>RedHat Enterprise Linux 8</strong> on AWS. This is because MongoDB generally performs better with the xfs file-system.</p>\n<h2 id=\"spin-up-an-ec2-instance\" style=\"position:relative;\"><a href=\"#spin-up-an-ec2-instance\" aria-label=\"spin up an ec2 instance permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Spin up an EC2 Instance</h2>\n<p>I’ve used a <code>t3.small</code> instance that comes with <strong>2 vCPUs</strong> and <strong>2Gb of RAM</strong> albeit you can select any instance of your choice.</p>\n<blockquote>\n<p>It is recommended that your DB should have access to at least <strong>1GB of RAM</strong> and <strong>2 real cores</strong> as that directly affects the performance during caching &#x26; concurrency mechanisms as handled by the default engine <a href=\"https://docs.mongodb.com/manual/core/wiredtiger/\"><strong>WiredTiger</strong></a>. You can read more about the <a href=\"https://docs.mongodb.com/manual/administration/production-notes/#allocate-sufficient-ram-and-cpu\"><strong>production notes related to the RAM and CPU requirements here</strong></a>.</p>\n</blockquote>\n<p><em>Configuration Overview:</em></p>\n<ul>\n<li>OS: <strong>Redhat Enterprise Linux 8 (x64 intel-based)</strong></li>\n<li>Instance Type: <strong>t3.small</strong></li>\n<li>Storage: <strong>10GB</strong>(os) + <strong>30GB</strong>(data) + <strong>3GB</strong>(logs) of <strong>EBS</strong> i.e. 3 separate volumes</li>\n</ul>\n<p>I’m assuming that you’re familiar with creating a VM on AWS.</p>\n<p>Now, once the instance is in running state, assign an <strong>Elastic IP</strong> to it and then simply do a remote login into the machine.</p>\n<blockquote>\n<p>We'll need the <strong>Elastic IP</strong> to setup public hostname for the instance</p>\n</blockquote>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"0\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">$ ssh -i &lt;PEM_FILE&gt; ec2-user@&lt;ELASTIC_IP&gt;</span></span></code></pre>\n<h2 id=\"mount-additional-volumes\" style=\"position:relative;\"><a href=\"#mount-additional-volumes\" aria-label=\"mount additional volumes permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Mount Additional Volumes</h2>\n<p>We have added 2 additional EBS volumes other than the Root FS for Data and Logs which are yet to be mounted (<em>Remember the 30Gb and 3Gb?</em>). You can list the volume blocks using,</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"1\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">$ sudo lsblk</span></span></code></pre>\n<p>The additional volumes will be listed right after the root block (refer to the arrows)</p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 353px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 25.21246458923513%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAFCAIAAADKYVtkAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA8klEQVQY0x2PyW6DMBCGeYKeUEmhbFJDCeBQFKAsYTFmSykW4lBVqtRz3/8J+sffYTRj+5vxSNM0DcMgy3Jd133fM8auAuQ4ybIMsaoqPMPVOI4oNU17FkhN00DWDb2l7crX4Exc1w3DsBEkSYIuaZoahmHbtmmalmXpgrvs+z6ldP34vA0zX/jri+McHUJIWZYYAnmeZ8iY9iQ4HA6Koqiqepcv8WXshmPlVT9s/LqdaeQGLgkI5xwyNHw4z/M4jqMoeheg9DwPjaSOdexKH7JH8pflv/TtO3Ojk3/y8LooCkTsiaQVLMuCptu27fuO7f4B7lI+vFGhNDMAAAAASUVORK5CYII='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"&quot;sudo lsblk&quot;\"\n        title=\"List volume blocks\"\n        src=\"/static/e89cd4d9897ca07cc7ffb0edcda7119e/6c115/lsblk.png\"\n        srcset=\"/static/e89cd4d9897ca07cc7ffb0edcda7119e/6c115/lsblk.png 353w\"\n        sizes=\"(max-width: 353px) 100vw, 353px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></p>\n<p>In the image above, you can see that the additional volumes are named</p>\n<ol>\n<li><strong>xvdb</strong> (30Gb space to store data)</li>\n<li><strong>xvdc</strong> (3Gb space to store logs)</li>\n</ol>\n<p>Now, let’s create the file-systems in those volumes.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"2\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">$ sudo mkfs.xfs -L mongodata /dev/xvdb</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">$ sudo mkfs.xfs -L mongologs /dev/xvdc</span></span></code></pre>\n<blockquote>\n<p><code>-L</code> is an alias option for setting the <strong>volume label</strong></p>\n</blockquote>\n<p>And then mount the volumes.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"3\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">$ sudo mount -t xfs /dev/xvdb /var/lib/mongo</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">$ sudo mount -t xfs /dev/xvdc /var/log/mongodb</span></span></code></pre>\n<p>In order for these changes to reflect, the system must be rebooted. Hence, now we also need the partition persistence so that in case of an unintentional reboot we don’t lose the Database storage.</p>\n<p>We can achieve this by specifying the mount rules in the fstab file. <a href=\"https://geek-university.com/linux/etc-fstab-file/\">You can read more about it here</a>.</p>\n<p>Before that let's copy the UUID of the above partitions(<em>because they are unique and won't change over a system restart</em>)</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"4\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">$ sudo blkid</span></span></code></pre>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 9.846153846153847%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAACCAIAAADXZGvcAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAaUlEQVQI1x2KvQrFIAyF+xiCk5ODg1i7FBJsoWkrGlO47/8uN/gNh/O3EFEp5ZkMHnAi/A7+uLUmIsysB/W991rrO1GTc3bOLbohoma66Rty8b0LrpuueZ2klFQBQJsQQozRe2+Msdb+AZEjHOgCyMRoAAAAAElFTkSuQmCC'); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"&quot;sudo blkid&quot;\"\n        title=\"List attached block info\"\n        src=\"/static/a37188eaa209c947db818b61fd19dfbb/e5715/blkid.png\"\n        srcset=\"/static/a37188eaa209c947db818b61fd19dfbb/a6d36/blkid.png 650w,\n/static/a37188eaa209c947db818b61fd19dfbb/e5715/blkid.png 768w,\n/static/a37188eaa209c947db818b61fd19dfbb/20c85/blkid.png 999w\"\n        sizes=\"(max-width: 768px) 100vw, 768px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></p>\n<p>Copy the UUIDs listed for <strong>/dev/xvdb</strong> and <strong>/dev/xvdc</strong>. Refer to the <strong>“LABEL”</strong> for block identification</p>\n<p>Now open the <code>/etc/fstab</code> file and paste the configuration in the following format.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"5\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">UUID=&lt;COPIED_UUID_FOR_DATA&gt; /var/lib/mongo xfs defaults,nofail 0 0</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">UUID=&lt;COPIED_UUID_FOR_LOGS&gt; /var/log/mongodb xfs defaults,nofail 0 0</span></span></code></pre>\n<h2 id=\"update-hostname\" style=\"position:relative;\"><a href=\"#update-hostname\" aria-label=\"update hostname permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Update Hostname</h2>\n<p>The hostname will be used to identify your database server on the network. You can either use the above assigned <strong>Elastic IP</strong> or Domain name (if available). Open the <code>/etc/hostname</code> file and append the entry. For e.g.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"6\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">ip-xx.us-east-2.compute.internal **&lt;ELASTIC_IP&gt; &lt;DOMAIN_1&gt; &lt;DOMAIN_2&gt;** ...</span></span></code></pre>\n<h2 id=\"update-the-process-limits-optional\" style=\"position:relative;\"><a href=\"#update-the-process-limits-optional\" aria-label=\"update the process limits optional permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Update the Process Limits (Optional)</h2>\n<p>This is optionally required in order to control the maximum number of acceptable connections while keeping the system stable.\nOpen the <code>/etc/security/limits.conf</code> file and add the following entries.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"7\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">* soft nofile 64000</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">* hard nofile 64000</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">* soft nproc 32000</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">* hard nproc 32000</span></span></code></pre>\n<p>Now that all of the infra related prerequisites are sorted, <strong>reboot</strong> the instance, and let’s proceed to MongoDB installation.</p>\n<hr />\n<h1 id=\"1-setting-up-mongodb\" style=\"position:relative;\"><a href=\"#1-setting-up-mongodb\" aria-label=\"1 setting up mongodb permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>1. Setting up MongoDB</h1>\n<h2 id=\"add-the-repo-source\" style=\"position:relative;\"><a href=\"#add-the-repo-source\" aria-label=\"add the repo source permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Add the Repo Source</h2>\n<p>Create a file <code>/etc/yum.repos.d/mongodb-org.4.2.repo</code> and add the following package repository details.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"8\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">[mongodb-org-4.2]</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">name=MongoDB Repository</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">baseurl=https://repo.mongodb.org/yum/redhat/</span><span class=\"mtk12\">$releasever</span><span class=\"mtk1\">/mongodb-org/4.2/x86_64/</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">gpgcheck=1</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">enabled=1</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">gpgkey=https://www.mongodb.org/static/pgp/server-4.2.asc</span></span></code></pre>\n<p>Now let’s install MongoDB.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"9\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">$ sudo yum -y install mongodb-org</span></span></code></pre>\n<h2 id=\"create-directories-and-setup-permissions\" style=\"position:relative;\"><a href=\"#create-directories-and-setup-permissions\" aria-label=\"create directories and setup permissions permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Create directories and setup permissions</h2>\n<p>MongoDB by default uses the following paths to store the data and the internal logs:</p>\n<blockquote>\n<p><strong>/var/lib/mongo</strong> → Data<br><strong>/var/log/mongodb</strong> → Logs</p>\n</blockquote>\n<p><strong>Create the directories</strong></p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"10\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">$ sudo mkdir /var/lib/mongo</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">$ sudo mkdir /var/log/mongodb</span></span></code></pre>\n<p><strong>Change user &#x26; group permissions</strong></p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"11\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">$ sudo chown mongod:mongod /var/lib/mongo</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">$ sudo chown mongod:mongod /var/log/mongod</span></span></code></pre>\n<h2 id=\"create-an-admin-user\" style=\"position:relative;\"><a href=\"#create-an-admin-user\" aria-label=\"create an admin user permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Create an Admin User</h2>\n<p>The <strong>mongod daemon/service</strong> must be first running before we proceed to create a user.\nLet’s use the default config(stored in <code>/etc/mongod.conf</code>) for now and start the daemon process.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"12\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">$ sudo -u mongod mongod -f /etc/mongod.conf</span></span></code></pre>\n<p>The above command will start the mongod daemon in fork mode (default).</p>\n<p>Now, let’s login to the server and create our first admin user.</p>\n<p><strong>Open a mongo shell</strong></p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"13\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">$ mongo</span></span></code></pre>\n<p><strong>Use the \"admin\" database to create the root-admin</strong></p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"14\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">&gt; use admin</span></span></code></pre>\n<p><strong>Create the admin user</strong></p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"15\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">&gt; db.createUser({user: </span><span class=\"mtk8\">&quot;admin&quot;</span><span class=\"mtk1\">, pwd: </span><span class=\"mtk8\">&quot;password&quot;</span><span class=\"mtk1\">, roles: [{role: </span><span class=\"mtk8\">&quot;root&quot;</span><span class=\"mtk1\">, db: </span><span class=\"mtk8\">&quot;admin&quot;</span><span class=\"mtk1\">}]})</span></span></code></pre>\n<p><strong>Create a regular user</strong></p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"16\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">&gt; db.createUser({user: </span><span class=\"mtk8\">&quot;normal_user&quot;</span><span class=\"mtk1\">, pwd: </span><span class=\"mtk8\">&quot;password&quot;</span><span class=\"mtk1\">, roles: [{role: </span><span class=\"mtk8\">&quot;readWriteAnyDatabase&quot;</span><span class=\"mtk1\">, db: </span><span class=\"mtk8\">&quot;admin&quot;</span><span class=\"mtk1\">}]})</span></span></code></pre>\n<p><strong>Shutdown the server for now. We'll restart again with the modified config</strong></p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"17\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">&gt; </span><span class=\"mtk11\">db.shutDownServer</span><span class=\"mtk1\">()</span></span></code></pre>\n<h2 id=\"setting-up-authentication\" style=\"position:relative;\"><a href=\"#setting-up-authentication\" aria-label=\"setting up authentication permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Setting up Authentication</h2>\n<p>Here, we’ll enable the database authentication and modify the bind-address for our server to be accessible in the public domain.\nOpen <code>/etc/mongod.conf</code> and make the below changes.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"18\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk3\"># network interfaces</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">net:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  port: 27017</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  bindIp: 0.0.0.0 </span><span class=\"mtk3\"># accessible on the network address</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">security:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  authorization: enabled </span><span class=\"mtk3\"># creds will be required for making db operations</span></span></code></pre>\n<p>Save the config and <strong>restart</strong> the server.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"19\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">$ sudo -u mongod mongod -f /etc/mongod.conf</span></span></code></pre>\n<h2 id=\"test-login\" style=\"position:relative;\"><a href=\"#test-login\" aria-label=\"test login permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Test Login</h2>\n<p>You can verify if the credentials work using,</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"20\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">$ mongo -u admin -p password</span></span></code></pre>\n<p>That is it about the initial setup! Please stay tuned for my next related post on the detailed migration process and tips on keeping the DB production-ready.</p>\n<p>P.S. Thanks to <a href=\"https://twitter.com/MrEnvoy17\">Piyush Kumar</a> for helping curate this post!</p>\n<style class=\"grvsc-styles\">\n  .grvsc-container {\n    overflow: auto;\n    -webkit-overflow-scrolling: touch;\n    padding-top: 1rem;\n    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));\n    padding-bottom: 1rem;\n    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));\n    border-radius: 8px;\n    border-radius: var(--grvsc-border-radius, 8px);\n    font-feature-settings: normal;\n  }\n  \n  .grvsc-code {\n    display: inline-block;\n    min-width: 100%;\n  }\n  \n  .grvsc-line {\n    display: inline-block;\n    box-sizing: border-box;\n    width: 100%;\n    padding-left: 1.5rem;\n    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));\n    padding-right: 1.5rem;\n    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));\n  }\n  \n  .grvsc-line-highlighted {\n    background-color: var(--grvsc-line-highlighted-background-color, transparent);\n    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, transparent);\n  }\n  \n  .dark-default-dark {\n    background-color: #1E1E1E;\n    color: #D4D4D4;\n  }\n  .dark-default-dark .mtk1 { color: #D4D4D4; }\n  .dark-default-dark .mtk12 { color: #9CDCFE; }\n  .dark-default-dark .mtk8 { color: #CE9178; }\n  .dark-default-dark .mtk11 { color: #DCDCAA; }\n  .dark-default-dark .mtk3 { color: #6A9955; }\n</style>","frontmatter":{"date":"June 30, 2020","updated_date":null,"description":"Learn how to optimize your DB cost? This article will help you with the complete migration steps from a cloud to a self-hosted environment.","title":"Self-Hosted MongoDB","tags":["MongoDB","Mongo","AWS","Atlas"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":2.0408163265306123,"src":"/static/504642ca3a1f7d78dea8509436faa4c6/14b42/cover.jpg","srcSet":"/static/504642ca3a1f7d78dea8509436faa4c6/f836f/cover.jpg 200w,\n/static/504642ca3a1f7d78dea8509436faa4c6/2244e/cover.jpg 400w,\n/static/504642ca3a1f7d78dea8509436faa4c6/14b42/cover.jpg 800w,\n/static/504642ca3a1f7d78dea8509436faa4c6/d8343/cover.jpg 925w","sizes":"(max-width: 800px) 100vw, 800px"}}},"author":{"id":"Chinmaya Pati","github":"cnp96","avatar":null}}}},{"node":{"excerpt":"Roadmap of IDX-auto-tester We're delightfully Announcing the upcoming releases of LoginRadius Identity-Experience-Framework Open-Source…","fields":{"slug":"/engineering/roadmap-idx-autotester/"},"html":"<h1 id=\"roadmap-of-idx-auto-tester\" style=\"position:relative;\"><a href=\"#roadmap-of-idx-auto-tester\" aria-label=\"roadmap of idx auto tester permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Roadmap of IDX-auto-tester</h1>\n<p>We're delightfully Announcing the upcoming releases of LoginRadius Identity-Experience-Framework Open-Source Automation</p>\n<p>These full-version releases will include more test coverage and major changes with several improvements &#x26; code optimizations, the details have been given below.<br>\nThe below changes are planned to go live in multiple scheduled major releases starting with mid of June 2020.  </p>\n<h2 id=\"release-roadmap\" style=\"position:relative;\"><a href=\"#release-roadmap\" aria-label=\"release roadmap permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Release Roadmap:</h2>\n<h3 id=\"july-2020\" style=\"position:relative;\"><a href=\"#july-2020\" aria-label=\"july 2020 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>July 2020:</h3>\n<h4 id=\"test-cases\" style=\"position:relative;\"><a href=\"#test-cases\" aria-label=\"test cases permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Test Cases:</h4>\n<ul>\n<li><strong>Improving the ratio of Good Test Cases in Test repository:</strong> We will be adding more test cases in Registration and Login flow to cover as much as possible Use Cases.</li>\n<li><strong>Increasing Negative Test Case Coverage:</strong> We are also focusing on negative test cases that are the most important part of the Test Coverage in Testing Life Cycle.</li>\n<li><strong>Delivering Manual Test Cases</strong>: We know that understanding of the test steps or mining the test cases by reading the code is not so easy for everyone, so we will also deliver the written Test Cases with the expected outcomes.</li>\n</ul>\n<blockquote>\n<p><em>CI/CD pipelines for automation is to make everyday development tasks simple that can save time and reduce human intervention to check them every single code commit.</em></p>\n</blockquote>\n<h3 id=\"august-2020\" style=\"position:relative;\"><a href=\"#august-2020\" aria-label=\"august 2020 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>August 2020:</h3>\n<h4 id=\"usability-improvements\" style=\"position:relative;\"><a href=\"#usability-improvements\" aria-label=\"usability improvements permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Usability Improvements:</h4>\n<ul>\n<li>Adding Command-line parameters for parallel run.</li>\n<li>Improving the naming conventions of functions for better readability.  </li>\n<li>Better Error and Exception Handling for failed assertions.</li>\n<li>Adding detailed descriptive comments to functions, custom-commands, and test cases for better understanding.</li>\n</ul>\n<h4 id=\"documentations\" style=\"position:relative;\"><a href=\"#documentations\" aria-label=\"documentations permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Documentations:</h4>\n<ul>\n<li>Improved Installation &#x26; usage guide</li>\n<li>More about different nightwatch configurations.</li>\n<li>More about working with <code>headless</code> mode</li>\n</ul>\n<blockquote>\n<p><em>We are not just delivering automation we deliver values to our customers, some useful tips \"to working with selenium and nightwatch\" can be expected with this release</em></p>\n</blockquote>\n<h3 id=\"september-2020\" style=\"position:relative;\"><a href=\"#september-2020\" aria-label=\"september 2020 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>September 2020:</h3>\n<h4 id=\"code-level-improvements-and-optimizations\" style=\"position:relative;\"><a href=\"#code-level-improvements-and-optimizations\" aria-label=\"code level improvements and optimizations permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Code Level Improvements and Optimizations:</h4>\n<ul>\n<li>Applying Page Object Model for application pages instead of static CSS-selector class.</li>\n<li>Applying async functioning in Test Cases and Custom-Commands to overcome the callback.    </li>\n<li>Updating the Custom-Command as per the latest version of nightwatch.</li>\n<li>Browser Compatibility Testing.</li>\n</ul>\n<h4 id=\"better-reporting\" style=\"position:relative;\"><a href=\"#better-reporting\" aria-label=\"better reporting permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Better Reporting:</h4>\n<ul>\n<li>More detailed, readable and graphical-representation of html reports will be added.</li>\n</ul>\n<blockquote>\n<p><em>Although current configuration does not support different browsers, still you can run on any browser by making few changes in nightwatch.json detailed guide is <a href=\"https://nightwatchjs.org/guide/running-tests/\">here</a></em></p>\n</blockquote>\n<h3 id=\"october-2020\" style=\"position:relative;\"><a href=\"#october-2020\" aria-label=\"october 2020 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>October 2020:</h3>\n<h4 id=\"overcoming-the-limitations\" style=\"position:relative;\"><a href=\"#overcoming-the-limitations\" aria-label=\"overcoming the limitations permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Overcoming the Limitations:</h4>\n<ul>\n<li>The build will be coming up with testing support of IEF feature <code>optional</code> and <code>disabled</code> email verification flows.</li>\n<li>Test Cases for <code>multifactor-authentication</code></li>\n</ul>\n<p>It is agreed that we are committed to delivering you a seamless experience in automation, but still, if you face any issue or need any enhancements, please report us <a href=\"https://github.com/LoginRadius/idx-auto-tester/issues\">here </a></p>\n<!--stackedit_data:\neyJoaXN0b3J5IjpbMjY2MTYyNjE4LDE5MDkzNjIxNjIsLTIyNT\ngwODM3OSwtNDI4ODY2Mjk2LDk1NTk3ODQ4NSwtMTU4Mjc5MDcy\nOF19\n-->\n<style class=\"grvsc-styles\">\n  .grvsc-container {\n    overflow: auto;\n    -webkit-overflow-scrolling: touch;\n    padding-top: 1rem;\n    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));\n    padding-bottom: 1rem;\n    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));\n    border-radius: 8px;\n    border-radius: var(--grvsc-border-radius, 8px);\n    font-feature-settings: normal;\n  }\n  \n  .grvsc-code {\n    display: inline-block;\n    min-width: 100%;\n  }\n  \n  .grvsc-line {\n    display: inline-block;\n    box-sizing: border-box;\n    width: 100%;\n    padding-left: 1.5rem;\n    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));\n    padding-right: 1.5rem;\n    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));\n  }\n  \n  .grvsc-line-highlighted {\n    background-color: var(--grvsc-line-highlighted-background-color, transparent);\n    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, transparent);\n  }\n  \n</style>","frontmatter":{"date":"June 30, 2020","updated_date":null,"description":null,"title":"Roadmap of idx-auto-tester","tags":["Automation","idx","roadmap"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1.7699115044247788,"src":"/static/b5c43b2bffb92542e899a8b9837bd4c5/ee604/roadmap_idx_auto_tester.png","srcSet":"/static/b5c43b2bffb92542e899a8b9837bd4c5/69585/roadmap_idx_auto_tester.png 200w,\n/static/b5c43b2bffb92542e899a8b9837bd4c5/497c6/roadmap_idx_auto_tester.png 400w,\n/static/b5c43b2bffb92542e899a8b9837bd4c5/ee604/roadmap_idx_auto_tester.png 800w,\n/static/b5c43b2bffb92542e899a8b9837bd4c5/f3583/roadmap_idx_auto_tester.png 1200w,\n/static/b5c43b2bffb92542e899a8b9837bd4c5/e4d72/roadmap_idx_auto_tester.png 1280w","sizes":"(max-width: 800px) 100vw, 800px"}}},"author":{"id":"Rakesh Pareek","github":"rkpareek","avatar":null}}}},{"node":{"excerpt":"Today we will learn about the progressive web app, a very interesting and trending topic in current times,  We will start with the basic…","fields":{"slug":"/engineering/build-pwa-using-vanilla-javascript/"},"html":"<p>Today we will learn about the progressive web app, a very interesting and trending topic in current times,  We will start with the basic steps first on how Progressive Web App works with vanilla js. Also, we’ll cover the concept of PWAS without using any of the frameworks, it's just a plain <code>vanillaJS</code>.</p>\n<h2 id=\"what-are-progressive-web-apps\" style=\"position:relative;\"><a href=\"#what-are-progressive-web-apps\" aria-label=\"what are progressive web apps permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>What are Progressive Web Apps?</h2>\n<p>A Progressive Web app is an application which is built on top of <em>HTML</em>, <em>JS</em> and <em>CSS</em> with some extra features like <code>service worker</code> and <code>manifest.json</code> file. These extra features will give the ability to run the web application offline.</p>\n<p>Various big companies are moving towards the progressive web app instead of native apps, as it gives some much flexibility to end-users. In some websites you can find the + icon at the right side of the address bar, those are progressive web apps. </p>\n<h2 id=\"setup-your-base-app-for-pwa\" style=\"position:relative;\"><a href=\"#setup-your-base-app-for-pwa\" aria-label=\"setup your base app for pwa permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Setup your base app for PWA</h2>\n<p>We will be using <code>npm</code> to start our project, so firstly create a root folder using this command <code>mkdir first-pwa-app</code> or another name of your choice then go to that directory by using this command <code>cd first-pwa-app</code>. Run <code>npm init</code></p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"sh\" data-index=\"0\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">npm init</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">package name: (first-pwa-app)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">version: (1.0.0)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">description: This is the first PWA example</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">entry point: (index.js): index.html</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk11\">test</span><span class=\"mtk1\"> command:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">git repository:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">keywords:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">author: Mohammed Modi</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">license: (ISC)</span></span></code></pre>\n<p>Once you fill up those details your final output of the <code>package.json</code> file will be below</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"json\" data-index=\"1\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">{</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">&quot;name&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;first-pwa-app&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">&quot;version&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;1.0.0&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">&quot;description&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;This is the first PWA example&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">&quot;main&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;index.html&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">&quot;scripts&quot;</span><span class=\"mtk1\">: {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk12\">&quot;test&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;echo </span><span class=\"mtk6\">\\&quot;</span><span class=\"mtk8\">Error: no test specified</span><span class=\"mtk6\">\\&quot;</span><span class=\"mtk8\"> && exit 1&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  },</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">&quot;author&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;Mohammed Modi&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">&quot;license&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;ISC&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span></code></pre>\n<p>After that, we need to install the <code>serve</code> dependency to serve the application in localhost so install it using npm <code>npm i serve --save</code>. And then add a script in the <code>package.json</code> file.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"json\" data-index=\"2\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">{</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk14\">...</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">&quot;scripts&quot;</span><span class=\"mtk1\">: {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk12\">&quot;test&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;echo </span><span class=\"mtk6\">\\&quot;</span><span class=\"mtk8\">Error: no test specified</span><span class=\"mtk6\">\\&quot;</span><span class=\"mtk8\"> && exit 1&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk12\">&quot;serve&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;serve .&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  },</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk14\">...</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span></code></pre>\n<p>So finally our application is ready to serve in localhost. Now let's add some <code>html</code> and <code>css</code></p>\n<h3 id=\"setting-up-the-javascript\" style=\"position:relative;\"><a href=\"#setting-up-the-javascript\" aria-label=\"setting up the javascript permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Setting up the Javascript</h3>\n<p>Create a directory for the app and add js, css, and images subdirectories. It should look like this when you’re finished:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"3\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">/first-pwa-app   # Project Folder</span>\n<span class=\"grvsc-line\">    /css     # Stylesheets</span>\n<span class=\"grvsc-line\">    /js      # Javascript</span>\n<span class=\"grvsc-line\">    /images  # Image files.</span>\n<span class=\"grvsc-line\">    package.json</span>\n<span class=\"grvsc-line\">    package-lock.json</span>\n<span class=\"grvsc-line\">    index.html</span>\n<span class=\"grvsc-line\">    manifest.json</span>\n<span class=\"grvsc-line\">    sw.js</span></code></pre>\n<p>You will understand the use of <code>manifest.json</code> and <code>sw.js</code> files once we move ahead in this tutorial.</p>\n<h3 id=\"add-some-code-for-app-interface\" style=\"position:relative;\"><a href=\"#add-some-code-for-app-interface\" aria-label=\"add some code for app interface permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Add Some code for app interface</h3>\n<p>When writing the code for Progressive Web Application we need to keep in mind two requirements</p>\n<ol>\n<li>The landing page should have some content even if the javascript is not loaded</li>\n<li>The App should be responsive and can be properly interactive in any device.</li>\n</ol>\n<p>For this app, to handle the first requirement we will add the static text in the Html page and for the second requirement, we will use the viewport.</p>\n<p>So let's add this code inside the <code>index.html</code> file.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"html\" data-index=\"4\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">&lt;!</span><span class=\"mtk12\">DOCTYPE</span><span class=\"mtk1\"> </span><span class=\"mtk12\">html</span><span class=\"mtk1\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">html</span><span class=\"mtk1\"> </span><span class=\"mtk12\">lang</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;en&quot;</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">head</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">meta</span><span class=\"mtk1\"> </span><span class=\"mtk12\">charset</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;utf-8&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk17\">/&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">title</span><span class=\"mtk17\">&gt;</span><span class=\"mtk1\">My First PWA</span><span class=\"mtk17\">&lt;/</span><span class=\"mtk4\">title</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">link</span><span class=\"mtk1\"> </span><span class=\"mtk12\">rel</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;stylesheet&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk12\">href</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;css/style.css&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk17\">/&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">meta</span><span class=\"mtk1\"> </span><span class=\"mtk12\">name</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;viewport&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk12\">content</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;width=device-width, initial-scale=1.0&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk17\">/&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk17\">&lt;/</span><span class=\"mtk4\">head</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">body</span><span class=\"mtk1\"> </span><span class=\"mtk12\">class</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;fullscreen&quot;</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">div</span><span class=\"mtk1\"> </span><span class=\"mtk12\">class</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;container&quot;</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">      </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">h1</span><span class=\"mtk1\"> </span><span class=\"mtk12\">class</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;title&quot;</span><span class=\"mtk17\">&gt;</span><span class=\"mtk1\">My First PWA!</span><span class=\"mtk17\">&lt;/</span><span class=\"mtk4\">h1</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk17\">&lt;/</span><span class=\"mtk4\">div</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk17\">&lt;/</span><span class=\"mtk4\">body</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk17\">&lt;/</span><span class=\"mtk4\">html</span><span class=\"mtk17\">&gt;</span></span></code></pre>\n<p>Next, we need to create a file <code>css/style.css</code> and paste this code inside this</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"css\" data-index=\"5\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk6\">body</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">font-family</span><span class=\"mtk1\">: </span><span class=\"mtk8\">sans-serif</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">/* Make content area fill the entire browser window */</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">/* Make content area fill the entire browser window */</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk6\">html</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk6\">.fullscreen</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">display</span><span class=\"mtk1\">: </span><span class=\"mtk8\">flex</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">height</span><span class=\"mtk1\">: </span><span class=\"mtk7\">100%</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">margin</span><span class=\"mtk1\">: </span><span class=\"mtk7\">0</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">padding</span><span class=\"mtk1\">: </span><span class=\"mtk7\">0</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">width</span><span class=\"mtk1\">: </span><span class=\"mtk7\">100%</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">/* Center the content in the browser window */</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk6\">.container</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">margin</span><span class=\"mtk1\">: </span><span class=\"mtk8\">auto</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk6\">.title</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">font-size</span><span class=\"mtk1\">: </span><span class=\"mtk7\">3rem</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span></code></pre>\n<p>Once you add the code save all the files and run the script <code>npm run serve</code> which will start your application in <code>http://localhost:5000/</code></p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 80.76923076923077%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAQCAYAAAAWGF8bAAAACXBIWXMAABYlAAAWJQFJUiTwAAABbElEQVQ4y8WUy2rCQBSG8yCikmiSjpPEBLPrQuiq9DWkbxB7odA2bZ/Jnasq8bITfAe3Kgpe8jdzYCRqK9FND/zMwMDHdzgzo7yHnwg/vvD6FiJM9k/PLwiaj2j+kiB4oPNG4x6sYoFbDq2McRSLKu0VXFCj0Qh+zYPnVmGaJhzHBuccnudB2W63yJrVakXAzncHls1Rv6nDtjg0TYOu6yiXy1DiOEbWbDYbAkbdLnSniuvbO3DGoKoqQUUIKEqup0oCe71eAjJRcy1qWdgZhkE5Av5ldwS0KnD9WjIQRmalUomipM1OWaZbFkABMa4YGcp2dy2nLWazGabTKebzORaLBa3L5XLPMIoi5PN5MpJ2R0AxRVHD4RCtVgvj8Rj9fh/tdhuTyYTO1uv1DlgoFGiqaejFLUtDCUznoqGcBcxybf4PmPmlHAxlD5jV7tAwl8vRkzuMIq/LOYaDwYB+F9/34boubNtOfhyH8gPOd+KYkgDmUgAAAABJRU5ErkJggg=='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"First Build\"\n        title=\"First Build\"\n        src=\"/static/328993f8670367e5593427d2344d31d6/e5715/1.png\"\n        srcset=\"/static/328993f8670367e5593427d2344d31d6/a6d36/1.png 650w,\n/static/328993f8670367e5593427d2344d31d6/e5715/1.png 768w,\n/static/328993f8670367e5593427d2344d31d6/53e84/1.png 2074w\"\n        sizes=\"(max-width: 768px) 100vw, 768px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></p>\n<h3 id=\"testing-the-app\" style=\"position:relative;\"><a href=\"#testing-the-app\" aria-label=\"testing the app permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Testing the App</h3>\n<p>As we can see our application is running in the browser, let test it using the <a href=\"https://chrome.google.com/webstore/detail/lighthouse/blipmdconlkpinefehnmjammfjpmpbjk?hl=en\">LightHouse Extension</a> in Google Chrome browser. For the best result, I recommend testing in an <strong>incognito tab</strong> of google chrome.</p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 58.15384615384615%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAABYlAAAWJQFJUiTwAAABuklEQVQoz5WS3Y4SQRCFeQtuRIb5H5jp+elp1sVkE5P1VTS+gOia1QtXfbfdGbiFfQ8gZIHjqVkhIeqKlVQq3Ul/dU51tb7efMfNtx+4/vwF4/FHjD9cHeV73l19usabt++QqAxpmh8yjhUc18do9BKXl69xcfEKLZwY9/MZhjrD6PwMxpTIsgz9fh++7yMIAnieyyYKrc1mg30+PPye6/W6Ad7d3qIfBggIsCwL3W4XnU6nqc+eW2i327BtG63dboenUhpJ1HWNTOcojUGhdZNRFKHX68Fx7KaWZfloWR7+LQ7AqoIKQ+h4gDJJoFWCkGcBiTJR2gD3MKmLxQLL5bKpq9XqSOFkMoEZGkScl03LDkF72B+B2+0W0+kUs9msyfl83gDlXqKq7qCoThcFdJ6jkErbotImWOZqOI7TLXOGWikUgwFiz4PrOOhRmfVLqSiUBkeWn/wUzjBPUxS0lVGdIjwkMOKH+ExRmHC2hz38F7AisOCDF7R7XuQ44x4mvoeEaiOqFaVxHJ9uuaorpFyboS5hqNLQnmID2UvHflT4X8CawISfIrbkoXyG67rcQQcuVTqux/sEPwHkdpQSGWEwNAAAAABJRU5ErkJggg=='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"First Test\"\n        title=\"First Test\"\n        src=\"/static/7e9a07953900a7deec8b038fe9524e96/e5715/2.png\"\n        srcset=\"/static/7e9a07953900a7deec8b038fe9524e96/a6d36/2.png 650w,\n/static/7e9a07953900a7deec8b038fe9524e96/e5715/2.png 768w,\n/static/7e9a07953900a7deec8b038fe9524e96/d9ed5/2.png 2880w\"\n        sizes=\"(max-width: 768px) 100vw, 768px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></p>\n<p>As you can see we have green signals for both of our above requirement:</p>\n<ol>\n<li>Has a <meta name=\"viewport\"> tag with width or initial-scale</li>\n<li>Contains some content when JavaScript is not available</li>\n</ol>\n<p>But still, there is lots of work to do, so let's start with the first feature of PWA's.</p>\n<h3 id=\"adding-a-web-app-manifest\" style=\"position:relative;\"><a href=\"#adding-a-web-app-manifest\" aria-label=\"adding a web app manifest permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Adding a Web App Manifest</h3>\n<p>Let's create a new file called <code>manifest.json</code> in the root of our application. To understand more about the manifest file check out [this doc]</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"json\" data-index=\"6\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">{</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">&quot;name&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;My First Progressive Web app&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">&quot;short_name&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;First PWA&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">&quot;lang&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;en-US&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">&quot;start_url&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;/index.html&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">&quot;display&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;standalone&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">&quot;background_color&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;white&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">&quot;theme_color&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;white&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span></code></pre>\n<p>Now update the <code>index.html</code> head tag by adding the manifest.json file as a link</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"html\" data-index=\"7\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">head</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  ...</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">link</span><span class=\"mtk1\"> </span><span class=\"mtk12\">rel</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;manifest&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk12\">href</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;/manifest.json&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk17\">/&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  ...</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk17\">&lt;/</span><span class=\"mtk4\">head</span><span class=\"mtk17\">&gt;</span></span></code></pre>\n<p>We should also declare the theme colour which should match with your manifest.json file as <code>meta tag</code>.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"html\" data-index=\"8\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">head</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  ...</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">meta</span><span class=\"mtk1\"> </span><span class=\"mtk12\">name</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;theme-color&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk12\">content</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;white&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk17\">/&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  ...</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk17\">&lt;/</span><span class=\"mtk4\">head</span><span class=\"mtk17\">&gt;</span></span></code></pre>\n<p>Once you run the lighthouse test again you can see we got green signals in some points like</p>\n<ol>\n<li>Sets a theme colour for the address bar.</li>\n</ol>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 58.00000000000001%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAABYlAAAWJQFJUiTwAAABuElEQVQoz5WTWW7bMBiEfYv0xdFqWdQuUopRB2jRB18m6A2cNjDykOVohuxnu72GDcPwMhnSC4o2bRMCAwEC+HFmfrL18PiMx6dnjEb3GN5+x+1vGg6/4e5uhJubr8jyEkUhjXIqSXP4foB+/xqDwQCfPn9BC29cP3/M0FMl+h97qKoKRZ4jigSCIEDQ7RLsI8sytLbbLbQ2m82rWq/XBjgejxGJEF0CHMeBbdu4bLdhWTba1MXFB7iui9Z+v8e/pA/TazKZoFQSVX0FqZSREAIu4Z7nmkO0cxNZb/zbOgObBhmjyTiCTBKoNIUIQ9gEaWeWZR2AJ5j+LhYLLJdLo9VqdXC4OwKnU9S9GoJQ17HhEaRdOYSdgIquz8DdbocpN81mM6P5fG6A+r9eDR0WaYJKSqiyRM3vVaVMr6dO3xeZHUpOsUxiRJ0OBKcqfA++e+jvD4f/HQodqiKnq8q4zNmjju0eY2uHKXs938PXYL86bOhQyQJ9Tvq6rqEyDsXzENCpc3SZ8JA3R24mDZIy4yvha2GHJV3GBHQY33TIyO8C6g4rdqSLVxoWxwh5bfRLCUO+mDA2kV8AAfuU5aBuRe0AAAAASUVORK5CYII='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Improving the Application\"\n        title=\"Improving the Application\"\n        src=\"/static/1a6d6e4f756d84ce7645f20d106d8b3b/e5715/3.png\"\n        srcset=\"/static/1a6d6e4f756d84ce7645f20d106d8b3b/a6d36/3.png 650w,\n/static/1a6d6e4f756d84ce7645f20d106d8b3b/e5715/3.png 768w,\n/static/1a6d6e4f756d84ce7645f20d106d8b3b/d9ed5/3.png 2880w\"\n        sizes=\"(max-width: 768px) 100vw, 768px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></p>\n<h3 id=\"app-icons\" style=\"position:relative;\"><a href=\"#app-icons\" aria-label=\"app icons permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>App Icons</h3>\n<p>Still, we need to add more attributes to our <code>manifest.json</code> files like <strong>icons</strong> so let's add the icons inside the <code>images</code> folder, I have used to icons <code>pwa-icon-256.png</code> and <code>pwa-icon-256.png</code> for this demo you can find in this repo. You can use various sizes in it. And finally, add the <code>favicon.png</code> in the root of the project.</p>\n<p>So let's add the <code>icons</code> attribute after the <code>short-name</code></p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"json\" data-index=\"9\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">{</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">&quot;name&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;My First Progressive Web app&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">&quot;short_name&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;First PWA&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">&quot;icons&quot;</span><span class=\"mtk1\">: [</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">      </span><span class=\"mtk12\">&quot;src&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;.images/pwa-icon-256.png&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">      </span><span class=\"mtk12\">&quot;sizes&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;256x256&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">      </span><span class=\"mtk12\">&quot;type&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;image/png&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    },</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">      </span><span class=\"mtk12\">&quot;src&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;.images/pwa-icon-512.png&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">      </span><span class=\"mtk12\">&quot;sizes&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;512x512&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">      </span><span class=\"mtk12\">&quot;type&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;image/png&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  ],</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">&quot;lang&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;en-US&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">&quot;start_url&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;/index.html&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">&quot;display&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;standalone&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">&quot;background_color&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;white&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">&quot;theme_color&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;white&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span></code></pre>\n<p>And the index.html will head can will look like</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"html\" data-index=\"10\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">head</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  ...</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">link</span><span class=\"mtk1\"> </span><span class=\"mtk12\">rel</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;apple-touch-icon&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk12\">href</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;images/pwa-icon-256.png&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk17\">/&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  ...</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk17\">&lt;/</span><span class=\"mtk4\">head</span><span class=\"mtk17\">&gt;</span></span></code></pre>\n<p>You can also verify the <code>manifest.json</code> file by opening Chrome DevTools, in the <strong>Application Tab</strong>, the first tab in the sidebar <strong>manifest</strong></p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 121.23076923076923%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAYCAYAAAD6S912AAAACXBIWXMAABYlAAAWJQFJUiTwAAADbUlEQVQ4y41VyU7jUBD0dwBCJCGb7diOncSOsxL2JSAkhu9h/gDOLDckOCCExIHhyAUuiE+q6erkRYbJYQ6t5+fY5arq6hdrd3cXSZKg2Wyi2+2i1WohTVMkcaz3G42GViz7lZUVFAoFLC0twfd89JsR0qSOlvwWRaE+Zx0fH2Nvbw+bm5sK0G63tTqdDmq1GuJ2iuFoHWm3h2KxqICrq6u65ln5wuQ6n0elUoE1Ho9xcvILp6enODjYx2AwUECy9TxPylf2tm3rS3zZFIFNFaSq1SqsjY0NlcgiSBiGqNfruvKBIBBp/b7eI8NyuYySFFcC5XM5/VBOVt6zxoeHyore0QMCRVGk17ZdRdK00R8O0ekPVH6SdtDpDdSCehjBdly4Yo3j1uD7ASw2hSxHo5H6SPMJSkDHseHYRXi+D78eoibyWX4QSNUz15M9P2Dt7OyIdwc4OjrC+vq6+mUA6ZsnXw1Fbk46nM/nZg2Y7CdStWRfKpVgbW9vK0OyIwi9MpIdx1GfjHeOyKuHDUSNJuIkRaMVoxknqIjX/JA2hZExOSQzUwQlILNHULJlhQJGwGyHTYw0Nnv7+xjSdMldr9dDc9oYw5AgZM1rExdKnQeoDCl1JN5xpXSCZj1UVrIPxHh6xD0Db0D+YchgE6QnGeTa+MHQjJvjugLkossPih3Kdp5kslpbW8O+SN/a2lL5WUAjhcV9W3JYKldQmMrOjqICGqlsDrPIgFOekUyZrrAjIPdxpqtzm0JWBOLKCJEtZ5ldJyM2gLGhb9UfQNmZ/sZwOFxTMLKkZBMjAjK0PFXIjkyZvVbSnttlDTZBKJPRyBZzqF0W0IqEOjc9BDgt+dn1dD89hQhssRmUrN0VkGhaxkOyCmVGJ132ZH49HUfON2fZkxl25X6pVFZQi2C+/BhlwLI5JECSdlVmS8YtEPaBHBQ8EAgay/1EPC+LfwrIDhuJ2dHT2AggZ9jTU8ZTBZeXl3h5ecHj4yNeX//g99mZesfGqWSeMIzJXEDxjw+6sjrTifn6+sL19TXu7+/x9PSkwAsLC7PmfAPMgmZPG7Kk8YzO+/s7rq6ucHt7i4eHB9zd3emf1lyG8wDNQcARZIM+Pz9xfn6Om5sbBSXDxcXF/wek0ebfjvvn52d8fHzg7e1NwS8uLrC8vDwD/As3uxARKwst4AAAAABJRU5ErkJggg=='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Application Manifest\"\n        title=\"Application Manifest\"\n        src=\"/static/1fa7bbfafde2b8b0c2a364cca9c89f36/e5715/5.png\"\n        srcset=\"/static/1fa7bbfafde2b8b0c2a364cca9c89f36/a6d36/5.png 650w,\n/static/1fa7bbfafde2b8b0c2a364cca9c89f36/e5715/5.png 768w,\n/static/1fa7bbfafde2b8b0c2a364cca9c89f36/fbf76/5.png 1252w\"\n        sizes=\"(max-width: 768px) 100vw, 768px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></p>\n<p>After running the test again, we can see all the <code>manifest.json</code> related issues are solved, The remaining issues can be resolved by adding the service worker.</p>\n<h3 id=\"adding-service-worker\" style=\"position:relative;\"><a href=\"#adding-service-worker\" aria-label=\"adding service worker permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Adding Service Worker</h3>\n<p>The next requirement of our app will be the service worker. The service worker is a script that runs in the background without any user interaction.</p>\n<p>The task of service worker will be to download and cache our content and then serve it when the user is offline. To understand more on service workers you can check this doc <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API\">from mozilla</a>.</p>\n<p>To integrate service workers we need to create a file called <code>sw.js</code> in the root of our project.</p>\n<blockquote>\n<p><strong>Note</strong>: Service worker will only have the access to the files of the <strong>current and sub-directories</strong> hence we need to place it in the root of our project</p>\n</blockquote>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"javascript\" data-index=\"11\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk4\">let</span><span class=\"mtk1\"> </span><span class=\"mtk12\">cacheName</span><span class=\"mtk1\"> = </span><span class=\"mtk8\">&quot;my-first-pwa&quot;</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">let</span><span class=\"mtk1\"> </span><span class=\"mtk12\">filesToCache</span><span class=\"mtk1\"> = [</span><span class=\"mtk8\">&quot;/&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk8\">&quot;/index.html&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk8\">&quot;/css/style.css&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk8\">&quot;/js/main.js&quot;</span><span class=\"mtk1\">];</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">/* Start the service worker and cache all of the app&#39;s content */</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">self</span><span class=\"mtk1\">.</span><span class=\"mtk11\">addEventListener</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;install&quot;</span><span class=\"mtk1\">, (</span><span class=\"mtk12\">e</span><span class=\"mtk1\">) </span><span class=\"mtk4\">=&gt;</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">e</span><span class=\"mtk1\">.</span><span class=\"mtk11\">waitUntil</span><span class=\"mtk1\">(</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk12\">caches</span><span class=\"mtk1\">.</span><span class=\"mtk11\">open</span><span class=\"mtk1\">(</span><span class=\"mtk12\">cacheName</span><span class=\"mtk1\">).</span><span class=\"mtk11\">then</span><span class=\"mtk1\">(</span><span class=\"mtk4\">function</span><span class=\"mtk1\"> (</span><span class=\"mtk12\">cache</span><span class=\"mtk1\">) {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">      </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> </span><span class=\"mtk12\">cache</span><span class=\"mtk1\">.</span><span class=\"mtk11\">addAll</span><span class=\"mtk1\">(</span><span class=\"mtk12\">filesToCache</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    })</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  );</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">});</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">/* Serve cached content when offline */</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">self</span><span class=\"mtk1\">.</span><span class=\"mtk11\">addEventListener</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;fetch&quot;</span><span class=\"mtk1\">, (</span><span class=\"mtk12\">e</span><span class=\"mtk1\">) </span><span class=\"mtk4\">=&gt;</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">e</span><span class=\"mtk1\">.</span><span class=\"mtk11\">respondWith</span><span class=\"mtk1\">(</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk12\">caches</span><span class=\"mtk1\">.</span><span class=\"mtk11\">match</span><span class=\"mtk1\">(</span><span class=\"mtk12\">e</span><span class=\"mtk1\">.</span><span class=\"mtk12\">request</span><span class=\"mtk1\">).</span><span class=\"mtk11\">then</span><span class=\"mtk1\">((</span><span class=\"mtk12\">response</span><span class=\"mtk1\">) </span><span class=\"mtk4\">=&gt;</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">      </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> </span><span class=\"mtk12\">response</span><span class=\"mtk1\"> || </span><span class=\"mtk11\">fetch</span><span class=\"mtk1\">(</span><span class=\"mtk12\">e</span><span class=\"mtk1\">.</span><span class=\"mtk12\">request</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    })</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  );</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">});</span></span></code></pre>\n<p>The first 2 variables <code>cacheName</code> and <code>filesToCache</code> are used to create an offline cache in the browser. <code>cacheName</code> is used to create a cache of specific name and <code>filesToCache</code> will be the list of files that we need to cache, <code>/</code> will store the root files that is <code>index.html</code> even if the user does not specify the file name in the URL and then all other files specified in the array.</p>\n<blockquote>\n<p><strong>Note</strong>: Here I have used the <code>filesToCache</code> array as a list of static files just to demonstrate the purpose of PWA, it will stop working in production if even one file fails to load.</p>\n</blockquote>\n<p>Finally, we will load our service worker, for that create <code>js/main.js</code> file and copy the below code.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"js\" data-index=\"12\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk12\">window</span><span class=\"mtk1\">.</span><span class=\"mtk11\">onload</span><span class=\"mtk1\"> = () </span><span class=\"mtk4\">=&gt;</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk8\">&quot;use strict&quot;</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> (</span><span class=\"mtk8\">&quot;serviceWorker&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk4\">in</span><span class=\"mtk1\"> </span><span class=\"mtk12\">navigator</span><span class=\"mtk1\">) {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk12\">navigator</span><span class=\"mtk1\">.</span><span class=\"mtk12\">serviceWorker</span><span class=\"mtk1\">.</span><span class=\"mtk11\">register</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;./sw.js&quot;</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  }</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">};</span></span></code></pre>\n<p>And add this script in the <code>index.html</code> file.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"html\" data-index=\"13\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">...</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">script</span><span class=\"mtk1\"> </span><span class=\"mtk12\">src</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;js/main.js&quot;</span><span class=\"mtk17\">&gt;&lt;/</span><span class=\"mtk4\">script</span><span class=\"mtk17\">&gt;</span></span></code></pre>\n<p>So the final version of our <code>index.html</code> file will look like:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"html\" data-index=\"14\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">&lt;!</span><span class=\"mtk12\">DOCTYPE</span><span class=\"mtk1\"> </span><span class=\"mtk12\">html</span><span class=\"mtk1\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">html</span><span class=\"mtk1\"> </span><span class=\"mtk12\">lang</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;en&quot;</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">head</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">meta</span><span class=\"mtk1\"> </span><span class=\"mtk12\">charset</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;utf-8&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk17\">/&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">title</span><span class=\"mtk17\">&gt;</span><span class=\"mtk1\">Hello World</span><span class=\"mtk17\">&lt;/</span><span class=\"mtk4\">title</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">link</span><span class=\"mtk1\"> </span><span class=\"mtk12\">rel</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;apple-touch-icon&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk12\">href</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;images/pwa-icon-256.png&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk17\">/&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">link</span><span class=\"mtk1\"> </span><span class=\"mtk12\">rel</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;stylesheet&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk12\">href</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;css/style.css&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk17\">/&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">link</span><span class=\"mtk1\"> </span><span class=\"mtk12\">rel</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;manifest&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk12\">href</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;/manifest.json&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk17\">/&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">meta</span><span class=\"mtk1\"> </span><span class=\"mtk12\">name</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;viewport&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk12\">content</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;width=device-width, initial-scale=1.0&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk17\">/&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">meta</span><span class=\"mtk1\"> </span><span class=\"mtk12\">name</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;theme-color&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk12\">content</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;white&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk17\">/&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk17\">&lt;/</span><span class=\"mtk4\">head</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">body</span><span class=\"mtk1\"> </span><span class=\"mtk12\">class</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;fullscreen&quot;</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">div</span><span class=\"mtk1\"> </span><span class=\"mtk12\">class</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;container&quot;</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">      </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">h1</span><span class=\"mtk1\"> </span><span class=\"mtk12\">class</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;title&quot;</span><span class=\"mtk17\">&gt;</span><span class=\"mtk1\">Hello World!</span><span class=\"mtk17\">&lt;/</span><span class=\"mtk4\">h1</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk17\">&lt;/</span><span class=\"mtk4\">div</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">script</span><span class=\"mtk1\"> </span><span class=\"mtk12\">src</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;js/main.js&quot;</span><span class=\"mtk17\">&gt;&lt;/</span><span class=\"mtk4\">script</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk17\">&lt;/</span><span class=\"mtk4\">body</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk17\">&lt;/</span><span class=\"mtk4\">html</span><span class=\"mtk17\">&gt;</span></span></code></pre>\n<p>Now our application is made as fully PWA supported, you can verify it by running the lighthouse test.</p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 58.769230769230774%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAABYlAAAWJQFJUiTwAAAB4ElEQVQoz42SXWsaQRSG/RFNum4I3Zn9/nI/dFeTDYUYKJQW8ldCb1ITelXb/kPBCy9T9cY7Lbjq2zOz1W5Kiz3wMMxcPLxnzmkMv3zD5+FXDImHx0+4//hQcT/AYPCIu7sP6GRdhGGEOE7RihJERJy05d22Xbiuj37/BtfXfTRwpH6slnj/9g3yTht5niFKIvihB8s24XgOLMeEaZmwTMKy0NhsNqhTlhXr9VoKvz89IUsTqM0mVF2FwhScnL+AHdtQeROn5yf09hKKqkBRFDR2ux3+xna7lcL5fI4sy6CeqeAeg8EN+I6Pd7e36HZ70DUD3OHgFgNnvGpZCP6s/dtsNkNRFPRXNqyI2mqZCDsB3NhBQKcdu2CBDo2/gqaxKqGosiyxXC6xWq0k4i6F0xkurgrE1HbezdHO2giiAIxr4AJdg64zMErHOf8tXCwWGI1GmEwmGI/HUl4JpyS8pCFYCHwfvsDz4RomPF2X2CRijFXCoy2T8PLmNUKarqEblKxKIk6NJIK97FnCfw1FtNyjhFESI01T2r3qdF23Ev0SHhIeE05pKFc0lDRJpEy0bNLOsZqozjNhvQ4JSdgrLhBGLbk+AsMwaKLaoc06/yUUQ/HDQCYUhGEo16iedC/8CYFTXfCHL/ezAAAAAElFTkSuQmCC'); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Full PWA Supported\"\n        title=\"Full PWA Supported\"\n        src=\"/static/909cf0352662de4275cd17be5d1e96c0/e5715/6.png\"\n        srcset=\"/static/909cf0352662de4275cd17be5d1e96c0/a6d36/6.png 650w,\n/static/909cf0352662de4275cd17be5d1e96c0/e5715/6.png 768w,\n/static/909cf0352662de4275cd17be5d1e96c0/34e83/6.png 2852w\"\n        sizes=\"(max-width: 768px) 100vw, 768px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></p>\n<h4 id=\"finishing-up\" style=\"position:relative;\"><a href=\"#finishing-up\" aria-label=\"finishing up permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Finishing Up</h4>\n<p>We are done with the code, now the last thing remaining in to host it in any of the <code>https</code> domain. As the PWA will be required to run in <a href=\"/everything-you-want-to-know-about-authorization-headers/\">the secure domain</a>.</p>\n<p>You can get the full source code of this example in this <a href=\"https://github.com/LoginRadius/engineering-blog-samples/tree/master/ProgressiveWebApp/MyFirstPWA\">Github repo</a></p>\n<p>I hope you enjoyed the progressive web apps using vanilla js tutorial and found it useful. Please let me know what you think in the comments below.</p>\n<style class=\"grvsc-styles\">\n  .grvsc-container {\n    overflow: auto;\n    -webkit-overflow-scrolling: touch;\n    padding-top: 1rem;\n    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));\n    padding-bottom: 1rem;\n    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));\n    border-radius: 8px;\n    border-radius: var(--grvsc-border-radius, 8px);\n    font-feature-settings: normal;\n  }\n  \n  .grvsc-code {\n    display: inline-block;\n    min-width: 100%;\n  }\n  \n  .grvsc-line {\n    display: inline-block;\n    box-sizing: border-box;\n    width: 100%;\n    padding-left: 1.5rem;\n    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));\n    padding-right: 1.5rem;\n    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));\n  }\n  \n  .grvsc-line-highlighted {\n    background-color: var(--grvsc-line-highlighted-background-color, transparent);\n    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, transparent);\n  }\n  \n  .dark-default-dark {\n    background-color: #1E1E1E;\n    color: #D4D4D4;\n  }\n  .dark-default-dark .mtk1 { color: #D4D4D4; }\n  .dark-default-dark .mtk11 { color: #DCDCAA; }\n  .dark-default-dark .mtk12 { color: #9CDCFE; }\n  .dark-default-dark .mtk8 { color: #CE9178; }\n  .dark-default-dark .mtk6 { color: #D7BA7D; }\n  .dark-default-dark .mtk14 { color: #F44747; }\n  .dark-default-dark .mtk17 { color: #808080; }\n  .dark-default-dark .mtk4 { color: #569CD6; }\n  .dark-default-dark .mtk3 { color: #6A9955; }\n  .dark-default-dark .mtk7 { color: #B5CEA8; }\n  .dark-default-dark .mtk15 { color: #C586C0; }\n</style>","frontmatter":{"date":"June 26, 2020","updated_date":null,"description":"A simple step-by-step tutorial, all done with pure JavaScript, to set up a simple PWA that can be accessed offline using a web app manifest and a service worker.","title":"How to Build a PWA in Vanilla JS","tags":["PWA","JavaScript"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1.7699115044247788,"src":"/static/1c496ce8fd476e70f4dbf1a97f08619a/ee604/cover.png","srcSet":"/static/1c496ce8fd476e70f4dbf1a97f08619a/69585/cover.png 200w,\n/static/1c496ce8fd476e70f4dbf1a97f08619a/497c6/cover.png 400w,\n/static/1c496ce8fd476e70f4dbf1a97f08619a/ee604/cover.png 800w,\n/static/1c496ce8fd476e70f4dbf1a97f08619a/f3583/cover.png 1200w,\n/static/1c496ce8fd476e70f4dbf1a97f08619a/e4d72/cover.png 1280w","sizes":"(max-width: 800px) 100vw, 800px"}}},"author":{"id":"Mohammed Modi","github":"mohammed786","avatar":null}}}}]},"markdownRemark":{"excerpt":"Google has prepared a roadmap to restrict third-party cookies in Chrome. Since 04 January 2024, Chrome has rolled out third-party cookie…","fields":{"slug":"/engineering/identity-impact-of-google-chrome-thirdparty-cookie-restrictions/"},"html":"<p>Google has prepared a roadmap to restrict third-party cookies in Chrome. Since 04 January 2024, Chrome has rolled out third-party cookie restrictions for 1% of stable clients and 20% of Canary, Dev, and Beta clients.</p>\n<p><strong>What does it mean for user authentication?</strong></p>\n<p>On one hand, Google believes third-party cookies are widely used for cross-site tracking, greatly affecting user privacy. Hence, Google wants to phase out (or restrict) supporting third-party cookies in Chrome by early Q2 2025 (subject to regulatory processes).</p>\n<p>On the other hand, Google introduced Privacy Sandbox to support the use cases (other than cross-site tracking and advertising) previously implemented using third-party cookies.</p>\n<p>In this article, we’ll discuss:</p>\n<ul>\n<li>How is user authentication (identity) affected?</li>\n<li>What is Google offering as part of Privacy Sandbox to support various identity use cases when third-party cookies are phased out?</li>\n</ul>\n<h2 id=\"how-is-user-authentication-affected\" style=\"position:relative;\"><a href=\"#how-is-user-authentication-affected\" aria-label=\"how is user authentication affected permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>How is User Authentication Affected?</h2>\n<p>Third-party cookie restrictions affect user authentication in three ways, as follows.</p>\n<h3 id=\"external-identity-providers\" style=\"position:relative;\"><a href=\"#external-identity-providers\" aria-label=\"external identity providers permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>External Identity Providers</h3>\n<p>If your website or app uses an external Identity Provider (IdP) — like LoginRadius, the IdP sets a third-party cookie when the user authenticates on your app.</p>\n<h3 id=\"web-sso\" style=\"position:relative;\"><a href=\"#web-sso\" aria-label=\"web sso permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Web SSO</h3>\n<p>If you have multiple apps across domains within your organization and authentication is handled using an IdP (internal or external) with web SSO, you already use third-party cookies to facilitate seamless access for each user using a single set of credentials.</p>\n<p>If you have implemented web SSO with one primary domain and multiple sub-domains of the primary domain, third-party cookie restrictions may not apply. For now, Google doesn’t consider the cookies set by sub-domains as third-party cookies, although this stance may change in the future.</p>\n<p>For example, you have apps at <code>example.com</code>, <code>travel.example.com</code>, <code>stay.example.com</code>, and web SSO is handled by <code>auth.example.com</code>. In this case, third-party cookie restrictions don’t apply.</p>\n<h3 id=\"federated-sso\" style=\"position:relative;\"><a href=\"#federated-sso\" aria-label=\"federated sso permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Federated SSO</h3>\n<p>Federated SSO is similar to, albeit different from, web SSO. It can handle multiple IdPs and applications—aka., Service Providers (SPs)—spanning multiple organizations. It can also implement authentication scenarios that are usually implemented through web SSO.</p>\n<p>Usually, authentication is handled on a separate pop-up or page when the user wants to authenticate rather than on the application or website a user visits. </p>\n<p>For example, you already use federated SSO if you facilitate authentication for a set of apps through multiple social identity providers as well as traditional usernames and passwords.</p>\n<blockquote>\n<p><strong>Note</strong>: It is also possible to store tokens locally, not within cookies. In this case, third-party cookie restrictions won’t affect token-based authentication. However, the restrictions still affect authentication where tokens are stored within third-party cookies (a common and secure method).</p>\n</blockquote>\n<h2 id=\"chromes-alternatives-for-third-party-cookies\" style=\"position:relative;\"><a href=\"#chromes-alternatives-for-third-party-cookies\" aria-label=\"chromes alternatives for third party cookies permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Chrome’s Alternatives for Third-Party Cookies</h2>\n<p>Google has been developing alternative features and capabilities for Chrome to replace third-party cookies as part of its Privacy Sandbox for Web initiative.</p>\n<p>Specific to authentication, Google recommends the following:</p>\n<ol>\n<li>Cookies Having Independent Partitioned State (CHIPS)</li>\n<li>Storage Access API</li>\n<li>Related Website Sets</li>\n<li>Federated Credential Management (FedCM) API</li>\n</ol>\n<h3 id=\"cookies-having-independent-partitioned-state-chips\" style=\"position:relative;\"><a href=\"#cookies-having-independent-partitioned-state-chips\" aria-label=\"cookies having independent partitioned state chips permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Cookies Having Independent Partitioned State (CHIPS)</h3>\n<p><a href=\"https://developers.google.com/privacy-sandbox/3pcd/chips\">CHIPS</a> are a restricted way of setting third-party cookies on a top-level site without making them accessible on other top-level sites. Thus, they limit cross-site tracking and enable specific cross-site functionalities, such as maps, chat, and payment embeds.</p>\n<p>For example, a user visits <code>a.com</code> with a map embed from <code>map-example.com</code>, which can set a partitioned cookie that is only accessible on a.com. </p>\n<p>If the user visits <code>b.com</code> with a map embed from <code>map-example.com</code>, it cannot access the partitioned cookie set on <code>a.com</code>. It has to create a separate partitioned cookie specific to <code>b.com</code>, thus blocking cross-site tracking yet allowing limited cross-site functionality.</p>\n<p>You should specifically opt for partitioned cookies (CHIPS), which are set with partitioned and secure cookie attributes.</p>\n<p>If you’re using an external identity provider for your application, CHIPS is a good option to supplant third-party cookie restrictions. </p>\n<p>However, CHIPS may not be ideal if you have a web SSO or federated SSO implementation. It creates separate partitioned cookies for each application with a separate domain, which can increase complexity and create compatibility issues.</p>\n<h3 id=\"storage-access-api\" style=\"position:relative;\"><a href=\"#storage-access-api\" aria-label=\"storage access api permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Storage Access API</h3>\n<p>With <a href=\"https://developers.google.com/privacy-sandbox/3pcd/storage-access-api\">Storage Access API</a>, you can access the local storage in a third-party context through iframes, similar to when users visit it as a top-level site in a first-party context. That is, it gives access to unpartitioned cookies and storage.</p>\n<p>Storage Access API requires explicit user approval to grant access, similar to locations, camera, and microphone permissions. If the user denies access, unpartitioned cookies and storage won’t be accessible in a third-party context.</p>\n<p>It is most suitable when loading cross-site resources and interactions, such as:</p>\n<p>Verifying user sessions when allowing interactions on an embedded social post or providing personalization for an embedded video.\nEmbedded documents requiring user verification status to be accessible.</p>\n<p>As it requires explicit user approval, it is advisable to use Storage Access API when you can’t implement an identity use case with the other options.</p>\n<h3 id=\"related-website-sets\" style=\"position:relative;\"><a href=\"#related-website-sets\" aria-label=\"related website sets permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Related Website Sets</h3>\n<p>With <a href=\"https://developers.google.com/privacy-sandbox/3pcd/related-website-sets\">Related Website Sets</a>, you can declare a <code>primary</code> website and <code>associatedSites</code> for limited purposes to grant third-party cookie access and local storage for a limited number of sites.</p>\n<p>Chrome automatically recognizes related website sets declared, accepted, and maintained in this open-source GitHub repository: <a href=\"https://github.com/GoogleChrome/related-website-sets\">Related Website Sets</a></p>\n<p>It provides access through Storage Access API directly without prompting for user approval, but only after the user interacts with the relevant iframe.</p>\n<p>It is important to declare a limited number of domains in related website sets that are meaningful and used for specific purposes. Google may block or suspend any exploitative use of this feature.</p>\n<p>The top-level site can also request approval for specific cross-site resources and scripts to Storage Access API using <code>resuestStorageAccessFor()</code> API.</p>\n<p>If you’re using an external identity provider for your web application, you can declare the domain of the identity provider in the related set to ensure limited third-party cookies and storage access to the identity provider, thus ensuring seamless user authentication.</p>\n<p>Related Website Sets can also work to supplement third-party cookie restrictions in web SSO and federated SSO if the number of web applications (or domains) is limited.</p>\n<h3 id=\"federated-credential-management-fedcm-api\" style=\"position:relative;\"><a href=\"#federated-credential-management-fedcm-api\" aria-label=\"federated credential management fedcm api permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Federated Credential Management (FedCM) API</h3>\n<p>FedCM API enables federated SSO without third-party cookies.</p>\n<p>With FedCM API, a user follows these steps for authentication:</p>\n<ol>\n<li>The User navigates to a Service Provider (SP) — aka., Relying Party (RP)</li>\n<li>As the user requests to authenticate, the SP requests the browser through FedCM API to initiate authentication.</li>\n<li>The browser displays a list of available identity providers (supported by the RP), such as social IdPs like Google, Apple, LinkedIn, and Facebook, or other OAuth IdPs like LoginRadius.</li>\n<li>Once the user selects an IdP, the browser communicates with the IdP. Upon valid authentication, the IdP generates a secure token.\nThe browser delivers this secure token to the RP to facilitate user authorization.</li>\n</ol>\n<p>You can access a user demo of FedCM here: <a href=\"https://fedcm-rp-demo.glitch.me/\">FedCM</a>. </p>\n<p>For more information about implementing federated SSO with FedCM API, go through the <a href=\"https://developers.google.com/privacy-sandbox/3pcd/fedcm-developer-guide\">FedCM developer guide</a>.</p>\n<h2 id=\"how-is-loginradius-preparing-for-the-third-party-cookie-phase-out\" style=\"position:relative;\"><a href=\"#how-is-loginradius-preparing-for-the-third-party-cookie-phase-out\" aria-label=\"how is loginradius preparing for the third party cookie phase out permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>How is LoginRadius Preparing for the Third-party Cookie Phase-out?</h2>\n<p>Firstly, we’re committed to solving our customers' user identity pain points — and preparing for the third-party cookies phase-out is no different.</p>\n<p>We’ll implement the most relevant and widely useful solutions to facilitate a smooth transition for our customers.</p>\n<p>Please subscribe to our blog for more information. We’ll update you on how we help with the third-party cookie phase-out.</p>\n<h2 id=\"in-conclusion\" style=\"position:relative;\"><a href=\"#in-conclusion\" aria-label=\"in conclusion permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>In Conclusion</h2>\n<p>The proposed changes to phase out third-party cookies and suggested alternatives are evolving as Google has been actively collaborating and discussing changes with the border community.</p>\n<p>Moreover, browsers like Firefox, Safari, and Edge may approach restricting third-party cookies differently than Google does.</p>\n<p>From LoginRadius, we’ll keep you updated on what we’re doing as a leading Customer Identity and Access Management (CIAM) vendor to prepare for the third-party cookie phase-out.</p>\n<h2 id=\"glossary\" style=\"position:relative;\"><a href=\"#glossary\" aria-label=\"glossary permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Glossary</h2>\n<p><strong>Top-level site</strong>: It is the primary site a user has visited.</p>\n<p><strong>First-party cookie</strong>: A cookie set by the top-level site.</p>\n<p><strong>Third-party cookie</strong>: A cookie set by a domain other than the top-level site. For example, let’s assume that a user has visited <code>a.com</code>, which might use an embed from <code>loginradius.com</code> to facilitate authentication. If <code>loginradius.com</code> sets a cookie when the user visits <code>a.com</code>, it is called a third-party cookie as the user hasn’t directly visited <code>loginradius.com</code>.</p>\n<h2 id=\"references\" style=\"position:relative;\"><a href=\"#references\" aria-label=\"references permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>References</h2>\n<ul>\n<li><a href=\"https://developers.google.com/privacy-sandbox/3pcd/prepare/prepare-for-phaseout\">Changes to Chrome's treatment of third-party cookies</a></li>\n<li><a href=\"https://developers.google.com/privacy-sandbox/3pcd/guides/identity\">Check the impact of the third-party cookie changes on your sign-in workflows</a></li>\n</ul>\n<style class=\"grvsc-styles\">\n  .grvsc-container {\n    overflow: auto;\n    -webkit-overflow-scrolling: touch;\n    padding-top: 1rem;\n    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));\n    padding-bottom: 1rem;\n    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));\n    border-radius: 8px;\n    border-radius: var(--grvsc-border-radius, 8px);\n    font-feature-settings: normal;\n  }\n  \n  .grvsc-code {\n    display: inline-block;\n    min-width: 100%;\n  }\n  \n  .grvsc-line {\n    display: inline-block;\n    box-sizing: border-box;\n    width: 100%;\n    padding-left: 1.5rem;\n    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));\n    padding-right: 1.5rem;\n    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));\n  }\n  \n  .grvsc-line-highlighted {\n    background-color: var(--grvsc-line-highlighted-background-color, transparent);\n    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, transparent);\n  }\n  \n</style>","frontmatter":{"date":"July 08, 2024","updated_date":null,"description":"Google Chrome has planned to phase out third-party cookies, which will affect different website functionalities depending on third-party cookies. This blog focuses on how this phase-out affects identity and user authentication and discusses alternatives for overcoming challenges.","title":"How Chrome’s Third-Party Cookie Restrictions Affect User Authentication?","tags":["Identity","Cookies","Chrome"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1.5037593984962405,"src":"/static/eb7396060c0adc430dbed2d04b63d431/ee604/third-party-cookies-phaseout-chrome.png","srcSet":"/static/eb7396060c0adc430dbed2d04b63d431/69585/third-party-cookies-phaseout-chrome.png 200w,\n/static/eb7396060c0adc430dbed2d04b63d431/497c6/third-party-cookies-phaseout-chrome.png 400w,\n/static/eb7396060c0adc430dbed2d04b63d431/ee604/third-party-cookies-phaseout-chrome.png 800w,\n/static/eb7396060c0adc430dbed2d04b63d431/f3583/third-party-cookies-phaseout-chrome.png 1200w","sizes":"(max-width: 800px) 100vw, 800px"}}},"author":{"id":"Raghunath Reddy","github":"raghunath-r-a","avatar":null}}}},"pageContext":{"limit":6,"skip":198,"currentPage":34,"type":"//engineering//","numPages":52,"pinned":"17fa0d7b-34c8-51c4-b047-df5e2bbaeedb"}},"staticQueryHashes":["1171199041","1384082988","2100481360","23180105","528864852"]}