{"id":1299,"date":"2019-02-16T04:38:19","date_gmt":"2019-02-16T04:38:19","guid":{"rendered":"https:\/\/www.appservgrid.com\/paw93\/?p=1299"},"modified":"2019-02-17T02:38:54","modified_gmt":"2019-02-17T02:38:54","slug":"deploy-python-application-open-source-load-balancer","status":"publish","type":"post","link":"https:\/\/www.appservgrid.com\/paw93\/index.php\/2019\/02\/16\/deploy-python-application-open-source-load-balancer\/","title":{"rendered":"Deploy Python Application | Open Source Load Balancer"},"content":{"rendered":"<p><a href=\"http:\/\/cdn.rancher.com\/wp-content\/uploads\/2015\/05\/12160315\/google-cloud-platform.jpg\"><img decoding=\"async\" src=\"http:\/\/cdn.rancher.com\/wp-content\/uploads\/2015\/05\/12160315\/google-cloud-platform.jpg\" alt=\"google cloud\nplatform\" \/><\/a>Recently<br \/>\nRancher provided a disk image to be used to deploy RancherOS v0.3 on<br \/>\nGoogle Compute Engine (GCE). The image supports RancherOS cloud config<br \/>\nfunctionality. Additionally, it merges the SSH keys from the project,<br \/>\ninstance and cloud-config and adds them to the rancher user.<\/p>\n<h2>Building The Setup<\/h2>\n<p>In this post, I will cover how to use the RancherOS image on GCE to set<br \/>\nup a MongoDB Replica Set. Additionally I will cover how to use one of<br \/>\nthe recent features of Rancher platform which is the Load Balancer. In<br \/>\norder to make the setup more realistic, I created a simple python<br \/>\napplication, that will count the number of hits on the website and save<br \/>\nthis number on MongoDB database. The setup will include multiple servers<br \/>\non different cloud hosting providers:<\/p>\n<ol>\n<li>three (g1-small) servers on GCE to deploy the MongoDB replicaset.<\/li>\n<li>one (n1-standard-1) server on GCE to install the Rancher platform.<\/li>\n<li>one server on Digital Ocean to hold the application containers.<\/li>\n<li>one server on Digital Ocean which will be used as a Load Balancer on<br \/>\nRancher platform.<\/li>\n<\/ol>\n<h2>RancherOS On GCE<\/h2>\n<p>We will import RancherOS disk image on GCE to be used later in the<br \/>\nsetup. To import the image you need to create a Google Cloud Storage<br \/>\nobject which we will upload the RancherOS disk image. To create cloud<br \/>\nstorage object, you can use the web UI:<br \/>\n<a href=\"http:\/\/cdn.rancher.com\/wp-content\/uploads\/2015\/05\/12160315\/1.jpg\"><img decoding=\"async\" src=\"http:\/\/cdn.rancher.com\/wp-content\/uploads\/2015\/05\/12160315\/1.jpg\" alt=\"1\" \/><\/a><br \/>\nOr you can use gsutil tool that lets you access Google Cloud<br \/>\nStorage service from the command line, but first you need to<br \/>\n<a href=\"https:\/\/cloud.google.com\/storage\/docs\/gsutil_install#authenticate\">authenticate<\/a><br \/>\ngsutil to be able to create new storage object. Now you need to upload<br \/>\nthe image to the newly created storage object:<br \/>\n<a href=\"http:\/\/cdn.rancher.com\/wp-content\/uploads\/2015\/05\/12160315\/2.jpg\"><img decoding=\"async\" src=\"http:\/\/cdn.rancher.com\/wp-content\/uploads\/2015\/05\/12160315\/2.jpg\" alt=\"2\" \/><\/a><br \/>\nThe only thing left to do is creating the RancherOS image which will be<br \/>\nused later, click on create new image under the Images section:<br \/>\n<a href=\"http:\/\/cdn.rancher.com\/wp-content\/uploads\/2015\/05\/12160315\/3.jpg\"><img decoding=\"async\" src=\"http:\/\/cdn.rancher.com\/wp-content\/uploads\/2015\/05\/12160315\/3.jpg\" alt=\"3\" \/><\/a><\/p>\n<h2>Start RancherOS On GCE<\/h2>\n<p>After creating RancherOS image, create three machines that will be used<br \/>\nto set up a MongoDB replica set and select RancherOS as their image:<br \/>\n<a href=\"http:\/\/cdn.rancher.com\/wp-content\/uploads\/2015\/05\/12160315\/5.jpg\"><img decoding=\"async\" src=\"http:\/\/cdn.rancher.com\/wp-content\/uploads\/2015\/05\/12160315\/5.jpg\" alt=\"5\" \/><\/a><br \/>\nFor the sake of this setup I created a Networking zone with one rule<br \/>\nthat opens every TCP\/UDP port on the server. Obviously, you shouldn\u2019t do<br \/>\nthat on a production server.<\/p>\n<h2>Docker Images<\/h2>\n<p>Now since the RancherOS image is ready, we need to get the Docker images<br \/>\nready too. We will be using a Docker image for MongoDB and for the<br \/>\nPython application. I will be using the <a href=\"https:\/\/registry.hub.docker.com\/_\/mongo\/\">official<br \/>\nMongoDB<\/a> image, which will<br \/>\nsimply run MongoDB server. However, to run the container as a part of<br \/>\nthe replica set you need to add &#8211;replicaSet option to the running<br \/>\ncommand. And for the python application I will be using a Docker image<br \/>\nwhich will pull the Flask application from github and run it using<br \/>\nGunicorn, of course if you need to add more sense of \u201cproduction\u201d to the<br \/>\nsetup you will need to add more tweaks to the Docker image, but this<br \/>\nexample is good enough to give you a good idea about the setup. The<br \/>\nDockerfile of the python application:<\/p>\n<p>FROM ubuntu:latest<br \/>\nMAINTAINER Hussein Galal<\/p>\n<p>RUN apt-get -q update<br \/>\nRUN apt-get install -yqq python python-dev python-distribute python-pip python-virtualenv<br \/>\nRUN apt-get install -yqq build-essential git<\/p>\n<p>RUN mkdir -p \/var\/www\/app<br \/>\nADD run.sh \/tmp\/run.sh<br \/>\nADD gunicorn.py \/var\/www\/app\/<br \/>\nRUN chmod u+x \/tmp\/run.sh<br \/>\nEXPOSE 80<br \/>\nWORKDIR \/var\/www\/app\/<br \/>\nENTRYPOINT \/tmp\/run.sh<\/p>\n<p>The run.sh script will pull the <a href=\"https:\/\/github.com\/galal-hussein\/Flask-example-app.git\">Flask<br \/>\nApplication<\/a><br \/>\nfrom github and run Gunicorn:<\/p>\n<p>git clone https:\/\/github.com\/galal-hussein\/Flask-example-app.git ..\/app<\/p>\n<p>virtualenv venv<br \/>\n.\/venv\/bin\/pip install gunicorn<br \/>\n.\/venv\/bin\/pip install -r requirements.txt<br \/>\n.\/venv\/bin\/gunicorn -c gunicorn.py app:app<\/p>\n<p>Let\u2019s now build and push this image to Docker hub to be used later when<br \/>\nwe deploy the applications:<\/p>\n<p>~# docker build -t husseingalal\/flask_app .<br \/>\n~# docker push husseingalal\/flask_app<\/p>\n<p>The flask application is very simple, it displays the number of<br \/>\npageviews and the os hostname just to make sure that the load balancer<br \/>\nis working fine, here is a small snippet from the application:<\/p>\n<p>@app.route(&#8216;\/&#8217;)<br \/>\ndef cntr():<br \/>\nmongo.db.rancher.update({&#8220;Project&#8221; : &#8220;Rancher&#8221;}, {&#8220;$inc&#8221; : {&#8220;pageviews&#8221; : 1}}, True)<br \/>\nposts = mongo.db.rancher.find({&#8220;Project&#8221;:&#8221;Rancher&#8221;})[0]<br \/>\nreturn render_template(&#8216;index.html&#8217;, posts=posts, hostname=socket.gethostname())<\/p>\n<h2>Rancher Platform<\/h2>\n<p>Rancher is a container management platform, that can connect containers<br \/>\nacross different host and it provides a set of features including: load<br \/>\nbalancing, monitoring, logging, and integration with existing user<br \/>\ndirectories (e.g., GitHub) for identity management. To deploy Rancher<br \/>\nplatform on a machine, login to the machine and run this command:<\/p>\n<p>~# docker run -d -p 8080:8080 rancher\/server<\/p>\n<p>This command will create a Docker instance with a Rancher server that<br \/>\nlistens on port 8080 and proxy that port to port 8080 on the host. After<br \/>\nrunning that command wait a few minutes until the server is ready, and<br \/>\nthen login to the server:<br \/>\n<a href=\"http:\/\/cdn.rancher.com\/wp-content\/uploads\/2015\/05\/12160315\/6.jpg\"><img decoding=\"async\" src=\"http:\/\/cdn.rancher.com\/wp-content\/uploads\/2015\/05\/12160315\/6.jpg\" alt=\"6\" \/><\/a><br \/>\nThe next step is to register the machines with the Rancher platform,<br \/>\non Rancher platform, click on \u201cAdd Host\u201d to register the each machine.<br \/>\nOn Rancher platform you have the option to use the Docker Machine<br \/>\nintegration to directly create Digital Ocean, or Amazon EC2 machines, or<br \/>\nyou can just copy the registering command to any server that has Docker<br \/>\ninstalled:<br \/>\n<a href=\"http:\/\/cdn.rancher.com\/wp-content\/uploads\/2015\/05\/12160315\/7.jpg\"><img decoding=\"async\" src=\"http:\/\/cdn.rancher.com\/wp-content\/uploads\/2015\/05\/12160315\/7.jpg\" alt=\"7\" \/><\/a><br \/>\nAfter running the command on the 3 MongoDB servers, you will see<br \/>\nsomething like that:<br \/>\n<a href=\"http:\/\/cdn.rancher.com\/wp-content\/uploads\/2015\/05\/12160315\/8.jpg\"><img decoding=\"async\" src=\"http:\/\/cdn.rancher.com\/wp-content\/uploads\/2015\/05\/12160315\/8.jpg\" alt=\"8\" \/><\/a><\/p>\n<h2>MongoDB Replica Set<\/h2>\n<p>Replication ensures that your data will exist on different servers to<br \/>\nincrease availability, in MongoDB you can set up replication by creating<br \/>\nreplica set. Replica set is a group of MongoDB servers. A primary server<br \/>\nand multiple secondary servers that keep identical copies of the primary<br \/>\nserver. MongoDB achieves that by keeping a log of operations called<br \/>\noplog, that contain the write operations. The secondary servers also<br \/>\nmaintain their own oplog, they fetch the operations from the member they<br \/>\nare syncing from. I \u2019ll create 3 MongoDB containers, each on different<br \/>\nhost. Each container will run with &#8211;replSet option which specify a<br \/>\nname for the replica set:<br \/>\n<a href=\"http:\/\/cdn.rancher.com\/wp-content\/uploads\/2015\/05\/12160315\/9.jpg\"><img decoding=\"async\" src=\"http:\/\/cdn.rancher.com\/wp-content\/uploads\/2015\/05\/12160315\/9.jpg\" alt=\"9\" \/><\/a><br \/>\nCreate the rest of the MongoDB containers with the same option to be<br \/>\npart of the replication group. After creating the 3 containers you<br \/>\nshould initiate the replication by connecting to the MongoDB instance<br \/>\nand run rs.initiate(config) in the MongoDB Javascript shell:<\/p>\n<p>&gt; config = {<br \/>\n&#8220;_id&#8221; : &#8220;rancher&#8221;,<br \/>\n&#8220;members&#8221; : [<br \/>\n{&#8220;_id&#8221; : 0, &#8220;host&#8221; : &#8220;&lt;ip-of-the-1st-container&gt;:27017&#8221;},<br \/>\n{&#8220;_id&#8221; : 1, &#8220;host&#8221; : &#8220;&lt;ip-of-the-2nd-container&gt;:27017&#8221;},<br \/>\n{&#8220;_id&#8221; : 2, &#8220;host&#8221; : &#8220;&lt;ip-of-the-3rd-container&gt;:27017&#8221;}<br \/>\n]<br \/>\n}<br \/>\n&gt; rs.initiate(config)<\/p>\n<p>rancher:PRIMARY&gt;<\/p>\n<p>That means that this container is the primary server for the MongoDB<br \/>\nreplica set.<\/p>\n<h2>Deploy The App Containers<\/h2>\n<p>Now let\u2019s deploy the application container that we created earlier,<br \/>\nwe\u2019ll create two app containers which we will load balancer between<br \/>\nthem in the next section. To differentiate between each app container i<br \/>\nwill specify the hostname of each container as an option when we create<br \/>\nthe container:<br \/>\n<a href=\"http:\/\/cdn.rancher.com\/wp-content\/uploads\/2015\/05\/12160315\/10.jpg\"><img decoding=\"async\" src=\"http:\/\/cdn.rancher.com\/wp-content\/uploads\/2015\/05\/12160315\/10.jpg\" alt=\"10\" \/><\/a><br \/>\nThe second container will be created with the same options as the first<br \/>\none, but we will map the port 80 to port 8001 to be able to test the<br \/>\ncontainer separately.<\/p>\n<h2>Rancher\u2019s Load Balancer<\/h2>\n<p>The final step is to create a load balancer to bounce the requests<br \/>\nbetween the two app containers, Rancher\u2019s Load Balancer distributes<br \/>\nnetwork traffic across a number of containers. For each host that will<br \/>\nbe selected to be a Load Balancer a Load Balancer Agent system container<br \/>\nis started and HAProxy software is installed in it. For more information<br \/>\nabout <a href=\"http:\/\/rancher.com\/load-balancing-support-for-docker-in-rancher\/\">Rancher\u2019s Load<br \/>\nBalancer.<\/a><br \/>\nTo create a Load Balancer using Rancher\u2019s platform, make sure to select<br \/>\nthe application containers, and select the port you will be receiving<br \/>\nand sending requests. Also note that we used round robin algorithm to<br \/>\ndistribute the requests between the two app containers, the other<br \/>\nalgorithms available to use are leastconn, and source.<br \/>\n<a href=\"http:\/\/cdn.rancher.com\/wp-content\/uploads\/2015\/05\/12160315\/11.jpg\"><img decoding=\"async\" src=\"http:\/\/cdn.rancher.com\/wp-content\/uploads\/2015\/05\/12160315\/11.jpg\" alt=\"11\" \/><\/a><br \/>\n<a href=\"http:\/\/cdn.rancher.com\/wp-content\/uploads\/2015\/05\/12160315\/12.jpg\"><img decoding=\"async\" src=\"http:\/\/cdn.rancher.com\/wp-content\/uploads\/2015\/05\/12160315\/12.jpg\" alt=\"12\" \/><\/a><br \/>\nYou can also configure Health Checks to monitor the availability of<br \/>\nthe application containers, you can configure the health checks by using<br \/>\nGET, HEAD, POST, etc. In this example, i created an endpoint called<br \/>\n\/healthcheck that will be used to check if the application server is<br \/>\nup and running:<br \/>\n<a href=\"http:\/\/cdn.rancher.com\/wp-content\/uploads\/2015\/05\/12160315\/13.jpg\"><img decoding=\"async\" src=\"http:\/\/cdn.rancher.com\/wp-content\/uploads\/2015\/05\/12160315\/13.jpg\" alt=\"13\" \/><\/a><br \/>\nNow let\u2019s test the setup, by access the url of the Load Balancer:<br \/>\n<a href=\"http:\/\/cdn.rancher.com\/wp-content\/uploads\/2015\/05\/12160315\/14.jpg\"><img decoding=\"async\" src=\"http:\/\/cdn.rancher.com\/wp-content\/uploads\/2015\/05\/12160315\/14.jpg\" alt=\"14\" \/><\/a><br \/>\n<a href=\"http:\/\/cdn.rancher.com\/wp-content\/uploads\/2015\/05\/12160315\/15.jpg\"><img decoding=\"async\" src=\"http:\/\/cdn.rancher.com\/wp-content\/uploads\/2015\/05\/12160315\/15.jpg\" alt=\"15\" \/><\/a><br \/>\nAlso you can check the \/healthcheck endpoint to check that the app is up<br \/>\nand running:<\/p>\n<p>$ curl http:\/\/45.55.210.170\/healthcheck<br \/>\n200 OK From app1<\/p>\n<p>$ curl http:\/\/45.55.210.170\/healthcheck<br \/>\n200 OK From app2<\/p>\n<h2>Conclusion<\/h2>\n<p>Now RancherOS V0.3.0 can be deployed in Google Compute Engine (GCE).<br \/>\nUsing RancherOS and Rancher platform you can put together a production<br \/>\nenvironment that uses the most recent features of Rancher platform like<br \/>\nload balancing which allow devs and ops to deploy large-scale<br \/>\napplications. Both Rancher and RancherOS are open source tools, and can<br \/>\nbe downloaded from <a href=\"https:\/\/github.com\/rancherio\">Github<\/a>. If you\u2019re<br \/>\ninterested in learning more, join our next Online Meetup to hear from<br \/>\nsome of our developers, and see the latest features going into the<br \/>\nRancher and RancherOS projects. You can register below:<\/p>\n<p><a href=\"https:\/\/rancher.com\/deploying-a-python-app-with-mongodb-replicaset-using-rancher-and-rancheros\/\" target=\"_blank\" rel=\"noopener\">Source<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Recently Rancher provided a disk image to be used to deploy RancherOS v0.3 on Google Compute Engine (GCE). The image supports RancherOS cloud config functionality. Additionally, it merges the SSH keys from the project, instance and cloud-config and adds them to the rancher user. Building The Setup In this post, I will cover how to &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/www.appservgrid.com\/paw93\/index.php\/2019\/02\/16\/deploy-python-application-open-source-load-balancer\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Deploy Python Application | Open Source Load Balancer&#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-1299","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\/1299","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=1299"}],"version-history":[{"count":1,"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/posts\/1299\/revisions"}],"predecessor-version":[{"id":1312,"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/posts\/1299\/revisions\/1312"}],"wp:attachment":[{"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/media?parent=1299"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/categories?post=1299"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/tags?post=1299"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}