Kubeflow Component分析#1-Jupyter Notebook(Notebook権限の変更)


1.背景


Kubeflowをインストールして作成したシードは、複数の構成部品が存在することを決定します.Kubeflowベースのプラットフォームを開発したり、Kubeflowを正しく使用したりするには、各コンポーネントの役割と操作手順を理解する必要があります.このため,素子の学習を順次記録する.

2.Notebookの作成方法と構造


一般ユーザーがKubeflowでノートパソコンを使用する方法は非常に簡単です.DashboardノートパソコンMenuから作成し、接続して使用します.自分のNamespaceで割り当てられた使用可能なリソースを分割および使用できます.

ノートパソコンの作成が完了すると、podの作成がネーミングスペースに表示されます.notebookという名前のCRDで作成すると、Statefulsetで展開されていることがわかります.

Notebook CRDの名前はnotebooks.kubeflow.orgで、Describeコマンドで詳細を表示できます.CRDはオブジェクトのみを定義するため、Kubernets内のオブジェクトを維持するためにコントローラが必要です.たとえば、オブジェクトの作成と再起動(必要な状態を維持)などです.これらのキャラクタのコントローラはnotebook-controller-deploymentです.実際のコントローラがこれらの所望の状態を達成するために実行する動作を協調と呼び、実際のコントローラのコード#コード#をチェックすることで、協調機能によってNotebookの動作手順を表示することができる.(コード解析を更新しようとしています)
func (r *NotebookReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
	ctx := context.Background()
	log := r.Log.WithValues("notebook", req.NamespacedName)

	// TODO(yanniszark): Can we avoid reconciling Events and Notebook in the same queue?
	event := &corev1.Event{}
	var getEventErr error
	getEventErr = r.Get(ctx, req.NamespacedName, event)
	if getEventErr == nil {
		log.Info("Found event for Notebook. Re-emitting...")

		// Find the Notebook that corresponds to the triggered event
		involvedNotebook := &v1beta1.Notebook{}
		nbName, err := nbNameFromInvolvedObject(r.Client, &event.InvolvedObject)
		if err != nil {
			return ctrl.Result{}, err
		}

		involvedNotebookKey := types.NamespacedName{Name: nbName, Namespace: req.Namespace}
		if err := r.Get(ctx, involvedNotebookKey, involvedNotebook); err != nil {
			log.Error(err, "unable to fetch Notebook by looking at event")
			return ctrl.Result{}, ignoreNotFound(err)
		}

		// re-emit the event in the Notebook CR
		log.Info("Emitting Notebook Event.", "Event", event)
		r.EventRecorder.Eventf(involvedNotebook, event.Type, event.Reason,
			"Reissued from %s/%s: %s", strings.ToLower(event.InvolvedObject.Kind), event.InvolvedObject.Name, event.Message)
		return ctrl.Result{}, nil
	}

3.Notebook作成プロセス


上記の構成を採用したノートパソコンは、jupyter-web-app-deploymentによってAPI通信を実現し、作成する.
これらの内容は、jupyter-web-app-deploymentの内部で確認でき、フラスコからなるAPIサーバ上で通信できます.Notebook作成フォームからデータを抽出し、PVCを生成し、Notebookを作成およびマウントします.
@bp.route("/api/namespaces/<namespace>/notebooks", methods=["POST"])
@decorators.request_is_json_type
@decorators.required_body_params("name")
def post_pvc(namespace):
    body = request.get_json()
    log.info("Got body: %s" % body)

    notebook = helpers.load_param_yaml(
        utils.NOTEBOOK_TEMPLATE_YAML,
        name=body["name"],
        namespace=namespace,
        serviceAccount="default-editor",
    )

    defaults = utils.load_spawner_ui_config()

    form.set_notebook_image(notebook, body, defaults)
    form.set_notebook_image_pull_policy(notebook, body, defaults)
    form.set_server_type(notebook, body, defaults)
    form.set_notebook_cpu(notebook, body, defaults)
    form.set_notebook_memory(notebook, body, defaults)
    form.set_notebook_gpus(notebook, body, defaults)
    form.set_notebook_tolerations(notebook, body, defaults)
    form.set_notebook_affinity(notebook, body, defaults)
    form.set_notebook_configurations(notebook, body, defaults)
    form.set_notebook_shm(notebook, body, defaults)

    # Notebook volumes
    api_volumes = []
    api_volumes.extend(form.get_form_value(body, defaults, "datavols",
                                           "dataVolumes"))
    workspace = form.get_form_value(body, defaults, "workspace",
                                    "workspaceVolume", optional=True)
    if workspace:
        api_volumes.append(workspace)

    # ensure that all objects can be created
    api.create_notebook(notebook, namespace, dry_run=True)
    for api_volume in api_volumes:
        pvc = volumes.get_new_pvc(api_volume)
        if pvc is None:
            continue

        api.create_pvc(pvc, namespace, dry_run=True)

    # create the new PVCs and set the Notebook volumes and mounts
    for api_volume in api_volumes:
        pvc = volumes.get_new_pvc(api_volume)
        if pvc is not None:
            logging.info("Creating PVC: %s", pvc)
            pvc = api.create_pvc(pvc, namespace)

        v1_volume = volumes.get_pod_volume(api_volume, pvc)
        mount = volumes.get_container_mount(api_volume, v1_volume["name"])

        notebook = volumes.add_notebook_volume(notebook, v1_volume)
        notebook = volumes.add_notebook_container_mount(notebook, mount)

    log.info("Creating Notebook: %s", notebook)
    api.create_notebook(notebook, namespace)

    return api.success_response("message", "Notebook created successfully.")
api.create_notebook(notebook, namespace)コードにKubernetes Python clientを使用するノートブックを作成します.


Dashboardで実際のノートパソコンを作成すると、対応するAPIアドレスにデータが転送されます.

4.Notebook作成権限の変更


Kubeflowでノートパソコンを作成するときはJovyan(UID:1000,GID:100)を使用します.Jovyanは、イメージ作成時に適用されるユーザです.

したがって、ノートパソコンの内部にファイルを作成し、PVで検証すると、サーバの1000:100が表示されます.
#ec2-user의 UID 1000
#GID 100 users

-rw-r--r--.  1 ec2-user users   10  4월 15 04:43 test.txt
ノートパソコン作成ユーザーのグループを100回ではなく特定のグループに設定する必要があるため、変更する必要があります.これを変更するには、さまざまな方法がありますが、KubernetsのSecurityContextを使用して変更できます.そのため、jupyter-web-app-deploymentのコードを変更してください.コードを変更するためにkubeflow githubをクローンしました.
ノートパソコンを作成すると、基本YAMLが取得され、notebook_template.yamlにあるObejctが作成されます.このセクションでは、SecurityContextを追加して、シードの実行時にユーザーとグループを作成する権限を追加します.

UID、GIDが手動で設定されているため、この状態で操作可能であるが、将来のGIDを動的に受信するためにコードを追加することができる.(これは実際には適用されません)
jupyter/backend/apps/common/forms.pySecurityContextを設定する関数を作成し、post.pyに作成する関数を設定します.

画像を作成して、これらの変更を適用するコード.Jupyterフォルダに存在するDockerfileの場所が正しくないため、構築に失敗します.そのため、Dockerfileを一歩上に移動してください(crud-web-apps).

次に、画像をNexusアドレスとしてマークし、プッシュします.

Kubernetesは、jupyter-web-app-deploymentの画像を変更して画像を適用する.nexusは画像を受信するため、imagePullSecretを追加した.

新しいノートパソコンが作成されると、UID Jovyan(1000)とGID 1500ファイルの作成が表示されます.