{"id":4656,"date":"2022-09-03T20:50:48","date_gmt":"2022-09-03T20:50:48","guid":{"rendered":"https:\/\/dalelane.co.uk\/blog\/?p=4656"},"modified":"2022-09-06T20:38:12","modified_gmt":"2022-09-06T20:38:12","slug":"geo-steering-with-ibm-code-engine-and-cloud-internet-services","status":"publish","type":"post","link":"https:\/\/dalelane.co.uk\/blog\/?p=4656","title":{"rendered":"Geo-steering with IBM Code Engine and Cloud Internet Services"},"content":{"rendered":"<p><strong>In this post, I want to share a small tip from how I run Machine Learning for Kids: how I run instances of the site in different regions, and use geo-steering so that users are directed to the instance of the site nearest to them.<\/strong><\/p>\n<p><img decoding=\"async\" src=\"\/\/dalelane.co.uk\/blog\/post-images\/220903-cis\/20220903-mlforkids.png\" style=\"border: thin black solid\"\/><\/p>\n<p><!--more--><\/p>\n<h3>Using multiple regions for reliability and resilience<\/h3>\n<p>I started by following the Code Engine docs for &#8220;<a href=\"https:\/\/cloud.ibm.com\/docs\/codeengine?topic=codeengine-deploy-multiple-regions\">Deploying an app across multiple regions<\/a>&#8220;.<\/p>\n<p>In that example, they run two instances of their app: one in the US, one in the EU.<\/p>\n<p>They send all traffic to the US app instance, and if a redirect doesn&#8217;t work, they send that request to the EU instance as a fall-back.<\/p>\n<p><img decoding=\"async\" src=\"\/\/dalelane.co.uk\/blog\/post-images\/220903-cis\/20220903-docs-1.png\" style=\"border: thin black solid\"\/><br \/>\n<img decoding=\"async\" src=\"\/\/dalelane.co.uk\/blog\/post-images\/220903-cis\/20220903-docs-2.png\" style=\"border: thin black solid\"\/><\/p>\n<p>That does work. But I didn&#8217;t like that as an approach.<\/p>\n<p>It has a very noticeable impact on the responsiveness of your site for users who aren&#8217;t in the US to send all your traffic to an instance hosted in Dallas.<\/p>\n<p>Plus, using the EU instance of the app as a hot stand-by in this way means that, most of the time, it would never get any traffic, which feels like a waste of resources. <sup>[1]<\/sup><\/p>\n<h3>Using multiple regions for responsiveness and usability<\/h3>\n<p>I want to run my site in multiple regions, and I want to use all of them. I don&#8217;t want a fall-back region, I want to send traffic to every instance of the app.<\/p>\n<p>More importantly, I know that it makes my site noticeably more responsive to send users to an instance of the app hosted near to them, and I want those usability and performance benefits.<\/p>\n<p>To do this, I did things slightly differently to the approach described in the official docs. I&#8217;ll describe it here in case you think it might be useful for your app.<\/p>\n<p>The full gorpy detail for how I run Machine Learning for Kids is in <a href=\"https:\/\/github.com\/IBM\/taxinomitis\/blob\/master\/DEPLOYMENT.md\">GitHub<\/a> but a simplified version looks like this:<\/p>\n<p><img decoding=\"async\" src=\"\/\/dalelane.co.uk\/blog\/post-images\/220903-cis\/20220903-mlforkids.png\" style=\"border: thin black solid\"\/><\/p>\n<p>I run three instances of each of the microservices that make up the Machine Learning for Kids site:<\/p>\n<ul>\n<li>one in the US<\/li>\n<li>one in Europe<\/li>\n<li>one in Australia<\/li>\n<\/ul>\n<p>I added an &#8220;<strong>IP geolocation header<\/strong>&#8221; Page Rule to all of the site subdomains. (For more details about how to do this, see the docs on &#8220;<a href=\"https:\/\/cloud.ibm.com\/docs\/cis?topic=cis-use-page-rules\">Using page rules<\/a>&#8220;.)<\/p>\n<p><img decoding=\"async\" src=\"\/\/dalelane.co.uk\/blog\/post-images\/220903-cis\/20220903-pagerule.png\" style=\"border: thin black solid\"\/><\/p>\n<p>This adds a new request header to incoming requests: <code style=\"font-weight: bold\">cf-ipcountry<\/code> (For more details about this header, see the Cloudflare docs on &#8220;<a href=\"https:\/\/developers.cloudflare.com\/fundamentals\/get-started\/reference\/http-request-headers\/#cf-ipcountry\">HTTP request headers<\/a>&#8220;).<\/p>\n<p>The header is a two-character code for the country that the user is in. I&#8217;m using this to decide which instance of the site to send the user to.<\/p>\n<p>I could have just mapped each country code to the nearest instance of the app to that country, but that felt like it would&#8217;ve been a pain to maintain. I&#8217;ll likely want to change the number of instances of the app in future.<\/p>\n<p>(For example, at the moment I&#8217;m sending traffic from Middle East and African countries to the instance in the European region, but I want to be able to add a fourth instance of the app for those countries &#8211; without needing to make changes to the mappings for dozens of countries).<\/p>\n<p>Instead, I&#8217;ve mapped each of the country codes that I could get in the cf-ipcountry header to the Cloudflare region that the country is in.<br \/>\n(You can see these in <a href=\"https:\/\/github.com\/IBM\/taxinomitis\/blob\/master\/cis\/countries.json\">countries.json<\/a>.)<\/p>\n<p><img decoding=\"async\" src=\"\/\/dalelane.co.uk\/blog\/post-images\/220903-cis\/20220903-countries.png\" style=\"border: thin black solid\"\/><\/p>\n<p>Then I&#8217;ve mapped each Cloudflare region to one of my Code Engine projects.<br \/>\n(You can see these in <a href=\"https:\/\/github.com\/IBM\/taxinomitis\/blob\/master\/cis\/regions.json\">regions.json<\/a>.)<\/p>\n<p><img decoding=\"async\" src=\"\/\/dalelane.co.uk\/blog\/post-images\/220903-cis\/20220903-regions.png\" style=\"border: thin black solid\"\/><\/p>\n<p>This means if I decide to run a new instance of the app for one of these regions, it will make it super easy to direct traffic from a Cloudflare region to it.<\/p>\n<p>You can see what it looks like to combine this with the edge function shown in the official docs in my <a href=\"https:\/\/github.com\/IBM\/taxinomitis\/blob\/4e1fe383004b46d99d5e49b0b2c0bfdd6b91bbf9\/cis\/edge-functions.js#L22-L101\">edge-functions.js<\/a> file.<\/p>\n<p><img decoding=\"async\" src=\"\/\/dalelane.co.uk\/blog\/post-images\/220903-cis\/20220903-edgefunction.png\" style=\"border: thin black solid\"\/><\/p>\n<p>Notice that I&#8217;m still keeping the reliability benefits from the official approach &#8211; if the redirect to the nearest instance fails because of an outage in that region, I still want to be able to fall back to another region.<\/p>\n<h3>For more info<\/h3>\n<p>If you&#8217;d like to know more about how the Machine Learning for Kids site is deployed, have a look at <a href=\"https:\/\/github.com\/IBM\/taxinomitis\/blob\/master\/DEPLOYMENT.md\">the DEPLOYMENT.md page<\/a> on GitHub, or please feel free to ask me. Most of it is fairly specific and unique to my site, but I thought this aspect in particular was worth sharing.<\/p>\n<hr \/>\n<p>[1] &#8211; To be fair, you could set the min-instances to 0 and let it scale to zero. But when your primary instance is unavailable, I wouldn&#8217;t want to be waiting for my fall-back region to spin up &#8211; so I&#8217;m not a fan of that, either.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this post, I want to share a small tip from how I run Machine Learning for Kids: how I run instances of the site in different regions, and use geo-steering so that users are directed to the instance of the site nearest to them.<\/p>\n","protected":false},"author":1,"featured_media":4665,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7,4],"tags":[587],"class_list":["post-4656","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-code","category-ibm","tag-mlforkids-tech"],"_links":{"self":[{"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/posts\/4656","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=4656"}],"version-history":[{"count":0,"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/posts\/4656\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/media\/4665"}],"wp:attachment":[{"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=4656"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=4656"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dalelane.co.uk\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=4656"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}