{"id":1356,"date":"2019-02-21T07:21:42","date_gmt":"2019-02-21T07:21:42","guid":{"rendered":"https:\/\/www.appservgrid.com\/paw93\/?p=1356"},"modified":"2019-03-07T20:19:16","modified_gmt":"2019-03-07T20:19:16","slug":"architecture-of-ranchers-docker-machine-integration","status":"publish","type":"post","link":"https:\/\/www.appservgrid.com\/paw93\/index.php\/2019\/02\/21\/architecture-of-ranchers-docker-machine-integration\/","title":{"rendered":"Architecture of Rancher&#8217;s Docker-machine Integration"},"content":{"rendered":"<p>As you may have seen, Rancher <a href=\"http:\/\/rancher.com\/rancher-adds-support-for-docker-machine-provisioning\/\">recently announced\u00a0<\/a>our integration<br \/>\nwith <a href=\"https:\/\/github.com\/docker\/machine\">docker-machine<\/a>. This<br \/>\nintegration will allow users to spin up Rancher compute nodes across<br \/>\nmultiple cloud providers right from the Rancher UI. In our initial<br \/>\nrelease, we supported Digital Ocean. Amazon EC2 is soon to follow and<br \/>\nwe\u2019ll continue to add more cloud providers as interest dictates. We<br \/>\nbelieve this feature will really help the Zero-to-Docker _(and<br \/>\nZero-to-Rancher)_ experience. But the feature itself is not the focus<br \/>\nof this post. In this post, I want to detail the software architerture<br \/>\nemployed to achieve this integration. First, it\u2019s important to<br \/>\nunderstand that everyhting in Rancher is an API resource with a process<br \/>\nlifecycle. Containers, images, networks, and accounts are all API<br \/>\nresources with their own process lifecycles. When you deploy a machine<br \/>\nin the Rancher UI, you\u2019re creating a machine resource. It has three<br \/>\nlife cycle processes: 1. Create 2. Bootstrap 3. Delete The create<br \/>\nprocess is kicked off when the user creates a machine in the UI. When<br \/>\nthe create process completes, it auotmatically kicks off the bootstrap<br \/>\nprocess. Delete (perhaps obviously) occurs when the user chooses to<br \/>\ndelete or destroy the host. Our integration with machine is achieved<br \/>\nthrough a microservice that hooks into Rancher machine lifecycle events<br \/>\nand execs out to the docker-machine binary accordingly. You can check<br \/>\nout the source code for this service here:<br \/>\nh<a href=\"\/\/github.com\/rancherio\/go-machine-service\">ttps:\/\/github.com\/rancherio\/go-machine-service<\/a>.<br \/>\nLogically, the interaction looks like this:<br \/>\n<a href=\"http:\/\/cdn.rancher.com\/wp-content\/uploads\/2015\/03\/31092535\/machine.png\"><img decoding=\"async\" src=\"http:\/\/cdn.rancher.com\/wp-content\/uploads\/2015\/03\/31092535\/machine.png\" alt=\"machine\" \/><\/a><br \/>\n<em>&#8230;Sorry for the bad graphic. Anyway&#8230;<\/em> When you spin up Rancher<br \/>\nwith docker run rancher\/server &#8230; with the default configuration, the<br \/>\nRancher API, Rancher Process Server, DB, and Machine Microservice are<br \/>\nall processes living inside that container (and in fact, the API and<br \/>\nprocess server are the same process). The docker-machine binary is in<br \/>\nthe container as well but only runs when it is called. You may at this<br \/>\npoint be wondering about that event bus. In Rancher, <em>we keep eventing<br \/>\ndead-simple<\/em> and above all follow this principle:<\/p>\n<blockquote><p>There is no such thing as reliable messaging.<\/p><\/blockquote>\n<p>So, that \u201cevent bus\u201d consists of the microservice making a POST<br \/>\nrequest to the \/subsribe API endpoint. The response is a stream of<br \/>\nnewline-terminated json events, similar in concept to the <a href=\"http:\/\/www.craigjellick.com\/working-with-docker-events\/\">docker event<br \/>\nstream<\/a>. The<br \/>\nprocess server is responsible for firing (and refiring) events until it<br \/>\nreceives a reply event (another API POST) indicating the event was<br \/>\nhandled. Further event handlers are blocked until the current event<br \/>\nhandler replies successfully. The microservice is responsible for<br \/>\nhandling the events, replying, and acting idempotently so that refires<br \/>\ncan occur without ill-effect. So when the machine microservie receives a<br \/>\ncreate event, it translate the machine API resource\u2019s prooperties into<br \/>\na docker-machine cli command and execs out to it. Since the machine<br \/>\ncreation process is long lived, the service monitors the standard out<br \/>\nand error of the call and sends corresponding status updates to the<br \/>\nRancher server. These are then presented to the user in the UI. When<br \/>\ndocker-machine reports that the machine was successfully created, the<br \/>\nmicroservice will reply to the original event it received from the<br \/>\nRancher server. The successful end of the create event will cause the<br \/>\nprocess server to automatically kick off the bootstrap event, which<br \/>\nmakes it way right back down to the machine microservice. When that<br \/>\nevent is received, we\u2019ll again exec out to docker-machine to get the<br \/>\ndetails needed to connect to the machine\u2019s docker daemon. We do this by<br \/>\nexecuting the docker-machine config command and parsing the response.<br \/>\nWith the connection parameters in hand, the service fires up a rancher<br \/>\nagent on the machine via docker run &#8230; rancher\/agent &#8230;. This is the<br \/>\nexact same command that a user would run if they wanted to manaully join<br \/>\na server to Rancher. When that container is up and running, it will<br \/>\nreport into the Rancher server and start hooking into container<br \/>\nlifecycle events in much the same way that this service hooks into<br \/>\nmachine lifecycle events. From there, it\u2019s business as normal for the<br \/>\nRancher server and the machine\u2019s rancher-agent. That about does it for<br \/>\nthe technical architecture of our docker-machine integration. There are<br \/>\na lot more interesting but minor technical detail to share, but I<br \/>\ndidn\u2019t want to go too far off into the weeds in this post. I\u2019ll write<br \/>\nup some follow up post sharing those details in the not-too-distant<br \/>\nfuture. Finally, shout out (and thanks) to <a href=\"https:\/\/github.com\/ehazlett\">Evan<br \/>\nHaslett<\/a>, <a href=\"https:\/\/github.com\/bfirsh\">Ben<br \/>\nFirshman<\/a>, and the rest of the docker-machine<br \/>\nteam and community for the help along the way. We look forward to more<br \/>\nexciting work with the docker-machine, including getting RancherOS in<br \/>\nthere. If you\u2019d like to learn more about Rancher, please schedule a<br \/>\ndemo and we\u2019ll walk you through the latest features, and our<br \/>\nfuture roadmap. <em>Note: This post also appears<br \/>\non Craig\u2019s personal blog<br \/>\n<a href=\"http:\/\/www.craigjellick.com\/architercutre-of-rancher-docker-machine-integration\/\">here<\/a>.<br \/>\nFeel free to check out that blog for more software engineering<br \/>\ninsights.<\/em><\/p>\n<p><a href=\"https:\/\/rancher.com\/architercutre-of-ranchers-docker-machine-integration\/\" target=\"_blank\" rel=\"noopener\">Source<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>As you may have seen, Rancher recently announced\u00a0our integration with docker-machine. This integration will allow users to spin up Rancher compute nodes across multiple cloud providers right from the Rancher UI. In our initial release, we supported Digital Ocean. Amazon EC2 is soon to follow and we\u2019ll continue to add more cloud providers as interest &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/www.appservgrid.com\/paw93\/index.php\/2019\/02\/21\/architecture-of-ranchers-docker-machine-integration\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Architecture of Rancher&#8217;s Docker-machine Integration&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[],"class_list":["post-1356","post","type-post","status-publish","format-standard","hentry","category-kubernetes"],"_links":{"self":[{"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/posts\/1356","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/comments?post=1356"}],"version-history":[{"count":1,"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/posts\/1356\/revisions"}],"predecessor-version":[{"id":1431,"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/posts\/1356\/revisions\/1431"}],"wp:attachment":[{"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/media?parent=1356"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/categories?post=1356"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/tags?post=1356"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}