<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Ivan Ermilov on Medium]]></title>
        <description><![CDATA[Stories by Ivan Ermilov on Medium]]></description>
        <link>https://medium.com/@ivanermilov?source=rss-1ecc07b04f2e------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/0*PBML3gmTFQZJbNXo.jpg</url>
            <title>Stories by Ivan Ermilov on Medium</title>
            <link>https://medium.com/@ivanermilov?source=rss-1ecc07b04f2e------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 15 Nov 2026 10:32:39 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@ivanermilov/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Adventures in Rotterdam or ART Hotel Rotterdam is scam]]></title>
            <link>https://medium.com/@ivanermilov/adventures-in-rotterdam-or-art-hotel-rotterdam-is-scam-9a123e575fa7?source=rss-1ecc07b04f2e------2</link>
            <guid isPermaLink="false">https://medium.com/p/9a123e575fa7</guid>
            <category><![CDATA[art-hotel-rotterdam]]></category>
            <category><![CDATA[rotterdam]]></category>
            <category><![CDATA[travel]]></category>
            <category><![CDATA[ranting]]></category>
            <category><![CDATA[hotel]]></category>
            <dc:creator><![CDATA[Ivan Ermilov]]></dc:creator>
            <pubDate>Thu, 27 Dec 2018 10:16:53 GMT</pubDate>
            <atom:updated>2018-12-27T14:26:55.303Z</atom:updated>
            <content:encoded><![CDATA[<p>These are my travel notes from a trip to Rotterdam, where me and my wife had an encounter with ART Hotel Rotterdam. In this post I will be ranting, because the ART Hotel Rotterdam is the largest scam I have seen in my little trip. STAY AWAY FROM THIS HOTEL.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*I5xGJ0cs2S0QO332XpWDUQ.jpeg" /></figure><p>The arrival and check in was quite normal with friendly ladies helping you charge money from your credit card. This part almost never fails, right? Me and my wife went to an elevator and put out baggage in the room and went to explore the city. The problems started when we came back.</p><p>When you just come into the room, there is a kitchen. That’s awesome, right? And then some details come into light. It is equipped with an exhaust hood (I’ve checked it actually works), but there is no cooking surface (wtf?). Looks like a grotesque joke to me. With only 2 glasses, 2 cups and a tiny water boiler. No tea or coffee are available on arrival. There are no knifes, no forks, nothing.</p><p>The next thing, the heating did not work. The heating was the largest problem for me, because my wife got cold easily. When I complained to reception…</p><p>Good luck on reaching out to the reception by the internal phone line. They do not pick up the phone or pick up and put you on hold. <em>I had to come down from the 10th floor to talk to them. Twice.</em></p><p>So the reception, they had a standard procedure to go to the heating room and reset the heating system. Took them around 40 minutes to do so. After they realize that the problem is not solvable (I feel they were not surprised), they borrowed me an electric heater. Which I obviously can not use in the shower. Thus I should be ready to have wet air in the room for all duration of the stay. And yes of course, the heating problem is a <strong>regular</strong> issue. I spend twenty minutes reading bad reviews on Google maps for this hotel.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*D7KnzCDauP3dPXj_wqlYKQ.jpeg" /></figure><p><em>The screenshot is taken on 27.12.2018, a month ago would be in November 2018. </em>Every second review is complaining about not working heating.</p><p>The building itself is built like an old Stalin’s panel house. When you expect this.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*87Wvs67gEoxkf3mNAf2CzA.jpeg" /></figure><p>You should actually see this picture in your mind.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*RAE3J2nbuy8L3BiWC4-oQQ.jpeg" /></figure><p>You can hear the farts of your neighbors. What is ridiculous is that they write to be quiet and do not play &#39;loud&#39; music or disturb your neighbors by obnoxious behavior. I wonder if they consider farts to be obnoxious. I could hear people talking in the rooms nearby. The hotel was built from the ground up with no investment in the sound proofing. Just one more fact: our room was on the tenth floor and I could still hear the trains and the cars down there. Do not expect good sleep here.</p><p>And the house rules, omfg. Alarm! Somebody chew on your house rules. But wait, shouldn’t they have house rules with corporate style design and on good paper in a 4 star hotel? And &quot;Tell your complaints to managers&quot; they say. In our case, the management was simply not available. It was second day of Christmas, but it is a hotel. And it does not have anybody, who can take on responsibility to solve any problems. Yes, they can charge you for getting a room. No, they can not change a room in case of a problem.</p><p>I rant, rant, and rant again. What did I do to solve this? I called booking.com and in the end switched to another hotel. In the middle of the night, together with my wife. Trying to get my money back now.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=9a123e575fa7" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to fix: “inotify cannot be used, reverting to polling: Too many open files”]]></title>
            <link>https://medium.com/@ivanermilov/how-to-fix-inotify-cannot-be-used-reverting-to-polling-too-many-open-files-bb1c1437dbf?source=rss-1ecc07b04f2e------2</link>
            <guid isPermaLink="false">https://medium.com/p/bb1c1437dbf</guid>
            <category><![CDATA[linux]]></category>
            <category><![CDATA[linux-kernel]]></category>
            <category><![CDATA[inotify]]></category>
            <dc:creator><![CDATA[Ivan Ermilov]]></dc:creator>
            <pubDate>Tue, 17 Jul 2018 11:37:38 GMT</pubDate>
            <atom:updated>2018-07-17T11:37:38.007Z</atom:updated>
            <content:encoded><![CDATA[<p>You are here because you had encountered the error in the title. In this article I will explain the error and steps necessary to reproduce and fix it.</p><p>The most relevant documentation for inotify is the <a href="https://linux.die.net/man/7/inotify">inotify man page,</a> that you can also read locally with:</p><blockquote>$ man inotify</blockquote><p>inotify has three parameters, that can be set in /proc interfaces: `max_user_instances`, `max_user_watches` and `max_queued_events`. We will look into each of them separately.</p><blockquote>$ cat /proc/sys/fs/inotify/max_user_instances<br>128</blockquote><p>This specifies an upper limit on the number of inotify instances that can be created per real user ID. inotify instance is created by inotify_init (2) call and returns a file descriptor referring to the inotify instance. Usually each process (e.g. tail) creates one inotify instance. There is an example down below.</p><blockquote>$ cat /proc/sys/fs/inotify/max_user_watches<br>8192</blockquote><p>This specifies an upper limit on the number of watches that can be created per real user ID. Each “watch” in the watch list specifies the pathname of a file or directory, along with some set of events that the kernel should monitor for the file referred to by that pathname. One inotify instance can have several inotify watches, which points to different directories/files.</p><blockquote>$ cat /proc/sys/fs/inotify/max_queued_events <br>16384</blockquote><p>`max_queued_events` is an upper limit on the number of events that can be queued to the corresponding inotify instance. As one inotify instance can have several “watches” (i.e. watching potentially large amount of directories/files), not all of the events (like file change, new file etc.) can be processed immediately. In this case, the events will populate an event queue, which has limit of 16384 events by default. the event queue can overflow. In this case, events are dropped (lost).</p><p>Now, I demonstrate how max_user_instances and max_user_watches work together. For the demo I will use the following commands:</p><blockquote>$ export ILIMIT=128<br>$ for((i=0;i&lt;=$ILIMIT;i+=1)); do echo $i &gt;&gt; $i.tmp; done<br>$ for((i=0;i&lt;=$ILIMIT;i+=1)); do bash -c “tail -f $i.tmp &amp;”; done<br>$ ps aux | grep -v grep | grep tail | awk ‘{print $2}’ | xargs kill -9</blockquote><p>The first one is simply exports ILIMIT variable to your current shell and sets its’ value to 128. The second command creates ($ILIMIT+1) files in your current working directory with names 0.tmp, 1.tmp, 2.tmp etc. The third command starts tail -f ($ILIMIT + 1) times on all the files created by the previous command. Finally the last command look for all the tail processes and kills them.</p><p>Now, try to execute the commands with the $ILIMIT set to 128:</p><blockquote>cd /tmp<br>export ILIMIT=128<br>for((i=0;i&lt;=$ILIMIT;i+=1)); do echo $i &gt;&gt; $i.tmp; done<br>for((i=0;i&lt;=$ILIMIT;i+=1)); do bash -c “tail -f $i.tmp &amp;”; done</blockquote><p>On Ubuntu 18.04 I hit the limit on 86th instance:</p><blockquote>tail: inotify cannot be used, reverting to polling: Too many open files</blockquote><p>I will now increase max_user_instances to set it higher than max_user_watches:</p><blockquote>sudo sysctl -w fs.inotify.max_user_instances=10000<br>$ cat /proc/sys/fs/inotify/max_user_instances <br>10000</blockquote><p>Clean up your previous tail commands:</p><blockquote>ps aux | grep -v grep | grep tail | awk ‘{print $2}’ | xargs kill -9</blockquote><p>Now try to create 8500 tail processes, which is lower than default max_user_watches value:</p><blockquote>cd /tmp<br>export ILIMIT=8500<br>for((i=0;i&lt;=$ILIMIT;i+=1)); do echo $i &gt;&gt; $i.tmp; done<br>for((i=0;i&lt;=$ILIMIT;i+=1)); do bash -c “tail -f $i.tmp &amp;”; done</blockquote><p>I hit the limit on 7996 and have another inotify error message now:</p><blockquote>tail: inotify resources exhausted<br>tail: inotify cannot be used, reverting to polling</blockquote><p>Now let’s increase the max_user_watches and keep it in the same proportion as in default settings. Each inotify instance should have 64 watches available:</p><blockquote>sudo sysctl -w fs.inotify.max_user_watches=640000<br>$ cat /proc/sys/fs/inotify/max_user_watches <br>640000</blockquote><p>Clean up tail processes spawned previously:</p><blockquote>ps aux | grep -v grep | grep tail | awk ‘{print $2}’ | xargs kill -9</blockquote><p>Now let’s try it again:</p><blockquote>cd /tmp<br>export ILIMIT=8500<br>for((i=0;i&lt;=$ILIMIT;i+=1)); do echo $i &gt;&gt; $i.tmp; done<br>for((i=0;i&lt;=$ILIMIT;i+=1)); do bash -c “tail -f $i.tmp &amp;”; done</blockquote><p>And now it has been successfully executed! To make a permanent change to the max_user_instances and max_user_watches variable, simply append these lines to /etc/sysctl.conf:</p><blockquote>fs.inotify.max_user_instances=10000<br>fs.inotify.max_user_watches=640000</blockquote><p>This will persist the changes after reboot of the machine. To apply the changes immediately, you need to reload the file:</p><blockquote>$ sudo sysctl -p</blockquote><p>I hope it clarifies a bit why this error happens and how to fix it.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=bb1c1437dbf" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Crawling and Filtering CKAN Metadata Stores]]></title>
            <link>https://medium.com/@ivanermilov/crawling-and-filtering-ckan-metadata-stores-ca01acb4c72a?source=rss-1ecc07b04f2e------2</link>
            <guid isPermaLink="false">https://medium.com/p/ca01acb4c72a</guid>
            <category><![CDATA[open-data]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[rdf]]></category>
            <category><![CDATA[ckan]]></category>
            <dc:creator><![CDATA[Ivan Ermilov]]></dc:creator>
            <pubDate>Wed, 30 Aug 2017 07:51:49 GMT</pubDate>
            <atom:updated>2017-08-30T07:51:49.446Z</atom:updated>
            <content:encoded><![CDATA[<p>In this blogpost I highlight <a href="https://github.com/dice-group/ckan-aggregator-py">ckan-aggregator-py</a>, a Python library, which crawls <a href="https://ckan.org/">CKAN</a> metadata stores and can specifically filter RDF datasets. The library was developed as a helper for <a href="http://lodstats.aksw.org/">LODStats</a> application and was used to scrape RDF datasets and load them into the application for further processing (see figure 1). At the moment of writing the following CKAN stores are available for crawling using ckan-aggregator-py:</p><ul><li><a href="http://catalog.data.gov/">data.gov</a></li><li><a href="http://datahub.io/">datahub.io</a></li><li><a href="http://open.canada.ca/data/en/">opencanada</a></li><li><a href="http://publicdata.eu/">publicdata.eu</a></li><li><a href="https://opendata.leipzig.de/">opendata.leipzig.de</a></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*x66xv2W61W0Illj2CYCZtw.png" /><figcaption>Figure 1. LODStats architecture overview.</figcaption></figure><p>To install ckan-aggregator-py, simply execute the following commands (you may need to install <a href="https://virtualenvwrapper.readthedocs.io/">virtualenvwrapper</a> before proceeding):</p><pre>$ mkvirtualenv aggregator-py<br>$ cdvirtualenv<br>$ mkdir src &amp;&amp; cd src<br>$ git clone git@github.com:dice-group/ckan-aggregator-py.git &amp;&amp; cd ckan-aggregator-py<br>$ pip install -r requirements.txt</pre><p>This will create Python virtual environment called aggregator-py and clone ckan-aggregator-py src/ckan-aggregator-py in the created virtual env.</p><p>Now, run init.sh script to create folders for storing crawled data:</p><pre>$ ./init.sh</pre><p>By default ckan-aggregator-py can access CKAN without the API key. If you want to have more requests to a CKAN endpoint than an average user, it is a good idea to register on a CKAN instance and use an API key. To configure an API key simply override <em>__init__.py</em> with <em>__init__.py-example-key</em> from the same folder. For example, for datahub.io:</p><pre>$ cp ckanaggregatorpy/datahubio/__init__.py-example-key ckanaggregatorpy/datahubio/__init__.py</pre><p>Then edit the new <em>__init__.py</em> file in your favorite editor.</p><p>We are now ready to crawl a CKAN datastore. Here we demonstrate usage of ckan-aggregator-py for scraping the Open Leipzig data portal. For this example, we implemented open-leipzig.py script. To run the example simply execute the script:</p><pre>$ python open-leipzig.py</pre><p>You will see output showing the number of packages in the CKAN instance, the number of RDF packages and example metadata of a single RDF package.</p><pre>Leipzig Open Data portal contains 579 packages.<br>Updating the local package cache<br>...<br>...<br>...<br>Leipzig Open Data portal contains 85 packages, which contain RDF data<br>Showing metadata from CKAN for the first RDF package<br>{u&#39;author&#39;: u&#39;Amt f\xfcr Statistik und Wahlen&#39;,<br>u&#39;author_email&#39;: u&#39;mailto:statistik-wahlen@leipzig.de&#39;,<br>u&#39;ckan_url&#39;: u&#39;https://opendata.leipzig.de//dataset/allgemeinbildende-schulen&#39;,<br>u&#39;creator_user_id&#39;: u&#39;2046a73a-e0c2-42b6-bd8c-8da6ad8c552d&#39;,<br>...<br>...<br>...<br>u&#39;version&#39;: None}</pre><p>The metadata of the filtered packages can be further processed, transformed and loaded into applications (e.g. LODStats).</p><p>To read more blog posts on Data Science tools and libraries, subscribe to <a href="https://cs.uni-paderborn.de/ds/news-list/">the blog of our DICE research group</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ca01acb4c72a" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Big Data Europe Integrator Platform Release]]></title>
            <link>https://medium.com/@ivanermilov/big-data-europe-integrator-platform-release-add291585151?source=rss-1ecc07b04f2e------2</link>
            <guid isPermaLink="false">https://medium.com/p/add291585151</guid>
            <category><![CDATA[spark]]></category>
            <category><![CDATA[docker-swarm]]></category>
            <category><![CDATA[docker]]></category>
            <category><![CDATA[hadoop]]></category>
            <category><![CDATA[deb]]></category>
            <dc:creator><![CDATA[Ivan Ermilov]]></dc:creator>
            <pubDate>Wed, 03 May 2017 09:02:21 GMT</pubDate>
            <atom:updated>2017-05-03T09:02:28.608Z</atom:updated>
            <content:encoded><![CDATA[<p>We are happy to release BDE Integrator platform. I have prepared a screencast on how to deploy Hadoop and Spark together with Hue Filebrowser using the platform. In the screencast I also show the UI Integrator, upload files to HDFS using Hue Filebrowser and deploy two Spark applications on the cluster. The Makefile and all the docker-compose files used in the screencast are available <a href="https://github.com/big-data-europe/demo-release-webinar-platform">on BDE github</a>.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2F5T0OJ0Fi0OY%3Ffeature%3Doembed&amp;url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D5T0OJ0Fi0OY&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2F5T0OJ0Fi0OY%2Fhqdefault.jpg&amp;key=d04bfffea46d4aeda930ec88cc64b87c&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/8f41fe49c2613d12e408b0887ad6d36a/href">https://medium.com/media/8f41fe49c2613d12e408b0887ad6d36a/href</a></iframe><p>You might want to join our release webinar today (in under 4 hours). Registration and further details are available here: <a href="https://www.big-data-europe.eu/platform-launch-is-coming/">https://www.big-data-europe.eu/platform-launch-is-coming/</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=add291585151" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Developing Spark applications with Docker and BDE]]></title>
            <link>https://medium.com/@ivanermilov/developing-spark-applications-with-docker-and-bde-ca7f39b8414f?source=rss-1ecc07b04f2e------2</link>
            <guid isPermaLink="false">https://medium.com/p/ca7f39b8414f</guid>
            <category><![CDATA[hadoop]]></category>
            <category><![CDATA[devops]]></category>
            <category><![CDATA[docker]]></category>
            <category><![CDATA[spark]]></category>
            <category><![CDATA[deb]]></category>
            <dc:creator><![CDATA[Ivan Ermilov]]></dc:creator>
            <pubDate>Fri, 28 Apr 2017 13:29:46 GMT</pubDate>
            <atom:updated>2017-04-28T13:38:09.548Z</atom:updated>
            <content:encoded><![CDATA[<p>In <a href="http://www.big-data-europe.eu/">Big Data Europe</a> (BDE) project we aim to lower the barriers between industry as well as academia experts and Big Data. We tailor our tools towards variety of users including developers. One of the major categories among them are Spark developers. <a href="http://spark.apache.org/">Apache Spark</a> has been developed since 2012 and is being used as a Big Data processing framework by Amazon and Tencent <a href="http://spark.apache.org/powered-by.html">among many others</a>. Despite the wide adoption, Apache Spark suffers from a steep learning curve and has high entrance requirements for new developers. The particular difficulty is installation and configuration of Hadoop and Spark. To lower the barrier, we developed <a href="https://github.com/big-data-europe/docker-hadoop-spark-workbench">Hadoop/Spark Workbench</a> (see previous <a href="https://medium.com/@ivanermilov/scalable-spark-hdfs-setup-using-docker-2fd0ffa1d6bf">blog post</a> for more detailed description) and Spark application templates. We will guide the reader through the usage of the Workbench together with Java application template.</p><p>Spark Java applications have to be packaged into a .jar before it can be submitted to a Spark cluster. The packaging process is out of scope of this blog post, we will assume that you already have project with assembly tools (e.g. Maven or Gradle) set up and ready . For demonstration purposes we will use example application for Pi calculation from <a href="https://github.com/apache/spark">Spark Github</a> repository:</p><pre>$ mkdir SparkTutorial &amp;&amp; cd SparkTutorial<br>$ git clone <a href="https://github.com/apache/spark">https://github.com/apache/spark</a> &amp;&amp; cd spark<br>$ build/mvn -DskipTests clean package</pre><p>The “<em>mvn clean package</em>” will create an executable .jar file that is located in examples/target/ folder, which contains example applications. Spark project build takes a considerable amount of time and resources (~25 mins depending on your hardware) you might want to skip it. If you want to skip this step, you can download prebuilt .jar using the following commands:</p><pre>$ mkdir examples/target<br>$ wget <a href="https://dl.dropboxusercontent.com/u/4882345/spark-examples/original-spark-examples_2.11-2.3.0-SNAPSHOT.jar">https://dl.dropboxusercontent.com/u/4882345/spark-examples/original-spark-examples_2.11-2.3.0-SNAPSHOT.jar</a> -O examples/target/original-spark-examples_2.11-2.3.0-SNAPSHOT.jar</pre><p>The next step is to start the Workbench. We will only start the parts of it that are necessary to run the application (i.e. only Hadoop and Spark without Hue/Spark-Notebook). You can download the most up to date docker-compose.yml for the Hadoop/Spark:</p><pre>$ wget <a href="https://raw.githubusercontent.com/big-data-europe/docker-spark/2.1.0-hadoop2.8-hive-java8/docker-compose-minimal.yml">https://raw.githubusercontent.com/big-data-europe/docker-spark/2.1.0-hadoop2.8-hive-java8/docker-compose-minimal.yml</a> -O docker-compose.yml<br></pre><p>For the convenience we will create a Makefile containing the following:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/ee34a712517b9e9faa4beb03bb8628d0/href">https://medium.com/media/ee34a712517b9e9faa4beb03bb8628d0/href</a></iframe><p>You can download Makefile using the following command:</p><pre>$ wget <a href="https://dl.dropboxusercontent.com/u/4882345/spark-examples/Makefile">https://dl.dropboxusercontent.com/u/4882345/spark-examples/Makefile</a></pre><p>Now we can start up the Workbench with “<em>make up</em>” command, stop it with “<em>make down</em>” and deploy our application with “<em>make app</em>” (we will create docker-compose-spark-app.yml in a moment). Start the Workbench:</p><pre>$ make up</pre><p>Check the workbench status by running:</p><pre>$ docker ps</pre><p>You should see 4 running containers: namenode, datanode, spark-master and spark-worker with status “Up xx seconds (healthy)”.</p><p>Now the Workbench is ready and we can pack and deploy the application. First create Dockerfile in the root of the project. We will pack .jar from examples/target/ folder:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/807f392c885d971eecb1526341fda079/href">https://medium.com/media/807f392c885d971eecb1526341fda079/href</a></iframe><p>You can copy/paste above snippet in Dockerfile or download our Dockerfile using the following command:</p><pre>$ wget <a href="https://dl.dropboxusercontent.com/u/4882345/spark-examples/Dockerfile">https://dl.dropboxusercontent.com/u/4882345/spark-examples/Dockerfile</a> -O Dockerfile</pre><p>The next step is to create docker-compose-spark-app.yml (also in the root of the project). It is very short docker-compose file, that simply runs the application in the same docker network as the Workbench:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f536e8ba2ef55f9cbcbac2ca3f443bbf/href">https://medium.com/media/f536e8ba2ef55f9cbcbac2ca3f443bbf/href</a></iframe><p>Also, just copy/paste above snippet or simply run the following command to download our docker-compose file:</p><pre>$ wget <a href="https://dl.dropboxusercontent.com/u/4882345/spark-examples/docker-compose-spark-app.yml">https://dl.dropboxusercontent.com/u/4882345/spark-examples/docker-compose-spark-app.yml</a></pre><p>We are ready to run the application by executing the following command:</p><pre>$ make app</pre><p>In the execution logs you should see the result of execution:</p><pre>app_1  | Pi is roughly 3.143235716178581</pre><p>When you modify your application, you can easily rebuild and redeploy the project by using the following commands:</p><pre>$ make build<br>$ make app</pre><p>To summarize: we added the following files to the root of sample Maven project:</p><pre>├── docker-compose-spark-app.yml<br>├── docker-compose.yml<br>├── Dockerfile<br>└── Makefile</pre><p>We can start the Hadoop/Spark Workbench by executing:</p><pre>$ make up</pre><p>We can terminate Hadoop/Spark Workbench by executing:</p><pre>$ make down</pre><p>The application can be built and deployed by executing the following:</p><pre>$ make build<br>$ make app</pre><p>You can find a similar ready-made setup in <a href="https://github.com/big-data-europe/docker-spark/tree/2.1.0-hadoop2.8-hive-java8">docker-spark repository</a> (see <a href="https://github.com/big-data-europe/docker-spark/blob/2.1.0-hadoop2.8-hive-java8/README.md#example-application">README.md</a>).</p><p>For more information on BDE project refer to the <a href="http://www.big-data-europe.eu/">project website</a>, <a href="https://github.com/big-data-europe/">github org</a>, <a href="https://twitter.com/BigData_Europe">twitter</a>. Also, are also having a <a href="https://www.big-data-europe.eu/platform-launch-is-coming/">release webinar on 3rd of May</a> (next week). You can <a href="https://www.big-data-europe.eu/platform-launch-is-coming/">register and participate here</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ca7f39b8414f" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Limiting request rate to your services inside Docker containers]]></title>
            <link>https://medium.com/@ivanermilov/limiting-request-rate-to-your-services-inside-docker-containers-f92d0e4d0772?source=rss-1ecc07b04f2e------2</link>
            <guid isPermaLink="false">https://medium.com/p/f92d0e4d0772</guid>
            <category><![CDATA[devops]]></category>
            <category><![CDATA[repose]]></category>
            <category><![CDATA[openrepose]]></category>
            <category><![CDATA[user-control]]></category>
            <category><![CDATA[docker]]></category>
            <dc:creator><![CDATA[Ivan Ermilov]]></dc:creator>
            <pubDate>Tue, 21 Feb 2017 13:00:05 GMT</pubDate>
            <atom:updated>2017-02-21T13:00:05.263Z</atom:updated>
            <content:encoded><![CDATA[<p>In our research group <a href="http://aksw.org/About.html">AKSW</a> we stumbled upon a task to limit the request rate to our services. And we found a simple solution using <a href="http://www.openrepose.org/">OpenRepose</a> and <a href="http://docker.com/">Docker</a>.</p><p>The complete example is located on <a href="https://github.com/earthquakesan/repose-compose">my Github</a>.</p><p>The basic idea behind the solution was not to modify any of the existing services, but to introduce a middleware, which will block users from making excessive amount of requests. As we are running most of our services in Docker containers, the solution should be able to run in the Docker. It is indeed possible with OpenRepose and the simplest setup inside <a href="https://github.com/earthquakesan/repose-compose/blob/master/docker-compose.yml">docker-compose.yml</a> looks like this:</p><pre>version: “2.1”</pre><pre>services:<br> repose-proxy:<br> image: rackerlabs/repose:8.4.0.1<br> volumes:<br> — ./etc/repose:/etc/repose<br> ports:<br> — 80:80</pre><pre>nginx:<br> image: nginx</pre><p>Our actual service nginx is not exposed to the outside world and thus is hidden behind repose-proxy, which controls the flow of requests. The configuration of repose includes several things.</p><p>Main configuration file <a href="https://github.com/earthquakesan/repose-compose/blob/master/etc/repose/system-model.cfg.xml"><strong>system-model.cfg.xml</strong></a> (located in ./etc/repose/system-model.cfg.xml) defines which port the Repose will listen to (port 80, which is bound to port 80 on outside host in docker-compose.yml, the binding in docker compose is always HOST:CONTAINER):</p><pre>&lt;node id=”repose_node1&quot; hostname=”localhost” http-port=”80&quot;/&gt;</pre><p>Defines two active filters (<strong>rate-limiting</strong> filter <em>requires</em> <strong>ip-user</strong> filter to inject X-PP-User HTTP header based on user IP address):</p><pre>&lt;filter name=”ip-user”/&gt;<br>&lt;filter name=”rate-limiting”/&gt;</pre><p>And the default proxy destination — nginx service (the hostname <strong>nginx</strong> should match the service name in docker-compose.yml definition and be in the same docker network as repose service):</p><pre>&lt;endpoint id=”service” protocol=”http” hostname=”nginx” root-path=”/” port=”80&quot; default=”true”/&gt;</pre><p>The next thing is to configure IP ranges and assign them various user groups. In this example, we only define one user group <strong>match-all</strong>. The IP ranges configuration is <a href="https://github.com/earthquakesan/repose-compose/blob/master/etc/repose/ip-user.cfg.xml"><strong>ip-user.cfg.xml</strong></a> (located in ./etc/repose/ip-user.cfg.xml). We define <strong>match-all</strong> to match all IPv4 and IPv6:</p><pre>&lt;group name=”match-all”&gt;<br> &lt;cidr-ip&gt;0.0.0.0/0&lt;/cidr-ip&gt;<br> &lt;cidr-ip&gt;0::0/0&lt;/cidr-ip&gt;<br>&lt;/group&gt;</pre><p>Now we can define the rate limit for the <strong>match-all</strong> group. The rate limit configuration is <a href="https://github.com/earthquakesan/repose-compose/blob/master/etc/repose/rate-limiting.cfg.xml">rate-limiting.cfg.xml</a> (located in ./etc/repose/rate-limiting.cfg.xml). It uses the groups of users you defined in the IP ranges configuration previously (e.g. <strong>match-all</strong> group). Also, you can define the global limit for all the users:</p><pre>&lt;global-limit-group&gt;<br> &lt;limit id=”global” uri=”*” uri-regex=”.*” value=”1000&quot; unit=”MINUTE”/&gt;<br>&lt;/global-limit-group&gt;</pre><p>The global limit affects the whole amount of requests to 1000 per minute. If this amount of requests is exceeded, no more requests will be possible. To limit requests for a particular group of users (i.e. <strong>match-all</strong> group) we define a limit group:</p><pre>&lt;limit-group id=”limited” groups=”match-all” default=”true”&gt;<br> &lt;limit id=”all” uri=”*” uri-regex=”/.*” http-methods=”POST PUT GET DELETE” unit=”MINUTE” value=”10&quot;/&gt;<br>&lt;/limit-group&gt;</pre><p>This will limit requests for any given IP address within previously specified IP range (any IP addresses in this case) to 10 per one minute.</p><p>For additional information on OpenRepose refer to the <a href="https://repose.atlassian.net/wiki/">official wiki</a> and see examples (located in ./etc/repose/examples) folder for available filter configurations.</p><p>Thank you for reading, <a href="https://github.com/earthquakesan">Ivan</a> <a href="http://aksw.org/IvanErmilov.html">Ermilov</a> :)</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f92d0e4d0772" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Setting up Hadoop/Spark/Hive development environment on Ubuntu]]></title>
            <link>https://medium.com/@ivanermilov/setting-up-hadoop-spark-hive-development-environment-on-ubuntu-94f0f8166ef1?source=rss-1ecc07b04f2e------2</link>
            <guid isPermaLink="false">https://medium.com/p/94f0f8166ef1</guid>
            <category><![CDATA[big-data]]></category>
            <category><![CDATA[hadoop]]></category>
            <category><![CDATA[spark]]></category>
            <category><![CDATA[hive]]></category>
            <dc:creator><![CDATA[Ivan Ermilov]]></dc:creator>
            <pubDate>Wed, 20 Jul 2016 20:29:01 GMT</pubDate>
            <atom:updated>2016-07-22T11:12:59.796Z</atom:updated>
            <content:encoded><![CDATA[<p>In this blog post I want to tell you how to setup Hadoop/Spark/Hive development environment on your PC. I assume, that you are running Ubuntu LTS (as I have tested these instructions on Ubuntu 14.04).</p><p>What I want from development setup is:</p><ul><li>It should be portable. I install it in a directory, then remove it at one point and forget about it. No apt-get, no packages.</li><li>I can reinstall it any number of times in different directories on my PC. And it should not take much time (and no effort).</li><li>All the binaries (hadoop, spark-submit etc.) should be available from a terminal session, but only if I work on a Spark project. Something similar to <a href="http://virtualenvwrapper.readthedocs.io/en/latest/index.html">virtualenv in Python</a>.</li><li>A memo of the commands in one place, that can start pyspark shell or Hive beeline client.</li></ul><p>What I created was a Makefile to install everything into one folder. It is available <a href="https://github.com/earthquakesan/hdfs-spark-hive-dev-setup">on the Github.</a> For the full installation instructions, please read README.md, I will put the commands here which you need to run to install the environment:</p><pre>mkdir -p ~/Workspace/hadoop-spark-hive &amp;&amp; cd ~/Workspace/hadoop-spark-hive<br>git clone https://github.com/earthquakesan/hdfs-spark-hive-dev-setup ./<br>make download<br>make configure</pre><p>And then you can run start Hadoop/Spark with:</p><pre>make start_hadoop<br>make start_spark</pre><p>Check Hadoop at <a href="http://localhost:50070/">http://localhost:50070</a> (one datanode should be available), Spark at <a href="http://localhost:8080/">http://localhost:8080</a> (one spark worker should be available) and Hive with:</p><pre>#Hive configuration requires Hadoop/HDFS running<br>make configure_hive<br>make start_hive_server<br>#In another terminal start beeline client<br>make start_hive_beeline_client</pre><p>Then throw these queries into the client:</p><pre>CREATE TABLE pokes (foo INT, bar STRING);<br>LOAD DATA LOCAL INPATH &#39;./tools/apache-hive-2.1.0-bin/examples/files/kv1.txt&#39; OVERWRITE INTO TABLE pokes;<br>DESCRIBE pokes;<br>SELECT * FROM pokes;</pre><p>If you’ve got no error messages, congratulations — it works!</p><p>Ok, now the fun part. To start Python interactive shell:</p><pre>make pyspark</pre><p>To start Scala interactive shell:</p><pre>make spark_shell</pre><p>To export Hadoop/Spark/Hive binaries to your PATH:</p><pre>make activate<br>source activate</pre><p>Now you can access the HDFS easily:</p><pre>➜  hdfs dfs -ls /<br>Found 2 items<br>drwxrwxr-x   - ivan supergroup          0 2016-07-20 12:08 /tmp<br>drwxr-xr-x   - ivan supergroup          0 2016-07-20 16:16 /user</pre><p>Or do spark-submit for your application.</p><h4>Submitting example Spark application to your HDFS/Spark/Hive setup</h4><p>As an example, I will use an application from <a href="http://shop.oreilly.com/product/0636920028512.do">O’Reilly “Learning Spark”</a> (I recommend this book, it is written by Spark devs and provides a lot of useful insights). The code is available from <a href="https://github.com/databricks/learning-spark">the databricks github.</a></p><pre>cd ~/Workspace/hadoop-spark-hive<br>mkdir src &amp;&amp; cd src<br>git clone <a href="https://github.com/databricks/learning-spark">https://github.com/databricks/learning-spark</a><br>cd learning-spark/mini-complete-example</pre><p>Now, you have to change build.sbt to match our Spark version to look like this (we use Spark “1.6.2”, spark-core should be the same version):</p><pre>➜ cat build.sbt <br>name := &quot;learning-spark-mini-example&quot;</pre><pre>version := &quot;0.0.1&quot;</pre><pre>scalaVersion := &quot;2.10.4&quot;</pre><pre>// additional libraries<br>libraryDependencies ++= Seq(<br>  &quot;org.apache.spark&quot; %% &quot;spark-core&quot; % &quot;1.6.2&quot; % &quot;provided&quot;<br>)</pre><p>Now can build and submit the app to Spark:</p><pre>sbt clean package<br>spark-submit --class com.oreilly.learningsparkexamples.mini.scala.WordCount<br>./target/scala-2.10/learning-spark-mini-example_2.10-0.0.1.jar<br>file://$(pwd)/README.md file://$(pwd)/wordcounts</pre><p>It will read the file from your current working directory (the project root) and write the results to wordcounts/ folder. If you will not use file:// prefix, Spark will read/write to HDFS.</p><p>That’s it! If you have any questions or something did not work, please open an issue on <a href="https://github.com/earthquakesan/hdfs-spark-hive-dev-setup">github</a>. Also, for more cool stuff on Big Data, visit <a href="http://www.big-data-europe.eu/">Big Data Europe project blog</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=94f0f8166ef1" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Scalable Spark/HDFS Setup using Docker]]></title>
            <link>https://medium.com/@ivanermilov/scalable-spark-hdfs-setup-using-docker-2fd0ffa1d6bf?source=rss-1ecc07b04f2e------2</link>
            <guid isPermaLink="false">https://medium.com/p/2fd0ffa1d6bf</guid>
            <category><![CDATA[spark]]></category>
            <category><![CDATA[docker]]></category>
            <category><![CDATA[devops]]></category>
            <dc:creator><![CDATA[Ivan Ermilov]]></dc:creator>
            <pubDate>Wed, 16 Mar 2016 20:51:07 GMT</pubDate>
            <atom:updated>2016-03-23T17:27:37.124Z</atom:updated>
            <content:encoded><![CDATA[<p><strong>Note: extended version (with Hue HDFS FileBrowser) of this article is published on </strong><a href="http://www.big-data-europe.eu/scalable-sparkhdfs-workbench-using-docker/"><strong>BDE2020 project blog</strong></a><strong>. Repository is migrated to </strong><a href="https://github.com/big-data-europe/docker-hadoop-spark-workbench"><strong>BDE2020 github</strong></a><strong>.</strong></p><p>In this article I discuss how I created scalable HDFS/Spark setup using <a href="https://www.docker.com/">docker</a> and <a href="https://docs.docker.com/compose/">docker-compose</a>.</p><p>So, why do I need to pack Spark into docker in the first place? We have a cluster with three servers, each has 256 GB RAM and 64 CPU cores. As we run some other applications on this cluster, we have chosen Docker to isolate applications from each other. Yet being able to connect them when necessary. Also, docker can restrict RAM and set up CPU quota for each container. Thus, in theory you can spawn several spark-workers isolated from each other on the same machine. For instance, you can spawn 60 spark-workers on one of those servers with 2 GB RAM and 1/70 of CPU time each.</p><p>Docker exists for a couple of years already and has an ecosystem, where users can find dozens of docker images for almost all of mainstream technologies. Including HDFS/Spark. So I collected all the available images by searching for “spark” in the <a href="https://hub.docker.com/">Docker Hub</a> looking for something I can use out of the box. I put all of those images into <a href="https://imagelayers.io/">imagelayers</a> and got a nice <a href="https://goo.gl/kmDrfe">visualization</a>. Then I shortlisted them by the following criteria:</p><ul><li>Less than 1 GB in size. The bigger images most likely do not have separation of components, which makes them hard to scalable.</li><li>HDFS/Spark separated? I want to scale HDFS nodes separately from Spark nodes.</li><li>Is it easy to install? Is there documentation?</li><li>Can I scale Spark with this image?</li><li>Is it easy to connect Spark to HDFS?</li></ul><p>After checking against criteria 1 and 2, which are relatively easy to figure out without trying images out, I had to run all of them one by one. And I found out that none of the images fit criterion 4.</p><p>If I throw out scaling, <a href="https://bitbucket.org/uhopper/hadoop-docker">uhopper/hadoop-spark</a> looks good. So, I <a href="https://github.com/earthquakesan/HDFS-Spark-Workbench">forked</a> it and modified for the setup. Let’s see how to use my simplified version! (use git to clone my repo).</p><pre>$ ./buildall.sh<br>$ docker network create hadoop<br>$ docker-compose up</pre><p>That’s it! <em>buildall.sh</em> will iterate through all the Dockerfiles inside the repo and build necessary images. As I am using version 1 of docker-compose, you’ll have to <a href="https://docs.docker.com/engine/userguide/networking/dockernetworks/">create docker network manually</a>.</p><p>You have 1 namenode, 2 datanodes, 1 spark master and 1 spark worker as well as <a href="http://spark-notebook.io/">spark-notebook</a> running. Navigate to http://your.docker.host:50070 to see status of your HDFS and to <a href="http://your.docker.host/">http://your.docker.host</a>:8080 for Spark.</p><p>On Spark page you will only see 1 worker. Let’s scale it up to 5.</p><pre>$ docker-compose scale spark-worker=5</pre><p>Refresh the page on <a href="http://your.docker.host/">http://your.docker.host</a><a href="http://localhost:8080/">:8080</a>. You will see 5 spark-workers registered now.</p><p>Let’s throw some data into our HDFS now and run a simple job. Let’s use <a href="http://www.europeandataportal.eu/data/en/dataset/http---data-norge-no-node-1427/resource/ec7e01b7-a331-422d-9c9d-03be16bcfb48">Waterworks — Treatment</a> csv dataset from the <a href="http://www.europeandataportal.eu/">EU data portal</a>.</p><pre>&lt;-- you should be inside gitrepo folder (and run docker-compose, data dir would be created automatically)<br>$ cd data<br>$ wget <a href="https://data.mattilsynet.no/vannverk/vannbehandlingsanlegg.csv">https://data.mattilsynet.no/vannverk/vannbehandlingsanlegg.csv</a><br>$ docker run -it --rm --env-file=../hadoop.env --net hadoop uhopper/hadoop hadoop fs -mkdir -p /user/root<br>$ docker run -it --rm --env-file=../hadoop.env --volume $(pwd):/data --net hadoop uhopper/hadoop hadoop fs -put /data/vannbehandlingsanlegg.csv /user/root</pre><p>Go to <a href="http://localhost:50070/">http://localhost:50070</a> and check if file exists under the path ‘/user/root/vannbehandlingsanlegg.csv’.</p><p>Open spark-notebook on localhost:9000 and choose “core/simple spark” example. Run the cells by clicking on them and pushing play button. Then add new cell (using a plus button in the toolbar). Let’s read our file:</p><pre>val textFile = sc.textFile(“/user/root/vannbehandlingsanlegg.csv”)<br>textFile.count()</pre><p>It will show you the execution time and the result as such:</p><pre>textFile: org.apache.spark.rdd.RDD[String] = /user/root/vannbehandlingsanlegg.csv MapPartitionsRDD[2] at textFile at &lt;console&gt;:53<br>res8: Long = 4071<br>4071</pre><p>That’s it! If you have any questions, feel free to open new issues on github, or leave a comment to this article.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2fd0ffa1d6bf" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>