zero-to-jupyterhub如何自定义内存和CPU

jupyterhub on k8s 用户自定义资源大小:

 

 

 

1. 首先需要将前端的数据传到后端:

/usr/local/share/jupyterhub/templates/spawn.html

{% extends "page.html" %}
{% if announcement_spawn %}
{% set announcement = announcement_spawn %}
{% endif %}

{% block main %}

<div class="container">
    {% block heading %}
    <div class="row text-center">
        <h1>Server Options</h1>
    </div>
    {% endblock %}
    <div class="row col-sm-offset-2 col-sm-8">
        {% if for_user and user.name != for_user.name -%}
        <p>Spawning server for {{ for_user.name }}</p>
        {% endif -%}
        {% if error_message -%}
        <p class="spawn-error-msg text-danger">
            Error: {{error_message}}
        </p>
        {% endif %}
        <form enctype="multipart/form-data" id="spawn_form" action="{{url}}" method="post" role="form" onsubmit="return dis()">
            {{spawner_options_form | safe}}
            <label for="self-profile" class="form-control input-group">
                <div class="col-md-1">
                    <input type="radio" name="profile" id="self-profile" value="self-profile">
                </div>
                <div class="col-md-11">
                    <strong>Spark && Hail && GD environment.  <i>Customize specified resources here: </i></strong>
                    <p>Memory: <input type="number" name="memory" id="memory">G &nbsp;&nbsp;CPU: <input type="number" name="cpu" id="cpu">C</p>
                    <div id="resource-error" style="display: none;color: red">资源申请不合法! Mem:[1:30]G CPU:[0:3.6]C</div>
                </div>
            </label>
            <br>
            <input type="submit" value="Start" class="btn btn-jupyter form-control">
        </form>
    </div>
    <script type="text/javascript">
        const txtMem = document.getElementById('memory');
        const txtCPU = document.getElementById('cpu');
        const txtErr = document.getElementById('resource-error');//校验
        function dis() {
            //获取输入框内容
            txtErr.style.display = "none" ;

const tMem = txtMem.value;
            const tCPU = txtCPU.value;
            const profile_value = document.querySelector('input:checked').value;
//判断 if (profile_value != 'self-profile') { return true; } if (!(tMem >= 1 && tMem <= 30)) { txtErr.style.display = 'inline-block'; return false;//校验不通过  } if (!(tCPU >= 0 && tCPU <= 3.6)) { txtErr.style.display = 'inline-block'; return false; } return true; } </script> </div> {% endblock %}

 

2. 解析传送到后端的数据

 /usr/local/lib/python3.6/dist-packages/jupyterhub/handlers/pages.py

            if 'self-profile' in form_options.get("profile") and "memory" in form_options  and "cpu" in form_options:
                try:
                    memory = form_options.get("memory", [])[0]
                    cpu = form_options.get("cpu", [])[0]
                    profile = f"mem:{memory}G, cpu:{cpu}"
                    options = {"memory": memory, "cpu": cpu, "profile": profile}
                except Exception as e:
                    options = await maybe_future(spawner.options_from_form(form_options))
            else:
                options = await maybe_future(spawner.options_from_form(form_options))
            await self.spawn_single_user(user, server_name=server_name, options=options)

 

3. 加载配置

    @gen.coroutine
    def _load_profile(self, profile_name):
        """Load a profile by name

        Called by load_user_options
        """

        # find the profile
        default_profile = self._profile_list[0]
        if 'mem:' in profile_name and 'cpu:' in profile_name:
            resource_info = dict([_.strip().split(":") for _ in profile_name.split(",")])
            mem_value = resource_info.get("mem").strip()
            cpu_value = float(resource_info.get("cpu").strip())
            kubespawner_override = {
                'mem_guarantee': str(int(float(mem_value[:-1]) * 0.6)) + "G",
                'mem_limit': mem_value,
                'cpu_guarantee': cpu_value * 0.6,
                'cpu_limit': cpu_value
            }
        else:
            for profile in self._profile_list:
                if profile.get('default', False):
                    # explicit default, not the first
                    default_profile = profile

                if profile['display_name'] == profile_name:
                    break
            else:
                if profile_name:
                    # name specified, but not found
                    raise ValueError("No such profile: %s. Options include: %s" % (
                        profile_name, ', '.join(p['display_name'] for p in self._profile_list)
                    ))
                else:
                    # no name specified, use the default
                    profile = default_profile

            self.log.debug("Applying KubeSpawner override for profile '%s'", profile['display_name'])
            kubespawner_override = profile.get('kubespawner_override', {})
        for k, v in kubespawner_override.items():
            if callable(v):
                v = v(self)
                self.log.debug(".. overriding KubeSpawner value %s=%s (callable result)", k, v)
            else:
                self.log.debug(".. overriding KubeSpawner value %s=%s", k, v)
            setattr(self, k, v)

 

Dockerfile

FROM  jupyterhub/k8s-hub:0.9.0-beta.4

USER root

COPY pages.py /usr/local/lib/python3.6/dist-packages/jupyterhub/handlers/pages.py
COPY spawner.py  /usr/local/lib/python3.6/dist-packages/kubespawner/spawner.py 
COPY spawn.html  /usr/local/share/jupyterhub/templates/spawn.html 
RUN chmod 777  /usr/local/share/jupyterhub/templates/spawn.html

USER jovyan

 

posted @ 2020-06-16 12:54  similarface  阅读(833)  评论(3编辑  收藏  举报