{"action":"created","comment":{"url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/pulls/comments/23253321","id":23253321,"diff_hunk":"@@ -0,0 +1,97 @@\n+---\n+layout: post\n+title: \"How did we serve > 20,000 IPython notebooks for Nature readers?\"\n+date: 2015-01-20\n+comments: true\n+author: Kyle Kelley\n+published: true\n+categories:\n+    - IPython\n+    - Science\n+    - Data Science\n+    - Docker\n+    - tmpnb\n+    - Jupyter\n+    - Ephemeral\n+---\n+The IPython/Jupyter notebook is a wonderful environment for computations, prose, plots, and interactive widgets that you can share with collaborators. People use the notebook [all](http://blog.quantopian.com/quantopian-research-your-backtesting-data-meets-ipython-notebook/) [over](http://nbviewer.ipython.org/github/GoogleCloudPlatform/ipython-soccer-predictions/blob/master/predict/wc-final.ipynb) [the](https://github.com/facebook/iTorch) [place](http://nbviewer.ipython.org/url/norvig.com/ipython/TSPv3.ipynb) across [many varied languages](https://github.com/ipython/ipython/wiki/IPython-kernels-for-other-languages). It gets used by [data scientists](http://nbviewer.ipython.org/gist/wrobstory/1eb8cb704a52d18b9ee8/Up%20and%20Down%20PyData%202014.ipynb), researchers, analysts, developers, and people in between.\n+\n+As I alluded to in a writeup on [Instant Temporary Notebooks](http://lambdaops.com/ipythonjupyter-tmpnb-debuts/), we (combination of IPython/Jupyter and Rackspace) were prepping for a big demo as part of a [Nature article on IPython Notebooks](http://www.nature.com/news/interactive-notebooks-sharing-the-code-1.16261) by [Helen Shen](https://twitter.com/HelenShenWrites). The impetus behind the demo was to show off the IPython notebook to readers in an interactive format. What better way than to [provide a live notebook server to readers on demand](http://www.nature.com/news/ipython-interactive-demo-7.21492)?\n+\n+[![Screenshot 2015-01-15 21.17.15.png](https://d23f6h5jpj26xu.cloudfront.net/nvqcj7okftoqw_small.png)](http://img.svbtle.com/nvqcj7okftoqw.png)\n+\n+To do this, we created a [temporary notebook service](https://tmpnb.org) in collaboration with the IPython/Jupyter team.\n+\n+### How does this temporary notebook service work?\n+\n+[tmpnb](https://github.com/jupyter/tmpnb) is a service that spawns new notebook servers, backed by Docker, for each user. Everyone gets their own sandbox to play in, assigned a unique path.\n+\n+When a user hits the main endpoint, they're actually hitting an [http proxy](https://github.com/jupyter/configurable-http-proxy) which routes initial traffic to tmpnb's orchestrator. From here a new user container is set up and a new route (e.g. `/user/fX104pghHEha/tree`) is assigned on the proxy.\n+\n+[![tmpnb-setup.gif](https://d23f6h5jpj26xu.cloudfront.net/z9gjan4yftabyq_small.gif)](http://img.svbtle.com/z9gjan4yftabyq.gif)\n+\n+Working our way up to the Nature demo, we had several live alpha prototypes around the same time at Strata NYC 2014:\n+\n+* Paco Nathan's Just Enough Math tutorial at Strata, in coordination with O'Reilly Media\n+\n+* tmpnb was announced and used during the very first PyData talk at Strata by Fernando Perez\n+\n+* Olivier Grisel used it in his scikit learn tutorial\n+\n+After a whole bunch of local activity, we learned quite a bit:\n+\n+### Static assets should be served via nginx instead of within each user container\n+\n+```\n+location ~ /(user[-/][a-zA-Z0-9]*)/static/(.*) {\n+    alias /srv/ipython/IPython/html/static/$2;\n+}\n+```\n+\n+This is both for speed and to use less file descriptors across the system.\n+\n+We ended up pulling some neat tricks with our deployment setup to [mount a dummy user container's static files into an nginx container](https://github.com/jupyter/tmpnb-deploy/pull/3).\n+\n+HOWEVER, if you don't do this, you get the neat side effect of never having caching problems when launching userland containers and even means you could ship different ones to different users! ","path":"src/site_source/_posts/2015-01-20-how-did-we-serve-more-than-20000-ipython-notebooks-for-nature.md","position":55,"original_position":55,"commit_id":"901d5e2de6996802a317f5a5ee61cd4c1a57a930","original_commit_id":"901d5e2de6996802a317f5a5ee61cd4c1a57a930","user":{"login":"smashwilson","id":17565,"avatar_url":"https://avatars.githubusercontent.com/u/17565?v=3","gravatar_id":"","url":"https://api.github.com/users/smashwilson","html_url":"https://github.com/smashwilson","followers_url":"https://api.github.com/users/smashwilson/followers","following_url":"https://api.github.com/users/smashwilson/following{/other_user}","gists_url":"https://api.github.com/users/smashwilson/gists{/gist_id}","starred_url":"https://api.github.com/users/smashwilson/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/smashwilson/subscriptions","organizations_url":"https://api.github.com/users/smashwilson/orgs","repos_url":"https://api.github.com/users/smashwilson/repos","events_url":"https://api.github.com/users/smashwilson/events{/privacy}","received_events_url":"https://api.github.com/users/smashwilson/received_events","type":"User","site_admin":false},"body":"I wouldn't capitalize \"HOWEVER\" here. Also, you might consider combining these three paragraphs into one. Maybe (with another tweak or two):\r\n\r\n> This is both for speed and to use fewer file descriptors across the system. We ended up pulling some neat tricks with our deployment setup to [mount a dummy user container's static files into an nginx container](https://github.com/jupyter/tmpnb-deploy/pull/3). However, if you don't do this, you get the neat side effect of never having caching problems when launching new versions of userland containers, and even means you could ship different ones to different users! ","created_at":"2015-01-20T20:35:10Z","updated_at":"2015-01-20T20:35:10Z","html_url":"https://github.com/rackerlabs/developer.rackspace.com/pull/1021#discussion_r23253321","pull_request_url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/pulls/1021","_links":{"self":{"href":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/pulls/comments/23253321"},"html":{"href":"https://github.com/rackerlabs/developer.rackspace.com/pull/1021#discussion_r23253321"},"pull_request":{"href":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/pulls/1021"}}},"pull_request":{"url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/pulls/1021","id":27698133,"html_url":"https://github.com/rackerlabs/developer.rackspace.com/pull/1021","diff_url":"https://github.com/rackerlabs/developer.rackspace.com/pull/1021.diff","patch_url":"https://github.com/rackerlabs/developer.rackspace.com/pull/1021.patch","issue_url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/issues/1021","number":1021,"state":"open","locked":false,"title":"[WIP] Initial stab at Nature blog post.","user":{"login":"rgbkrk","id":836375,"avatar_url":"https://avatars.githubusercontent.com/u/836375?v=3","gravatar_id":"","url":"https://api.github.com/users/rgbkrk","html_url":"https://github.com/rgbkrk","followers_url":"https://api.github.com/users/rgbkrk/followers","following_url":"https://api.github.com/users/rgbkrk/following{/other_user}","gists_url":"https://api.github.com/users/rgbkrk/gists{/gist_id}","starred_url":"https://api.github.com/users/rgbkrk/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rgbkrk/subscriptions","organizations_url":"https://api.github.com/users/rgbkrk/orgs","repos_url":"https://api.github.com/users/rgbkrk/repos","events_url":"https://api.github.com/users/rgbkrk/events{/privacy}","received_events_url":"https://api.github.com/users/rgbkrk/received_events","type":"User","site_admin":false},"body":"Here's the start of a blog post for the [nature demo](http://www.nature.com/news/ipython-interactive-demo-7.21492?article=1.16261).\r\n\r\nSince I'm letting myself get stuck in writer's block, I'm pushing this out as a WIP and to ask for feedback from colleagues.","created_at":"2015-01-20T17:57:54Z","updated_at":"2015-01-20T20:35:10Z","closed_at":null,"merged_at":null,"merge_commit_sha":"8a6a87ce657de2a02495477cd0ff31ce5d50e0cc","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/pulls/1021/commits","review_comments_url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/pulls/1021/comments","review_comment_url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/pulls/comments/{number}","comments_url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/issues/1021/comments","statuses_url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/statuses/901d5e2de6996802a317f5a5ee61cd4c1a57a930","head":{"label":"rgbkrk:nature_demo","ref":"nature_demo","sha":"901d5e2de6996802a317f5a5ee61cd4c1a57a930","user":{"login":"rgbkrk","id":836375,"avatar_url":"https://avatars.githubusercontent.com/u/836375?v=3","gravatar_id":"","url":"https://api.github.com/users/rgbkrk","html_url":"https://github.com/rgbkrk","followers_url":"https://api.github.com/users/rgbkrk/followers","following_url":"https://api.github.com/users/rgbkrk/following{/other_user}","gists_url":"https://api.github.com/users/rgbkrk/gists{/gist_id}","starred_url":"https://api.github.com/users/rgbkrk/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rgbkrk/subscriptions","organizations_url":"https://api.github.com/users/rgbkrk/orgs","repos_url":"https://api.github.com/users/rgbkrk/repos","events_url":"https://api.github.com/users/rgbkrk/events{/privacy}","received_events_url":"https://api.github.com/users/rgbkrk/received_events","type":"User","site_admin":false},"repo":{"id":17523565,"name":"developer.rackspace.com","full_name":"rgbkrk/developer.rackspace.com","owner":{"login":"rgbkrk","id":836375,"avatar_url":"https://avatars.githubusercontent.com/u/836375?v=3","gravatar_id":"","url":"https://api.github.com/users/rgbkrk","html_url":"https://github.com/rgbkrk","followers_url":"https://api.github.com/users/rgbkrk/followers","following_url":"https://api.github.com/users/rgbkrk/following{/other_user}","gists_url":"https://api.github.com/users/rgbkrk/gists{/gist_id}","starred_url":"https://api.github.com/users/rgbkrk/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rgbkrk/subscriptions","organizations_url":"https://api.github.com/users/rgbkrk/orgs","repos_url":"https://api.github.com/users/rgbkrk/repos","events_url":"https://api.github.com/users/rgbkrk/events{/privacy}","received_events_url":"https://api.github.com/users/rgbkrk/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/rgbkrk/developer.rackspace.com","description":"Gen 3 of the developer.rackspace.com Portal","fork":true,"url":"https://api.github.com/repos/rgbkrk/developer.rackspace.com","forks_url":"https://api.github.com/repos/rgbkrk/developer.rackspace.com/forks","keys_url":"https://api.github.com/repos/rgbkrk/developer.rackspace.com/keys{/key_id}","collaborators_url":"https://api.github.com/repos/rgbkrk/developer.rackspace.com/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/rgbkrk/developer.rackspace.com/teams","hooks_url":"https://api.github.com/repos/rgbkrk/developer.rackspace.com/hooks","issue_events_url":"https://api.github.com/repos/rgbkrk/developer.rackspace.com/issues/events{/number}","events_url":"https://api.github.com/repos/rgbkrk/developer.rackspace.com/events","assignees_url":"https://api.github.com/repos/rgbkrk/developer.rackspace.com/assignees{/user}","branches_url":"https://api.github.com/repos/rgbkrk/developer.rackspace.com/branches{/branch}","tags_url":"https://api.github.com/repos/rgbkrk/developer.rackspace.com/tags","blobs_url":"https://api.github.com/repos/rgbkrk/developer.rackspace.com/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/rgbkrk/developer.rackspace.com/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/rgbkrk/developer.rackspace.com/git/refs{/sha}","trees_url":"https://api.github.com/repos/rgbkrk/developer.rackspace.com/git/trees{/sha}","statuses_url":"https://api.github.com/repos/rgbkrk/developer.rackspace.com/statuses/{sha}","languages_url":"https://api.github.com/repos/rgbkrk/developer.rackspace.com/languages","stargazers_url":"https://api.github.com/repos/rgbkrk/developer.rackspace.com/stargazers","contributors_url":"https://api.github.com/repos/rgbkrk/developer.rackspace.com/contributors","subscribers_url":"https://api.github.com/repos/rgbkrk/developer.rackspace.com/subscribers","subscription_url":"https://api.github.com/repos/rgbkrk/developer.rackspace.com/subscription","commits_url":"https://api.github.com/repos/rgbkrk/developer.rackspace.com/commits{/sha}","git_commits_url":"https://api.github.com/repos/rgbkrk/developer.rackspace.com/git/commits{/sha}","comments_url":"https://api.github.com/repos/rgbkrk/developer.rackspace.com/comments{/number}","issue_comment_url":"https://api.github.com/repos/rgbkrk/developer.rackspace.com/issues/comments/{number}","contents_url":"https://api.github.com/repos/rgbkrk/developer.rackspace.com/contents/{+path}","compare_url":"https://api.github.com/repos/rgbkrk/developer.rackspace.com/compare/{base}...{head}","merges_url":"https://api.github.com/repos/rgbkrk/developer.rackspace.com/merges","archive_url":"https://api.github.com/repos/rgbkrk/developer.rackspace.com/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/rgbkrk/developer.rackspace.com/downloads","issues_url":"https://api.github.com/repos/rgbkrk/developer.rackspace.com/issues{/number}","pulls_url":"https://api.github.com/repos/rgbkrk/developer.rackspace.com/pulls{/number}","milestones_url":"https://api.github.com/repos/rgbkrk/developer.rackspace.com/milestones{/number}","notifications_url":"https://api.github.com/repos/rgbkrk/developer.rackspace.com/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/rgbkrk/developer.rackspace.com/labels{/name}","releases_url":"https://api.github.com/repos/rgbkrk/developer.rackspace.com/releases{/id}","created_at":"2014-03-07T18:42:52Z","updated_at":"2014-07-16T20:57:37Z","pushed_at":"2015-01-20T17:48:33Z","git_url":"git://github.com/rgbkrk/developer.rackspace.com.git","ssh_url":"git@github.com:rgbkrk/developer.rackspace.com.git","clone_url":"https://github.com/rgbkrk/developer.rackspace.com.git","svn_url":"https://github.com/rgbkrk/developer.rackspace.com","homepage":null,"size":40426,"stargazers_count":0,"watchers_count":0,"language":"CSS","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"dev"}},"base":{"label":"rackerlabs:master","ref":"master","sha":"26824d0273e845efe60a798074c82ad4fdc59ab5","user":{"login":"rackerlabs","id":84293,"avatar_url":"https://avatars.githubusercontent.com/u/84293?v=3","gravatar_id":"","url":"https://api.github.com/users/rackerlabs","html_url":"https://github.com/rackerlabs","followers_url":"https://api.github.com/users/rackerlabs/followers","following_url":"https://api.github.com/users/rackerlabs/following{/other_user}","gists_url":"https://api.github.com/users/rackerlabs/gists{/gist_id}","starred_url":"https://api.github.com/users/rackerlabs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rackerlabs/subscriptions","organizations_url":"https://api.github.com/users/rackerlabs/orgs","repos_url":"https://api.github.com/users/rackerlabs/repos","events_url":"https://api.github.com/users/rackerlabs/events{/privacy}","received_events_url":"https://api.github.com/users/rackerlabs/received_events","type":"Organization","site_admin":false},"repo":{"id":17407497,"name":"developer.rackspace.com","full_name":"rackerlabs/developer.rackspace.com","owner":{"login":"rackerlabs","id":84293,"avatar_url":"https://avatars.githubusercontent.com/u/84293?v=3","gravatar_id":"","url":"https://api.github.com/users/rackerlabs","html_url":"https://github.com/rackerlabs","followers_url":"https://api.github.com/users/rackerlabs/followers","following_url":"https://api.github.com/users/rackerlabs/following{/other_user}","gists_url":"https://api.github.com/users/rackerlabs/gists{/gist_id}","starred_url":"https://api.github.com/users/rackerlabs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rackerlabs/subscriptions","organizations_url":"https://api.github.com/users/rackerlabs/orgs","repos_url":"https://api.github.com/users/rackerlabs/repos","events_url":"https://api.github.com/users/rackerlabs/events{/privacy}","received_events_url":"https://api.github.com/users/rackerlabs/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/rackerlabs/developer.rackspace.com","description":"Gen 3 of the developer.rackspace.com Portal","fork":false,"url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com","forks_url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/forks","keys_url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/keys{/key_id}","collaborators_url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/teams","hooks_url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/hooks","issue_events_url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/issues/events{/number}","events_url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/events","assignees_url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/assignees{/user}","branches_url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/branches{/branch}","tags_url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/tags","blobs_url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/git/refs{/sha}","trees_url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/git/trees{/sha}","statuses_url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/statuses/{sha}","languages_url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/languages","stargazers_url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/stargazers","contributors_url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/contributors","subscribers_url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/subscribers","subscription_url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/subscription","commits_url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/commits{/sha}","git_commits_url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/git/commits{/sha}","comments_url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/comments{/number}","issue_comment_url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/issues/comments/{number}","contents_url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/contents/{+path}","compare_url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/compare/{base}...{head}","merges_url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/merges","archive_url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/downloads","issues_url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/issues{/number}","pulls_url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/pulls{/number}","milestones_url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/milestones{/number}","notifications_url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/labels{/name}","releases_url":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/releases{/id}","created_at":"2014-03-04T15:51:08Z","updated_at":"2015-01-20T20:23:06Z","pushed_at":"2015-01-20T20:32:01Z","git_url":"git://github.com/rackerlabs/developer.rackspace.com.git","ssh_url":"git@github.com:rackerlabs/developer.rackspace.com.git","clone_url":"https://github.com/rackerlabs/developer.rackspace.com.git","svn_url":"https://github.com/rackerlabs/developer.rackspace.com","homepage":null,"size":62948,"stargazers_count":37,"watchers_count":37,"language":"CSS","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":55,"mirror_url":null,"open_issues_count":104,"forks":55,"open_issues":104,"watchers":37,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/pulls/1021"},"html":{"href":"https://github.com/rackerlabs/developer.rackspace.com/pull/1021"},"issue":{"href":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/issues/1021"},"comments":{"href":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/issues/1021/comments"},"review_comments":{"href":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/pulls/1021/comments"},"review_comment":{"href":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/pulls/comments/{number}"},"commits":{"href":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/pulls/1021/commits"},"statuses":{"href":"https://api.github.com/repos/rackerlabs/developer.rackspace.com/statuses/901d5e2de6996802a317f5a5ee61cd4c1a57a930"}}}}