{"id":2176,"date":"2015-07-21T16:34:28","date_gmt":"2015-07-21T23:34:28","guid":{"rendered":"https:\/\/www.microsoft.com\/reallifecode\/index.php\/2015\/07\/21\/microservice-orchestration-with-fleet-on-azure\/"},"modified":"2020-03-18T23:30:12","modified_gmt":"2020-03-19T06:30:12","slug":"microservice-orchestration-with-fleet-on-azure","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/ise\/microservice-orchestration-with-fleet-on-azure\/","title":{"rendered":"Microservice Orchestration with Fleet on Azure"},"content":{"rendered":"<p>Micro-service architecture, the concept of providing a large scale service as a collection of small, highly available services is becoming increasingly popular in today\u2019s modern cloud service deployments. However, with the rise of Docker and other containerization and orchestration technologies, it can be difficult to get started.<\/p>\n<p>In this post, we\u2019ll explore how we collaborated with two Italian tech companies for a week to show how Fleet, a distributed init system and CoreOS, an operating system designed for clusters can be deployed on Microsoft Azure as a collection of high-availability \u2018Dockerized\u2019 microservices.<\/p>\n<h2 id=\"the-problem\">The Problem<\/h2>\n<p>Docebo.com and TOK.tv are two Italian tech companies whose infrastructure currently runs on Amazon Web Services. Docebo.com is an E-Learning platform and hosts instances of its application for various organizations. TOK.tv is the voice social platform designed to help soccer teams offer their fans a unique engagement experience and powers the Real Madrid and Juventus apps, integrating its Social Button and allowing fans of the clubs to talk with voice, send stadium sounds and take social selfies.<\/p>\n<p>Docebo.com already uses Docker containers for its customer deployments and has customized orchestration infrastructure for their instances. However they eventually want to run their infrastructure on CoreOS and will be looking at Fleet for controlling its deployments on Azure.<\/p>\n<p>Tok.tv at the time did not have any containerized services and wanted an orchestration solution that was transparent and flexible enough to run their app services. In particular Tok.tv is primarily composed of a PHP web application API and a real-time voice service.<\/p>\n<h2 id=\"overview-of-the-solution\">Overview of the Solution<\/h2>\n<p>We worked face to face with the partners to create a prototype solution of deploying Dockerized microservices across a cluster of CoreOS machines using fleet. Fleet is a distributed init system which can deploy arbitrary processes across a cluster of machines. Often it\u2019s used to deploy Docker containers. It contains settings to ensure that a service runs on separate nodes within the cluster to ensure high availability. To provision CoreOS we used an Azure CoreOS <a href=\"https:\/\/github.com\/Azure\/azure-quickstart-templates\/tree\/master\/coreos-with-fleet-multivm\">resource manager template<\/a> which allows easy creation of a CoreOS cluster with an external load balancer.<\/p>\n<p>We used a private Docker registry to deploy the Docker images for service deployment. Private registries are useful when you don\u2019t want to expose the internals of your service infrastructure as open source images on the Docker Hub. Although Docker Hub hosts private registries for a monthly fee, it is also easy to host your own private registry on premesis or on other cloud platforms such as Microsoft Azure. These registries can hold images of all your deployment services, from support services like HTTP servers to application-level images for things like websites and background workers.<\/p>\n<p>The private registry server is deployed from the Docker Hub and its image store is backed by Azure blob storage. This makes our Docker registry \u2018portable\u2019 allowing us to deploy services using Fleet by pushing images to our private repository from anywhere with access to Azure storage, including your local machine:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/cse\/wp-content\/uploads\/sites\/55\/2020\/03\/2015-07-21-TokTvDoceboFleetCaseStudy_images-image001.png\" alt=\"Architecture\" \/><\/p>\n<p>Figure 1. Service Deployment via Azure Storage-backed Private Docker Registry<\/p>\n<p>In the image above, we use our no-cost single Docker Hub repository to store the Docker image of our registry server. The server image is built with our Azure storage credentials and can be run from anywhere with an Internet connection.<\/p>\n<p>This enables the architecture in <strong>Figure 1<\/strong>, which allows us to deploy our registry as a Fleet global service, which basically means one registry server runs on every server. This is because Docker requires images in private repositories be tagged with the name of their host. By hosting a light-weight registry server on each CoreOS instance we greatly simplify deploying images.<\/p>\n<p>Once our registry service is deployed across the cluster with Fleet, we can deploy any image within that registry as a service on the cluster. The graphic above depicts the scenario of a developer, running a registry on their local machine and pushing an image to Azure storage via the server. The service is then restarted and the new image is deployed to the appropriate nodes.<\/p>\n<p>Using an external image store allows us to run a private Docker image repository without having to worry about SSL and authenticating users to our repository. We also get the advantage of the redundancy and backup features of Azure Storage.<\/p>\n<p><strong>Service Discovery<\/strong><\/p>\n<p>CoreOS uses <u>etcd<\/u>, a demon service that is essentially a distributed key-value store that allows services to announce their presence by publishing keys with a Time-to-live (TTL). Each deployed application instance is deployed with an accompanying \u2018announcer\u2019 service which is simply a bash script that periodically writes its host ip address and port number for it\u2019s corresponding web server.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/cse\/wp-content\/uploads\/sites\/55\/2020\/03\/2015-07-21-TokTvDoceboFleetCaseStudy_images-image002.png\" alt=\"Architecture\" \/><\/p>\n<p>Figure 2. Service Discovery with \u2018Sidekick\u2019 Services &amp; Etcd<\/p>\n<p>Fleet allows us to specifically define announcer or \u2018<a href=\"https:\/\/coreos.com\/docs\/launching-containers\/launching\/launching-containers-fleet\/#run-a-simple-sidekick\">sidekick<\/a>\u2019 services, which are guaranteed to run on the same machine as the service it monitors. When the accompanying application service goes down so does the sidekick service. Because etcd has time-to-live values for each key etcd keeps up-to-date in the case of application failures, updates and restarts since the sidekick will stop writing to etcd.<\/p>\n<p><strong>Figure 2<\/strong> shows each <strong>router<\/strong> instance subscribes to etcd and it uses published keys in etcd to build its routing and load balancing rules via <a href=\"https:\/\/github.com\/kelseyhightower\/confd\">confd<\/a> templating. For example, <strong>App1<\/strong> exists on the first two VMs and between the two instances their corresponding \u2018sidekick\u2019 services update the service directory key App1 with the key-value pairs @1: 192.168.1.1:3000 and @2 192.168.1.2:3000. Routing and load-balancing within the cluster is done via <a href=\"http:\/\/nginx.org\/en\">Nginx<\/a>, a popular high performance web server. Because the <strong>nginx<\/strong> router is subscribed to etcd it automatically rebuilds its routing template. Requests going for <strong>app1<\/strong> will route to either of these two machines in a round-robin load-balancing manner. The same goes for App2 &#8211; this design allows for any number of applications to be deployed backed by any number of instances.<\/p>\n<p>Here\u2019s what the App1 <a href=\"\/\/\/\\UserssteveDocumentsfleet-boostrapperexample-appexample-app@.service\">service<\/a> <a href=\"https:\/\/github.com\/sedouard\/fleet-bootstrapper\/blob\/master\/example-app\/example-app%40.service\">file<\/a> looks like:<\/p>\n<div class=\"highlighter-rouge\">\n<pre class=\"highlight\"><code># example-app@.service\r\n# the '@' in the file name denotes that this unit file is a model Description=Example High-Availabilty Web App After=router.service  \r\n\r\n[Service]\r\nEnvironmentFile=\/etc\/environment\r\nExecStartPre=\/usr\/bin\/docker pull localhost:5000\/example-app:latest\r\nExecStart=\/usr\/bin\/docker run --name example -p 3000:3000 localhost:5000\/example-app:latest ExecStop=\/usr\/bin\/docker stop example\r\nExecStopPost=\/usr\/bin\/docker kill example\r\nExecStopPost=\/usr\/bin\/docker rm example\r\n\r\n[X-Fleet]\r\nConflicts=example-app@*.service\r\n<\/code><\/pre>\n<\/div>\n<p>This <a href=\"https:\/\/coreos.com\/docs\/launching-containers\/launching\/fleet-unit-files\/\">Unit File<\/a> refers to the docker image example-app in our private azure docker registry. To start this unit we simply do:<\/p>\n<div class=\"highlighter-rouge\">\n<pre class=\"highlight\"><code># upload the service model to fleet\r\nfleetctl submit example-app@.service\r\n# start an instance of the service\r\nfleetctl start example-app@1.service\r\n<\/code><\/pre>\n<\/div>\n<p>The X-Fleet Conflicts tag in the unit file instructs fleet that we don\u2019t want more than one of this unit, an instance of the service, running on the same machine in order to have high availability.<\/p>\n<p><strong>Routing &amp; Load Balancing<\/strong><\/p>\n<p>The entire cluster sits behind a load balancer and has one public virtual IP address. This public IP address points to an Azure load balancer, which serves requests to any of our nodes.<\/p>\n<p>One advantage of using an external load balancer for the cluster is that you only need one public IP address, rather than a unique one for each instance. Cloud service providers such as Microsoft Azure have limits to public IP allocation per subscription. Also, as machines go up and down, the public IP address doesn\u2019t change and simplifies DNS zone file settings.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/cse\/wp-content\/uploads\/sites\/55\/2020\/03\/2015-07-21-TokTvDoceboFleetCaseStudy_images-image003.png\" alt=\"Architecture\" \/><\/p>\n<p>Figure 3. Azure Load Balancer spreads loads to each internal NginX instance<\/p>\n<p>When a user request comes in, because we have the <strong>router<\/strong> running and listening on port 80 and port 443 on each node, we can handle the request no matter what node it comes to. Further, because of <strong>etcd<\/strong> service discovery each router has knowledge about where all the services are located and can route the request the appropriate container.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/cse\/wp-content\/uploads\/sites\/55\/2020\/03\/2015-07-21-TokTvDoceboFleetCaseStudy_images-image004.png\" alt=\"Architecture\" \/><\/p>\n<p>Figure 4. Internal NginX instance routes request and load balances between app containers<\/p>\n<p>This means that the actual container, which provides the service, doesn\u2019t necessarily need to be on the machine that the Azure load balancer selects, as show in <strong>Figure 5.<\/strong><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/cse\/wp-content\/uploads\/sites\/55\/2020\/03\/2015-07-21-TokTvDoceboFleetCaseStudy_images-image005.png\" alt=\"Architecture\" \/><\/p>\n<p>Figure 5. The Machines Selected by Azure Load Balancer doesn\u2019t need to actually run requested App<\/p>\n<p>Furthermore, the Azure load balancer load balances requests amongst our router, but each <strong>router<\/strong> service unit load balances the containers for each service.<\/p>\n<p>This prototype solution we built during the hackfest will be the basis of Tok.tv and Docebo\u2019s microservice architecture.<\/p>\n<h2 id=\"code-artifacts\">Code Artifacts<\/h2>\n<p><a href=\"https:\/\/github.com\/sedouard\/fleet-bootstrapper\">How to Deploy High Availability Apps to Azure using CoreOS with Fleet &amp; etcd \u2013 A getting started guide &amp; code sample for Docker Orchestration w\/ Fleet<\/a><\/p>\n<p><a href=\"https:\/\/github.com\/docker\/docker.github.io\/blob\/master\/registry\/storage-drivers\/azure.md\">Azure Storage driver for Docker Registry Server<\/a><\/p>\n<h2 id=\"opportunities-for-reuse\">Opportunities for Reuse<\/h2>\n<p>The <a href=\"https:\/\/github.com\/sedouard\/fleet-bootstrapper\">Fleet bootstrapper guide<\/a> can be reused for anyone who wants to use portable, private Docker registries along with Fleet to deploy high-availability apps across a CoreOS cluster.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Micro-service architecture, the concept of providing a large scale service as a collection of small, highly available services is becoming increasingly popular in today&#8217;s modern cloud service deployments. However, with the rise of Docker and other containerization and orchestration technologies, it can be difficult to get started.<\/p>\n","protected":false},"author":21345,"featured_media":12725,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[16],"tags":[60,135,156,179],"class_list":["post-2176","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devops","tag-azure","tag-coreos","tag-docker","tag-fleet"],"acf":[],"blog_post_summary":"<p>Micro-service architecture, the concept of providing a large scale service as a collection of small, highly available services is becoming increasingly popular in today&#8217;s modern cloud service deployments. However, with the rise of Docker and other containerization and orchestration technologies, it can be difficult to get started.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/posts\/2176","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/users\/21345"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/comments?post=2176"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/posts\/2176\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/media\/12725"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/media?parent=2176"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/categories?post=2176"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/tags?post=2176"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}