<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Yuvaraj (Yuvi) | 2i2c</title><link>https://deploy-preview-612--2i2c-org.netlify.app/author/yuvaraj-yuvi/</link><atom:link href="https://deploy-preview-612--2i2c-org.netlify.app/author/yuvaraj-yuvi/index.xml" rel="self" type="application/rss+xml"/><description>Yuvaraj (Yuvi)</description><generator>Hugo Blox Builder (https://hugoblox.com)</generator><language>en-us</language><image><url>https://deploy-preview-612--2i2c-org.netlify.app/author/yuvaraj-yuvi/avatar_huc33b170c6d7c951ba6ff8e7ef074ee49_9242_270x270_fill_q75_lanczos_center.jpeg</url><title>Yuvaraj (Yuvi)</title><link>https://deploy-preview-612--2i2c-org.netlify.app/author/yuvaraj-yuvi/</link></image><item><title>Announcing our public roadmap for open development</title><link>https://deploy-preview-612--2i2c-org.netlify.app/blog/public-roadmap/</link><pubDate>Fri, 06 Feb 2026 00:00:00 +0000</pubDate><guid>https://deploy-preview-612--2i2c-org.netlify.app/blog/public-roadmap/</guid><description>&lt;p>At the core of 2i2c&amp;rsquo;s service is a commitment to doing our work in a way that follows open principles and practices.
We commit to
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/open-practices/" >doing all of our work in the open&lt;/a> and
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/open-technology/" >only managing and developing open infrastructure&lt;/a>.
As part of this effort, we&amp;rsquo;re shifting our strategy to
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/blog/public-roadmap/../strategy-update-2026/" >lean more heavily into co-creation&lt;/a> with member communities and open source communities.&lt;/p>
&lt;p>Today we&amp;rsquo;re excited to share a first step towards making our development process more participatory, transparent, and useful: &lt;strong>we&amp;rsquo;re opening up our initiatives roadmap&lt;/strong>.
You can find it here:&lt;/p>
&lt;p>👉
&lt;a href="https://2i2c.org/roadmap" target="_blank" rel="noopener" >2i2c.org/roadmap&lt;/a>&lt;/p>
&lt;p>You can find all of our roadmap initiatives in this GitHub repository (please comment and engage with us there!):&lt;/p>
&lt;p>👉
&lt;a href="https://github.com/2i2c-org/initiatives" target="_blank" rel="noopener" >&lt;i class='fa-brands fa-github'>&lt;/i> github.com/2i2c-org/initiatives&lt;/a>&lt;/p>
&lt;p>Moving forward, the roadmap will be a key part of our
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/membership/" >service to member organizations&lt;/a>.&lt;/p>
&lt;h2 id="why-were-opening-up-our-roadmap">
Why we&amp;rsquo;re opening up our roadmap
&lt;a class="header-anchor" href="#why-were-opening-up-our-roadmap">#&lt;/a>
&lt;/h2>&lt;p>At 2i2c,
&lt;a href="https://github.com/2i2c-org/initiatives" target="_blank" rel="noopener" >initiatives drive most of our work&lt;/a>.
They represent major chunks of value with multiple steps needed to implement and unlock it.
They range from making core infrastructure improvements to our member network, to making upstream contributions that enable new functionality on behalf of our member communities.
While initiatives are generally public, they are spread across many places, and we&amp;rsquo;ve managed their prioritization, sequencing, and refinement in internal team spaces.
This made it difficult for others to follow along, signal-boost, and potentially support initiatives they wanted to see done.&lt;/p>
&lt;p>For this reason, we decided to build a
&lt;a href="https://2i2c.org/roadmap" target="_blank" rel="noopener" >public view of our initiatives roadmap&lt;/a>. This reflects our current team priorities and what is coming down the pipeline.&lt;/p>
&lt;p>We&amp;rsquo;ve also put our platform initiatives in a
&lt;a href="https://github.com/2i2c-org/initiatives" target="_blank" rel="noopener" >public repository&lt;/a>. This gives us a public space for member communities (or anybody else) to discuss, collaborate, and support ideas in the open.&lt;/p>
&lt;p>By opening this up, we hope to accomplish these goals:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Make it easier for everyone to see and influence our priorities&lt;/strong>.&lt;/li>
&lt;li>&lt;strong>Make it easier for member organizations to fund or collaborate on work&lt;/strong>.&lt;/li>
&lt;li>&lt;strong>Make it easier for open source communities to see what&amp;rsquo;s driving our contributions&lt;/strong>.&lt;/li>
&lt;li>&lt;strong>Make it easier to give credit to member communities that fund work&lt;/strong>.&lt;/li>
&lt;/ol>
&lt;p>In short, we want to &lt;strong>model what sustainable open development can look like&lt;/strong>.
Our hope is that this will both create more transparency and trust with our stakeholder communities, and invite them to tell us how we can best use our team capacity.&lt;/p>
&lt;h2 id="we-hope-to-use-a-shared-roadmap-to-funnel-more-resources-into-open-source">
We hope to use a shared roadmap to funnel more resources into open source
&lt;a class="header-anchor" href="#we-hope-to-use-a-shared-roadmap-to-funnel-more-resources-into-open-source">#&lt;/a>
&lt;/h2>&lt;p>We also hope we can leverage this as a &lt;strong>shared roadmap across our member communities&lt;/strong> that helps focus our attention and drive fundraising for our work.
To begin, we&amp;rsquo;re inviting any
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/members/" >member community&lt;/a> to provide financial support for these items as a way to influence our timelines and priorities, and we&amp;rsquo;re exploring ways to facilitate fractional co-funding across our member communities to help share the cost of development across many organizations.&lt;/p>
&lt;p>This is an early experiment in collaborative and radically transparent development, and we will iterate and learn as we get feedback from member communities.
We&amp;rsquo;re excited to see where this goes!&lt;/p>
&lt;p>Please
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/blog/public-roadmap/mailto:hello@2i2c.org" >give feedback on this idea&lt;/a>. If you&amp;rsquo;re interested in being a member organization of 2i2c,
&lt;a href="https://2i2c.org/join" target="_blank" rel="noopener" >reach out to us about membership&lt;/a>.&lt;/p></description></item><item><title>Fixing the mybinder.org usage analytics archive</title><link>https://deploy-preview-612--2i2c-org.netlify.app/blog/mybinder-analytics-fix/</link><pubDate>Tue, 14 Oct 2025 00:00:00 +0000</pubDate><guid>https://deploy-preview-612--2i2c-org.netlify.app/blog/mybinder-analytics-fix/</guid><description>&lt;p>The analytics archive at &lt;code>archive.analytics.mybinder.org&lt;/code> powers the
&lt;a href="https://hub.jupyter.org/binder-data/" target="_blank" rel="noopener" >mybinder.org usage dashboards&lt;/a> and provides a
&lt;a href="https://github.com/jupyterhub/binder-data" target="_blank" rel="noopener" >daily-published dataset&lt;/a> that researchers and communities use to understand how Binder is being used across different domains and scientific communities.&lt;/p>
&lt;p>While updating our
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/blog/mybinder-analytics-fix/../binder-report-q3/" >quarterly Binder impact report&lt;/a>, we discovered the archive index page had stopped updating. The analytics publisher was writing index files to temporary storage before uploading to Google Cloud Storage, but for some reason the upload step stopped working. We
&lt;a href="https://github.com/jupyterhub/mybinder.org-deploy/pull/3462" target="_blank" rel="noopener" >deployed a fix&lt;/a> that eliminates the temporary files entirely - the code now generates the HTML index as a string in memory and uploads directly.&lt;/p>
&lt;figure id="figure-the-mybinderorg-analytics-archivehttpsarchiveanalyticsmybinderorg-shows-a-list-of-daily-usage-reports-that-anybody-can-download">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img src="./featured.png" alt="The [mybinder.org analytics archive](https://archive.analytics.mybinder.org) shows a list of daily usage reports that anybody can download." loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
The
&lt;a href="https://archive.analytics.mybinder.org" target="_blank" rel="noopener" >mybinder.org analytics archive&lt;/a> shows a list of daily usage reports that anybody can download.
&lt;/figcaption>&lt;/figure>
&lt;p>Fortunately, we didn&amp;rsquo;t lose any data! Thanks to some smart design decisions, the daily analytics files were being collected properly the entire time, only the index page listing them was broken. You can find
&lt;a href="https://archive.analytics.mybinder.org" target="_blank" rel="noopener" >the full archive here&lt;/a>.&lt;/p>
&lt;h2 id="learn-more">
Learn more
&lt;a class="header-anchor" href="#learn-more">#&lt;/a>
&lt;/h2>&lt;ul>
&lt;li>
&lt;a href="https://github.com/jupyterhub/mybinder.org-deploy/pull/3462" target="_blank" rel="noopener" >Pull request with the fix&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://hub.jupyter.org/binder-data/" target="_blank" rel="noopener" >mybinder.org usage dashboards&lt;/a>&lt;/li>
&lt;li>The
&lt;a href="https://github.com/jupyterhub/binder-data" target="_blank" rel="noopener" >&lt;code>binder-data/&lt;/code> repository&lt;/a> is where we aggregate and publish archive data to be more accessible.&lt;/li>
&lt;li>
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/blog/mybinder-analytics-fix/../binder-report-q3/" >Our quarterly impact report from mybinder.org&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="acknowledgements">
Acknowledgements
&lt;a class="header-anchor" href="#acknowledgements">#&lt;/a>
&lt;/h2>&lt;ul>
&lt;li>Thanks to the
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/collaborators/jupyterhub/" >JupyterHub community&lt;/a> for their collaboration on mybinder.org infrastructure&lt;/li>
&lt;/ul></description></item><item><title>Combating tcp scanning on mybinder.org with the tcpflowkiller</title><link>https://deploy-preview-612--2i2c-org.netlify.app/blog/mybinder-antiabuse-scanning/</link><pubDate>Wed, 08 Oct 2025 00:00:00 +0000</pubDate><guid>https://deploy-preview-612--2i2c-org.netlify.app/blog/mybinder-antiabuse-scanning/</guid><description>&lt;p>We&amp;rsquo;ve deployed a new tool to &lt;code>mybinder.org&lt;/code> that automatically detects and stops port scanning activity, helping us maintain service reliability while being responsible citizens of the internet.&lt;/p>
&lt;p>Port scanning is a common part of network-based exploits, and many server hosts prohibit this activity (including Hetzner, where the 2i2c &lt;code>mybinder.org&lt;/code> infrastructure lives). We developed a little tool called
&lt;a href="https://github.com/cryptnono/cryptnono/pull/46" target="_blank" rel="noopener" >tcpflowkiller&lt;/a> as part of the
&lt;a href="https://github.com/cryptnono/cryptnono" target="_blank" rel="noopener" >cryptnono&lt;/a> project (our anti-abuse set of tools for hosted JupyterHub and Binder infrastructure) to automatically kill processes that exhibit port scanning behavior. This reduces the likelihood of triggering our server host&amp;rsquo;s abuse policies and helps keep &lt;code>mybinder.org&lt;/code> running reliably.&lt;/p>
&lt;h2 id="why-this-matters">
Why this matters
&lt;a class="header-anchor" href="#why-this-matters">#&lt;/a>
&lt;/h2>&lt;p>As providers of public compute, it&amp;rsquo;s our responsibility to make sure people can&amp;rsquo;t use our infrastructure to abuse others. This is part of being responsible citizens of the internet. It also saves us time in dealing with outages because cloud providers (understandably) block access when they suspect there is abuse.&lt;/p>
&lt;p>Hetzner and similar hosts have many benefits (including
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/blog/mybinder-antiabuse-scanning/../binder-singlenode/" >significant cost savings&lt;/a>), and tools like tcpflowkiller help keep hubs and binders running smoothly on such hosts, which have different abuse policies than the big commercial cloud providers.&lt;/p>
&lt;p>AWS and other cloud providers have proprietary ways to combat abuse (like
&lt;a href="https://docs.aws.amazon.com/guardduty/latest/ug/what-is-guardduty.html" target="_blank" rel="noopener" >AWS GuardDuty&lt;/a>). We could have spent our time investing in developing rules there. Instead, contributing to cryptnono helps provide the same set of features in a cloud-agnostic way, in line with
&lt;a href="https://2i2c.org/open-practices/" target="_blank" rel="noopener" >our principles&lt;/a> of supporting open infrastructure that gives communities control over their infrastructure.&lt;/p>
&lt;p>This tool
&lt;a href="https://github.com/jupyterhub/mybinder.org-deploy/pull/3436" target="_blank" rel="noopener" >has now been deployed to mybinder.org&lt;/a>, and we&amp;rsquo;ll monitor its effectiveness over time. We may roll this out to 2i2c public BinderHubs in the future based on patterns we observe.&lt;/p>
&lt;h2 id="learn-more">
Learn more
&lt;a class="header-anchor" href="#learn-more">#&lt;/a>
&lt;/h2>&lt;ul>
&lt;li>
&lt;a href="https://github.com/cryptnono/cryptnono/pull/46" target="_blank" rel="noopener" >tcpflowkiller pull request&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://github.com/jupyterhub/mybinder.org-deploy/pull/3436" target="_blank" rel="noopener" >mybinder.org deployment&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://en.wikipedia.org/wiki/Port_scanner" target="_blank" rel="noopener" >Port scanning on Wikipedia&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="acknowledgements">
Acknowledgements
&lt;a class="header-anchor" href="#acknowledgements">#&lt;/a>
&lt;/h2>&lt;ul>
&lt;li>Thanks to
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/collaborators/gesis/" >GESIS&lt;/a> for their continued support of &lt;code>mybinder.org&lt;/code> and to
&lt;a href="https://github.com/rgaiacs" target="_blank" rel="noopener" >Raniere Silva&lt;/a> for collaborating on this deployment with us.&lt;/li>
&lt;li>More reliable Binder infrastructure is also supported by
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/collaborators/nasa-open-science/" >NASA Open Science / Science Core&lt;/a>, whose tutorials run on the opensci binders that depend on this same anti-abuse stack.&lt;/li>
&lt;/ul></description></item><item><title>From scattered effort to strategic impact: How we're systematizing our Foundational open source contributions</title><link>https://deploy-preview-612--2i2c-org.netlify.app/blog/foundational-contributions/</link><pubDate>Fri, 26 Sep 2025 00:00:00 +0000</pubDate><guid>https://deploy-preview-612--2i2c-org.netlify.app/blog/foundational-contributions/</guid><description>&lt;p>Over the past year we&amp;rsquo;ve experimented with being more strategic about supporting upstream communities &lt;em>as a team&lt;/em>. This post summarizes our current plan, including team targets and practices we&amp;rsquo;ll continue to pilot. We&amp;rsquo;ll revisit this as we learn more.&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Note&lt;/strong>: This document is about the &lt;em>Foundational&lt;/em> contributions we make so that open source communities are healthier and more impactful. It is not about &lt;em>Directed&lt;/em> upstream contributions we make as part of our own product work. See
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/blog/good-citizen/" >On being a good open source citizen: supporting a healthy ecosystem through directed and foundational contributions&lt;/a>.&lt;/p>
&lt;/blockquote>
&lt;h2 id="the-challenge-why-scattered-individual-efforts-arent-enough">
The challenge: Why scattered individual efforts aren&amp;rsquo;t enough
&lt;a class="header-anchor" href="#the-challenge-why-scattered-individual-efforts-arent-enough">#&lt;/a>
&lt;/h2>&lt;p>Healthy open source communities rely on both individual and institutional contributions.
2i2c
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/blog/good-citizen/" >aims to be an &lt;em>excellent &amp;ldquo;upstream citizen&amp;rdquo;&lt;/em>&lt;/a>, so we need a structured approach with clear goals and rationale for why it&amp;rsquo;s the best use of our team&amp;rsquo;s time.&lt;/p>
&lt;p>Without a coordinated approach, we risk two problematic outcomes:&lt;/p>
&lt;p>&lt;strong>Best case&lt;/strong>: Scattered, individual efforts that are subject to the
&lt;a href="https://www.jofreeman.com/joreen/tyranny.htm" target="_blank" rel="noopener" >Tyranny of Structurelessness&lt;/a>. We help at the margins but not meaningfully.&lt;/p>
&lt;p>&lt;strong>Worst case&lt;/strong>: Our organizational capacity inadvertently dominates communities, making 2i2c the sole stakeholder capable of meaningful development and maintenance. We &lt;em>functionally take over the project&lt;/em>.&lt;/p>
&lt;p>By setting explicit goals, both our member communities and upstream projects can hold us accountable for actions that strengthen rather than undermine community health.&lt;/p>
&lt;h2 id="our-long-term-goal-multi-stakeholder-resilient-communities">
Our long-term goal: Multi-stakeholder, resilient communities
&lt;a class="header-anchor" href="#our-long-term-goal-multi-stakeholder-resilient-communities">#&lt;/a>
&lt;/h2>&lt;p>With this in mind, we&amp;rsquo;ve chosen the following &lt;em>outcomes&lt;/em> as our major goals for upstream contribution:&lt;/p>
&lt;blockquote>
&lt;p>We want the Jupyter&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup> community to be a &lt;em>multi-stakeholder&lt;/em>&lt;sup id="fnref:2">&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup>, &lt;em>diverse&lt;/em>&lt;sup id="fnref:3">&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref">3&lt;/a>&lt;/sup> community with a very high
&lt;a href="https://en.wikipedia.org/wiki/Bus_factor" target="_blank" rel="noopener" >&lt;em>bus factor&lt;/em>&lt;/a>, because we believe this is a critical pre-requisite for advancing
&lt;a href="https://compass.2i2c.org/organization/mission/" target="_blank" rel="noopener" >our mission and value proposition&lt;/a>.&lt;/p>
&lt;/blockquote>
&lt;p>We want to build team processes that help upstream communities make progress towards this goal, so everyone can equitably participate with the support they need.&lt;/p>
&lt;h2 id="two-key-objectives">
Two key objectives
&lt;a class="header-anchor" href="#two-key-objectives">#&lt;/a>
&lt;/h2>&lt;p>Starting with
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/collaborators/jupyterhub/" >JupyterHub&lt;/a>, we&amp;rsquo;ve identified two objectives that will guide our work:&lt;/p>
&lt;style>
blockquote {
font-size: 1.4em;
}
&lt;/style>
&lt;blockquote>
&lt;p>&lt;strong>Objective 1&lt;/strong>: Increase the number of casual but returning contributors to the JupyterHub community&lt;/p>
&lt;p>&lt;strong>Objective 2&lt;/strong>: Increase the number of total maintainers in the JupyterHub community&lt;/p>
&lt;/blockquote>
&lt;p>We&amp;rsquo;ve chosen these objectives because (1) they have impact, (2) we can make meaningful progress on them, and (3) we can integrate this work into our team&amp;rsquo;s workflow.&lt;/p>
&lt;p>For each activity below, we&amp;rsquo;ve brainstormed some Key Performance Indicators (KPIs) to track progress and ensure we&amp;rsquo;re learning effectively.&lt;/p>
&lt;h2 id="four-pilot-activities">
Four pilot activities
&lt;a class="header-anchor" href="#four-pilot-activities">#&lt;/a>
&lt;/h2>&lt;p>We&amp;rsquo;ll experiment with these four activities&lt;sup id="fnref:4">&lt;a href="#fn:4" class="footnote-ref" role="doc-noteref">4&lt;/a>&lt;/sup>:&lt;/p>
&lt;ul>
&lt;li>
&lt;a href="#review-prs" >&lt;strong>Review pull requests from non-maintainers&lt;/strong>&lt;/a>&lt;/li>
&lt;li>
&lt;a href="#issue-triage" >&lt;strong>Issue Triage office hours&lt;/strong>&lt;/a>&lt;/li>
&lt;li>
&lt;a href="#mentoring-maintainers" >&lt;strong>Sponsoring and Mentoring new Maintainers&lt;/strong>&lt;/a>&lt;/li>
&lt;li>
&lt;a href="#release-diversity" >&lt;strong>Increase bus factor and diversity of people making releases&lt;/strong>&lt;/a>&lt;/li>
&lt;/ul>
&lt;h3 id="review-prs">
Review Pull Requests from non-maintainers
&lt;a class="header-anchor" href="#review-prs">#&lt;/a>
&lt;/h3>&lt;p>Imagine two different scenarios:&lt;/p>
&lt;ol>
&lt;li>You casually contribute a PR to some OSS project. Someone responds the next day, you have a pleasant back and forth, and it gets merged (or rejected) within a few days.&lt;/li>
&lt;li>You casually contribute a PR to some OSS project. Nobody responds for a year. Eventually someone leaves a comment. You have forgotten everything, and don&amp;rsquo;t even respond. Much later, your PR gets closed as stale.&lt;/li>
&lt;/ol>
&lt;p>Which experience will encourage you to come back and contribute again?&lt;/p>
&lt;p>It&amp;rsquo;s clearly (1). We should use our institutional capacity to bring the community closer to (1).&lt;/p>
&lt;p>We&amp;rsquo;ll accomplish this by including the following work item in every sprint:&lt;/p>
&lt;blockquote>
&lt;p>&lt;code>Review of N PRs by non-maintainers of JupyterHub&lt;/code>&lt;/p>
&lt;/blockquote>
&lt;p>We will build skills (via pairing, training, etc) inside 2i2c, as not everyone will feel comfortable reviewing pull requests for all projects, nor have rights to merge or close PRs. We may also do additional work like new contributor drives, better documentation, and policy advocacy. We will include pull requests of all types, not just code contributions.&lt;/p>
&lt;h4 id="kpis">
KPIs
&lt;a class="header-anchor" href="#kpis">#&lt;/a>
&lt;/h4>&lt;p>We imagine two KPIs for this activity:&lt;/p>
&lt;ol>
&lt;li>Number of PRs merged (or closed) through our sprint planning activity.&lt;/li>
&lt;li>Number of &lt;em>returning&lt;/em> contributors whose PRs were reviewed by us.&lt;/li>
&lt;/ol>
&lt;h3 id="issue-triage">
Issue Triage office hours
&lt;a class="header-anchor" href="#issue-triage">#&lt;/a>
&lt;/h3>&lt;p>Issue Triage involves combing through an upstream repository&amp;rsquo;s issue tracker, engaging with new issues, refining them to be actionable, and signal boosting important ones for team action.
This is hard for newcomers, as it often requires deep knowledge of various components to understand how to direct an issue or refine it.
It&amp;rsquo;s also challenging for team members still learning open source community dynamics. We&amp;rsquo;d like to upskill our team members within 2i2c and our upstream open source communities.&lt;/p>
&lt;p>As part of our sprints, we will run regular &amp;ldquo;Issue Triage&amp;rdquo; office hours.
We&amp;rsquo;ll begin by upskilling our &lt;em>own 2i2c team members&lt;/em> in effective issue triaging. We&amp;rsquo;ll then explore opening issue triage sessions to the broader upstream community.&lt;/p>
&lt;h4 id="kpis-1">
KPIs
&lt;a class="header-anchor" href="#kpis-1">#&lt;/a>
&lt;/h4>&lt;ol>
&lt;li>Number of issues triaged by 2i2c team members.&lt;sup id="fnref:5">&lt;a href="#fn:5" class="footnote-ref" role="doc-noteref">5&lt;/a>&lt;/sup>&lt;/li>
&lt;/ol>
&lt;h3 id="mentoring-maintainers">
Sponsoring and Mentoring new Maintainers
&lt;a class="header-anchor" href="#mentoring-maintainers">#&lt;/a>
&lt;/h3>&lt;p>OSS communities must grow their &lt;em>contributors&lt;/em> into &lt;em>maintainers&lt;/em>, or they will die.&lt;/p>
&lt;figure id="figure-xkcd-comic-about-dependency">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;a href="https://xkcd.com/2347/" target="_blank" rel="noopener">&lt;img src="https://imgs.xkcd.com/comics/dependency.png" alt="XKCD comic about dependency" loading="lazy" />&lt;/a>&lt;/div>
&lt;/div>&lt;figcaption>
XKCD comic about dependency
&lt;/figcaption>&lt;/figure>
&lt;p>Growing new maintainers takes time and effort from both the potential maintainer and existing maintainers who mentor and sponsor them. The focus on sponsorship is important, as
&lt;a href="https://larahogan.me/blog/what-sponsorship-looks-like/" target="_blank" rel="noopener" >laid out by Lara Hogan&lt;/a>. This work takes years, not months, to manifest.&lt;/p>
&lt;p>We will build structures to identify potential maintainers and create pathways for them to gain maintainership status. As JupyterHub lacks an explicit maintainer pathway, we will build our own process via these focus areas:&lt;/p>
&lt;ol>
&lt;li>Identifying potential candidates for maintainership&lt;/li>
&lt;li>Identifying potential community work they can do to help get involved (contributing bug fixes, code reviewing, issue triage, helping answer questions, contributing code / documentation, release management, etc)&lt;/li>
&lt;li>Build pathways for candidates to do (2) as appropriate.&lt;/li>
&lt;li>Iteratively continue until candidates have done &amp;rsquo;enough&amp;rsquo; work to gain maintainership status.&lt;/li>
&lt;/ol>
&lt;p>This work is nebulous but worthwhile. We will coordinate this effort closely with community leaders, recognizing it takes time to actualize.&lt;/p>
&lt;p>In the Jupyter community, maintainership status is tied to individuals, not to organizations they work for. Nobody should get maintainership status &lt;em>simply&lt;/em> because they work for a specific organization (such as 2i2c). We should look for diverse candidates, ideally funded by different organizations, who are &lt;em>interested&lt;/em> in becoming maintainers.&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Note&lt;/strong>: We&amp;rsquo;d also like to start with individuals
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/collaborators/" >in our &lt;strong>collaborator network&lt;/strong>&lt;/a>. For example, we&amp;rsquo;re using an engagement between
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/collaborators/nasa-veda/" >NASA VEDA&lt;/a> and
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/collaborators/devseed/" >Development Seed&lt;/a> to onboard several team members into these projects.&lt;/p>
&lt;/blockquote>
&lt;h4 id="kpi">
KPI
&lt;a class="header-anchor" href="#kpi">#&lt;/a>
&lt;/h4>&lt;p>This measurement moves slowly, but is very clearly impactful:&lt;/p>
&lt;ol>
&lt;li>Number of people who have become maintainers due to our concerted efforts.&lt;/li>
&lt;/ol>
&lt;h3 id="release-diversity">
Increase bus factor and diversity of people making releases
&lt;a class="header-anchor" href="#release-diversity">#&lt;/a>
&lt;/h3>&lt;p>Making releases is often thankless but important to community health. It involves coordinating testing, writing changelogs, and providing upgrade instructions. Institutions can help by dedicating team time to perform this task regularly. To advance the &amp;lsquo;multi-stakeholder&amp;rsquo; and &amp;lsquo;high bus factor&amp;rsquo; aspects of our goal, we will have many different people do releases, via mentorship and sponsorship. This will integrate into our regular workstreams.&lt;/p>
&lt;h4 id="kpis-2">
KPIs
&lt;a class="header-anchor" href="#kpis-2">#&lt;/a>
&lt;/h4>&lt;ol>
&lt;li>Number of releases performed by 2i2c engineers&lt;/li>
&lt;li>Number of releases performed by others with sponsorship / mentorship from 2i2c engineers&lt;/li>
&lt;/ol>
&lt;h2 id="criteria-for-upstream-projects-to-support">
Criteria for upstream projects to support
&lt;a class="header-anchor" href="#criteria-for-upstream-projects-to-support">#&lt;/a>
&lt;/h2>&lt;p>Our long-term goal applies to upstream communities that:&lt;/p>
&lt;ol>
&lt;li>We strategically &lt;em>depend&lt;/em> on to serve
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/members/" >our member communities&lt;/a> as part of
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/platform/" >our community hub service&lt;/a>&lt;/li>
&lt;li>We &lt;em>need&lt;/em> to help sustain, given upstream community dynamics&lt;/li>
&lt;li>We have the &lt;em>ability&lt;/em> to help sustain&lt;/li>
&lt;/ol>
&lt;p>For example, Kubernetes satisfies (1) but not (2) or (3), while JupyterLab meets (1) and (2) but not (3) (presently). Currently this policy only applies to JupyterHub, but may change as our organization evolves.&lt;/p>
&lt;h2 id="how-well-implement-this">
How we&amp;rsquo;ll implement this
&lt;a class="header-anchor" href="#how-well-implement-this">#&lt;/a>
&lt;/h2>
&lt;h3 id="who-is-responsible">
Who is responsible
&lt;a class="header-anchor" href="#who-is-responsible">#&lt;/a>
&lt;/h3>&lt;p>Implementation is the responsibility of
&lt;a href="https://compass.2i2c.org/product-and-services/" target="_blank" rel="noopener" >2i2c&amp;rsquo;s Product &amp;amp; Services team&lt;/a>. These activities must integrate into the team&amp;rsquo;s daily practices, not become an external shadow process for some members.&lt;/p>
&lt;h3 id="how-well-fund-this-work">
How we&amp;rsquo;ll fund this work
&lt;a class="header-anchor" href="#how-well-fund-this-work">#&lt;/a>
&lt;/h3>&lt;p>Foundational upstream support requires significant work and expertise. We plan to fund this through:&lt;/p>
&lt;ul>
&lt;li>Fees from
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/members/" >our member communities&lt;/a>. A percentage of our membership fees includes covering the cost of Foundational contributions like this.&lt;/li>
&lt;li>Targeted contributions from
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/collaborators/" >some of our collaborators&lt;/a>. Some collaborators have funds and want to support open source at a foundational level, in some cases we use funds from these collaborators to cover our costs.&lt;/li>
&lt;/ul>
&lt;p>We still need to explore what these efforts cost and mechanisms to recover those costs.&lt;/p>
&lt;h2 id="next-step-learning-in-public">
Next step: Learning in public
&lt;a class="header-anchor" href="#next-step-learning-in-public">#&lt;/a>
&lt;/h2>&lt;p>We&amp;rsquo;re excited to experiment with more effective upstream contribution and eager to learn. We&amp;rsquo;ll share our experiences so others can learn from and comment on our process.&lt;/p>
&lt;h2 id="acknowledgements">
Acknowledgements
&lt;a class="header-anchor" href="#acknowledgements">#&lt;/a>
&lt;/h2>&lt;ul>
&lt;li>
&lt;a href="https://github.com/minrk" target="_blank" rel="noopener" >@MinRK&lt;/a> and -
&lt;a href="https://github.com/bsipocz" target="_blank" rel="noopener" >@bsipocz&lt;/a> for helping review a draft of this!&lt;/li>
&lt;li>
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/author/chris-holdgraf/" >@choldgraf&lt;/a> for feedback, guidance, and editing for this post and the team practices in it.&lt;/li>
&lt;li>
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/collaborators/jupyterhub/" >JupyterHub&lt;/a>,
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/collaborators/jupyter-book/" >JupyterBook&lt;/a>, and
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/collaborators/jupyter/" >Project Jupyter&lt;/a> for teaching us a lot about open source over the years.&lt;/li>
&lt;/ul>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>Currently this is particularly JupyterHub and Jupyter-wide leadership. We&amp;rsquo;re
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/blog/jb-for-communities/" >exploring how to incorporate JupyterBook into our service&lt;/a> and are thus investing Foundation contributions there as well.&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>With different kinds and sizes of organizations (companies, non-profits, universities, etc) and individuals being stakeholders. We want to avoid a single organization monopolizing power within any community.&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:3">
&lt;p>Across the power spectrum - from users to bug reporters to casual contributors to maintainers to people on governance duty&amp;#160;&lt;a href="#fnref:3" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:4">
&lt;p>&lt;strong>Implementation note&lt;/strong>: We will not start doing &lt;strong>all&lt;/strong> these immediately! We will consult with the rest of the team, and start these 1 at a time so we can build these processes sustainably and equitably.&amp;#160;&lt;a href="#fnref:4" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:5">
&lt;p>This requires a definition of &amp;ldquo;an issue that has been triaged&amp;rdquo;, and to our knowledge no such definition exists. We&amp;rsquo;d like to learn how to measure something abstract like &amp;ldquo;issue triage&amp;rdquo; - perhaps it is something specific putting it on a board for further action or applying a label, or something more abstract like &amp;ldquo;increasing how clear and actionable the issue is&amp;rdquo;. We&amp;rsquo;ll explore this when we start to make progress towards this objective.&amp;#160;&lt;a href="#fnref:5" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>On being a good open source citizen: supporting a healthy ecosystem through directed and foundational contributions</title><link>https://deploy-preview-612--2i2c-org.netlify.app/blog/good-citizen/</link><pubDate>Wed, 03 Sep 2025 00:00:00 +0000</pubDate><guid>https://deploy-preview-612--2i2c-org.netlify.app/blog/good-citizen/</guid><description>&lt;p>Any organization building on open source faces a fundamental tension: how do you serve the needs of your organizational stakeholders while also acting as a responsible steward of the upstream projects you depend on?
This is harder than it looks - simply &amp;ldquo;making PRs&amp;rdquo; leaves a number of open source needs unaddressed, and can burn out both your team members and the open source maintainers. We think about this a lot at 2i2c, and want to share our framework to navigate this challenge intentionally.&lt;/p>
&lt;p>Here are a few questions we&amp;rsquo;ve been grappling with:&lt;/p>
&lt;ul>
&lt;li>How do we tie general upstream maintenance to value delivered to our user communities?&lt;/li>
&lt;li>How can we scope upstream support so that it doesn&amp;rsquo;t detract from our service needs and product strategy?&lt;/li>
&lt;li>How can we encourage team members to work on the most impactful aspects of upstream support?&lt;/li>
&lt;li>How can we intentionally and equitably support open source communities as a team, rather than a collection of individuals?&lt;/li>
&lt;/ul>
&lt;p>Along the way, we realized there are &lt;strong>two very different kinds of upstream contributions&lt;/strong>:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Directed Contributions&lt;/strong>: A contribution driven by the needs of our member communities and product roadmap. We call these &amp;ldquo;Directed&amp;rdquo; contributions because they address a targeted need driven by one stakeholder (us!).&lt;/li>
&lt;li>&lt;strong>Foundational contributions&lt;/strong>: A contribution driven by the needs of the upstream community. We call these &amp;ldquo;Foundational contributions&amp;rdquo; because they&amp;rsquo;re meant to provide the healthy foundation on which a community can operate and grow.&lt;/li>
&lt;/ol>
&lt;p>Historically we have conflated these types of contributions, but we think it&amp;rsquo;s key that we treat them differently.&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Note&lt;/strong>: For a more practical guide that describes the systems we&amp;rsquo;ve set up to accomplish &lt;em>Foundational&lt;/em> upstream contributions, see
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/blog/foundational-contributions/" >From scattered effort to strategic impact: How we&amp;rsquo;re systematizing our Foundational open source contributions&lt;/a>.&lt;/p>
&lt;/blockquote>
&lt;h2 id="everybody-has-an-open-source-hat-and-a-stakeholder-hat">
Everybody has an open source hat and a stakeholder hat
&lt;a class="header-anchor" href="#everybody-has-an-open-source-hat-and-a-stakeholder-hat">#&lt;/a>
&lt;/h2>&lt;p>Open source teams&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup> are usually two kinds of teams that overlap heavily:&lt;/p>
&lt;ol>
&lt;li>A collection of &lt;em>stakeholders working together&lt;/em> on the open source project, each with their own goals and interests.&lt;/li>
&lt;li>An &lt;em>open source team&lt;/em> with a shared goal and strategy for the open source project.&lt;/li>
&lt;/ol>
&lt;p>In this case, stakeholders can be individuals or companies. They use and contribute to the open source project because it advances their own interests. For example, an enthusiast contributing to a project because it brings them joy, or a company contributing to a project because they build a product that depends on the open source technology.&lt;/p>
&lt;p>However, for open source projects to be successful they also need their own unique identity, goals, strategy for impact, and system of work. This allows a diverse collection of stakeholders to &lt;em>work together effectively&lt;/em> and &lt;em>create impactful technology&lt;/em>. This team is made up of the same stakeholders described above, but with a responsibility to lead and support the open source team, rather than just serve their individual interests as stakeholders.&lt;/p>
&lt;p>Thus, any open source stakeholder has two hats: they are both &lt;em>representatives of a stakeholder&lt;/em> and &lt;em>members of an open source team&lt;/em>. While it&amp;rsquo;s possible to &lt;em>align the interests&lt;/em> of these two groups, we think it&amp;rsquo;s still important to &lt;em>distinguish between them&lt;/em>.&lt;/p>
&lt;h2 id="directed-contributions-benefit-the-stakeholder-you-represent">
Directed Contributions benefit the stakeholder you represent
&lt;a class="header-anchor" href="#directed-contributions-benefit-the-stakeholder-you-represent">#&lt;/a>
&lt;/h2>&lt;p>A &lt;em>Directed Contribution&lt;/em> is primarily driven by the needs of a stakeholder in an open source project. To use 2i2c as an example, let&amp;rsquo;s take a quote from 2i2c&amp;rsquo;s value proposition:&lt;/p>
&lt;blockquote>
&lt;p>2i2c serves a global network of community hubs for interactive learning and discovery&lt;/p>
&lt;/blockquote>
&lt;p>&lt;em>Community&lt;/em> here does &lt;strong>not&lt;/strong> refer to open source upstream software provider communities (like JupyterHub or Kubernetes), but instead to downstream &lt;em>user communities&lt;/em> (like
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/collaborators/cryocloud/" >CryoCloud&lt;/a>,
&lt;a href="https://openscapes.org" target="_blank" rel="noopener" >Openscapes&lt;/a>, or
&lt;a href="https://www.earthdata.nasa.gov/data/tools/veda" target="_blank" rel="noopener" >NASA VEDA&lt;/a>).&lt;/p>
&lt;p>When 2i2c makes a Directed Contribution, it means we are trying to &lt;em>deliver value to one or more of our member communities&lt;/em> by making an upstream contribution.&lt;/p>
&lt;p>Satisfying community needs often involves directly working on the software they use. Driven by our
&lt;a href="https://2i2c.org/right-to-replicate/" target="_blank" rel="noopener" >right to replicate&lt;/a> principles, this means we mostly work on software that is not proprietary to 2i2c nor solely owned by us permanently - but by contributing to an upstream software community. These are all Directed Contributions.&lt;/p>
&lt;p>Some illustrative examples:&lt;/p>
&lt;ol>
&lt;li>
&lt;a href="https://github.com/jupyterhub/oauthenticator/pull/719" target="_blank" rel="noopener" >Allow login to be gated on OAuth2 granted scopes&lt;/a> was a feature we added to support one of our communities&amp;rsquo; auth flow (
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/collaborators/earthscope/" >EarthScope&lt;/a>)&lt;/li>
&lt;li>
&lt;a href="https://github.com/pangeo-data/pangeo-docker-images/pull/426" target="_blank" rel="noopener" >Changing how &lt;code>.pyc&lt;/code> files are kept in images&lt;/a> was work we did as a result of a support ticket investigating spawn timeout issues in the
&lt;a href="https://leap.columbia.edu/" target="_blank" rel="noopener" >LEAP&lt;/a> hub.&lt;/li>
&lt;li>
&lt;a href="https://github.com/jupyter-book/myst-theme/pull/531" target="_blank" rel="noopener" >Adding landing pages functionality to Jupyter Book and MyST&lt;/a> was work we did to support member communities like
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/collaborators/cryocloud/" >CryoCloud&lt;/a> and
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/collaborators/pythia/" >Project Pythia&lt;/a>.&lt;/li>
&lt;/ol>
&lt;p>The fact that these are open source contributions is &lt;em>incidental&lt;/em>. We are &lt;em>primarily&lt;/em> doing this work to deliver value to &lt;em>our community network&lt;/em>.&lt;/p>
&lt;h3 id="we-plan-directed-contributions-according-to-our-roadmap-and-member-feedback">
We plan Directed Contributions according to our roadmap and member feedback
&lt;a class="header-anchor" href="#we-plan-directed-contributions-according-to-our-roadmap-and-member-feedback">#&lt;/a>
&lt;/h3>&lt;p>Directed Contributions naturally align with 2i2c&amp;rsquo;s overall goals and strategy, so we use our
&lt;a href="https://compass.2i2c.org/product-and-services/" target="_blank" rel="noopener" >product processes&lt;/a> for planning and delivering on them. However, we also want to provide transparency to upstream communities so that they understand who is driving the contributions that we&amp;rsquo;re making.&lt;/p>
&lt;p>With that in mind, here are a few ways that Directed Contributions relate to our practices:&lt;/p>
&lt;ul>
&lt;li>Directed Contributions should be defined by our product roadmap and prioritization processes.&lt;/li>
&lt;li>We allocate engineering time for these upstream contributions as part of our product lifecycle, &lt;em>including the extra coordination and communication work needed to work at the pace of the upstream community&lt;/em>.&lt;/li>
&lt;li>We cross-link 2i2c product initiatives to upstream issues and pull-requests wherever we can to provide transparency about why we&amp;rsquo;re making a contribution.&lt;/li>
&lt;li>We communicate this work via our blog so that 2i2c&amp;rsquo;s member communities know about the contributions we&amp;rsquo;ve made on their behalf.&lt;/li>
&lt;/ul>
&lt;h2 id="foundational-contributions-support-a-healthy-open-source-community">
Foundational Contributions support a healthy open source community
&lt;a class="header-anchor" href="#foundational-contributions-support-a-healthy-open-source-community">#&lt;/a>
&lt;/h2>&lt;p>However, contributions can&amp;rsquo;t always be driven by a stakeholder&amp;rsquo;s needs or the open source team will not have an identity or support structure of its own. Here&amp;rsquo;s another excerpt from our value proposition:&lt;/p>
&lt;blockquote>
&lt;p>We need infrastructure services that are driven by community needs and values, that follow the same open source science practices we wish to see in others, and that believe in the power of shared community resources and knowledge.&lt;/p>
&lt;/blockquote>
&lt;p>Being a &amp;ldquo;healthy upstream citizen&amp;rdquo; is core to 2i2c&amp;rsquo;s mission, and is also a way to help communities we rely on remain healthy. Some of our contributions should be &lt;em>Foundational&lt;/em> rather than &lt;em>Directed&lt;/em>. This means doing things that keep the overall ecosystem healthy even if it does not &lt;em>directly&lt;/em> address a specific member community need. The &lt;em>presence&lt;/em> of a healthy open source ecosystem is a value to our member communities in-and-of itself.&lt;/p>
&lt;p>Defining &amp;ldquo;Foundational&amp;rdquo; needs is difficult, because open source teams tend to have less structure and formally-stated goals and needs than most organizations. In 2i2c&amp;rsquo;s case, we focus our Foundational Contributions around &lt;em>maintaining the health of the open source ecosystem&lt;/em>.&lt;/p>
&lt;p>It includes things like:&lt;/p>
&lt;ol>
&lt;li>Grow and guide new contributors to grow team capacity&lt;/li>
&lt;li>Help making releases&lt;/li>
&lt;li>Provide code review&lt;/li>
&lt;li>Fix broken CI&lt;/li>
&lt;li>Write documentation and tutorials&lt;/li>
&lt;li>Manage and run meetings&lt;/li>
&lt;li>Align open source teams on goals and strategy&lt;/li>
&lt;/ol>
&lt;p>However, the real point is that these actions need to be driven by &lt;em>the upstream project&amp;rsquo;s goals and needs&lt;/em>, not by 2i2c&amp;rsquo;s needs.&lt;/p>
&lt;p>Here are a few common examples of contributions that are &lt;em>not considered&lt;/em> Foundational for our team:&lt;/p>
&lt;ol>
&lt;li>Opening a PR to add a major feature to an upstream project.&lt;/li>
&lt;li>Creating a brand new project in an open source organization in order to scratch your own itch.&lt;/li>
&lt;li>Engaging in reactive open-source work that isn&amp;rsquo;t driven by a clear strategy or goal (e.g., randomly responding to the last few GitHub issue comments you happened to notice)&lt;/li>
&lt;/ol>
&lt;h3 id="we-plan-foundational-contributions-alongside-our-engineering-roadmap">
We plan Foundational Contributions alongside our engineering roadmap
&lt;a class="header-anchor" href="#we-plan-foundational-contributions-alongside-our-engineering-roadmap">#&lt;/a>
&lt;/h3>&lt;p>Foundational Contributions are important to 2i2c both for strategic and tactical reasons. However, when left as unstructured time (as we have historically), it runs into all the problems of unstructured work - it happens in non-strategic ways, it isn&amp;rsquo;t evenly balanced across team members, it is more or less accessible depending on your personal comfort level and skills, etc.&lt;/p>
&lt;p>With that in mind, here are a few ways that Foundational Contributions relate to our practices:&lt;/p>
&lt;ul>
&lt;li>We need to &lt;em>own Foundational Contributions as a team&lt;/em>, rather than asking individuals to identify and do this work on their own.&lt;/li>
&lt;li>We need to define team &lt;em>goals&lt;/em> and &lt;em>strategy&lt;/em> to define the impact we want to have, and what kind of work leads to that impact.&lt;/li>
&lt;li>We need a team system for identifying and prioritizing the most impactful Foundational Contributions to perform.&lt;/li>
&lt;li>This system must spread the responsibility of Foundational Contributions across our whole product team.&lt;/li>
&lt;li>It means we need to give people support and training to do this effectively. For example, helping team members grow into roles that involve upstream work, rotating certain types of contributions across team members, etc.&lt;/li>
&lt;/ul>
&lt;p>To ensure this work is intentional and equitable across our team, we encourage Foundational contributions to happen within this framework. Contributions that falls outside of it is treated as a valued, but separate, personal contribution.&lt;/p>
&lt;h2 id="whats-next">
What&amp;rsquo;s next
&lt;a class="header-anchor" href="#whats-next">#&lt;/a>
&lt;/h2>&lt;p>By distinguishing between Directed and Foundational contributions, we can align and balance our immediate product needs with our long-term commitment to community health. We believe this framework allows organizations like ours to be better partners. We&amp;rsquo;d love feedback about this process, how we can improve it, and what others have learned along the way.&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>By &amp;ldquo;open source&amp;rdquo; we are focusing on multi-stakeholder open source projects with participatory and inclusive leadership and contributions. This wouldn&amp;rsquo;t apply to an organization- or person-specific open source project.&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>Sharing JupyterHub's vision for more flexible application deployment at the doepy talk series.</title><link>https://deploy-preview-612--2i2c-org.netlify.app/blog/doepy-yuvi/</link><pubDate>Wed, 03 Sep 2025 00:00:00 +0000</pubDate><guid>https://deploy-preview-612--2i2c-org.netlify.app/blog/doepy-yuvi/</guid><description>&lt;p>Our Technical Lead
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/blog/doepy-yuvi/../../authors/yuvi-panda/_index.md" >Yuvi Panda&lt;/a> recently gave a talk at the
&lt;a href="https://meetup.doepy.org/" target="_blank" rel="noopener" >doepy meetup&lt;/a> about JupyterHub&amp;rsquo;s interest in moving beyond the &amp;ldquo;single-user notebook application&amp;rdquo; and towards a more flexible approach to enabling administrators to deploy many different types of applications and environments.&lt;/p>
&lt;p>Check out a video of the talk here:&lt;/p>
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
&lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="allowfullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/vsbHMvvsFw8?autoplay=0&amp;controls=1&amp;end=0&amp;loop=0&amp;mute=0&amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"
>&lt;/iframe>
&lt;/div>
&lt;p>This is an important step for the JupyterHub project in order to support the many different kinds of workflows that data scientists need to use in their work. We hope that this generates more interest in the JupyterHub project and gives us useful feedback to guide the team&amp;rsquo;s understanding of this direction.&lt;/p>
&lt;h2 id="learn-more">
Learn more
&lt;a class="header-anchor" href="#learn-more">#&lt;/a>
&lt;/h2>&lt;ul>
&lt;li>
&lt;a href="https://www.youtube.com/watch?v=vsbHMvvsFw8" target="_blank" rel="noopener" >YouTube video of this talk&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://jupyter.zulipchat.com/#narrow/channel/469744-jupyterhub/topic/JupyterHub.20in.202025.3A.20Not.20just.20for.20Jupyter.20Notebooks/near/537708184" target="_blank" rel="noopener" >Jupyter Chat about this talk&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://www.linkedin.com/feed/update/urn:li:activity:7364763956525092868" target="_blank" rel="noopener" >LinkedIn post announcing the talk&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://www.linkedin.com/posts/cameron-riddell_we-dont-use-this-code-loved-having-yuvi-activity-7369421556516601859-qOxw?utm_medium=ios_app&amp;amp;rcm=ACoAADSgbM8BXeDyQi3bGVtD7qmmJg9b20KhG6A&amp;amp;utm_source=social_share_send&amp;amp;utm_campaign=copy_link" target="_blank" rel="noopener" >LinkedIn post describing the talk&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="acknowledgements">
Acknowledgements
&lt;a class="header-anchor" href="#acknowledgements">#&lt;/a>
&lt;/h2>&lt;ul>
&lt;li>
&lt;a href="https://meetup.doepy.org/" target="_blank" rel="noopener" >The doepy team&lt;/a> for inviting Yuvi to give this talk.&lt;/li>
&lt;li>
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/collaborators/jupyterhub/" >The JupyterHub team&lt;/a> for working with us on this strategy.&lt;/li>
&lt;li>
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/members/" >2i2c&amp;rsquo;s network of member communities&lt;/a> whose fees support our Foundational open source engagement.&lt;/li>
&lt;/ul></description></item><item><title>Solving classes of problems, rather than just an instance of a problem (with an example)</title><link>https://deploy-preview-612--2i2c-org.netlify.app/blog/automating-support-upgrades/</link><pubDate>Mon, 09 Jun 2025 00:00:00 +0000</pubDate><guid>https://deploy-preview-612--2i2c-org.netlify.app/blog/automating-support-upgrades/</guid><description>
&lt;h2 id="the-problem">
The Problem
&lt;a class="header-anchor" href="#the-problem">#&lt;/a>
&lt;/h2>&lt;p>Two of our the communities we serve (
&lt;a href="https://nmfs-openscapes.github.io/" target="_blank" rel="noopener" >NMFS Openscapes&lt;/a> and
&lt;a href="https://book.cryointhecloud.com" target="_blank" rel="noopener" >CryoCloud&lt;/a>) reported issues with starting GPU nodes on their hubs. Upon investigation, I discovered that the
&lt;a href="https://github.com/kubernetes/autoscaler" target="_blank" rel="noopener" >cluster autoscaler&lt;/a> seems to not recognize that GPUs were available in the cluster at all suddenly, and hence wasn&amp;rsquo;t provisioning the nodes. A restart of the cluster-autoscaler pod fixed the issue for both these communities.&lt;/p>
&lt;h2 id="an-incomplete-solution">
An incomplete solution
&lt;a class="header-anchor" href="#an-incomplete-solution">#&lt;/a>
&lt;/h2>&lt;p>But is that the end of the story? Not if we want to provide reliable long term infrastructure to communities with minimal
&lt;a href="https://sre.google/sre-book/eliminating-toil/" target="_blank" rel="noopener" >toil&lt;/a> on the part of 2i2c engineers!&lt;/p>
&lt;p>One of the engineering principles I&amp;rsquo;m trying to have us more intentionally and structurally embody is the idea that we don&amp;rsquo;t fix individual instances of problems, but &lt;strong>whole classes of problems, rather than just an individual instance of the problem&lt;/strong>. Fixing the immediate issue is &lt;em>not enough&lt;/em> - we need to understand what &lt;strong>class of issues&lt;/strong> was manifesting itself in this particular fashion, and fix &lt;em>that&lt;/em>.&lt;/p>
&lt;h2 id="what-was-the-class-of-issues-we-could-fix-here">
What was the &lt;strong>class of issues&lt;/strong> we could fix here?
&lt;a class="header-anchor" href="#what-was-the-class-of-issues-we-could-fix-here">#&lt;/a>
&lt;/h2>&lt;p>Digging in, I realized that our version of cluster-autoscaler was a little behind and not the latest. I &lt;em>presumed&lt;/em> this was a bug in cluster-autoscaler (given a restart fixed it, implying it is a bug about state). To me, the &lt;em>class of problem&lt;/em> here is that we were not rolling out releases to our &amp;ldquo;supporting infrastructure&amp;rdquo; fast enough. Perhaps if we were on the most recent cluster-autoscaler release, this issue would have never happened.&lt;/p>
&lt;p>Additionally, this failure to scale up was reported to us by the community rather than by an automated alert. We should change that too!&lt;/p>
&lt;h2 id="structured-solutions">
Structured solutions
&lt;a class="header-anchor" href="#structured-solutions">#&lt;/a>
&lt;/h2>&lt;p>We follow a two week sprint cycle, and I love the (hard won) structure it provides us. I don&amp;rsquo;t want to arbitrarily start doing work that upsets prior committed work from that structure. However, we also treat support requests seriously and try to work them into the sprint. So I timeboxed myself for one hour, and saw what I could accomplish. Turns out, a lot!&lt;/p>
&lt;ol>
&lt;li>I
&lt;a href="https://github.com/2i2c-org/infrastructure/pull/6183" target="_blank" rel="noopener" >upgraded all our support components&lt;/a>, tested them, and rolled them out to &lt;em>all&lt;/em> our communities! This included upgrading Grafana, Prometheus, nginx-ingress as well as the cluster-autoscaler. This also restarts the cluster-autoscaler across our clusters, fixing this issue for other communities (if any had it).&lt;/li>
&lt;li>I
&lt;a href="https://github.com/2i2c-org/infrastructure/pull/6182" target="_blank" rel="noopener" >re-enabled&lt;/a> the automatic once a month PR for upgrading these support tasks. We had switched to doing them on a manual sprint cadence, but clearly that was not fast enough nor automated enough. We will instead work these into the sprint once the bot opens the PR. Credit to
&lt;a href="https://github.com/consideratio" target="_blank" rel="noopener" >Erik Sundell&lt;/a> for initially setting this up&lt;/li>
&lt;li>Create
&lt;a href="https://github.com/2i2c-org/infrastructure/issues/6185" target="_blank" rel="noopener" >an issue&lt;/a> to track the alert creation, and put it in our sprint backlog.&lt;/li>
&lt;li>(In an additional fifteen minute timebox) Write this blog post, to communicate out both to the affected communities and others what we have done.&lt;/li>
&lt;/ol>
&lt;p>By timeboxing myself, I didn&amp;rsquo;t upset our sprint cadence and was able to continue doing other work I had committed to in the sprint, while also fixing this &lt;em>class of issues&lt;/em> to the best of my ability.&lt;/p>
&lt;h2 id="moving-forward">
Moving forward
&lt;a class="header-anchor" href="#moving-forward">#&lt;/a>
&lt;/h2>&lt;p>While we have been &lt;em>implicitly&lt;/em> trying to solve whole classes of issues rather than individual instances of an issue as a team for a while, I want us to &lt;em>explicitly&lt;/em> do it from now on. Communicating this out to our communities is an important part of that, as is internal team training. This blog post is the former, and we are continually working on the latter :)&lt;/p>
&lt;h2 id="acknowledgements">
Acknowledgements
&lt;a class="header-anchor" href="#acknowledgements">#&lt;/a>
&lt;/h2>&lt;ul>
&lt;li>Thanks to the
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/collaborators/openscapes/" >OpenScapes&lt;/a> and
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/collaborators/cryocloud/" >CryoCloud&lt;/a> communities for working with us closely on infrastructure to identify improvements like this.&lt;/li>
&lt;/ul></description></item><item><title>Simplifying and speeding up Binder builds with BuildKit</title><link>https://deploy-preview-612--2i2c-org.netlify.app/blog/binder-buildkit/</link><pubDate>Mon, 03 Mar 2025 00:00:00 +0000</pubDate><guid>https://deploy-preview-612--2i2c-org.netlify.app/blog/binder-buildkit/</guid><description>&lt;p>Chris and Yuvi recently wrote
&lt;a href="https://blog.jupyter.org/simplifying-and-speeding-up-binder-builds-with-buildkit-d44f96582994" target="_blank" rel="noopener" >a blog post on the Jupyter blog&lt;/a> about a recent experiment to significantly reduce the cost of running a node on the mybinder.org federation.&lt;/p>
&lt;h2 id="acknowledgements">
Acknowledgements
&lt;a class="header-anchor" href="#acknowledgements">#&lt;/a>
&lt;/h2>&lt;ul>
&lt;li>
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/collaborators/pythia/" >Project Pythia&lt;/a> and
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/collaborators/nasa-open-science/" >NASA Open Science / ScienceCore&lt;/a> provide support for some of our work with the Binder project.&lt;/li>
&lt;li>
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/collaborators/jupyterhub/" >JupyterHub&lt;/a> for working with us to get this new node deployed for mybinder.org.&lt;/li>
&lt;/ul></description></item><item><title>2i2c joins the mybinder.org federation with a cheaper and faster way to deploy Binderhub</title><link>https://deploy-preview-612--2i2c-org.netlify.app/blog/binder-singlenode/</link><pubDate>Wed, 29 Jan 2025 00:00:00 +0000</pubDate><guid>https://deploy-preview-612--2i2c-org.netlify.app/blog/binder-singlenode/</guid><description>&lt;div class="alert alert-note">
&lt;div>
If you&amp;rsquo;re interested in supporting &lt;code>mybinder.org&lt;/code> with cloud resources, financial resources, or human resources, please see the
&lt;p>&lt;a href="https://mybinder.readthedocs.io/en/latest/about/support.html" target="_blank" rel="noopener" >Support Binder&lt;/a> page for how you can help.&lt;/p>
&lt;/div>
&lt;/div>
&lt;blockquote>
&lt;p>&lt;code>tl;dr&lt;/code>: The 2i2c team is joining the mybinder.org federation with a
&lt;a href="https://github.com/jupyterhub/mybinder.org-deploy/pull/3169/" target="_blank" rel="noopener" >single-node BinderHub instance at &lt;code>2i2c.mybinder.org&lt;/code>&lt;/a>. It should be much cheaper to run than auto-scaling Kubernetes clusters, and might be a good way to support &lt;code>mybinder.org&lt;/code> more sustainably. For questions or comments, join
&lt;a href="https://jupyter.zulipchat.com/#narrow/channel/469744-jupyterhub/topic/ANN.3A.202i2c.20joins.20mybinder.2Eorg.20federation.20with.20new.20strategy/near/496811301" target="_blank" rel="noopener" >this Jupyter Zulip thread&lt;/a>.&lt;/p>
&lt;/blockquote>
&lt;p>
&lt;a href="https://mybinder.org" target="_blank" rel="noopener" >&lt;code>mybinder.org&lt;/code>&lt;/a> is a massive public service for creating and sharing reproducible computational environments. It is managed by the JupyterHub team and
&lt;a href="https://mybinder.readthedocs.io/en/latest/about/federation.html" target="_blank" rel="noopener" >members of the &lt;code>mybinder.org&lt;/code> federation&lt;/a>. One challenge in running
&lt;a href="https://mybinder.org" target="_blank" rel="noopener" >&lt;code>mybinder.org&lt;/code>&lt;/a> is identifying cloud credits or financial resources to support the cloud infrastructure that runs the service. Two years ago,
&lt;a href="https://medium.com/jupyter-blog/mybinder-org-reducing-capacity-c93ccfc6413f" target="_blank" rel="noopener" >Google stopped supporting &lt;code>mybinder.org&lt;/code> federation with cloud credits&lt;/a>, and last month
&lt;a href="https://discourse.jupyter.org/t/mybinder-org-reduced-capacity-stability/31750" target="_blank" rel="noopener" >the federation lost more capacity&lt;/a>, leaving only
&lt;a href="https://www.gesis.org/en/home" target="_blank" rel="noopener" >GESIS&lt;/a> and
&lt;a href="https://us.ovhcloud.com/" target="_blank" rel="noopener" >OVH&lt;/a> as remaining federation members&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup>. This makes &lt;code>mybinder.org&lt;/code> less reliable, slower, and generally less useful to the world.&lt;/p>
&lt;p>The landscape of cloud infrastructure technology and services has changed considerably, and we think that there&amp;rsquo;s a way to deploy BinderHub instances with lower costs and less complexity. We&amp;rsquo;ve accomplished this by deploying a &lt;strong>single-node Kubernetes cluster&lt;/strong> on a VM provider that is much cheaper, now running at &lt;code>2i2c.mybinder.org&lt;/code>. This both relieves Binder&amp;rsquo;s short-term capacity shortage and may provide an easier pathway for others to support the project in the future.&lt;/p>
&lt;p>Below, we&amp;rsquo;ll describe what has changed to enable this, what we&amp;rsquo;re deploying, and what the impact should be.&lt;/p>
&lt;h2 id="cloud-infrastructure-has-become-cheaper-and-more-commodified">
Cloud infrastructure has become cheaper and more commodified
&lt;a class="header-anchor" href="#cloud-infrastructure-has-become-cheaper-and-more-commodified">#&lt;/a>
&lt;/h2>&lt;p>A key theory of mybinder.org (and 2i2c) is that commercial cloud infrastructure will be commidified over time &amp;ndash; what begins as cutting-edge functionality will become commonplace and offered across all cloud providers. As a result, costs will go down over time. Abstractions like
&lt;a href="https://kubernetes.io/" target="_blank" rel="noopener" >Kubernetes&lt;/a> will allow you to easily migrate workflows and infrastructure between cloud providers. As a result, you&amp;rsquo;ll be able to easily &lt;em>follow those costs&lt;/em> where there are better options. That&amp;rsquo;s essentially what is happening here.&lt;/p>
&lt;p>There are two key changes that make it much easier to deploy a BinderHub instance at a fraction of the cost:&lt;/p>
&lt;p>First, &lt;strong>Kubernetes has matured and become easier to deploy&lt;/strong>. When mybinder.org started, it was using the cutting-edge of Kubernetes functionality. This meant that we needed to use cloud providers that provided a &lt;em>managed Kubernetes service&lt;/em> to deal with this complexity. A managed Kubernetes offering tends to be expensive, offered by only a few cloud providers, and thus raises costs across-the-board for the provider that offers it.&lt;/p>
&lt;p>However, this was almost a decade ago, and Kubernetes has become both more functional and more stable. There are now many more ways of running Kubernetes, especially for simpler workflows that don&amp;rsquo;t require autoscaling. In the last several months, we&amp;rsquo;ve been experimenting with &lt;strong>single-node Kubernetes workflows&lt;/strong> via
&lt;a href="https://k3s.io/" target="_blank" rel="noopener" >K3s&lt;/a>&lt;sup id="fnref:2">&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup>.
&lt;a href="https://k3s.io/" target="_blank" rel="noopener" >K3s&lt;/a> is a lightweight Kubernetes distribution that is much easier to deploy and manage. It&amp;rsquo;s designed for things like edge computing and low-resource environments, and it can be deployed with a single script!&lt;/p>
&lt;p>By running a Kubernetes cluster on a single node, we don&amp;rsquo;t need a &amp;ldquo;managed Kubernetes service&amp;rdquo;, which means &lt;strong>we can choose from a much larger pool of infrastructure / cloud providers&lt;/strong>. If all we need is a running VM, this is something the tech industry has been doing for decades.&lt;/p>
&lt;p>Second, &lt;strong>Managed Object Storage services have more open source options, and are more commodified and cheaper&lt;/strong>. In addition to Kubernetes, the other thing that BinderHub needs is a way to store and retrieve images for the environments that it builds. This also used to be a fairly complex problem, and thus required managed solutions from cloud providers that charged a premium for their service. However, a number of open source object storage solutions have emerged and made it much easier for providers to support this workflow.&lt;sup id="fnref:3">&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref">3&lt;/a>&lt;/sup>. Because these are open source, infrastructure providers can provide managed object storage at a fraction of the cost.&lt;/p>
&lt;p>Because of these two things, we&amp;rsquo;ve learned that we can run a BinderHub instance on a single VM from a much larger pool of infrastructure providers. This means &lt;strong>we should be able to run BinderHub instances at a fraction of the cost&lt;/strong>.&lt;sup id="fnref:4">&lt;a href="#fn:4" class="footnote-ref" role="doc-noteref">4&lt;/a>&lt;/sup>&lt;/p>
&lt;h2 id="deploying-binderhub-on-a-single-node-vm-is-cheaper-and-simpler">
Deploying BinderHub on a single-node VM is cheaper and simpler
&lt;a class="header-anchor" href="#deploying-binderhub-on-a-single-node-vm-is-cheaper-and-simpler">#&lt;/a>
&lt;/h2>&lt;p>Last week, we
&lt;a href="https://github.com/jupyterhub/mybinder.org-deploy/pull/3169" target="_blank" rel="noopener" >deployed 2i2c.mybinder.org&lt;/a>, a single-node Kubernetes instance on
&lt;a href="https://hetzner.com/cloud" target="_blank" rel="noopener" >Hetzner&lt;/a> cloud using
&lt;a href="https://k3s.io/" target="_blank" rel="noopener" >K3s&lt;/a>. This will run on a single node VM, with a Kubernetes instance that is entirely managed by us, and with managed object storage from Hetzner. Compared to other cloud providers, it is &lt;strong>around 5x cheaper per month&lt;/strong>.&lt;/p>
&lt;figure id="figure-comparison-of-rough-monthly-costs-across-different-cloud-providers-for-similar-vm-instances-these-are-rough-estimates-based-on-cloud-provider-pricing-pages-for-an-on-demand-vm-with-around-190gb-ram-pricing-pages-hetzner-cloudhttpswwwhetznercomcloud-300-microsoft-azurehttpsazurecomeda6294b08dfa49639f74caad1630bbe4-1300-google-cloud-platformhttpscloudgooglecomproductscalculatorhlendlcjhdavjrwlrbevpeumpnqzawtvrrmkxuumtnalv0t0rnnu5pmhpav1eywlrnmfphsxppve1rqve9praigirdrtq3qtywqy1dnum5ltq3qkqtqtm3ms05mjbcqju1qjngrjg-1500-amazon-web-serviceshttpscalculatorawsestimateida3bddb8bdbfa2058b941b669e408141e7fd18da4-1600">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Comparison of rough monthly costs across different cloud providers for similar VM instances. These are rough estimates based on cloud provider pricing pages for an on-demand VM with around 190GB RAM. Pricing pages: [Hetzner Cloud](https://www.hetzner.com/cloud) ~$300, [Microsoft Azure](https://azure.com/e/da6294b08dfa49639f74caad1630bbe4) ~$1,300, [Google Cloud Platform](https://cloud.google.com/products/calculator?hl=en&amp;amp;dl=CjhDaVJrWlRBeVpEUmpNQzAwTVRrMkxUUmtNalV0T0RnNU5pMHpaV1EyWlRnMFpHSXpPVE1RQVE9PRAIGiRDRTQ3QTYwQy1DNUM5LTQ3QkQtQTM3MS05MjBCQjU1QjNGRjg) ~$1,500, [Amazon Web Services](https://calculator.aws/#/estimate?id=a3bddb8bdbfa2058b941b669e408141e7fd18da4) ~$1,600." srcset="
/blog/binder-singlenode/featured_hu5599e630254656f9a400bcb8f9798a4e_195115_f1bc2f9ecf0ebdbd21595b574119a81a.webp 400w,
/blog/binder-singlenode/featured_hu5599e630254656f9a400bcb8f9798a4e_195115_79d88c8c7dddbe75eeb374dc7b9a0c75.webp 760w,
/blog/binder-singlenode/featured_hu5599e630254656f9a400bcb8f9798a4e_195115_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://deploy-preview-612--2i2c-org.netlify.app/blog/binder-singlenode/featured_hu5599e630254656f9a400bcb8f9798a4e_195115_f1bc2f9ecf0ebdbd21595b574119a81a.webp"
width="760"
height="540"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Comparison of rough monthly costs across different cloud providers for similar VM instances. These are rough estimates based on cloud provider pricing pages for an on-demand VM with around 190GB RAM. Pricing pages:
&lt;a href="https://www.hetzner.com/cloud" target="_blank" rel="noopener" >Hetzner Cloud&lt;/a> ~$300,
&lt;a href="https://azure.com/e/da6294b08dfa49639f74caad1630bbe4" target="_blank" rel="noopener" >Microsoft Azure&lt;/a> ~$1,300,
&lt;a href="https://cloud.google.com/products/calculator?hl=en&amp;amp;dl=CjhDaVJrWlRBeVpEUmpNQzAwTVRrMkxUUmtNalV0T0RnNU5pMHpaV1EyWlRnMFpHSXpPVE1RQVE9PRAIGiRDRTQ3QTYwQy1DNUM5LTQ3QkQtQTM3MS05MjBCQjU1QjNGRjg" target="_blank" rel="noopener" >Google Cloud Platform&lt;/a> ~$1,500,
&lt;a href="https://calculator.aws/#/estimate?id=a3bddb8bdbfa2058b941b669e408141e7fd18da4" target="_blank" rel="noopener" >Amazon Web Services&lt;/a> ~$1,600.
&lt;/figcaption>&lt;/figure>
&lt;!-- Machines for the figure above:
Hetzner: CCX63
Amazon Web Services: m8g.12xlarge
Google Cloud Platform: n2-standard-48
Microsoft Azure: D48as v5
-->
&lt;p>Running a single-node Kubernetes instance will be a cheap and effective way to handle a lot of &lt;code>mybinder.org&lt;/code>&amp;rsquo;s capacity needs. Because it&amp;rsquo;s a single node cluster, there is no auto-scaling (one reason it is so cheap), which reduces a lot of the complexity we&amp;rsquo;ll have to manage. These are acceptable tradeoffs for a service like &lt;code>mybinder.org&lt;/code>, which runs entirely ephemeral sessions with very limited resources and no promises about uptime, persistence, etc.&lt;/p>
&lt;p>You might be wondering: &amp;ldquo;I thought Kubernetes was supposed to &lt;em>save money&lt;/em>.&amp;rdquo; Normally, running Kubernetes for scalable workflows does save costs because you can scale infrastructure to match your capacity needs. Without scaling, you&amp;rsquo;d need to provide a VM that can &lt;em>always&lt;/em> handle your &lt;em>maximum capacity&lt;/em> needs (and pay for the costs the entire time). With Kubernetes, you can request and remove nodes to grow your capacity as-needed (and save money doing so). It looks something like this:&lt;/p>
&lt;figure id="figure-the-cost-difference-between-a-single-large-vm-vs-scalable-nodes-given-variable-usage-over-time-kubernetes-allows-you-to-scale-your-cost-up-and-down-with-need-which-is-more-efficient-than-paying-for-a-single-vm-that-can-withstand-your-maximum-capacity">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="The cost difference between a single large VM vs scalable nodes. Given variable usage over time, kubernetes allows you to scale your cost up and down with need, which is more efficient than paying for a single VM that can withstand your maximum capacity."
src="https://deploy-preview-612--2i2c-org.netlify.app/blog/binder-singlenode/images/scalable.excalidraw.svg"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
The cost difference between a single large VM vs scalable nodes. Given variable usage over time, kubernetes allows you to scale your cost up and down with need, which is more efficient than paying for a single VM that can withstand your maximum capacity.
&lt;/figcaption>&lt;/figure>
&lt;p>However, there is a built-in cost you pay when you use a service that provides managed Kubernetes. &lt;strong>Managed Kubernetes services are complex and expensive&lt;/strong>, and this is reflected across-the-board in the provider&amp;rsquo;s costs. What if we could achieve the same outcome with a much simpler cloud offering like a single VM?&lt;/p>
&lt;p>We did a bit of research and discovered that the Kubernetes and object storage landscape has indeed evolved significantly since the early days of mybinder.org. For example,
&lt;a href="https://www.hetzner.com/cloud/" target="_blank" rel="noopener" >Hetzner&lt;/a> is a cloud provider that has been around for a long time. It has single-node VMs that are about &lt;code>4x&lt;/code> cheaper than their counterparts in Google Cloud or AWS, and provides managed object storage that uses
&lt;a href="https://min.io/" target="_blank" rel="noopener" >MinIO&lt;/a> in a cost-effective way. Using
&lt;a href="https://k3s.io/" target="_blank" rel="noopener" >K3s&lt;/a>, we can run a lightweight, single-node Kubernetes runtime on this node, and deploy a BinderHub with the same infrastructure as any other BinderHub federation member.&lt;/p>
&lt;p>By our estimate, we could fit around &lt;strong>400 simultaneous sessions&lt;/strong> on &lt;code>mybinder.org&lt;/code> (because each session uses very few cloud resources). This is already the majority of mybinder.org&amp;rsquo;s capacity needs, and at a much lower cost than using a scalable Kubernetes cluster. The cost picture looks something like this:&lt;/p>
&lt;figure id="figure-if-your-single-vm-is-much-cheaper-it-might-still-be-the-cheapest-option-in-the-case-of-a-hetzner-vm-it-has-roughly-the-same-capacity-as-another-cloud-providers-vm-but-at-14-of-the-cost">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="If your single VM is much cheaper, it might still be the cheapest option. In the case of a Hetzner VM, it has roughly the same capacity as another cloud provider&amp;#39;s VM, but at 1/4 of the cost."
src="https://deploy-preview-612--2i2c-org.netlify.app/blog/binder-singlenode/images/single.excalidraw.svg"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
If your single VM is much cheaper, it might still be the cheapest option. In the case of a Hetzner VM, it has roughly the same capacity as another cloud provider&amp;rsquo;s VM, but at 1/4 of the cost.
&lt;/figcaption>&lt;/figure>
&lt;h2 id="2i2cmybinderorg-now-serves-70-of-the-mybinderorg-federation">
2i2c.mybinder.org now serves 70% of the mybinder.org federation
&lt;a class="header-anchor" href="#2i2cmybinderorg-now-serves-70-of-the-mybinderorg-federation">#&lt;/a>
&lt;/h2>&lt;p>About a week ago, we launched
&lt;a href="https://2i2c.mybinder.org" target="_blank" rel="noopener" >2i2c.mybinder.org&lt;/a> running via the methodology we described above. We intended to run this as a longer experiment, but believe that it has already proven useful enough to consider &amp;ldquo;ready for production&amp;rdquo;. We recently
&lt;a href="https://github.com/jupyterhub/mybinder.org-deploy/pull/3196" target="_blank" rel="noopener" >increased 2i2c.mybinder.org&amp;rsquo;s load to 70%&lt;/a> and will continue to monitor its performance over time. Here&amp;rsquo;s a plot of where each mybinder.org session has been run over the past ten days - you can see the moment where we turn on &lt;code>2i2c.mybinder.org&lt;/code> to the left:&lt;/p>
&lt;figure id="figure-sessions-launched-on-mybinderorgs-federation-over-the-past-ten-days-the-yellow-area-represents-sessions-run-on-2i2cmybinderorg-they-now-make-up-the-majority-of-launches-on-mybinderorg-prior-to-this-gesismybinderorg-was-the-only-remaining-federation-member">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Sessions launched on mybinder.org&amp;#39;s federation over the past ten days. The yellow area represents sessions run on `2i2c.mybinder.org`. They now make up the majority of launches on mybinder.org. Prior to this, `gesis.mybinder.org` was the only remaining federation member." srcset="
/blog/binder-singlenode/images/grafana_hu475853c06f9a32183866c212d09dafeb_419800_275a545bcca83f88b60067016558d1a1.webp 400w,
/blog/binder-singlenode/images/grafana_hu475853c06f9a32183866c212d09dafeb_419800_48678307c04cb5aa3d312f2d025029ad.webp 760w,
/blog/binder-singlenode/images/grafana_hu475853c06f9a32183866c212d09dafeb_419800_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://deploy-preview-612--2i2c-org.netlify.app/blog/binder-singlenode/images/grafana_hu475853c06f9a32183866c212d09dafeb_419800_275a545bcca83f88b60067016558d1a1.webp"
width="760"
height="455"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Sessions launched on mybinder.org&amp;rsquo;s federation over the past ten days. The yellow area represents sessions run on &lt;code>2i2c.mybinder.org&lt;/code>. They now make up the majority of launches on mybinder.org. Prior to this, &lt;code>gesis.mybinder.org&lt;/code> was the only remaining federation member.
&lt;/figcaption>&lt;/figure>
&lt;p>For now, 2i2c is sponsoring a max of €350 a month (with some currency conversion noise) to run this service. We&amp;rsquo;ll provide in-kind labor to run this node, and treat it as an organizational investment in supporting open science, as well as learning new Kubernetes and cloud infrastructure workflows. We&amp;rsquo;re going to use funds recovered from communities in our
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/platform/" >community hub network&lt;/a>, along with in-kind labor to build out this experiment.&lt;/p>
&lt;p>In six months, we&amp;rsquo;ll evaluate how much effort it was to run this node for &lt;code>mybinder.org&lt;/code>, whether it meaningfully helped with &lt;code>mybinder.org&lt;/code>&amp;rsquo;s capacity, and whether it was sustainable for us from a time and labor perspective.&lt;/p>
&lt;h2 id="others-can-join-the-mybinderorg-federation-using-this-approach-as-well">
Others can join the mybinder.org federation using this approach as well
&lt;a class="header-anchor" href="#others-can-join-the-mybinderorg-federation-using-this-approach-as-well">#&lt;/a>
&lt;/h2>&lt;p>We think that developing this single-node BinderHub workflow will make it much easier for others to join the mybinder.org federation, because it lowers the infrastructure and skills complexity needed to join.
&lt;a href="https://github.com/jupyterhub/mybinder.org-deploy/blob/72a1a34509e2c43aec788f602250c58d9d849a13/docs/source/deployment/k3s.md" target="_blank" rel="noopener" >Here is a brief guide we&amp;rsquo;ve written for deploying a BinderHub with K3s&lt;/a>. We are helping a few interested organizations deploy their own BinderHubs in this way in order to validate the idea, and are hopeful that this makes it much easier to grow mybinder.org&amp;rsquo;s capacity via new federation members.&lt;sup id="fnref:5">&lt;a href="#fn:5" class="footnote-ref" role="doc-noteref">5&lt;/a>&lt;/sup>&lt;/p>
&lt;p>We&amp;rsquo;re excited to experiment with new ways to support &lt;code>mybinder.org&lt;/code>. We think this is an excellent example of how open standards and technology lead to cloud workflows with lower costs and more flexibility. We also think it&amp;rsquo;s a good example of how it is valuable to have organizations aligned with open science (like 2i2c!) acting in this space. If you have any questions or comments, please join
&lt;a href="https://jupyter.zulipchat.com/#narrow/channel/469744-jupyterhub/topic/ANN.3A.202i2c.20joins.20mybinder.2Eorg.20federation.20with.20new.20strategy/near/496811301" target="_blank" rel="noopener" >this Jupyter Zulip thread&lt;/a>&lt;/p>
&lt;h2 id="anybody-want-to-fund-this">
Anybody want to fund this?
&lt;a class="header-anchor" href="#anybody-want-to-fund-this">#&lt;/a>
&lt;/h2>&lt;p>If you&amp;rsquo;re interested in making open science infrastructure like Binder more scalable and sustainable, we&amp;rsquo;d love to find more resources to both sustain this node and cover more development time to run this experiment.
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/blog/binder-singlenode/mailto:hello@2i2c.org" >Feel free to reach out here&lt;/a>.&lt;/p>
&lt;p>If you have access to VMs and object storage, and are interested in running a mybinder.org federation member using the methods described here, check out
&lt;a href="https://github.com/jupyterhub/mybinder.org-deploy/blob/72a1a34509e2c43aec788f602250c58d9d849a13/docs/source/deployment/k3s.md" target="_blank" rel="noopener" >our brief guide for deploying a BinderHub with K3s&lt;/a>.&lt;/p>
&lt;p>If you&amp;rsquo;re generally interested in supporting &lt;code>mybinder.org&lt;/code> with cloud resources, financial resources, or human resources, please see the
&lt;a href="https://mybinder.readthedocs.io/en/latest/about/support.html" target="_blank" rel="noopener" >Support Binder&lt;/a> page for how you can help.&lt;/p>
&lt;div class="alert alert-note">
&lt;div>
If you&amp;rsquo;re interested in supporting &lt;code>mybinder.org&lt;/code> with cloud resources, financial resources, or human resources, please see the
&lt;p>&lt;a href="https://mybinder.readthedocs.io/en/latest/about/support.html" target="_blank" rel="noopener" >Support Binder&lt;/a> page for how you can help.&lt;/p>
&lt;/div>
&lt;/div>
&lt;h2 id="acknowledgements">
Acknowledgements
&lt;a class="header-anchor" href="#acknowledgements">#&lt;/a>
&lt;/h2>&lt;ul>
&lt;li>Thanks to the
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/collaborators/jupyterhub/" >JupyterHub community&lt;/a> for helping us set up this new node.&lt;/li>
&lt;li>Thanks to
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/members/" >our member communities&lt;/a> whose fees currently support this work.&lt;/li>
&lt;/ul>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>Many thanks to
&lt;a href="https://www.gesis.org/en/home" target="_blank" rel="noopener" >GESIS&lt;/a> and
&lt;a href="https://us.ovhcloud.com/" target="_blank" rel="noopener" >OVH&lt;/a> for their continued support of mybinder.org, your contributions to keeping this service running are critical!&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>thanks to
&lt;a href="https://carlboettiger.info/" target="_blank" rel="noopener" >Carl Boettiger&lt;/a> for collaborating on this with us!&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:3">
&lt;p>One example is
&lt;a href="https://min.io/" target="_blank" rel="noopener" >MinIO&lt;/a>, which is used by
&lt;a href="https://hetzner.com/cloud" target="_blank" rel="noopener" >Hetzner&lt;/a> to provide managed object storage for their single-node VMs.&amp;#160;&lt;a href="#fnref:3" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:4">
&lt;p>For example,
&lt;a href="https://hetzner.com/cloud" target="_blank" rel="noopener" >Hetzner&lt;/a> provides a single-VM option with managed object storage that is roughly 25% of the cost of other cloud providers that also offer autoscaling Kubernetes services. There are many other infrastructure providers who could be used in this way.&amp;#160;&lt;a href="#fnref:4" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:5">
&lt;p>We&amp;rsquo;re also experimenting with a few other ways to reduce the complexity and costs of running a BinderHub even further, but will have more on that later as we learn more :-).&amp;#160;&lt;a href="#fnref:5" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>Announcing our formal commitment to open technology</title><link>https://deploy-preview-612--2i2c-org.netlify.app/blog/community-ownership/</link><pubDate>Wed, 15 Jan 2025 00:00:00 +0000</pubDate><guid>https://deploy-preview-612--2i2c-org.netlify.app/blog/community-ownership/</guid><description>&lt;p>In this post, we&amp;rsquo;re sharing our
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/open-technology/" >Commitment to Open Technology&lt;/a>. It is focused on &lt;em>software licenses&lt;/em> for reasons we&amp;rsquo;ll describe below. We hope that it clarifies what kind of licenses we&amp;rsquo;ll use, and assures our communities that we will not change our stance towards open source technology in the future. This ensures 2i2c&amp;rsquo;s long-term commitment to community-owned and open infrastructure.&lt;/p>
&lt;p>Being a platform and service provider gives us a lot of power, and also introduces a potential source of &lt;em>lock-in&lt;/em> for our member communities. While 2i2c&amp;rsquo;s organizational mission and culture are strongly aligned with open infrastructure, we believe it&amp;rsquo;s important to encode commitments like these in a formal way to provide both transparency and accountability to our member communities.&lt;/p>
&lt;h2 id="our-commitment-to-open-technology">
Our commitment to open technology
&lt;a class="header-anchor" href="#our-commitment-to-open-technology">#&lt;/a>
&lt;/h2>&lt;p>Below we copy the original language of this policy from our
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/open-technology/" >Commitment to Open Technology&lt;/a>:&lt;/p>
&lt;!-- TODO: When we switch to MyST, we should embed this rather than copy/paste -->
&lt;p>&lt;em>Definitions of MUST, MUST NOT, SHOULD, MAY, etc are defined in
&lt;a href="https://tools.ietf.org/html/rfc2119" target="_blank" rel="noopener" >RFC 2119&lt;/a>&lt;/em>&lt;/p>
&lt;ol>
&lt;li>All engineering artifacts (code, documentation, etc) produced by 2i2c&amp;rsquo;s engineering team MUST be licensed under an open source license approved by a non-profit organization that is not 2i2c.&lt;/li>
&lt;li>Open Source Projects originating at 2i2c, or stewarded by 2i2c, MUST NOT require a
&lt;a href="https://en.wikipedia.org/wiki/Contributor_License_Agreement" target="_blank" rel="noopener" >Contributor Licensing Agreement&lt;/a> that includes Copyright Assignment to 2i2c.&lt;/li>
&lt;li>The list of external organizations that define licenses we accept are
&lt;ol>
&lt;li>
&lt;a href="https://opensource.org/" target="_blank" rel="noopener" >the Open Source Initiative&lt;/a>&lt;/li>
&lt;li>the
&lt;a href="https://ethicalsource.dev/" target="_blank" rel="noopener" >Organization for Ethical Source&lt;/a>.&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>Modifying (1), (2), or (3) MUST be done through a 2/3 majority vote of 2i2c staff.&lt;/li>
&lt;/ol>
&lt;h2 id="what-does-this-commitment-mean">
What does this commitment mean?
&lt;a class="header-anchor" href="#what-does-this-commitment-mean">#&lt;/a>
&lt;/h2>&lt;p>In plain language, here&amp;rsquo;s what this commitment means:&lt;/p>
&lt;ol>
&lt;li>We&amp;rsquo;ll only use open source licenses that have been approved by standard non-profits that are broadly recognized by the tech industry.&lt;/li>
&lt;li>For anything we build, we won&amp;rsquo;t require contributors to give up the rights to their contributions via CLAs, so that it is much harder for 2i2c to change our licenses in the future.&lt;/li>
&lt;li>Changing this policy will require organization-wide agreement, and in the future we&amp;rsquo;ll give authority over this policy to a group of people representing our member communities.&lt;/li>
&lt;/ol>
&lt;h2 id="why-are-licenses-and-clas-important">
Why are licenses and CLAs important?
&lt;a class="header-anchor" href="#why-are-licenses-and-clas-important">#&lt;/a>
&lt;/h2>&lt;p>Many organizations claim to be committed to open infrastructure, while retaining the ability to &lt;em>change this commitment in the future when it is in their interests&lt;/em>. A classic example of this is a &amp;ldquo;bait and switch&amp;rdquo; that looks something like this:&lt;/p>
&lt;ol>
&lt;li>A company releases software under an open source license and professes to build an open source community around it.&lt;/li>
&lt;li>However, they retain the rights to all of the code in their projects through a
&lt;a href="https://en.wikipedia.org/wiki/Contributor_License_Agreement" target="_blank" rel="noopener" >Contributor License Agreement&lt;/a> (CLA) with copyright assignment. This generally means that contributors must &lt;em>give up the rights to their contribution&lt;/em> in order to make that contribution.&lt;/li>
&lt;li>Once their product has gained traction and it is in their interests, the company can &lt;em>change the license&lt;/em> to whatever they wish (even one that is not open source) because they retain the rights to all contributions in the codebase.&lt;/li>
&lt;li>They then leverage this new position as owners of a proprietary project to extract business value or grow their position in a market.&lt;/li>
&lt;/ol>
&lt;p>Think this sounds unlikely? Here are just a few recent examples of companies that have switched their license after many years of releasing their technology under an open source license:&lt;/p>
&lt;ul>
&lt;li>
&lt;a href="https://redis.io/blog/redis-adopts-dual-source-available-licensing/" target="_blank" rel="noopener" >Redis&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://www.hashicorp.com/blog/hashicorp-adopts-business-source-license" target="_blank" rel="noopener" >Hashicorp / Terraform&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://en.wikipedia.org/wiki/Elasticsearch#Licensing_changes" target="_blank" rel="noopener" >Elastic Search&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>We want to ensure our communities that 2i2c is not headed down this path, in order to give them confidence in treating us as a long-term service partner.&lt;/p>
&lt;h2 id="what-does-this-change-about-2i2cs-open-source-commitment">
What does this change about 2i2c&amp;rsquo;s open source commitment?
&lt;a class="header-anchor" href="#what-does-this-change-about-2i2cs-open-source-commitment">#&lt;/a>
&lt;/h2>&lt;p>In short: nothing. These are already the principles that 2i2c was committed to from its inception, and already implied via our
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/right-to-replicate/" >Right to Replicate&lt;/a>. However, we wanted to make these commitments more formally in order to give ourselves more accountability to sticking with them, and to provide more transparency for our community members and stakeholders.&lt;/p>
&lt;h2 id="who-is-this-for">
Who is this for?
&lt;a class="header-anchor" href="#who-is-this-for">#&lt;/a>
&lt;/h2>&lt;p>We imagine three audiences for this policy:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>2i2c present and future staff&lt;/strong> who want to ensure that their organization remains committed to our open principles. This document provides a sense of psychological safety to have bold discussions about structuring our approach to open source.&lt;/li>
&lt;li>&lt;strong>Member communities and 2i2c stakeholders&lt;/strong> who need to have an understanding of the guarantees that we provide in order to trust 2i2c as a service developer and provider. This is similar to the effect our
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/right-to-replicate/" >Right to Replicate&lt;/a> has.&lt;/li>
&lt;li>&lt;strong>Open source communities&lt;/strong> who need to understand our long-term commitment and goals around open technology in order to trust as a peer and collaborator within open source communities.&lt;/li>
&lt;/ol>
&lt;h2 id="wed-love-feedback">
We&amp;rsquo;d love feedback
&lt;a class="header-anchor" href="#wed-love-feedback">#&lt;/a>
&lt;/h2>&lt;p>We hope that these ideas both clarify our intent and the reason that we think it&amp;rsquo;s important. We&amp;rsquo;d love feedback about early refinements to these principles in order to make them more effective, as well as ways that we can provide more community oversight and participation in evolving these policies moving forward. If you have any thoughts to share, please send feedback via e-mail
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/blog/community-ownership/mailto:hello@2i2c.org" >hello@2i2c.org&lt;/a>.&lt;/p>
&lt;hr>
&lt;p>&lt;strong>Acknowledgements&lt;/strong>: &lt;em>The creation of this policy and the rationale behind it was led by
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/author/yuvaraj-yuvi/" >Yuvi Panda&lt;/a> with feedback from 2i2c&amp;rsquo;s team. This blog post was co-written with
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/author/chris-holdgraf/" >Chris Holdgraf&lt;/a>. Strategic work like this is supported by a grant from
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/collaborators/navigation/" >The Navigation Fund&lt;/a>&lt;/em>.&lt;/p></description></item><item><title>NASA VEDA &amp; 2i2c Update for Q4 2024 (Oct-Dec 2024)</title><link>https://deploy-preview-612--2i2c-org.netlify.app/blog/veda-update-q4-2024/</link><pubDate>Tue, 07 Jan 2025 15:18:37 -0800</pubDate><guid>https://deploy-preview-612--2i2c-org.netlify.app/blog/veda-update-q4-2024/</guid><description>&lt;p>A non-exhaustive list of things 2i2c and
&lt;a href="https://developmentseed.org/" target="_blank" rel="noopener" >Development Seed&lt;/a> did with the
&lt;a href="https://www.earthdata.nasa.gov/data/tools/veda" target="_blank" rel="noopener" >NASA VEDA&lt;/a> project last quarter!&lt;/p>
&lt;h2 id="automated-backups-and-alerting-with-jupyterhub-home-nfs">
Automated backups and alerting with &lt;code>jupyterhub-home-nfs&lt;/code>
&lt;a class="header-anchor" href="#automated-backups-and-alerting-with-jupyterhub-home-nfs">#&lt;/a>
&lt;/h2>&lt;p>
&lt;a href="https://github.com/NASA-IMPACT/veda-jupyterhub/issues/56" target="_blank" rel="noopener" >Tracking Issue&lt;/a>&lt;/p>
&lt;p>
&lt;a href="https://github.com/2i2c-org/jupyterhub-home-nfs/" target="_blank" rel="noopener" >jupyterhub-home-nfs&lt;/a> is a young project to provide flexible per-user home directory limits on JupyterHub - an important feature for controlling cloud costs.
&lt;a href="https://sunu.in/" target="_blank" rel="noopener" >Tarashish Mishra&lt;/a> and
&lt;a href="https://sgibson91.github.io/cv/" target="_blank" rel="noopener" >Sarah Gibson&lt;/a> have been leading this project for the last few months. Since we are moving away from
&lt;a href="https://aws.amazon.com/efs/" target="_blank" rel="noopener" >AWS Managed EFS&lt;/a> here, we had to do some work to recreate some of the benefits EFS gives us out of the box. During this quarter, we:&lt;/p>
&lt;ol>
&lt;li>Set up automated backups so we can recover files in cases of disaster&lt;/li>
&lt;li>Set up automated alerting (via prometheus and pagerduty) to know if our backing EBS device is getting full and we need to perform a manual intervention&lt;/li>
&lt;li>Deployed this to a few other communities (
&lt;a href="https://www.cryocloud.io/" target="_blank" rel="noopener" >CryoCloud&lt;/a> and
&lt;a href="https://nmfs-openscapes.github.io/" target="_blank" rel="noopener" >NMFS Openscapes&lt;/a>) to broaden adoption.&lt;/li>
&lt;/ol>
&lt;p>We will continue doing work on &lt;code>jupyterhub-home-nfs&lt;/code> in the upcoming quarter! If this is functionality you are interested in deploying, please reach out to us to collaborate!&lt;/p>
&lt;h2 id="enable-users-to-dynamically-build-environments-with-jupyterhub-fancy-profiles">
Enable users to dynamically build environments with &lt;code>jupyterhub-fancy-profiles&lt;/code>
&lt;a class="header-anchor" href="#enable-users-to-dynamically-build-environments-with-jupyterhub-fancy-profiles">#&lt;/a>
&lt;/h2>&lt;p>
&lt;a href="https://github.com/NASA-IMPACT/veda-jupyterhub/issues/58" target="_blank" rel="noopener" >Tracking Issue&lt;/a>&lt;/p>
&lt;p>We covered this more extensively in
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/blog/jupyterhub-fancy-profiles-rollout/" >another blog post&lt;/a>, so go read that!&lt;/p>
&lt;p>This work in particular is a good demonstrator of 2i2c&amp;rsquo;s value - it started off with a
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/blog/jupyterhub-binderhub-gesis/" >grant from GESIS&lt;/a>, and now with support from
&lt;a href="https://impact.earthdata.nasa.gov/" target="_blank" rel="noopener" >NASA IMPACT&lt;/a> we are able to bring it to a &lt;em>lot&lt;/em> of communities, not just the ones that funded it.&lt;/p>
&lt;p>Ongoing work here will focus on improving the UX as well as better documentation so users can actually use it!&lt;/p>
&lt;h2 id="open-in-qgis-from-veda-ui">
&amp;ldquo;Open in QGIS&amp;rdquo; from VEDA UI
&lt;a class="header-anchor" href="#open-in-qgis-from-veda-ui">#&lt;/a>
&lt;/h2>&lt;p>
&lt;a href="https://github.com/NASA-IMPACT/veda-jupyterhub/issues/59" target="_blank" rel="noopener" >Tracking Issue&lt;/a>&lt;/p>
&lt;p>We had worked in the past with many communities in enabling
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/blog/qgis-greenland/" >QGIS on the Cloud&lt;/a>, and this quarter we got closer to enabling a contextual &amp;lsquo;Open in QGIS&amp;rsquo; button in the
&lt;a href="https://www.earthdata.nasa.gov/dashboard/" target="_blank" rel="noopener" >VEDA Dashboard&lt;/a>! Here is a quick demo:&lt;/p>
&lt;p>&lt;video src="./open-in-qgis.mp4" muted controls>&lt;/video>&lt;/p>
&lt;p>(This shows the workflow when user is already logged into the JupyterHub and had started the server)&lt;/p>
&lt;p>You can play with this in
&lt;a href="https://deploy-preview-688--ghg-demo.netlify.app/exploration" target="_blank" rel="noopener" >this preview&lt;/a>, although you need to have access to the NASA VEDA hub to fully try it out at this point.&lt;/p>
&lt;p>Tarashish from Development Seed is again responsible for most of the work here, available in
&lt;a href="https://github.com/sunu/jupyter-remote-qgis-proxy" target="_blank" rel="noopener" >jupyter-remote-qgis-proxy&lt;/a>. You can use it to create &amp;lsquo;magic links&amp;rsquo; that will open QGIS in a desktop environment in your browser, and add a specific layer to it! Our hope is that this allows primarily GIS folks to better use tools they already are familiar with in cloud based contexts.&lt;/p>
&lt;h2 id="other-updates">
Other updates
&lt;a class="header-anchor" href="#other-updates">#&lt;/a>
&lt;/h2>&lt;ul>
&lt;li>We participated heavily in an evaluation process for the authentication and authorization solution to be used across NASA VEDA!
&lt;a href="https://github.com/NASA-IMPACT/veda-jupyterhub/issues/57" target="_blank" rel="noopener" >Tracking Issue&lt;/a>&lt;/li>
&lt;li>We are very close to
&lt;a href="https://github.com/2i2c-org/infrastructure/issues/5209" target="_blank" rel="noopener" >rolling out JupyterHub 5.0&lt;/a> and associated changes across all our hubs, which will enable us to eventually offer per-group shared directories!
&lt;a href="https://github.com/NASA-IMPACT/veda-jupyterhub/issues/61" target="_blank" rel="noopener" >Tracking Issue&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="acknowledgements">
Acknowledgements
&lt;a class="header-anchor" href="#acknowledgements">#&lt;/a>
&lt;/h2>&lt;ul>
&lt;li>Thanks to the
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/collaborators/nasa-veda/" >NASA VEDA project&lt;/a> for thir ongoing support for this work.&lt;/li>
&lt;li>Thanks to
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/collaborators/devseed/" >DevSeet&lt;/a> for their collaboration and leadership on this project.&lt;/li>
&lt;/ul></description></item><item><title>`frx-challenges`: A new tool to host data challenges for Frictionless Research Exchanges</title><link>https://deploy-preview-612--2i2c-org.netlify.app/blog/frx/</link><pubDate>Fri, 06 Dec 2024 00:00:00 +0000</pubDate><guid>https://deploy-preview-612--2i2c-org.netlify.app/blog/frx/</guid><description>&lt;p>2i2c is pleased to announce the &lt;code>frx-challenges&lt;/code> project, a new open source tool to help communities host data challenges on shared infrastructure:&lt;/p>
&lt;p>
&lt;a href="https://github.com/2i2c-org/frx-challenges" target="_blank" rel="noopener" >&lt;i class='fa-brands fa-github'>&lt;/i> 2i2c-org/frx-challenges&lt;/a>&lt;/p>
&lt;p>This project aims to make it easier for administrators to provide a service that enables users to &lt;strong>submit code and data&lt;/strong> that are &lt;strong>evaluated on secure infrastructure with access to private data and resources&lt;/strong>. It also provides a leaderboard that helps users compare their performance against others.&lt;/p>
&lt;figure id="figure-an-example-leaderboard-for-a-data-challenge-taken-from-the-cellmap-challengehttpscellmapchallengejaneliaorg-users-make-submissions-that-are-run-against-secure-and-private-infrastructure-and-data-and-provides-feedback-about-the-submissions-performance-learn-more-about-the-frx-challenges-project-here-https2i2corgfrx-challenges">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="An example leaderboard for a data challenge, taken from the [Cellmap Challenge](https://cellmapchallenge.janelia.org/). Users make submissions that are run against secure and private infrastructure and data, and provides feedback about the submission&amp;#39;s performance. Learn more about the FRX challenges project here: https://2i2c.org/frx-challenges/" srcset="
/blog/frx/images/leaderboard_hu1c5275577555814ddf920c106a29e815_883850_e8cf5edfc5977cc915c200d3d338ce2b.webp 400w,
/blog/frx/images/leaderboard_hu1c5275577555814ddf920c106a29e815_883850_64bd6d34f7f589cd624b5702b3fc5904.webp 760w,
/blog/frx/images/leaderboard_hu1c5275577555814ddf920c106a29e815_883850_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://deploy-preview-612--2i2c-org.netlify.app/blog/frx/images/leaderboard_hu1c5275577555814ddf920c106a29e815_883850_e8cf5edfc5977cc915c200d3d338ce2b.webp"
width="75%"
height="417"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
An example leaderboard for a data challenge, taken from the
&lt;a href="https://cellmapchallenge.janelia.org/" target="_blank" rel="noopener" >Cellmap Challenge&lt;/a>. Users make submissions that are run against secure and private infrastructure and data, and provides feedback about the submission&amp;rsquo;s performance. Learn more about the FRX challenges project here:
&lt;a href="https://2i2c.org/frx-challenges/" target="_blank" rel="noopener" >2i2c.org/frx-challenges/&lt;/a>
&lt;/figcaption>&lt;/figure>
&lt;p>It is designed to be lightweight and flexible, and can be run on a variety of shared infrastructure. For those who wish to run this project on cloud infrastructure, we&amp;rsquo;ve also published a
&lt;a href="https://2i2c.org/frx-challenges-helm-chart/" target="_blank" rel="noopener" >Helm Chart to help you deploy &lt;code>frx-challenges&lt;/code> with Kubernetes&lt;/a>.&lt;/p>
&lt;p>While it can be run on its own, we believe that it naturally complements other tools and services for interactive computing and data, such as &lt;strong>JupyterHub&lt;/strong>, &lt;strong>Jupyter Book&lt;/strong>, and &lt;strong>Binder&lt;/strong>. More on that below.&lt;/p>
&lt;p>Below is a brief description of the motivation behind this project.&lt;/p>
&lt;h2 id="what-are-frictionless-research-exchanges">
What are Frictionless Research Exchanges
&lt;a class="header-anchor" href="#what-are-frictionless-research-exchanges">#&lt;/a>
&lt;/h2>&lt;p>The project is heavily inspired by David Donoho&amp;rsquo;s vision of &lt;strong>Frictionless Research Exchanges&lt;/strong> (FRX) as described in
&lt;a href="https://arxiv.org/abs/2310.00865" target="_blank" rel="noopener" >&lt;em>Data Science at the Singularity&lt;/em>&lt;/a>.&lt;/p>
&lt;p>In this article, Donoho describes three key pillars for Frictionless Research Exchanges:&lt;/p>
&lt;blockquote>
&lt;p>The three initiatives are related but separate; and all three have to come together, and in a particularly strong way, to provide the conditions for the new era. Here they are:&lt;/p>
&lt;ul>
&lt;li>[FR-1: Data] datafication of everything, with a culture of research data sharing. One can now find datasets publicly available online on a bewildering variety of topics, from chest x-rays to cosmic microwave background measurements to uber routes to geospatial crop identifications.&lt;/li>
&lt;li>[FR-2: Re-execution] research code sharing including the ability to exactly re-execute the same complete workflow by different researchers.&lt;/li>
&lt;li>[FR-3: Challenges] adopting challenge problems as a new paradigm powering scientific research. The paradigm includes: a shared public dataset, a prescribed and quantified task performance metric, a set of enrolled competitors seeking to outperform each other on the task, and a public leaderboard. Thousands of such challenges with millions of entries have now taken place, across many fields.&lt;/li>
&lt;/ul>
&lt;/blockquote>
&lt;p>We considered the landscape of tools and services, and felt that [FR-1] and [FR-2] were already well-served by a variety of tools and services for community workspace infrastructure (e.g., JupyterHub:
&lt;a href="https://jupyterhub.readthedocs.io" target="_blank" rel="noopener" >jupyterhub.readthedocs.io&lt;/a>), sharable computational environments (e.g., BinderHub:
&lt;a href="https://binderhub.readthedocs.io" target="_blank" rel="noopener" >binderhub.readthedocs.io&lt;/a>), authoring and reading computational narratives (e.g., Jupyter Book:
&lt;a href="https://jupyterbook.org" target="_blank" rel="noopener" >jupyterbook.org&lt;/a> and MyST:
&lt;a href="https://mystmd.org" target="_blank" rel="noopener" >mystmd.org&lt;/a>), and data I/O tools and standards (e.g., Zarr:
&lt;a href="https://zarr.readthedocs.io" target="_blank" rel="noopener" >zarr.readthedocs.io&lt;/a> and Intake:
&lt;a href="https://intake.readthedocs.io" target="_blank" rel="noopener" >intake.readthedocs.io&lt;/a>).&lt;/p>
&lt;p>However there was a natural missing piece for &lt;strong>[FR-3 Challenges]&lt;/strong>, and we could not identify any community-managed infrastructure that facilitated data challenges. This is the goal of &lt;code>frx-challenges&lt;/code>.&lt;/p>
&lt;h2 id="why-facilitate-data-challenges">
Why facilitate data challenges?
&lt;a class="header-anchor" href="#why-facilitate-data-challenges">#&lt;/a>
&lt;/h2>&lt;p>Data challenges are harder than you think! While it is simple enough to run somebody else&amp;rsquo;s code locally, data challenges require a systematic, secure, and automated approach to accepting and evaluating submissions in a fair and repeatable way. Here are some of the big challenges to tackle:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Submissions must retain user and team identity&lt;/strong>, which means that we must keep track of users and their submissions over time, since data challenges are designed to encourage iterative improvement and optimization.&lt;/li>
&lt;li>&lt;strong>Evaluations must use potentially complex resources and data&lt;/strong> since many data challenges operate by publicly sharing a small dataset, and then running it against a much more complex dataset.&lt;/li>
&lt;li>&lt;strong>Evaluations must be totally secure&lt;/strong>, so that submissions can&amp;rsquo;t do nefarious things like mine cryptocurrency or extract the challenge&amp;rsquo;s private data in unintended ways.&lt;/li>
&lt;li>&lt;strong>Evaluations must be automated&lt;/strong>, so that running the challenge does not require extensive human intervention and can scale to many users.&lt;/li>
&lt;li>&lt;strong>Evaluation must be flexible&lt;/strong>, so that the infrastructure can accept a variety of types of submissions (e.g. code, data, model weights, etc), run them with arbitrary environments designed by the organizers, and run them with the right hardware to get the job done.&lt;/li>
&lt;/ul>
&lt;p>These are just a few of the major challenges that we&amp;rsquo;ve tried to address with &lt;code>frx-challenges&lt;/code>, and we&amp;rsquo;re excited to see how it goes with our first assisted community challenge: the
&lt;a href="https://cellmapchallenge.janelia.org/" target="_blank" rel="noopener" >Cellmap Challenge&lt;/a>.&lt;/p>
&lt;p>If you&amp;rsquo;re interested in learning more or participating in this project, follow along at its GitHub repository:&lt;/p>
&lt;p>
&lt;a href="https://github.com/2i2c-org/frx-challenges" target="_blank" rel="noopener" >&lt;i class='fa-brands fa-github'>&lt;/i> 2i2c-org/frx-challenges&lt;/a>&lt;/p>
&lt;p>This is still the &lt;strong>very early stages&lt;/strong> of the project, and we imagine it will evolve significantly. We welcome feedback for how it can more effectively serve a variety of communities.&lt;/p>
&lt;h2 id="acknowledgements">
Acknowledgements
&lt;a class="header-anchor" href="#acknowledgements">#&lt;/a>
&lt;/h2>&lt;p>Thanks to the
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/collaborators/hhmi/" >Howard Hughes Medical Institute&lt;/a> (HHMI) for collaborating with us on the
&lt;a href="https://cellmapchallenge.janelia.org/" target="_blank" rel="noopener" >Cellmap Challenge&lt;/a>, which led to the creation of this project.&lt;/p>
&lt;p>Thanks to Kristen Ratan and
&lt;a href="https://strategiesos.org/about/" target="_blank" rel="noopener" >Strategies for Open Science&lt;/a> (Stratos) for enabling this collaboration, and providing strategic guidance and support.&lt;/p></description></item><item><title>Improving the logged in home page experience in JupyterHub with `jupyterhub-fancy-profiles`</title><link>https://deploy-preview-612--2i2c-org.netlify.app/blog/jupyterhub-fancy-profiles-rollout/</link><pubDate>Mon, 18 Nov 2024 12:55:20 -0800</pubDate><guid>https://deploy-preview-612--2i2c-org.netlify.app/blog/jupyterhub-fancy-profiles-rollout/</guid><description>&lt;p>On most research oriented JupyterHub installations, users would like to customize their server (the environment, resources available, etc) after logging in. In Kubernetes based JupyterHub environments, a
&lt;a href="https://z2jh.jupyter.org/en/latest/jupyterhub/customizing/user-environment.html#using-multiple-profiles-to-let-users-select-their-environment" target="_blank" rel="noopener" >profile list&lt;/a> provides this functionality.&lt;/p>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img src="./classic-profiles.png" alt="image" loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
(Profile List for the NASA VEDA JupyterHub with the default implementation from KubeSpawner)&lt;/p>
&lt;p>The profile list is the de-facto &amp;ldquo;logged in homepage&amp;rdquo; for these users, as that is what they see after they have logged in.&lt;/p>
&lt;p>In collaboration with
&lt;a href="https://developmentseed.org/" target="_blank" rel="noopener" >Development Seed&lt;/a>, funded by our
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/blog/jupyterhub-binderhub-gesis/" >earlier grant&lt;/a> from
&lt;a href="https://www.gesis.org/home" target="_blank" rel="noopener" >GESIS&lt;/a> as well as the
&lt;a href="https://www.earthdata.nasa.gov/data/tools/veda" target="_blank" rel="noopener" >NASA VEDA project&lt;/a>, we have been building the
&lt;a href="https://github.com/2i2c-org/jupyterhub-fancy-profiles" target="_blank" rel="noopener" >&lt;code>jupyterhub-fancy-profiles&lt;/code>&lt;/a> project to improve this experience.&lt;/p>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img src="./fancy-profiles.png" alt="image" loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
(Profile List for the NASA VEDA JupyterHub with &lt;code>jupyterhub-fancy-profiles&lt;/code>)&lt;/p>
&lt;p>Last week, we rolled this new experience out to all 2i2c managed JupyterHubs! Here&amp;rsquo;s a quick rundown of what this enables:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Descriptions for choices in the dropdowns, making it much easier for users to know what they are getting with each environment (or resource selection).&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Fully backwards compatible with the existing KubeSpawner profile list implementation. In our PR to
&lt;a href="https://github.com/2i2c-org/infrastructure/pull/5083" target="_blank" rel="noopener" >roll this out&lt;/a> to all hubs, you notice that we didn&amp;rsquo;t have to change the structure of any profile lists! So you can safely roll this out to your hubs too without needing to fundamentally change how your profiles are set up.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>It is a modern web app (built with
&lt;a href="https://react.dev/" target="_blank" rel="noopener" >react&lt;/a>), just like the JupyterHub admin panel. This allows us to evolve and satisfy user needs much faster, as well as expanding the pool of people who can contribute to the project!&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Support for dynamically building images using
&lt;a href="https://mybinder.org" target="_blank" rel="noopener" >mybinder.org&lt;/a> style repositories! It talks to the
&lt;a href="https://github.com/jupyterhub/binderhub/" target="_blank" rel="noopener" >binderhub&lt;/a> API so users can build reproducible environments as they wish without admin involvement nor needing to fully understand how docker and containers work. Our
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/blog/jupyterhub-binderhub-gesis/" >earlier blog post&lt;/a> has more information.&lt;/p>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img src="./fancy-profiles-build.png" alt="image" loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>This is just the start, and thanks to ongoing funding from the
&lt;a href="https://www.earthdata.nasa.gov/data/tools/veda" target="_blank" rel="noopener" >NASA VEDA&lt;/a> project, we are going to continue making improvements to this experience.&lt;/p>
&lt;h2 id="use-this-in-your-jupyterhub">
Use this in your JupyterHub
&lt;a class="header-anchor" href="#use-this-in-your-jupyterhub">#&lt;/a>
&lt;/h2>&lt;p>As with everything we build at 2i2c (per our
&lt;a href="https://2i2c.org/right-to-replicate/" target="_blank" rel="noopener" >right to replicate&lt;/a> policy), this project can be used with &lt;em>any&lt;/em> JupyterHub installation that uses Kubernetes. There are
&lt;a href="https://github.com/2i2c-org/jupyterhub-fancy-profiles/?tab=readme-ov-file#how-to-use" target="_blank" rel="noopener" >instructions&lt;/a> in the README. Please try it out on yours and let us know what you think!&lt;/p>
&lt;h2 id="credit">
Credit
&lt;a class="header-anchor" href="#credit">#&lt;/a>
&lt;/h2>&lt;ul>
&lt;li>The project was initiated with funding generously provided by
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/collaborators/gesis/" >GESIS&lt;/a> (see our
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/blog/jupyterhub-binderhub-gesis/" >earlier blog post&lt;/a>).&lt;/li>
&lt;li>
&lt;a href="https://developmentseed.org/team/sanjay-bhangar/" target="_blank" rel="noopener" >Sanjay Bhangar&lt;/a> and
&lt;a href="https://oliverroick.net/" target="_blank" rel="noopener" >Oliver Roick&lt;/a> from
&lt;a href="https://developmentseed.org/" target="_blank" rel="noopener" >Development Seed&lt;/a> for advocating for this project and contributing heavily to it.&lt;/li>
&lt;li>The
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/collaborators/nasa-veda/" >NASA VEDA&lt;/a> project (in particular,
&lt;a href="https://github.com/freitagb/" target="_blank" rel="noopener" >Brian Freitag&lt;/a> and
&lt;a href="https://github.com/wildintellect" target="_blank" rel="noopener" >Alex Mandel&lt;/a>), for continued funding (in the form of engineering time) plus being early adopters!&lt;/li>
&lt;/ul></description></item><item><title>Collaborating with Development Seed to deliver cyberinfrastructure for NASA VEDA</title><link>https://deploy-preview-612--2i2c-org.netlify.app/blog/veda-devseed-collab/</link><pubDate>Fri, 12 Jul 2024 00:00:00 +0000</pubDate><guid>https://deploy-preview-612--2i2c-org.netlify.app/blog/veda-devseed-collab/</guid><description>&lt;p>&lt;em>Thank you to Sajjad Anwar and Sanjay Bhangar for contributing to this post.&lt;/em>&lt;/p>
&lt;p>
&lt;figure id="figure-the-veda-dashboardhttpswwwearthdatanasagovdashboard">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Landing page of the public-facing NASA VEDA dashboard" srcset="
/blog/veda-devseed-collab/featured_hu24026c3ba79339d6cab1fefe6f955a05_2636756_4b1df029ea65c7f3b4b044426866fb24.webp 400w,
/blog/veda-devseed-collab/featured_hu24026c3ba79339d6cab1fefe6f955a05_2636756_323a794370493087e930f822be2e27ba.webp 760w,
/blog/veda-devseed-collab/featured_hu24026c3ba79339d6cab1fefe6f955a05_2636756_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://deploy-preview-612--2i2c-org.netlify.app/blog/veda-devseed-collab/featured_hu24026c3ba79339d6cab1fefe6f955a05_2636756_4b1df029ea65c7f3b4b044426866fb24.webp"
width="760"
height="490"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
The
&lt;a href="https://www.earthdata.nasa.gov/dashboard/" target="_blank" rel="noopener" >VEDA dashboard&lt;/a>
&lt;/figcaption>&lt;/figure>
&lt;/p>
&lt;p>The 2i2c team are proud to continue our strong working collaboration with
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/collaborators/devseed/" >Development Seed&lt;/a>, following our previous work on launching the
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/blog/veda-devseed-collab/../2023/us-ghg-center-launches/index.md" >US GHG center&lt;/a> (also see the
&lt;a href="https://developmentseed.org/blog/2023-12-14-ghg-center" target="_blank" rel="noopener" >Development Seed blog post&lt;/a>). Together with scientists at NASA in our regular sync touchpoints, we have recently delivered a tranche of improvements to
&lt;a href="https://www.earthdata.nasa.gov/esds/veda" target="_blank" rel="noopener" >the Visualization, Exploration and Data Analysis (VEDA) project&lt;/a>.&lt;/p>
&lt;p>This platform is designed to thread open-source components together to consolidate GIS delivery mechanisms, processing, analysis and visualization tools, and presented in a collaborative interactive computing environment. All code repositories and associated resources stemming from this work are available on the
&lt;a href="https://github.com/NASA-IMPACT/VEDA/wiki" target="_blank" rel="noopener" >VEDA GitHub page&lt;/a>.&lt;/p>
&lt;p>In the spirit of fully open development, you can
&lt;a href="https://github.com/NASA-IMPACT/veda-jupyterhub/issues?q=is%3Aissue&amp;#43;jh&amp;#43;is%3Aclosed&amp;#43;label%3A%22PI&amp;#43;24.3%22&amp;#43;" target="_blank" rel="noopener" >see the objectives&lt;/a>
the combined 2i2c and Development Seed team had for the last quarter. In this blog post, we will describe some of the significant ones!&lt;/p>
&lt;h2 id="better-image-management-and-testing">
Better image management and testing
&lt;a class="header-anchor" href="#better-image-management-and-testing">#&lt;/a>
&lt;/h2>&lt;p>The
&lt;a href="https://github.com/jupyterhub/repo2docker-action" target="_blank" rel="noopener" >repo2docker-action&lt;/a> is a GitHub action simplifying image building and testing for use with JupyterHub, using either a &lt;code>Dockerfile&lt;/code> or various
&lt;a href="https://repo2docker.readthedocs.io/en/latest/config_files.html" target="_blank" rel="noopener" >configuration files&lt;/a> (like &lt;code>requirements.txt&lt;/code>, &lt;code>environment.yml&lt;/code>, etc) supported by
&lt;a href="https://github.com/jupyterhub/repo2docker" target="_blank" rel="noopener" >repo2docker&lt;/a>. We migrated our image building pipeline from a somewhat homegrown solution to this upstream action, making image updates and testing &lt;em>much&lt;/em> easier. In particular, we can
&lt;a href="https://github.com/NASA-IMPACT/pangeo-notebook-veda-image/pull/4" target="_blank" rel="noopener" >automatically run test notebooks&lt;/a> on every change we make to the image! This way, we can easily catch any breaking changes in library versions or other package installs without disrupting users. We also debugged and
&lt;a href="https://github.com/jupyterhub/repo2docker-action/pull/124" target="_blank" rel="noopener" >contributed upstream&lt;/a> fixes to the testing infrastructure so everyone could benefit from this, rather than just us.&lt;/p>
&lt;h2 id="automatically-pulling-example-notebooks-on-startup">
Automatically pulling example notebooks on startup
&lt;a class="header-anchor" href="#automatically-pulling-example-notebooks-on-startup">#&lt;/a>
&lt;/h2>&lt;p>When a user logs into a JupyterHub, it is very helpful if we could have a bunch of example notebooks and other content pre-populated for them so they can get started right away.
&lt;a href="https://nbgitpuller.readthedocs.io/" target="_blank" rel="noopener" >nbgitpuller&lt;/a> is heavily used for this particular use case. However, it requires that nbgitpuller is installed inside the image the user is using - and not all images have it installed. In particular, we wanted to continue using the (wonderful)
&lt;a href="https://rocker-project.org/" target="_blank" rel="noopener" >Rocker images&lt;/a> maintained upstream for R users, however they do not have nbgitpuller installed. To solve this problem we built
&lt;a href="https://github.com/NASA-IMPACT/jupyterhub-gitpuller-init" target="_blank" rel="noopener" >jupyterhub-gitpuller-init&lt;/a>, which can be used as an
&lt;a href="https://kubernetes.io/docs/concepts/workloads/pods/init-containers/" target="_blank" rel="noopener" >init container&lt;/a> to pre-populate user content on persistent home directories regardless of the image used. We also made sure to build this in a way that &lt;em>anyone&lt;/em> can use it, and it is not tied into either 2i2c or VEDA infrastructure!&lt;/p>
&lt;h2 id="opening-specific-visualizations-in-qgis-via-url">
Opening specific visualizations in QGIS via URL
&lt;a class="header-anchor" href="#opening-specific-visualizations-in-qgis-via-url">#&lt;/a>
&lt;/h2>&lt;p>
&lt;a href="https://www.qgis.org/" target="_blank" rel="noopener" >QGIS&lt;/a> is the world&amp;rsquo;s most used open source GIS software, and previously 2i2c had
&lt;a href="https://blog.jupyter.org/desktop-gis-software-in-the-cloud-with-jupyterhub-ddced297019a" target="_blank" rel="noopener" >worked with Openscapes and QGreenland&lt;/a> to bring this &lt;em>desktop&lt;/em> software to JupyterHub. We had previously worked on a
&lt;a href="https://github.com/2i2c-org/nasa-qgis-image" target="_blank" rel="noopener" >container image&lt;/a> that allows users to access large datasets stored in the cloud directly through QGIS on the JupyterHub, allowing users to work with much larger datasets than they could on their desktops by bringing cloud compute adjacent to the data. As a continuation of this work, we developed
&lt;a href="https://github.com/sunu/jupyter-remote-qgis-proxy" target="_blank" rel="noopener" >jupyter-remote-qgis-proxy&lt;/a>, which builds QGIS specific features on top of
&lt;a href="https://github.com/jupyterhub/jupyter-remote-desktop-proxy" target="_blank" rel="noopener" >jupyter-remote-desktop-proxy&lt;/a>. In particular, it allows creation of shareable links that when clicked, opens specific datasets and layers in QGIS in a JupyterHub! You can see this in action:&lt;/p>
&lt;figure>
&lt;video mute autoplay loop >
&lt;source src="https://deploy-preview-612--2i2c-org.netlify.app/blog/veda-devseed-collab/qgis.mp4" type="video/mp4">
&lt;/video>
&lt;figcaption>Launching QGIS on a Linux desktop served by the VEDA JupyterHub&lt;/figcaption>
&lt;/figure>
&lt;p>This opens up exciting future possibilities. Imagine this
&lt;a href="https://www.earthdata.nasa.gov/dashboard/data-catalog/campfire_ndvi_difference_2015_2022" target="_blank" rel="noopener" >exploration of the Camp Fire&lt;/a> having an &amp;lsquo;Open in QGIS&amp;rsquo; button that enables further exploration of the data without the user needing to download or install anything! Work will continue in the coming quarter towards achieving this vision.&lt;/p>
&lt;p>We are also excited to see recent work in this space
&lt;a href="https://blog.jupyter.org/jupytergis-d63b7adf9d0c" target="_blank" rel="noopener" >from QuantStack and Simula Labs&lt;/a>, and will follow up to ensure an orderly transition to more web native workflows for existing users of QGIS in due time.&lt;/p>
&lt;h2 id="better-profile-selection">
Better Profile Selection
&lt;a class="header-anchor" href="#better-profile-selection">#&lt;/a>
&lt;/h2>&lt;p>This is a continuation of our
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/blog/jupyterhub-binderhub-gesis/" >GESIS collaboration&lt;/a>. In the path to deploying dynamic image building to end users, we wanted to stabilize
&lt;a href="https://github.com/yuvipanda/jupyterhub-fancy-profiles" target="_blank" rel="noopener" >jupyterhub-fancy-profiles&lt;/a> enough to deploy to users of VEDA (and eventually everyone else). This is the primary interface users see &lt;em>after&lt;/em> they log in to JupyterHub, and was ripe for UX improvements. The default interface looks like this:&lt;/p>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Default profile list page" srcset="
/blog/veda-devseed-collab/old-profile_hu10b987728cacc6727099b87fdcffde73_116187_3ba716304cf974b6f820c2d01db2a898.webp 400w,
/blog/veda-devseed-collab/old-profile_hu10b987728cacc6727099b87fdcffde73_116187_5d665939450b0139d1cacccecd3c15e3.webp 760w,
/blog/veda-devseed-collab/old-profile_hu10b987728cacc6727099b87fdcffde73_116187_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://deploy-preview-612--2i2c-org.netlify.app/blog/veda-devseed-collab/old-profile_hu10b987728cacc6727099b87fdcffde73_116187_3ba716304cf974b6f820c2d01db2a898.webp"
width="734"
height="760"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;p>The revamped one is much more streamlined and looks like this:&lt;/p>
&lt;figure>
&lt;video mute autoplay loop >
&lt;source src="https://deploy-preview-612--2i2c-org.netlify.app/blog/veda-devseed-collab/new-profile.mp4" type="video/mp4">
&lt;/video>
&lt;figcaption>Revamped Profile Screen&lt;/figcaption>
&lt;/figure>
&lt;p>This is currently deployed to a staging hub and has helped us shake out a lot of bugs! We expect the improved interface will be rolled out to all users in the near future. We are also planning further development to make the user experience even better and smoother for everyone.&lt;/p>
&lt;h2 id="supporting-workshops">
Supporting workshops
&lt;a class="header-anchor" href="#supporting-workshops">#&lt;/a>
&lt;/h2>&lt;p>End users benefiting from our work is what ultimately gives meaning to our work. To that end, we were very happy to support running workshops during this collaboration – see our related blog post
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/blog/ghg-summer-school/" >US Greenhouse Gas Center supports summer school at CIRA&lt;/a> for more information.&lt;/p>
&lt;h2 id="ongoing-collaboration">
Ongoing Collaboration
&lt;a class="header-anchor" href="#ongoing-collaboration">#&lt;/a>
&lt;/h2>&lt;p>Delivering on these objectives in a timely way heavily depended on the success of the team collaboration.
&lt;a href="https://developmentseed.org/team/sanjay-bhangar" target="_blank" rel="noopener" >Sanjay Bhangar&lt;/a> of Development Seed commented&lt;/p>
&lt;blockquote>
&lt;p>Working closely with the 2i2c team on growing features to support users on the VEDA and GHG Center hubs has been absolutely amazing. With 2i2c’s deep experience in the Jupyter ecosystem, we have been able to implement some fairly complex features quite easily, and their strong open-source roots have ensured that whatever we work on is broadly useful to the wider Jupyter and scientific computing communities.&lt;/p>
&lt;/blockquote>
&lt;p>Take a look at the companion
&lt;a href="https://developmentseed.org/blog/2024-07-12-jupyter-geospatial" target="_blank" rel="noopener" >Development Seed blog post&lt;/a> of this work.&lt;/p>
&lt;p>This collaboration continues, and we have now
&lt;a href="https://github.com/NASA-IMPACT/veda-jupyterhub/issues?q=is%3Aissue&amp;#43;jh%3A&amp;#43;label%3A%22PI&amp;#43;24.4%22&amp;#43;" target="_blank" rel="noopener" >published our objectives for the coming quarter&lt;/a>. Watch this space!&lt;/p>
&lt;h2 id="acknowledgements">
Acknowledgements
&lt;a class="header-anchor" href="#acknowledgements">#&lt;/a>
&lt;/h2>&lt;ul>
&lt;li>
&lt;a href="https://developmentseed.org/" target="_blank" rel="noopener" >Development Seed&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://impact.earthdata.nasa.gov/" target="_blank" rel="noopener" >NASA IMPACT&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://sunu.in/" target="_blank" rel="noopener" >Tarashish Mishra&lt;/a>,
&lt;a href="https://jsignell.github.io/" target="_blank" rel="noopener" >Julia Signell&lt;/a>,
&lt;a href="https://oliverroick.net/" target="_blank" rel="noopener" >Oliver Roick&lt;/a>,
&lt;a href="https://slesa.com.np/" target="_blank" rel="noopener" >Slesa Adhikari&lt;/a> and
&lt;a href="https://developmentseed.org/team/sanjay-bhangar" target="_blank" rel="noopener" >Sanjay Bhangar&lt;/a> for various code contributions towards these objectives&lt;/li>
&lt;/ul></description></item><item><title>Openscapes Host a Surface Biology and Geology Workshop with Shared Password Feature</title><link>https://deploy-preview-612--2i2c-org.netlify.app/blog/openscapes-sbg-workshop/</link><pubDate>Tue, 09 Jul 2024 00:00:00 +0000</pubDate><guid>https://deploy-preview-612--2i2c-org.netlify.app/blog/openscapes-sbg-workshop/</guid><description>&lt;p>&lt;em>Thanks to Brianna Lind, Julia Lowndes and Andy Teucher for contributing to this blog post!&lt;/em>&lt;/p>
&lt;p>
&lt;figure id="figure-surface-biology-and-geology-vitals-workshop">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Cover slide from the SBG Workshop" srcset="
/blog/openscapes-sbg-workshop/featured_hue819d1810c727f509c70882af2906386_1363058_707a0ff4676ed6f6cfd5cc588f4c809c.webp 400w,
/blog/openscapes-sbg-workshop/featured_hue819d1810c727f509c70882af2906386_1363058_65059c4c89a880b7464be673cf73f87c.webp 760w,
/blog/openscapes-sbg-workshop/featured_hue819d1810c727f509c70882af2906386_1363058_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://deploy-preview-612--2i2c-org.netlify.app/blog/openscapes-sbg-workshop/featured_hue819d1810c727f509c70882af2906386_1363058_707a0ff4676ed6f6cfd5cc588f4c809c.webp"
width="760"
height="476"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Surface Biology and Geology: VITALS Workshop
&lt;/figcaption>&lt;/figure>
&lt;/p>
&lt;p>
&lt;a href="https://openscapes.org" target="_blank" rel="noopener" >Openscapes&lt;/a> is a value-based initiative that supports kinder, better science based on open source community.
&lt;a href="https://nasa-openscapes.github.io" target="_blank" rel="noopener" >NASA Openscapes&lt;/a> is in its fourth year as a project supporting NASA Earth science in the Cloud, co-developed by Julia Lowndes (Openscapes) and Erin Robinson (Metadata Game Changers).&lt;/p>
&lt;p>The initiative recently supported the
&lt;a href="https://nasa.github.io/VITALS/" target="_blank" rel="noopener" >Surface Biology and Geology: VITALS Workshop&lt;/a> hosted by NASA
&lt;a href="https://lpdaac.usgs.gov/" target="_blank" rel="noopener" >Land Processes Distributed Activate Archive Center (LP DAAC)&lt;/a> and NASA
&lt;a href="https://www.jpl.nasa.gov/" target="_blank" rel="noopener" >Jet Propulsion Laboratory (JPL)&lt;/a>.&lt;/p>
&lt;p>Instructors used the 2i2c Openscapes Hub to lead hands-on exercises teaching learners how to manipulate data collected from the
&lt;a href="https://ecostress.jpl.nasa.gov/" target="_blank" rel="noopener" >ECOSTRESS&lt;/a> and
&lt;a href="https://earth.jpl.nasa.gov/emit/" target="_blank" rel="noopener" >EMIT&lt;/a> instruments onboard the International Space Station. They used
&lt;a href="https://nasa.github.io/VITALS/python/01_Finding_Concurrent_Data.html" target="_blank" rel="noopener" >Jupyter notebooks&lt;/a> in the Hub to demonstrate how open source tools together with cloud data and compute resources could effectively analyse the the Canopy Water Content and the Land Surface Temperature over the
&lt;a href="https://www.dangermondpreserve.org/" target="_blank" rel="noopener" >Jack and Laura Dangermond Preserve&lt;/a>, Santa Barbara, CA.&lt;/p>
&lt;p>
&lt;figure id="figure-plot-of-the-canopy-water-content-over-the-jack-and-laura-dangermond-preserve-santa-barbara-ca-from-a-vitals-workshop-jupyter-notebookhttpsnasagithubiovitalspython03_emit_cwc_from_reflectancehtml">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Plot of the Canopy Water Content over the Jack and Laura Dangermond Preserve, Santa Barbara, CA." srcset="
/blog/openscapes-sbg-workshop/canopy-water-content_hu0373bdfe9208f8ce22ea7a38db775ed2_317466_6c2aa40b45d5b9a1502d1d0536c3307a.webp 400w,
/blog/openscapes-sbg-workshop/canopy-water-content_hu0373bdfe9208f8ce22ea7a38db775ed2_317466_16f677518b9718a81e27c013182289ed.webp 760w,
/blog/openscapes-sbg-workshop/canopy-water-content_hu0373bdfe9208f8ce22ea7a38db775ed2_317466_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://deploy-preview-612--2i2c-org.netlify.app/blog/openscapes-sbg-workshop/canopy-water-content_hu0373bdfe9208f8ce22ea7a38db775ed2_317466_6c2aa40b45d5b9a1502d1d0536c3307a.webp"
width="739"
height="601"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Plot of the Canopy Water Content over the Jack and Laura Dangermond Preserve, Santa Barbara, CA from a
&lt;a href="https://nasa.github.io/VITALS/python/03_EMIT_CWC_from_Reflectance.html" target="_blank" rel="noopener" >VITALS Workshop Jupyter notebook&lt;/a>.
&lt;/figcaption>&lt;/figure>
&lt;/p>
&lt;p>This event was attended by around 250 participants. An event of this size therefore requires a &lt;em>frictionless login flow&lt;/em> so that organizers could focus on the essential complexity of teaching data analysis rather than the accidental complexity of managing Hub authorization. GitHub authentication is the default option for most 2i2c Hubs for research use cases, but for an educational event of this size this option was not fit for purpose since organizers had to&lt;/p>
&lt;ol>
&lt;li>Retrieve the GitHub usernames of each participant (assuming everyone was familiar with GitHub!)&lt;/li>
&lt;li>Manually invite GitHub users to a GitHub organization to authorize access to the Hub (invitations would expire within seven days)&lt;/li>
&lt;li>Repeat the above two steps last-minute for participants who showed up on the day without preparing&lt;/li>
&lt;li>Manually remove GitHub users from the GitHub organization if they wanted to revoke access to the Hub after the event.&lt;/li>
&lt;/ol>
&lt;p>In response to this need, we developed a shared password feature so that workshop organizers can simply hand the share password out to learners for access to the Hub. This bypassed the manual labour of managing GitHub accounts while not adding to the learner&amp;rsquo;s high cognitive load and improving the participant&amp;rsquo;s learning experience overall.&lt;/p>
&lt;p>One of the elements that enabled us to recognize and solve this issue effectively is our close partnership with the Openscapes team. We engage in regular
&lt;a href="https://github.com/NASA-Openscapes/2i2cAccessPolicies/issues/7" target="_blank" rel="noopener" >6-weekly catch-ups&lt;/a> where we can learn about user requirements and how we can develop our infrastructure to co-create optimal solutions. Together with our
&lt;a href="https://team-compass.2i2c.org/product/deliveryflow/#defining-our-product-delivery-flow" target="_blank" rel="noopener" >Product Delivery Flow&lt;/a>, we were quickly able to architect the shared password solution in time for the workshop.&lt;/p>
&lt;p>
&lt;figure id="figure-feedback-from-brianna-lind-lp-daac">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="Slack message from Bri Lind" srcset="
/blog/openscapes-sbg-workshop/slack_hu92a99c5a2eca92e535f899967fd8b202_53752_664182742791ffee3dad226e811acaaf.webp 400w,
/blog/openscapes-sbg-workshop/slack_hu92a99c5a2eca92e535f899967fd8b202_53752_93d144017cd3d29ae0c1ae72ee4233b8.webp 760w,
/blog/openscapes-sbg-workshop/slack_hu92a99c5a2eca92e535f899967fd8b202_53752_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://deploy-preview-612--2i2c-org.netlify.app/blog/openscapes-sbg-workshop/slack_hu92a99c5a2eca92e535f899967fd8b202_53752_664182742791ffee3dad226e811acaaf.webp"
width="760"
height="219"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
Feedback from Brianna Lind (LP DAAC)
&lt;/figcaption>&lt;/figure>
&lt;/p>
&lt;p>We have documented the technical infrastructure changes required to enable a shared password for the Hub in our
&lt;a href="https://infrastructure.2i2c.org/hub-deployment-guide/configure-auth/shared-password/" target="_blank" rel="noopener" >Infrastructure Guide&lt;/a> and hope to support many future events with this mechanism!&lt;/p>
&lt;h2 id="acknowledgements">
Acknowledgements
&lt;a class="header-anchor" href="#acknowledgements">#&lt;/a>
&lt;/h2>&lt;ul>
&lt;li>
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/collaborators/openscapes/" >NASA Openscapes&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://lpdaac.usgs.gov/" target="_blank" rel="noopener" >NASA LP DAAC&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://www.jpl.nasa.gov/" target="_blank" rel="noopener" >NASA JPL&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://science.nasa.gov/researchers/" target="_blank" rel="noopener" >NASA ROSES funding&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/collaborators/nasa-open-science/" >NASA Open Science / ScienceCore&lt;/a> for supporting some of our work on JupyterHub.&lt;/li>
&lt;/ul></description></item><item><title>Enabling neuroscience in the cloud with HHMI Spyglass and MySQL on JupyterHub</title><link>https://deploy-preview-612--2i2c-org.netlify.app/blog/hhmi-spyglass-mysql/</link><pubDate>Fri, 05 Jul 2024 00:00:00 +0000</pubDate><guid>https://deploy-preview-612--2i2c-org.netlify.app/blog/hhmi-spyglass-mysql/</guid><description>&lt;p>
&lt;figure id="figure-the-hhmi-spyglass-tutorialhttpsspyglasshhmi2i2ccloud">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="HHMI Spyglass tutorial" srcset="
/blog/hhmi-spyglass-mysql/featured_huda5696297f7fdc49904c82761adc3edf_243308_bd8374537df26d753cf207ce605828be.webp 400w,
/blog/hhmi-spyglass-mysql/featured_huda5696297f7fdc49904c82761adc3edf_243308_6bf7febe689cf7ab6de5a884d311f33f.webp 760w,
/blog/hhmi-spyglass-mysql/featured_huda5696297f7fdc49904c82761adc3edf_243308_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://deploy-preview-612--2i2c-org.netlify.app/blog/hhmi-spyglass-mysql/featured_huda5696297f7fdc49904c82761adc3edf_243308_bd8374537df26d753cf207ce605828be.webp"
width="760"
height="498"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
The
&lt;a href="https://spyglass.hhmi.2i2c.cloud/" target="_blank" rel="noopener" >HHMI Spyglass tutorial&lt;/a>
&lt;/figcaption>&lt;/figure>
&lt;/p>
&lt;h2 id="spyglass">
Spyglass
&lt;a class="header-anchor" href="#spyglass">#&lt;/a>
&lt;/h2>&lt;p>
&lt;a href="https://github.com/LorenFrankLab/spyglass" target="_blank" rel="noopener" >Spyglass&lt;/a> is a framework for reproducible and shareable neuroscience research produced by
&lt;a href="https://github.com/LorenFrankLab" target="_blank" rel="noopener" >Loren Frank’s lab&lt;/a> at the University of California, San Francisco. Check out our
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/blog/hhmi-spyglass/" >blog post about the release of their preprint&lt;/a> to read more about the methods.&lt;/p>
&lt;p>This post focuses on the complex data storage needed for the project, which can be difficult to set up locally or at scale in the cloud. In particular, the analysis needed a MySQL database for reproducibility. This is a fairly common task across many fields. The aim of 2i2c is to enable researchers to focus on the essential complexity of what they were doing, i.e. the science, without managing the accidental complexity of how to do it &amp;ndash; in this case, setting up databases.&lt;/p>
&lt;p>We describe how you can do this too for your own JupyterHubs. Since 2i2c commits to running our infrastructure in line with open-source values as much as possible, you can also directly see the
&lt;a href="https://github.com/2i2c-org/infrastructure/blob/99071c38712ef8e6bed6609117ca4b894b89ae5c/config/clusters/hhmi/spyglass.values.yaml#L76" target="_blank" rel="noopener" >configuration for the hub&lt;/a> referenced in the paper.&lt;/p>
&lt;h2 id="what-is-a-sidecar-container">
What is a &amp;ldquo;sidecar container&amp;rdquo;?
&lt;a class="header-anchor" href="#what-is-a-sidecar-container">#&lt;/a>
&lt;/h2>&lt;p>The Kubernetes definition of a
&lt;a href="https://kubernetes.io/docs/concepts/workloads/pods/sidecar-containers/" target="_blank" rel="noopener" >sidecar container&lt;/a> is&lt;/p>
&lt;blockquote>
&lt;p>Sidecar containers are the secondary containers that run along with the main application container within the same Pod. These containers are used to enhance or to extend the functionality of the primary app container by providing additional services, or functionality such as logging, monitoring, security, or data synchronization, without directly altering the primary application code.&lt;/p>
&lt;/blockquote>
&lt;p>In this case, the &lt;em>primary&lt;/em> app container is the JupyterLab instance where people are interactively running code and doing science. We want to provide a MySQL database as a sidecar so that each user server gets their own independent MySQL server instance (that is not accessible to anyone else). We can then run code such as&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">%%bash
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">mysql -h 127.0.0.1 -u root --password=tutorial &amp;lt; path-to-sql-file-with-data
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>to load data into the database. Note the IP address &lt;code>127.0.0.1&lt;/code> - the MySQL server is listening on localhost, even though it is not running in the &lt;em>same container&lt;/em>! Thanks to the magic of
&lt;a href="https://lwn.net/Articles/580893/" target="_blank" rel="noopener" >Linux Network Namespaces&lt;/a>, the sidecar and main app container can share &lt;code>127.0.0.1&lt;/code>. This allows you to write code that works &lt;strong>in the exact same way&lt;/strong> on a user&amp;rsquo;s local computers as on the JupyterHub, making transitions and replication easier.&lt;/p>
&lt;h2 id="setting-up-sidecars-in-jupyterhub-on-kubernetes">
Setting up sidecars in JupyterHub on Kubernetes
&lt;a class="header-anchor" href="#setting-up-sidecars-in-jupyterhub-on-kubernetes">#&lt;/a>
&lt;/h2>&lt;p>We&amp;rsquo;re leveraging multiple tools from the open-source ecosystem - JupyterHub, Kubernetes, Linux as well as MySQL itself.&lt;/p>
&lt;p>Since this is a &lt;em>Kubernetes&lt;/em> feature, we can pass through config to it. There are
two layers here, which are&lt;/p>
&lt;ol>
&lt;li>
&lt;a href="https://z2jh.jupyter.org/en/latest/resources/reference.html#singleuser-extracontainers" target="_blank" rel="noopener" >singleuser.extraContainers&lt;/a> in
&lt;a href="https://z2jh.jupyter.org/en/stable/" target="_blank" rel="noopener" >z2jh&lt;/a> configuration&lt;/li>
&lt;li>
&lt;a href="https://jupyterhub-kubespawner.readthedocs.io/en/latest/spawner.html#kubespawner.KubeSpawner.extra_containers" target="_blank" rel="noopener" >KubeSpawner.extra_containers&lt;/a> in
&lt;a href="https://jupyterhub-kubespawner.readthedocs.io/en/latest/spawner.html" target="_blank" rel="noopener" >KubeSpawner&lt;/a> configuration&lt;/li>
&lt;/ol>
&lt;p>The hub configuration looks like&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">singleuser&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">extraContainers&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">mysql&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">datajoint/mysql:8.0&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># following the spyglass tutorial at https://lorenfranklab.github.io/spyglass/latest/notebooks/00_Setup/#existing-database&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">ports&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">mysql&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">containerPort&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">3306&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">resources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">limits&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c"># Best effort only. No more than 1 CPU, and if mysql uses more than 4G, restart it&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">memory&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">4Gi&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">cpu&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">1.0&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">requests&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c"># If we don&amp;#39;t set requests, k8s sets requests == limits!&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c"># So we set something tiny&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">memory&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">64Mi&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">cpu&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">0.01&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">env&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c"># Configured using the env vars documented in https://lorenfranklab.github.io/spyglass/latest/notebooks/00_Setup/#existing-database&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">MYSQL_ROOT_PASSWORD&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">value&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;tutorial&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>By setting this up, we allow users to insert the code snippet above&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">%%bash
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">mysql -h 127.0.0.1 -u root --password=tutorial &amp;lt; path-to-sql-file-with-data
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>into their
&lt;a href="https://github.com/LorenFrankLab/spyglass-demo/blob/main/notebooks/00_HubQuickStart.ipynb" target="_blank" rel="noopener" >Jupyter Notebooks&lt;/a>, which gives access to their MySQL database in the hub!&lt;/p>
&lt;p>However, this configuration does not include permanently store the database itself between hub server sessions. Thanks to a pilot in a prior collaboration with University of Texas, Austin, we do have
&lt;a href="https://github.com/2i2c-org/infrastructure/blob/main/docs/howto/features/per-user-db.md" target="_blank" rel="noopener" >some documentation&lt;/a> on how you can enable that as well!&lt;/p>
&lt;h2 id="acknowledgements">
Acknowledgements
&lt;a class="header-anchor" href="#acknowledgements">#&lt;/a>
&lt;/h2>&lt;ul>
&lt;li>
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/collaborators/hhmi/" >Howard Hughes Medical Institute&lt;/a>&lt;/li>
&lt;li>National Institute of Mental Health (NIMH), grant number RF1MH130623&lt;/li>
&lt;li>
&lt;a href="https://github.com/jupyterhub/kubespawner" target="_blank" rel="noopener" >kubespawner&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://github.com/jupyterhub/zero-to-jupyterhub-k8s/" target="_blank" rel="noopener" >zero-to-jupyterhub-k8s&lt;/a> and the
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/collaborators/jupyterhub/" >JupyterHub community&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Integrating BinderHub with JupyterHub: Empowering users to manage their own environments</title><link>https://deploy-preview-612--2i2c-org.netlify.app/blog/jupyterhub-binderhub-gesis/</link><pubDate>Wed, 03 Jan 2024 16:56:14 -0800</pubDate><guid>https://deploy-preview-612--2i2c-org.netlify.app/blog/jupyterhub-binderhub-gesis/</guid><description>&lt;p>&lt;em>Thanks to
&lt;a href="https://www.gesis.org/en/institute/staff/person/arnim.bleier" target="_blank" rel="noopener" >Arnim Bleier&lt;/a>,
&lt;a href="https://jnywong.github.io/" target="_blank" rel="noopener" >Jenny Wong&lt;/a>,
&lt;a href="https://github.com/GeorgianaElena" target="_blank" rel="noopener" >Georgiana Elena&lt;/a>,
&lt;a href="https://github.com/damianavila" target="_blank" rel="noopener" >Damián Avila&lt;/a>,
&lt;a href="https://colliand.com/" target="_blank" rel="noopener" >Jim Colliander&lt;/a> and
&lt;a href="https://github.com/jmunroe" target="_blank" rel="noopener" >James Munroe&lt;/a> for contributing to this blog post&lt;/em>&lt;/p>
&lt;p>
&lt;a href="https://mybinder.org" target="_blank" rel="noopener" >mybinder.org&lt;/a> is a very popular service that allows end users to specify and share the environment (languages, packages, etc) required for their notebooks to run correctly by placing
&lt;a href="https://repo2docker.readthedocs.io/en/latest/config_files.html#config-files" target="_blank" rel="noopener" >configuration files&lt;/a> they are already familiar with (like &lt;code>requirements.txt&lt;/code> or &lt;code>environment.yml&lt;/code>) along with their notebooks. While not without its own set of challenges, this is extremely powerful because it puts control of the &lt;em>environment&lt;/em> in the hands of the people who write the code. They can customize the environment to fit the needs of their code, instead of having to fit their code into the environment that admins have made available.&lt;/p>
&lt;p>But, mybinder.org (and the
&lt;a href="https://github.com/jupyterhub/binderhub/" target="_blank" rel="noopener" >BinderHub&lt;/a> software that powers it) is built for &lt;em>sharing&lt;/em> your work after you are done with it, &lt;em>not&lt;/em> for actively doing work. BinderHubs often do not have persistent storage nor persistent user identity, and UX is centered around &lt;em>ephemeral&lt;/em> interactivity that can be shared with others (via a link), rather than &lt;em>persistent&lt;/em> interactivity that a single user repeatedly comes back to.
&lt;a href="https://jupyter.org/hub" target="_blank" rel="noopener" >JupyterHub&lt;/a> is more commonly used for this kinda workflow, but doesn&amp;rsquo;t currently have the ability for users to easily build their own environments. Admins who are &lt;em>running&lt;/em> the JupyterHub can make
&lt;a href="https://z2jh.jupyter.org/en/stable/jupyterhub/customizing/user-environment.html#using-multiple-profiles-to-let-users-select-their-environment" target="_blank" rel="noopener" >multiple environments&lt;/a> available for users to choose from, but this still puts admins in the critical path for environment customization.&lt;/p>
&lt;p>Our
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/blog/gesis-2i2c-collaboration-update/" >collaboration&lt;/a> with
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/collaborators/gesis/" >GESIS&lt;/a>,
&lt;a href="https://www.nfdi4datascience.de" target="_blank" rel="noopener" >NFDI4DS&lt;/a>, and
&lt;a href="https://www.cessda.eu" target="_blank" rel="noopener" >CESSDA&lt;/a>, aims to bring this flexibility to JupyterHub directly. We aim to empower users to decide for themselves which applications and dependencies are installed on a per-project basis. Our work enables communities with heterogeneous requirements to share a single Hub. Our approach frees administrators from being overwhelmed by installation requests and transforms the JupyterHub platform into a platform for collaborative computational reproducibility. In this update, we report on our progress and upcoming steps in this project.&lt;/p>
&lt;h2 id="what-does-a-binderhub-do-exactly">
What does a BinderHub do, exactly?
&lt;a class="header-anchor" href="#what-does-a-binderhub-do-exactly">#&lt;/a>
&lt;/h2>&lt;p>It is helpful to understand that BinderHub primarily has 3 responsibilities:&lt;/p>
&lt;ol>
&lt;li>Present a UI to the end user for them to provide details on what to build (this is what you see when you go to mybinder.org)&lt;/li>
&lt;li>Call out to
&lt;a href="https://github.com/jupyterhub/repo2docker" target="_blank" rel="noopener" >repo2docker&lt;/a> in a scalable way to actually &lt;em>build and push&lt;/em> an image containing the environment for the given repository, and show the user logs as this build process happens. This also allows users to debug issues with their build more easily.&lt;/li>
&lt;li>Talk to a JupyterHub instance to launch a user server with the built docker image, and redirect the user to this.&lt;/li>
&lt;/ol>
&lt;p>(2) is really the &lt;em>core&lt;/em> feature of BinderHub, and we settled on figuring out how to make that available to JupyterHub users. It was really important to us that this was also done in a way that can be sustainably used by &lt;em>everyone&lt;/em>, not just 2i2c. This blog post discusses the various improvements to the broad ecosystem of projects in the Jupyter ecosystem to get this done.&lt;/p>
&lt;h2 id="demo">
Demo
&lt;a class="header-anchor" href="#demo">#&lt;/a>
&lt;/h2>&lt;p>But first, a very quick demo of how this looks like right now now!&lt;/p>
&lt;!-- generated from original .mov screen recording with `ffmpeg -i screencast.mov -c:v libx264 screencast.mp4` -->
&lt;p>&lt;video src="./screencast.mp4" autoplay muted controls>&lt;/video>&lt;/p>
&lt;p>This is very much a work in progress, but the basic flow can be seen clearly. Users see a Server Options menu after they log into JupyterHub. They can specify the two primary things that determine the server configuration:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>The resources allocated (RAM, CPU and maybe GPU)&lt;/p>
&lt;/li>
&lt;li>
&lt;p>The environment (container image) used, which can be specified in one of 3 ways:&lt;/p>
&lt;p>a. A pre-selected list of environments (container images), provided by the administrators who set up this JupyterHub
b. A blank text box where you can enter any publicly available docker image they want
c. A mybinder.org style way to specify a GitHub repository, which will be then dynamically built into a docker image for the user!&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>So what did we need to do to accomplish this, in a way that&amp;rsquo;s very upstream friendly and usable by everyone (and not just 2i2c)?&lt;/p>
&lt;h2 id="a-standalone-binderhub-service-helm-chart">
A Standalone &lt;code>binderhub-service&lt;/code> helm chart
&lt;a class="header-anchor" href="#a-standalone-binderhub-service-helm-chart">#&lt;/a>
&lt;/h2>&lt;p>The default upstream
&lt;a href="https://github.com/jupyterhub/binderhub/tree/main/helm-chart" target="_blank" rel="noopener" >BinderHub helm chart&lt;/a> &lt;em>includes&lt;/em> a JupyterHub as a dependency, and configures itself to be used primarily in a manner similar to
&lt;a href="https://mybinder.org" target="_blank" rel="noopener" >mybinder.org&lt;/a>. As the person who helped make that choice early on, I can tell you why it was made - for convenience! And it &lt;em>was&lt;/em> very convenient, as it allowed us to get mybinder.org going fast. However, it makes it difficult to install a BinderHub service &lt;em>alongside&lt;/em> an existing JupyterHub. To this end, we have created a standalone
&lt;a href="https://github.com/2i2c-org/binderhub-service/" target="_blank" rel="noopener" >BinderHub helm chart&lt;/a>, designed to be installed &lt;em>alongside&lt;/em> an existing JupyterHub, so we can use it &lt;em>purely&lt;/em> to build images. This allows the BinderHub instance to be used as a
&lt;a href="https://jupyterhub.readthedocs.io/en/stable/reference/services.html" target="_blank" rel="noopener" >JupyterHub Service&lt;/a>, which is what we want.&lt;/p>
&lt;p>While this helm chart is currently under the 2i2c GitHub org, the hope is that it can eventually migrate to a
&lt;a href="https://github.com/jupyterhub/team-compass/issues/519" target="_blank" rel="noopener" >jupyterhub-contrib&lt;/a> organization (once it is created), or it can become the upstream helm chart for BinderHub if enough work can be done in BinderHub to allow it to serve use cases like mybinder.org.&lt;/p>
&lt;p>As part of this work, we also added a way for BinderHub to run in
&lt;a href="https://github.com/jupyterhub/binderhub/pull/1647" target="_blank" rel="noopener" >API only mode&lt;/a>, so we can fully turn off the UI &lt;em>and&lt;/em> launching ability of BinderHub. This change decoupled the
&lt;a href="#what-does-a-binderhub-do-exactly" >three responsibilities of BinderHub&lt;/a> we discussed previously, allowing us to bring our own UI and JupyterHub. BinderHub could now be used &lt;em>purely&lt;/em> for its scalable image building features, which is exactly what we want!&lt;/p>
&lt;h2 id="sustainably-extending-kubespawners-profilelist">
Sustainably extending KubeSpawner&amp;rsquo;s &lt;code>profileList&lt;/code>
&lt;a class="header-anchor" href="#sustainably-extending-kubespawners-profilelist">#&lt;/a>
&lt;/h2>&lt;p>We identified KubeSpawner&amp;rsquo;s &lt;code>profileList&lt;/code> feature as the ideal location for UI to dynamically build environments (container images), making it just another &amp;rsquo;environment choice&amp;rsquo; people can choose, along with picking the resources their server needs. From an end-user perspective, it was also the logical place for them to specify a repository to build into an environment, as they could already choose some pre-built environments from here. They can also select other arbitrary resources they want (such as memory, GPU, etc) from here as well. From a maintainer perspective, it helps with long-term maintenance of the JupyterHub projects.&lt;/p>
&lt;p>The implementation of &lt;code>profileList&lt;/code> however, was not easy to extend at this point. So
&lt;a href="https://github.com/jupyterhub/kubespawner/pull/724" target="_blank" rel="noopener" >this PR&lt;/a> improved how easy it was to extend it in more complex ways, without making the implementation in KubeSpawner itself complicated. Even though this had &lt;em>no&lt;/em> visible end-user effects, it was an extremely important step in allowing us to experiment with UI in a &lt;em>sustainable&lt;/em> way without having to rely on upstream. These kinds of changes can sometimes be hard to sell to stakeholders but are extremely important in ensuring a continuous and sustainable relationship with upstream.&lt;/p>
&lt;h2 id="implementing-unlisted_choice-feature-in-kubespawner">
Implementing &lt;code>unlisted_choice&lt;/code> feature in KubeSpawner
&lt;a class="header-anchor" href="#implementing-unlisted_choice-feature-in-kubespawner">#&lt;/a>
&lt;/h2>&lt;p>The profileList feature was built to allow JupyterHub &lt;em>admins&lt;/em> to specify an explicit list of container images the end-user can choose from. It did not have a way for any choice that was &lt;em>not&lt;/em> pre-approved by the admin to be used. We needed this feature since the BinderHub API will build a new docker image for each environment the user wants, and so this can not be chosen from a pre-approved list. We had to safely add this feature to KubeSpawner in such a way that it was generally useful to everyone. Many other communities had been asking for such a feature anyway - the ability to simply &amp;rsquo;type in&amp;rsquo; an image and have that be used.&lt;/p>
&lt;p>
&lt;a href="https://www.earthdata.nasa.gov/esds/veda" target="_blank" rel="noopener" >NASA VEDA&lt;/a> was one such community, so we partnered with
&lt;a href="https://github.com/batpad/" target="_blank" rel="noopener" >Sanjay Bhangar&lt;/a> from
&lt;a href="https://developmentseed.org/" target="_blank" rel="noopener" >Development Seed&lt;/a> (an organization that helps run NASA VEDA) to implement this feature. Engineers from 2i2c contributed heavily to this feature as well, and after &lt;em>several&lt;/em> PRs (
&lt;a href="https://github.com/jupyterhub/kubespawner/pull/735" target="_blank" rel="noopener" >1&lt;/a>,
&lt;a href="https://github.com/jupyterhub/kubespawner/pull/766" target="_blank" rel="noopener" >2&lt;/a>,
&lt;a href="https://github.com/jupyterhub/kubespawner/pull/773" target="_blank" rel="noopener" >3&lt;/a>,
&lt;a href="https://github.com/jupyterhub/kubespawner/pull/774" target="_blank" rel="noopener" >4&lt;/a> and
&lt;a href="https://github.com/jupyterhub/kubespawner/pull/777" target="_blank" rel="noopener" >5&lt;/a>), this feature is now available for everyone to use!&lt;/p>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img src="./screenshot-featured.png" alt="Screenshot of Kubernetes Profiles with Unlisted Choice" loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;p>A key component of doing &lt;em>sustainable&lt;/em> upstream work is that every addition needs to be useful by itself for a broad group of people. This change was very helpful for many communities that wanted to allow their users the freedom to pick whatever image they want to use, regardless of wether they wanted to use dynamic image building or not. The broad interest allowed us to build a coalition with other interested parties, and get the change accepted upstream more easily!&lt;/p>
&lt;h2 id="jupyterhub-fancy-profiles">
&lt;code>jupyterhub-fancy-profiles&lt;/code>
&lt;a class="header-anchor" href="#jupyterhub-fancy-profiles">#&lt;/a>
&lt;/h2>&lt;p>Once we had all these pieces in place, it was time to actually work on the frontend UI that would allow users to build images dynamically and launch them. Since this will replace the &amp;lsquo;profileList&amp;rsquo; feature, it should also allow them to select different resources (RAM, CPU, etc) as needed, as well as type in an existing image if they desire. So it was a full re-implementation of the &lt;code>profileList&lt;/code> frontend.&lt;/p>
&lt;p>This is ongoing now at the
&lt;a href="https://github.com/yuvipanda/jupyterhub-fancy-profiles" target="_blank" rel="noopener" >jupyterhub-fancy-profiles&lt;/a> project. It is a pure frontend web application, using modern frontend tooling (
&lt;a href="https://react.dev/" target="_blank" rel="noopener" >React&lt;/a>,
&lt;a href="https://webpack.js.org/" target="_blank" rel="noopener" >webpack&lt;/a>,
&lt;a href="https://babeljs.io/" target="_blank" rel="noopener" >Babel&lt;/a>, etc) and written in JavaScript. It&amp;rsquo;s gone through a few revisions, but the demo provided earlier in the blog post is in its current state. Because the default profileList implementation is pure HTML / CSS with very &lt;em>minimal&lt;/em> JS, it is limited in what kind of UX it could have. &lt;code>jupyterhub-fancy-profiles&lt;/code> aims to be very helpful &lt;em>even&lt;/em> when dynamic image-building features are not enabled on a JupyterHub. We hope to roll this out to a few JupyterHubs and improve it over time based on feedback.&lt;/p>
&lt;h2 id="jupyterhubbinderhub-clienthttpswwwnpmjscompackagejupyterhubbinderhub-client-npm-package">
&lt;a href="https://www.npmjs.com/package/@jupyterhub/binderhub-client" target="_blank" rel="noopener" >&lt;code>jupyterhub/@binderhub-client&lt;/code>&lt;/a> npm package
&lt;a class="header-anchor" href="#jupyterhubbinderhub-clienthttpswwwnpmjscompackagejupyterhubbinderhub-client-npm-package">#&lt;/a>
&lt;/h2>&lt;p>While building &lt;code>jupyterhub-fancy-profiles&lt;/code>, we wanted to use the &lt;em>same&lt;/em> javascript code used by BinderHub frontend to interact with the BinderHub API, instead of re-implementing it. However, the existing BinderHub JavaScript code was not easily consumable by external projects. We refactored the code, added tests, migrated to use modern JS practices and published the
&lt;a href="https://www.npmjs.com/package/@jupyterhub/binderhub-client" target="_blank" rel="noopener" >&lt;code>jupyterhub/@binderhub-client&lt;/code> NPM package&lt;/a> that can be used not just by &lt;code>jupyerhub-fancy-profiles&lt;/code> but any external project for talking to the BinderHub API.&lt;/p>
&lt;p>This had to be done in such a way that current BinderHub installations (such as mybinder.org) do not break. That took quite a few pull requests:
&lt;a href="https://github.com/jupyterhub/binderhub/pull/1689" target="_blank" rel="noopener" >1&lt;/a>,
&lt;a href="https://github.com/jupyterhub/binderhub/pull/1693" target="_blank" rel="noopener" >2&lt;/a>,
&lt;a href="https://github.com/jupyterhub/binderhub/pull/1694" target="_blank" rel="noopener" >3&lt;/a>,
&lt;a href="https://github.com/jupyterhub/binderhub/pull/1741" target="_blank" rel="noopener" >4&lt;/a>,
&lt;a href="https://github.com/jupyterhub/binderhub/pull/1742" target="_blank" rel="noopener" >5&lt;/a>,
&lt;a href="https://github.com/jupyterhub/binderhub/pull/1758" target="_blank" rel="noopener" >6&lt;/a>,
&lt;a href="https://github.com/jupyterhub/binderhub/pull/1761" target="_blank" rel="noopener" >7&lt;/a>,
&lt;a href="https://github.com/jupyterhub/binderhub/pull/1771" target="_blank" rel="noopener" >8&lt;/a>,
&lt;a href="https://github.com/jupyterhub/binderhub/pull/1773" target="_blank" rel="noopener" >9&lt;/a>,
&lt;a href="https://github.com/jupyterhub/binderhub/pull/1775" target="_blank" rel="noopener" >10&lt;/a>,
&lt;a href="https://github.com/jupyterhub/binderhub/pull/1778" target="_blank" rel="noopener" >11&lt;/a>,
&lt;a href="https://github.com/jupyterhub/binderhub/pull/1779" target="_blank" rel="noopener" >12&lt;/a>,
&lt;a href="https://github.com/jupyterhub/binderhub/pull/1781" target="_blank" rel="noopener" >13&lt;/a>,
&lt;a href="https://github.com/jupyterhub/binderhub/pull/1782" target="_blank" rel="noopener" >14&lt;/a>,
&lt;a href="https://github.com/jupyterhub/binderhub/pull/1783" target="_blank" rel="noopener" >15&lt;/a>. This refactoring work was very helpful to us, and also appreciated by the broader community.&lt;/p>
&lt;h2 id="defending-against-cryptojacking-with-cryptnono">
Defending against cryptojacking with &lt;code>cryptnono&lt;/code>
&lt;a class="header-anchor" href="#defending-against-cryptojacking-with-cryptnono">#&lt;/a>
&lt;/h2>&lt;p>For Open Science to flourish, we need to allow access to resources without login / paywalls wherever possible. A new menace against this has been
&lt;a href="https://www.interpol.int/en/Crimes/Cybercrime/Cryptojacking" target="_blank" rel="noopener" >cryptojacking&lt;/a> - where attackers use up any and all available free compute to mine cryptocurrencies. This has affected &lt;em>many&lt;/em> folks on the internet, including
&lt;a href="https://www.bleepingcomputer.com/news/security/github-actions-being-actively-abused-to-mine-cryptocurrency-on-github-servers/" target="_blank" rel="noopener" >GitHub Actions&lt;/a> and mybinder.org, the primary public BinderHub installation. mybinder.org has some extra protections against cryptojacking that aren&amp;rsquo;t easily usable elsewhere, and this has unfortunately meant that the demo JupyterHubs we have with these features enabled have been behind a login wall. I personally believe login walls are long term antithetical to open science, and so this was an important problem to solve.&lt;/p>
&lt;p>
&lt;a href="https://github.com/cryptnono/cryptnono" target="_blank" rel="noopener" >cryptnono&lt;/a> is an open source project designed to help fight cryptojacking, and as part of this grant we ported some of this functionality out of mybinder.org specific code into cryptnono, so other deployments may also benefit from it! We also migrated to using the super efficient
&lt;a href="https://ebpf.io/" target="_blank" rel="noopener" >ebpf&lt;/a> Linux Kernel subsystem, allowing for more complex heuristics to catch a much broader range of cryptomining activity. We have been slowly tweaking the config on mybinder.org, and it has proven to be very effective! This will be very helpful for &lt;em>anyone&lt;/em> who wants to provide a JupyterHub (or any other computational service) without a login wall. If you are interested in using cryptnono in this fashion, please
&lt;a href="https://github.com/cryptnono/cryptnono/issues" target="_blank" rel="noopener" >reach out to us&lt;/a> so we can work together!&lt;/p>
&lt;h2 id="explored-pathways-that-were-then-discarded">
Explored pathways that were then discarded
&lt;a class="header-anchor" href="#explored-pathways-that-were-then-discarded">#&lt;/a>
&lt;/h2>&lt;p>List of things that were tried and then decided as not good pathways:&lt;/p>
&lt;ul>
&lt;li>
&lt;a href="https://github.com/consideRatio/repo2docker-service" target="_blank" rel="noopener" >repo2docker-service&lt;/a>, a separate JupyterHub service that could &lt;em>only&lt;/em> build images. As we worked on it, we realized that it was replicating a lot of features that BinderHub already has, so we pivoted to working on BinderHub directly instead.&lt;/li>
&lt;li>Building off of
&lt;a href="https://github.com/plasmabio/tljh-repo2docker" target="_blank" rel="noopener" >tljh-repo2docker&lt;/a>. While this already had a nice UI, it would be hard to port it to run on a distributed Kubernetes environment without it becoming a &amp;lsquo;hard fork&amp;rsquo;.&lt;/li>
&lt;/ul>
&lt;p>While these did slow down the implementation of the project, it has allowed us to be very confident that the methods we have chosen are long-term sustainable.&lt;/p>
&lt;h2 id="want-to-try-this-out">
Want to try this out?
&lt;a class="header-anchor" href="#want-to-try-this-out">#&lt;/a>
&lt;/h2>&lt;p>We have a demo of this running at
&lt;a href="https://imagebuilding-demo.2i2c.cloud" target="_blank" rel="noopener" >imagebuilding-demo.2i2c.cloud&lt;/a>, but unfortunately as we are still fine-tuning &lt;code>cryptnono&lt;/code> config, at this moment it is not open to the public. Please
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/blog/jupyterhub-binderhub-gesis/mailto:yuvipanda@2i2c.org" >contact me&lt;/a> with your GitHub account if you want access, and promise to not be a cryptominer and you shall be granted access.&lt;/p>
&lt;p>Want to set this up on your own JupyterHub? There is some
&lt;a href="https://github.com/2i2c-org/binderhub-service/pull/72" target="_blank" rel="noopener" >work in progress&lt;/a> documentation and more is being worked on. Drop a line in the linked pull request and we&amp;rsquo;ll be happy to help. The eventual goal is for &lt;em>anyone&lt;/em> to be able to simply follow documentation and set this up for themselves.&lt;/p>
&lt;p>We also have user facing documentation on using this service on
&lt;a href="https://docs.2i2c.org/user/environment/dynamic-imagebuilding#dynamic-image-building" target="_blank" rel="noopener" >docs.2i2c.org&lt;/a>.&lt;/p>
&lt;h2 id="future-work">
Future work
&lt;a class="header-anchor" href="#future-work">#&lt;/a>
&lt;/h2>&lt;p>This is not complete of course, and there is a lot of future work to be done.&lt;/p>
&lt;ol>
&lt;li>mybinder.org also helps you distribute your &lt;em>content&lt;/em>, not just the environment for your code to run in. Since JupyterHub usually comes with a persistent home directory for the user,
&lt;a href="https://github.com/jupyterhub/nbgitpuller/" target="_blank" rel="noopener" >nbgitpuller&lt;/a> is commonly used for this purpose instead. We should explore ways to integrate nbgitpuller (and other ways to distribute content) in the future.&lt;/li>
&lt;li>More thorough documentation for how you can recreate what is in the demo for yourself in your own JupyterHub installation.&lt;/li>
&lt;li>Better UX for specifying images, including figuring out how to &amp;lsquo;save&amp;rsquo; them for future reuse.&lt;/li>
&lt;li>Better compatibility with mybinder.org, particularly in allowing other sources of environments (not just GitHub, but Zenodo, raw git repositories, etc) and URL compatibility.&lt;/li>
&lt;li>Better authentication workflow between the frontend and the BinderHub API.&lt;/li>
&lt;/ol>
&lt;h2 id="credit">
Credit
&lt;a class="header-anchor" href="#credit">#&lt;/a>
&lt;/h2>&lt;p>All this work would not be possible without a large group of collaborators!&lt;/p>
&lt;ul>
&lt;li>From 2i2c:
&lt;a href="https://github.com/consideRatio" target="_blank" rel="noopener" >Erik Sundell&lt;/a>,
&lt;a href="https://github.com/GeorgianaElena" target="_blank" rel="noopener" >Georgiana Elena&lt;/a>,
&lt;a href="https://words.yuvi.in/" target="_blank" rel="noopener" >Yuvi&lt;/a>,
&lt;a href="https://github.com/jmunroe" target="_blank" rel="noopener" >James Munroe&lt;/a>, and
&lt;a href="https://github.com/damianavila" target="_blank" rel="noopener" >Damián Avila&lt;/a>.&lt;/li>
&lt;li>The
&lt;a href="https://github.com/gesiscss/persistent_BinderHub/" target="_blank" rel="noopener" >persistent BinderHub&lt;/a> project was the direct inspiration for all this work, with particular thanks to
&lt;a href="https://github.com/bitnik" target="_blank" rel="noopener" >Kenan Erdogan&lt;/a>.&lt;/li>
&lt;li>The
&lt;a href="https://github.com/plasmabio/tljh-repo2docker" target="_blank" rel="noopener" >tljh-repo2docker&lt;/a> project, which explores similar ideas in the context of running only on a single node.&lt;/li>
&lt;li>The broad JupyterHub and MyBinder.org community, particularly
&lt;a href="https://github.com/manics" target="_blank" rel="noopener" >Simon Li&lt;/a> and
&lt;a href="https://github.com/minrk/" target="_blank" rel="noopener" >MinRK&lt;/a>.&lt;/li>
&lt;li>Funding generously provided by
&lt;a href="http://gesis.org" target="_blank" rel="noopener" >GESIS&lt;/a> in cooperation with NFDI4DS (project number:
&lt;a href="https://gepris.dfg.de/gepris/projekt/460234259?context=projekt&amp;amp;task=showDetail&amp;amp;id=460234259&amp;amp;" target="_blank" rel="noopener" >460234259&lt;/a>) and
&lt;a href="https://www.cessda.eu" target="_blank" rel="noopener" >CESSDA&lt;/a>.&lt;/li>
&lt;li>
&lt;a href="https://www.gesis.org/en/institute/staff/person/arnim.bleier" target="_blank" rel="noopener" >Arnim Bleier&lt;/a> from GESIS was &lt;em>instrumental&lt;/em> in making this project happen.&lt;/li>
&lt;/ul></description></item><item><title>2i2c supports Jupyter Docker Stacks ARM builds</title><link>https://deploy-preview-612--2i2c-org.netlify.app/blog/docker-stacks-support/</link><pubDate>Fri, 01 Dec 2023 00:00:00 +0000</pubDate><guid>https://deploy-preview-612--2i2c-org.netlify.app/blog/docker-stacks-support/</guid><description>&lt;p>The
&lt;a href="https://jupyter-docker-stacks.readthedocs.io/" target="_blank" rel="noopener" >Jupyter Docker Stacks&lt;/a> project provides a collection of ready-to-use Docker images for Jupyter environments. These images are used by many in the Jupyter community, including 2i2c which uses them as base images for our JupyterHub deployments.&lt;/p>
&lt;p>The project recently began publishing
&lt;a href="https://github.com/jupyter/docker-stacks/issues/1019" target="_blank" rel="noopener" >ARM-compatible images&lt;/a> alongside the standard x86 images, making it easier for users with ARM-based systems (like M1 Macs) to use these environments. However, building and hosting these ARM images comes with additional cloud computing costs that were being personally covered by
&lt;a href="https://github.com/mathbunnyru" target="_blank" rel="noopener" >@mathbunnyru&lt;/a>, one of the project&amp;rsquo;s maintainers.&lt;/p>
&lt;p>A part of 2i2c&amp;rsquo;s mission is supporting upstream communities that we rely on, especially where the upstream project has limited resources. For this reason, we&amp;rsquo;ve decided to support Jupyter Docker Stack&amp;rsquo;s ARM building costs, with a total budget of &lt;code>$2000&lt;/code> (approximately &lt;code>$150&lt;/code> per month). As a regular user and beneficiary of the Jupyter Docker Stacks, we believe it&amp;rsquo;s important to contribute to the maintenance and sustainability of this crucial piece of infrastructure that benefits the entire Jupyter community.&lt;/p>
&lt;p>We hope this support helps the Docker Stacks project remain healthy, and continue providing high-quality, multi-architecture images that work across different computing platforms. We&amp;rsquo;ll revisit this decision as the landscape of technology providers changes and other options arise.&lt;/p>
&lt;h2 id="acknowledgments">
Acknowledgments
&lt;a class="header-anchor" href="#acknowledgments">#&lt;/a>
&lt;/h2>&lt;ul>
&lt;li>Thanks to
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/collaborators/jupyter/" >Project Jupyter&lt;/a> (particularly the &lt;code>jupyter-stacks&lt;/code> team) for this project.&lt;/li>
&lt;/ul></description></item><item><title>A QGIS desktop in the cloud with JupyterHub</title><link>https://deploy-preview-612--2i2c-org.netlify.app/blog/qgis-greenland/</link><pubDate>Sat, 05 Aug 2023 00:00:00 +0000</pubDate><guid>https://deploy-preview-612--2i2c-org.netlify.app/blog/qgis-greenland/</guid><description>&lt;p>
&lt;figure id="figure-the-qgreenland-researcher-workshophttpsqgreenland-workshop-2023-researchergithubio">
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="QGreenland Researcher Workshop" srcset="
/blog/qgis-greenland/featured_hu9562f6f382c010541578bd7b61c7cb4a_187505_a085d691b13f577db24aead3ae21385c.webp 400w,
/blog/qgis-greenland/featured_hu9562f6f382c010541578bd7b61c7cb4a_187505_9bd1833b93cf6052c08ff407d4528940.webp 760w,
/blog/qgis-greenland/featured_hu9562f6f382c010541578bd7b61c7cb4a_187505_1200x1200_fit_q75_h2_lanczos_3.webp 1200w"
src="https://deploy-preview-612--2i2c-org.netlify.app/blog/qgis-greenland/featured_hu9562f6f382c010541578bd7b61c7cb4a_187505_a085d691b13f577db24aead3ae21385c.webp"
width="760"
height="498"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;figcaption>
The
&lt;a href="https://qgreenland-workshop-2023-researcher.github.io/" target="_blank" rel="noopener" >QGreenland Researcher Workshop&lt;/a>
&lt;/figcaption>&lt;/figure>
&lt;/p>
&lt;p>JupyterHub is a versatile platform that can serve a desktop with Geospatial Information Systems (GIS) software in the cloud. This was demonstrated by the QGreenland Researcher Workshop that was hosted by the NASA
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/collaborators/cryocloud/" >CryoCloud&lt;/a> hub. The hands-on workshop trained 25-30 researchers, from Germany, India, France, Canada, Poland and the United States, on how to work with geospatial data in an open science framework.&lt;/p>
&lt;h2 id="qgreenland-overview">
QGreenland Overview
&lt;a class="header-anchor" href="#qgreenland-overview">#&lt;/a>
&lt;/h2>&lt;p>
&lt;a href="https://qgreenland.org/" target="_blank" rel="noopener" >QGreenland&lt;/a> is an open-source geospatial data package designed for QGIS, a community-owned GIS platform. It focuses on Greenland, offering researchers and educators a comprehensive toolset for FAIR (findable, accessible, interoperable and reproducible) data analysis. The package integrates a variety of datasets into a single, easy-to-use data-viewing and analysis platform, supporting both offline and online use. This makes it particularly valuable for remote fieldwork and areas with limited internet access.&lt;/p>
&lt;h2 id="workshop-success">
Workshop Success
&lt;a class="header-anchor" href="#workshop-success">#&lt;/a>
&lt;/h2>&lt;p>The QGreenland workshop demonstrated several key benefits of using JupyterHub for cloud-based GIS:&lt;/p>
&lt;ul>
&lt;li>Accessibility: Participants from across the world could access the same powerful GIS tools through a web browser, eliminating the need for complex local installations while enhancing reproducibility&lt;/li>
&lt;li>Cloud block storage: Using a JupyterHub in the cloud allowed for faster data access than a traditional NFS file store by provisioning each user with an elastic block store disk, reducing load times from 5 minutes to under 3 seconds.&lt;/li>
&lt;li>Cost Efficiency: Utilizing the
&lt;a href="https://deploy-preview-612--2i2c-org.netlify.app/collaborators/cryocloud/" >CryoCloud&lt;/a> JupyterHub instance managed by 2i2c drastically cut down setup costs and time, with only minimal cloud operating expenses of roughly $1/person/day.&lt;/li>
&lt;/ul>
&lt;h2 id="conclusion">
Conclusion
&lt;a class="header-anchor" href="#conclusion">#&lt;/a>
&lt;/h2>&lt;p>The success of the QGreenland workshop underscores the potential of integrating interactive software applications in JupyterHub. This approach not only democratizes access to advanced geospatial tools but also fosters a collaborative research environment. We look forward to supporting more workshops for QGreenland in the future!&lt;/p>
&lt;p>&lt;em>Want to know more? Check out the companion post by QGreenland on the
&lt;a href="https://blog.jupyter.org/desktop-gis-software-in-the-cloud-with-jupyterhub-ddced297019a" target="_blank" rel="noopener" >Jupyter Blog&lt;/a>&lt;/em>&lt;/p>
&lt;h2 id="acknowledgements">
Acknowledgements
&lt;a class="header-anchor" href="#acknowledgements">#&lt;/a>
&lt;/h2>&lt;ul>
&lt;li>
&lt;a href="https://cires.colorado.edu/people/trey-stafford" target="_blank" rel="noopener" >Trey Stafford&lt;/a>
&lt;a href="https://cires.colorado.edu/" target="_blank" rel="noopener" >(CIRES)&lt;/a>&lt;/li>
&lt;li>
&lt;a href="https://cires.colorado.edu/people/matthew-fisher" target="_blank" rel="noopener" >Matthew Fisher&lt;/a>
&lt;a href="https://cires.colorado.edu/" target="_blank" rel="noopener" >(CIRES)&lt;/a>&lt;/li>
&lt;li>*Fisher, M., *T. Stafford, T. Moon, and A. Thurber (2023). QGreenland (v3) [software], National Snow and Ice Data Center.&lt;/li>
&lt;li>Snow, Tasha, Millstein, Joanna, Scheick, Jessica, Sauthoff, Wilson, Leong, Wei Ji, Colliander, James, Pérez, Fernando, James Munroe, Felikson, Denis, Sutterley, Tyler, &amp;amp; Siegfried, Matthew. (2023).
&lt;a href="https://book.cryointhecloud.com" target="_blank" rel="noopener" >CryoCloud JupyterBook&lt;/a> (2023.01.26). Zenodo.
&lt;a href="https://doi.org/10.5281/zenodo.7576602" target="_blank" rel="noopener" >10.5281/zenodo.7576602&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>* Denotes co-equal lead authorship&lt;/p></description></item><item><title>Yuvaraj (Yuvi)</title><link>https://deploy-preview-612--2i2c-org.netlify.app/author/yuvaraj-yuvi/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://deploy-preview-612--2i2c-org.netlify.app/author/yuvaraj-yuvi/</guid><description>&lt;p>Building participatory open infrastructure for scientific &amp;amp; educational use cases. A Project Jupyter team member working on infrastructure related projects. Ex Wikimedia and ex-GNOME. Let&amp;rsquo;s eliminate accidental complexities wherever we find them.&lt;/p>
&lt;p>&lt;strong>Highlights&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>10+ years experience building open infrastructure for scientific and educational communities&lt;/li>
&lt;li>Jupyter Distinguished Contributor&lt;/li>
&lt;li>Leader in the JupyterHub and Binder projects&lt;/li>
&lt;li>Served as the Infrastructure Architect behind UC Berkeley’s scalable DataHub&lt;/li>
&lt;li>Former ops engineer at Wikimedia and GNOME.&lt;/li>
&lt;/ul></description></item></channel></rss>