avatarYao-Jen Kuo

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

9760

Abstract

s-attribute">NAME</span> STATUS ROLES AGE VERSIONgke-jupyterhub-default-pool-<span class="hljs-number">2</span>a2f588b-c291 Ready <none> <span class="hljs-number">20</span>m v1.<span class="hljs-number">15</span>.<span class="hljs-number">9</span>-gke.<span class="hljs-number">8</span>gke-jupyterhub-default-pool-<span class="hljs-number">2</span>a2f588b-jml2 Ready <none> <span class="hljs-number">20</span>m v1.<span class="hljs-number">15</span>.<span class="hljs-number">9</span>-gke.<span class="hljs-number">8</span></pre></div><p id="d467">把帳號調整至最大的管理員權限,替換 <google-email-account> 為自己的 Gmail 帳號。</google-email-account></p><div id="d1ae"><pre>username@cloudshell:~ (jupyterhub-<span class="hljs-keyword">with</span>-k8s) kubectl <span class="hljs-keyword">create</span> clusterrolebinding <span class="hljs-keyword">cluster</span>-<span class="hljs-keyword">admin</span>-binding \ <span class="hljs-comment">--clusterrole=cluster-admin \</span> <span class="hljs-comment">--user=&lt;GOOGLE-EMAIL-ACCOUNT&gt;</span></pre></div><div id="d99a"><pre>clusterrolebinding.rbac.<span class="hljs-keyword">authorization</span>.k8s.io/<span class="hljs-keyword">cluster</span>-<span class="hljs-keyword">admin</span>-binding created</pre></div><p id="659e">做一個最適化調整,完成建置 Kubernetes。</p><div id="edcc"><pre>gcloud beta container <span class="hljs-keyword">node</span><span class="hljs-title">-pools</span> create user-pool \ --machine-<span class="hljs-keyword">type</span> n1-standard-<span class="hljs-number">2</span> \ --num-nodes <span class="hljs-number">0</span> \ --enable-autoscaling \ --min-nodes <span class="hljs-number">0</span> \ --max-nodes <span class="hljs-number">3</span> \ --<span class="hljs-keyword">node</span><span class="hljs-title">-labels</span> hub.jupyter.org/<span class="hljs-keyword">node</span><span class="hljs-title">-purpose</span>=<span class="hljs-keyword">user</span> <span class="hljs-title">\ --node-taints</span> hub.jupyter.<span class="hljs-attr">org_dedicated=</span>user:NoSchedule \ --zone <span class="hljs-tag">&lt;ZONENAME&gt;</span> \ --cluster <span class="hljs-tag">&lt;CLUSTERNAME&gt;</span></pre></div><p id="a4c0">替換 <zonename> 為先前創建時所指定的機房區域、替換 <clustername> 為先前創建是所自訂的叢集名稱。</clustername></zonename></p><div id="72ac"><pre>username@cloudshell:~ (jupyterhub-with-k8s) gcloud beta container <span class="hljs-keyword">node</span><span class="hljs-title">-pools</span> create user-pool &gt; --machine-<span class="hljs-keyword">type</span> n1-standard-<span class="hljs-number">2</span> &gt; --num-nodes <span class="hljs-number">0</span> &gt; --enable-autoscaling &gt; --min-nodes <span class="hljs-number">0</span> &gt; --max-nodes <span class="hljs-number">3</span> &gt; --<span class="hljs-keyword">node</span><span class="hljs-title">-labels</span> hub.jupyter.org/<span class="hljs-keyword">node</span><span class="hljs-title">-purpose</span>=<span class="hljs-keyword">user</span> <span class="hljs-title">&gt; --node-taints</span> hub.jupyter.<span class="hljs-attr">org_dedicated=</span>user:NoSchedule &gt; --zone asia-east1-a &gt; --cluster jupyterhub</pre></div><div id="71cd"><pre>This will enable the autorepair feature for nodes. Please see https://cloud.google.com/kubernetes-engine/docs/<span class="hljs-keyword">node</span><span class="hljs-title">-auto-repair</span> for more <span class="hljs-literal">inf</span>ormation on <span class="hljs-keyword">node</span> <span class="hljs-title">autorepairs</span>.Creating <span class="hljs-keyword">node</span> <span class="hljs-title">pool</span> user-pool...done. Created [https://container.googleapis.com/v1beta1/projects/jupyterhub-with-k8s/zones/asia-east1-a/clusters/jupyterhub/nodePools/user-pool]. NAME MACHINE_TYPE DISK_SIZE_GB NODE_VERSIONuser-pool n1-standard-<span class="hljs-number">2</span> <span class="hljs-number">100</span> <span class="hljs-number">1.15</span>.<span class="hljs-number">9</span>-gke.<span class="hljs-number">8</span></pre></div><p id="43ae">恭喜完成建置 Kubernetes!接下來是設定 Helm。</p><h2 id="0582">設定 Helm</h2><p id="ff49"><a href="https://helm.sh/">Helm</a> 是 Kubernetes 的套件管理工具,可以協助我們在安裝、升級和管理套件,Helm 之於 K8s 就像是 pip 之於 Python、npm 之於 nodejs 的關係;我們將使用 Helm chart 管理 Kubernetes 設定檔,如此透過編輯 config.yaml 檔案即可完成 JupyterHub 的安裝與部署。</p><p id="3282">使用 <code>curl</code> 指令下載安裝指令並執行。</p><div id="fba4"><pre>curl https:<span class="hljs-regexp">//</span>raw.githubusercontent.com<span class="hljs-regexp">/kubernetes/</span>helm<span class="hljs-regexp">/master/</span>scripts/get | bash</pre></div><figure id="1a83"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*9fnvVQWocKknLZRuOu92Ng.png"><figcaption>使用 <code>curl</code> 指令下載安裝指令並執行</figcaption></figure><p id="782d">依序輸入下列指令啟動 Helm。</p><div id="e7d1"><pre>username<span class="hljs-variable">@cloudshell</span>:<span class="hljs-operator"></span> (jupyterhub<span class="hljs-operator">-</span><span class="hljs-keyword">with</span><span class="hljs-operator">-</span>k8s) kubectl <span class="hljs-comment">--namespace kube-system create serviceaccount tiller</span></pre></div><div id="b758"><pre>serviceaccount/tiller created</pre></div><div id="90ac"><pre>username<span class="hljs-variable">@cloudshell</span>:<span class="hljs-operator">~</span> (jupyterhub<span class="hljs-operator">-</span><span class="hljs-keyword">with</span><span class="hljs-operator">-</span>k8s) kubectl <span class="hljs-keyword">create</span> clusterrolebinding tiller <span class="hljs-comment">--clusterrole cluster-admin --serviceaccount=kube-system:tiller</span></pre></div><div id="5023"><pre>clusterrolebinding<span class="hljs-selector-class">.rbac</span><span class="hljs-selector-class">.authorization</span><span class="hljs-selector-class">.k8s</span>.io/tiller created</pre></div><div id="c363"><pre>username<span class="hljs-variable">@cloudshell</span>: (jupyterhub-<span class="hljs-keyword">with</span>-k8s)<span class="hljs-variable"> </span>helm init --service-account tiller --wait</pre></div><div id="a385"><pre>Creating <span class="hljs-regexp">/home/u</span>sername<span class="hljs-regexp">/.helmCreating /</span>home<span class="hljs-regexp">/username/</span>.helm<span class="hljs-regexp">/repositoryCreating /</span>home<span class="hljs-regexp">/username/</span>.helm<span class="hljs-regexp">/repository/</span>cacheCreating <span class="hljs-regexp">/home/u</span>sername<span class="hljs-regexp">/.helm/</span>repository<span class="hljs-regexp">/localCreating /</span>home<span class="hljs-regexp">/username/</span>.helm<span class="hljs-regexp">/pluginsCreating /</span>home<span class="hljs-regexp">/username/</span>.helm<span class="hljs-regexp">/startersCreating /</span>home<span class="hljs-regexp">/username/</span>.helm<span class="hljs-regexp">/cache/</span>archiveCreating <span class="hljs-regexp">/home/u</span>sername<span class="hljs-regexp">/.helm/</span>repository/repositories.yaml Adding stable repo with URL: https:<span class="hljs-regexp">//</span>kubernetes-charts.storage.googleapis.comAdding local repo with URL: http:<span class="hljs-regexp">//</span><span class="hljs-number">127.0</span>.<span class="hljs-number">0.1</span>:<span class="hljs-number">8879</span>/charts <span class="hljs-variable">HELM_HOME</span> has been configured at <span class="hljs-regexp">/home/</span>tonykuoyj/.helm.</pre></div><div id="4fd0"><pre>Tiller (the Helm <span class="hljs-keyword">server</span>-side component) has been installed <span class="hljs-keyword">into</span> your Kubernetes <span class="hljs-keyword">Cluster</span>.</pre></div><div id="4f39"><pre>Please note: <span class="hljs-keyword">by</span> <span class="hljs-keyword">default</span>, Tiller <span class="hljs-keyword">is</span> deployed <span class="hljs-keyword">with</span> an insecure <span class="hljs-string">'allow unauthenticated users'</span> <span class="hljs-keyword">policy</span>.<span class="hljs-keyword">To</span> prevent this, run helm init <span class="hljs-keyword">with</span> the <span class="hljs-comment">--tiller-tls-verify flag.For more information on securing your installation see: https://docs.helm.sh/using_helm/#securing-your-helm-installation</span></pre></div><div id="6f37"><pre>username@cloudshell:~ <span class="hljs-params">(jupyterhub-with-k8s)</span> kubectl <span class="hljs-keyword">patch</span> deployment tiller-deploy <span class="hljs-params">--namespace=kube-system</span> <span class="hljs-params">--type=json</span> <span class="hljs-params">--patch=</span>'[{<span class="hljs-string">"op"</span>: <span class="hljs-string">"add"</span>, <span class="hljs-string">"path"</span>: <span class="hljs-string">"/spec/template/spec/containers/0/command"</span>, <span class="hljs-string">"value"</span>: [<span class="hljs-string">"/tiller"</span>, <span class="hljs-string">"--listen=localhost:44134"</span>]}]'</pre></div><div id="b05c"><pre>deployment.extensions/tiller-deploy patched</pre></div><p id="b5ae">以 <code>helm version</code> 指令檢視 Helm 是否設定妥當。</p><div id="e791"><pre>username<span class="hljs-variable">@cloudshell</span>:~ (jupyterhub-<span class="hljs-keyword">with</span>-k8s)<span class="hljs-variable"> </span>helm version</pre></div><div id="5469"><pre>Client: &<span class="hljs-keyword">version</span>.<span class="hljs-keyword">Version</span>{SemVer:"v2.16.1", GitCommit:"bbdfe5e7803a12bbdf97e94cd847859890cf4050", GitTreeState:"clean"}<span class="hljs-keyword">Server</span>: &<span class="hljs-keyword">version</span>.<span class="hljs-keyword">Version</span>{SemVer:"v2.16.1", GitCommit:"bbdfe5e7803a12bbdf97e94cd847

Options

859890cf4050", GitTreeState:"clean"}</pre></div><p id="1fab">恭喜完成設定 Helm!接下來是安裝 JupyterHub。</p><h2 id="635d">安裝 JupyterHub</h2><p id="c636">Helm chart 是一組 Helm 模板讓管理員能夠以 <code>yaml</code> 檔對 Kubernetes 叢集進行套件的安裝、升級與管理。</p><p id="3907">在終端機以 <code>openssl rand -hex 32</code> 指令生成一組金鑰,並複製起來。</p><p id="55e4">在家目錄(/home/username)新增 <code>config.yaml</code> 檔,並貼入以下的內容,替換 <random_hex> 為前一個指令所生成的金鑰。</random_hex></p><div id="298d"><pre><span class="hljs-symbol">proxy:</span> <span class="hljs-symbol"> secretToken:</span> <span class="hljs-string">"<RANDOM_HEX>"</span></pre></div><p id="c030">新增 JupyterHub Heml chart 為安裝做準備。</p><div id="be0e"><pre>username<span class="hljs-variable">@cloudshell</span>:~ (jupyterhub-<span class="hljs-keyword">with</span>-k8s)<span class="hljs-variable"> </span>helm repo add jupyterhub <span class="hljs-symbol">https:</span>/<span class="hljs-regexp">/jupyterhub.github.io/helm</span>-chart/</pre></div><div id="b3c8"><pre><span class="hljs-string">"jupyterhub"</span> has <span class="hljs-keyword">been </span><span class="hljs-keyword">added </span>to your repositories</pre></div><div id="2c54"><pre>username<span class="hljs-variable">@cloudshell</span>:~ (jupyterhub-<span class="hljs-keyword">with</span>-k8s)<span class="hljs-variable"> </span>helm repo update</pre></div><div id="91a7"><pre>Hang tight <span class="hljs-keyword">while</span> we grab <span class="hljs-keyword">the</span> latest <span class="hljs-built_in">from</span> your chart repositories... ...Skip <span class="hljs-built_in">local</span> chart repository ...Successfully got <span class="hljs-keyword">an</span> update <span class="hljs-built_in">from</span> <span class="hljs-keyword">the</span> <span class="hljs-string">"jupyterhub"</span> chart repository ...Successfully got <span class="hljs-keyword">an</span> update <span class="hljs-built_in">from</span> <span class="hljs-keyword">the</span> <span class="hljs-string">"stable"</span> chart repository Update Complete.</pre></div><p id="c572">安裝 JupyterHub Heml chart,在執行這個指令前要確定工作目錄中 <code>config.yaml</code> 檔案已創建並儲存。</p><div id="50f8"><pre><span class="hljs-attribute">RELEASE</span>=jhub <span class="hljs-attribute">NAMESPACE</span>=jhub

helm<span class="hljs-built_in"> upgrade </span>--install <span class="hljs-variable">RELEASE</span> jupyterhub/jupyterhub \ --namespace <span class="hljs-variable">NAMESPACE</span>
<span class="hljs-attribute">--version</span>=0.9.0-beta.3
--values config.yaml</pre></div><p id="64c8">安裝過程可以 <code>kubectl get pod --namespace jhub</code> 指令檢視。</p><div id="c881"><pre>username<span class="hljs-variable">@cloudshell</span>:<span class="hljs-operator">~</span> (jupyterhub<span class="hljs-operator">-</span><span class="hljs-keyword">with</span><span class="hljs-operator">-</span>k8s) kubectl <span class="hljs-keyword">get</span> pod <span class="hljs-comment">--namespace jhub</span></pre></div><div id="44ee"><pre><span class="hljs-attribute">NAME</span> READY STATUS RESTARTS AGEhub-<span class="hljs-number">5</span>c67f4798-vnqmd <span class="hljs-number">1</span>/<span class="hljs-number">1</span> Running <span class="hljs-number">0</span> <span class="hljs-number">97</span>sproxy-<span class="hljs-number">5</span>c4b5cb574-mxfrd <span class="hljs-number">1</span>/<span class="hljs-number">1</span> Running <span class="hljs-number">0</span> <span class="hljs-number">97</span>s</pre></div><p id="9280">將自訂的名稱 jhub 輸入為 <code>namespace</code> 參數的預設值。</p><div id="4e99"><pre><span class="hljs-string">username</span>@<span class="hljs-string">cloudshell</span>:~ (<span class="hljs-string">jupyterhub-with-k8s</span>) <span class="hljs-string">kubectl</span> <span class="hljs-string">config</span> <span class="hljs-built_in">set-context</span> (<span class="hljs-string">kubectl</span> <span class="hljs-string">config</span> <span class="hljs-string">current-context</span>) <span class="hljs-built_in">--namespace</span> {<span class="hljs-string">NAMESPACE</span>:-<span class="hljs-string">jhub</span>}</pre></div><div id="5f0b"><pre><span class="hljs-keyword">Context</span> <span class="hljs-string">"gke_jupyterhub-with-k8s_asia-east1-a_jupyterhub"</span> modified.</pre></div><p id="3992">安裝完成後可以 <code>kubectl get service — namespace jhub</code> 指令檢視我們將使用哪個 EXTERNAL-IP 登入 JupyterHub,將 proxy-public 所對應的 EXTERNAL-IP 複製貼上至瀏覽器網址列即可來到 JupyterHub 的登入頁面。此時可以注意到登入頁面有一個警告訊息,JupyterHub with K8s 提示下一步應該要進行 HTTPS 設定,我們將在下個小節進行,如果您也想要跟著操作,要先購買一個網域名稱或在既有的網域中新增一個子網域,並且為它購買一個 SSL 憑證。</p><figure id="cf14"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*qt-nDv3KvgkaJjfAwe8wPw.png"><figcaption>將 proxy-public 所對應的 EXTERNAL-IP 複製貼上至瀏覽器網址列即可來到 JupyterHub 的登入頁面</figcaption></figure><p id="86e3">恭喜完成安裝 JupyterHub,接下來是 HTTPS 設定。</p><h2 id="435a">HTTPS 設定</h2><p id="3831">接著要手動設定 HTTPS 讓使用者安全地傳輸帳號、密碼與資料,首先我們要購買自己的網域(或子網域)以及一個 SSL 憑證,購買 SSL 憑證之後要先前往 Google Cloud Shell 以 <code>openssl req</code>指令生成憑證簽署要求 server.csr 與私有金鑰 server.key。</p><div id="deff"><pre>openssl req -<span class="hljs-keyword">new</span> <span class="hljs-type"></span>-<span class="hljs-keyword">new</span><span class="hljs-type">key</span> rsa:<span class="hljs-type">2048 -nodes -keyout server</span>.key -out server.csr</pre></div><p id="69e9">這時就要將 server.csr 的內容:</p><div id="4f6b"><pre><span class="hljs-params">-----BEGIN</span> CERTIFICATE REQUEST<span class="hljs-params">-----</span> <span class="hljs-string">...</span> <span class="hljs-params">-----END</span> CERTIFICATE REQUEST<span class="hljs-params">-----</span></pre></div><p id="a55e">回傳給 SSL 憑證的供應商,並依照驗證方式操作,以選擇 DNS 驗證為例,還需要新增 CNAME 記錄來讓供應商驗證我的身份,稍待片刻信箱就會收到 SSL 憑證:</p><div id="7ebc"><pre><span class="hljs-params">-----BEGIN</span> CERTIFICATE<span class="hljs-params">-----</span> <span class="hljs-string">...</span> <span class="hljs-params">-----END</span> CERTIFICATE<span class="hljs-params">-----</span></pre></div><p id="875d">接著修改 <code>config.yaml</code> 檔的內容,替換 <RANDOM_HEX> 為先前使用 <code>openssl rand -hex 32</code> 指令所生成的金鑰、替換 <your-domain-name> 為網域(子網域)名、替換 <your-server-key> 為 <code>openssl req</code> 指令所生成的 server.key 以及替換 <your-certificate> 為 SSL 供應商所發的憑證(要特別注意憑證簽署要求 CSR 與憑證 CERT 的差異)。</your-certificate></p><div id="17dc"><pre><span class="hljs-attr">proxy:</span> <span class="hljs-attr">secretToken :</span> <span class="hljs-string">"<RANDOM_HEX>"</span> <span class="hljs-attr">https:</span> <span class="hljs-attr">hosts:</span> <span class="hljs-bullet">-</span> <span class="hljs-string"><your-domain-name></span> <span class="hljs-attr">type:</span> <span class="hljs-string">manual</span> <span class="hljs-attr">manual:</span> <span class="hljs-attr">key:</span> <span class="hljs-string">| -----BEGIN RSA PRIVATE KEY----- <your-server-key> -----END RSA PRIVATE KEY----- </span> <span class="hljs-attr">cert:</span> <span class="hljs-string">| -----BEGIN CERTIFICATE----- <your-certificate> -----END CERTIFICATE-----</span></pre></div><p id="f0e6">更新 <code>config.yaml</code> 檔之後,再執行一次 <code>helm upgrade</code></p><div id="c3e7"><pre><span class="hljs-attribute">RELEASE</span>=jhub <span class="hljs-attribute">NAMESPACE</span>=jhub

helm<span class="hljs-built_in"> upgrade </span>--install <span class="hljs-variable">RELEASE</span> jupyterhub/jupyterhub \ --namespace <span class="hljs-variable">NAMESPACE</span>
<span class="hljs-attribute">--version</span>=0.9.0-beta.3
--values config.yaml</pre></div><p id="cae6">等候片刻,我們就能夠在瀏覽器的網址列以 <a href="https://yourhub.yourdomain.edu/">https://yourhub.yourdomain.edu</a> 來到 JupyterHub with K8s 的登入頁面,也可以注意到登入頁面的警告訊息已經消失了。</p><figure id="4fe0"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*zIYhUiJI0pNIw34EMe-9bQ.png"><figcaption><a href="https://yourhub.yourdomain.edu/">https://yourhub.yourdomain.edu</a> 來到 JupyterHub with K8s 的登入頁面</figcaption></figure><p id="66cf">大功告成,恭喜完成設定 HTTPS,我們在 GCP(Google Cloud Platform) 的 Kubernetes Engine(GKE) 上建置了一個 JupyterHub with K8s!</p><h2 id="a1d5">小結</h2><p id="b168">我們在這篇文章中介紹如何在 GCP(Google Cloud Platform) 的 Kubernetes Engine(GKE) 上建置一個可供數百至數千位課堂學員使用的 JupyterHub with Kubernetes,內容包含建置 Kubernetes、設定 Helm、安裝 JupyterHub 與 HTTPS 設定。</p><h2 id="efab">延伸閱讀</h2><div id="0167" class="link-block"> <a href="https://zero-to-jupyterhub.readthedocs.io/en/latest/index.html"> <div> <div> <h2>Zero to JupyterHub with Kubernetes - Zero to JupyterHub with Kubernetes 0.0.1-set.by.chartpress…</h2> <div><h3>JupyterHub allows users to interact with a computing environment through a webpage. As most devices have access to a…</h3></div> <div><p>zero-to-jupyterhub.readthedocs.io</p></div> </div> <div> <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/)"></div> </div> </div> </a> </div><div id="df82" class="link-block"> <a href="https://kubernetes.io/"> <div> <div> <h2>Production-Grade Container Orchestration</h2> <div><h3>Kubernetes (K8s) is an open-source system for automating deployment, scaling, and management of containerized…</h3></div> <div><p>kubernetes.io</p></div> </div> <div> <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*eZdUsvxa4pcd2Ago)"></div> </div> </div> </a> </div></article></body>

可擴展的 JupyterHub with Kubernetes

如何在 GKE 建置 JupyterHub

Source: https://portworx.com/

A multi-user version of the notebook designed for companies, classrooms and research labs.

Project Jupyter | JupyterHub

TL; DR 摘要

我們在這篇文章中介紹如何在 GCP(Google Cloud Platform) 的 Kubernetes Engine(GKE) 上建置一個可供數百至數千位課堂學員使用的 JupyterHub with Kubernetes,亦被稱為 JupyterHub with K8s。

什麼是 JupyterHub with K8s?

最輕量化的 JupyterHub:The Littlest JupyterHub 一文曾經討論過在選擇用哪種方式建置 JupyterHub 的時候可以自問自答兩個問題:

  1. 是否要使用伺服器叢集?
  2. 是否要使用容器技術?

如果這兩個問題的答案為「是」,那麼我們就可以考慮採用 JupyterHub with Kubernetes!Kubernetes(K8s)是一個提供「跨伺服器叢集的自動部署、可延展以及運行容器化應用程式」的開源系統,K8s 建構於 Google 正式環境運行工作負載的 15 年經驗以及社群開發者的想法和投入,隨著 2015 年 v1.0 版本的發行,Google 遂與 Linux 基金會創辦 Cloud Native Computing Foundation(CNCF)提供 K8s 技術支援和推廣;K8s 的特點有:

  • 強大的擴展度:K8s 基於 Google 每週執行數十億容器的原則進行開發,在擴充延展服務規模的時候不需同時擴充維護運作團隊人數
  • 彈性:K8s 的服務範疇從個人電腦的測試環境到全球型企業的正式環境都能兼顧
  • 便利攜帶:K8s 是開源系統並且可以在任何雲端服務商的主機上建置,包含 Google Cloud(GKE)、Microsoft Azure(AKS)、Amazon Web Services(EKS)、Red Hat OpenShift、IBM Cloud 與 Digital Ocean 等。

接著我們將依循下列步驟建置一個可供數百至數千位課堂學員使用的 JupyterHub with K8s:

  1. 建置 Kubernetes
  2. 設定 Helm
  3. 安裝 JupyterHub
  4. HTTPS 設定

建置 Kubernetes

Kubernetes 將負責雲端伺服器上的資源管理,官方文件 https://kubernetes.io/docs/setup/ 列出數十間支援 Kubernetes 建置的雲端服務供應商,我們選擇(理應是)最簡單的 Google Cloud Platform(GCP)。

首先前往 https://console.cloud.google.com/ 登入。

前往 https://console.cloud.google.com/ 登入

創建一個新的專案。

創建一個新的專案

來到新專案的儀表板之後,點選 Go to APIs overview。

點選 Go to APIs overview

點選 ENABLE APIS AND SERVICES。

點選 ENABLE APIS AND SERVICES

在搜尋文字方框中輸入 Kubernetes Engine API。

在搜尋文字方框中輸入 Kubernetes Engine API

點選 Kubernetes Engine API。

點選 Kubernetes Engine API

啟動 Kubernetes Engine API。

啟動 Kubernetes Engine API

在右上角點選 Activate Cloud Shell。

點選 Activate Cloud Shell

我們將要使用在 Google Cloud Shell 中已經安裝妥當的命令列工具程式 gcloud 來建置 Kubernetes,因此先運用 gcloud --version 確認是否能直接引用。

username@cloudshell:~ (jupyterhub-with-k8s)$ gcloud --version
Google Cloud SDK 278.0.0
alpha 2019.05.17
app-engine-go
app-engine-java 1.9.78
app-engine-php " "
app-engine-python 1.9.88
app-engine-python-extras 1.9.87
beta 2019.05.17
bq 2.0.52
cbt
cloud-build-localcloud-datastore-emulator 2.1.0
cloud_sql_proxycore 2020.01.24
datalab 20190610
docker-credential-gcrgsutil 4.47
kubectl 2019.11.04
pubsub-emulator 2019.09.27

gcloud container clusters create 指令建置 Kubernetes。

gcloud container clusters create --machine-type n1-standard-2 --num-nodes 2 --zone asia-east1-a --cluster-version latest jupyterhub

目前需要自行調整輸入的參數有:

username@cloudshell:~ (jupyterhub-with-k8s)$ gcloud container clusters create --machine-type n1-standard-2 --num-nodes 2 --zone asia-east1-a --cluster-version latest jupyterhub
This will enable the autorepair feature for nodes. Please see https://cloud.google.com/kubernetes-engine/docs/node-auto-repair for more information on node autorepairs.
Creating cluster jupyterhub in asia-east1-a... Cluster is being health-checked (master is healthy)...done.
Created [https://container.googleapis.com/v1/projects/jupyterhub-with-k8s/zones/asia-east1-a/clusters/jupyterhub].To inspect the contents of your cluster, go to: https://console.cloud.google.com/kubernetes/workload_/gcloud/asia-east1-a/jupyterhub?project=jupyterhub-with-k8s
kubeconfig entry generated for jupyterhub.
NAME        LOCATION      MASTER_VERSION  MASTER_IP        MACHINE_TYPE   NODE_VERSION  NUM_NODES  STATUS
jupyterhub  asia-east1-a  1.15.9-gke.8    104.199.133.219  n1-standard-2  1.15.9-gke.8  2          RUNNING

使用 kubectl get node 指令檢查叢集是否已經啟動,先前我們在 num-nodes 參數輸入 2 因此可以在這裡看到兩個狀態為 Ready 的 nodes。

username@cloudshell:~ (jupyterhub-with-k8s)$ kubectl get node
NAME                                        STATUS   ROLES    AGE   VERSIONgke-jupyterhub-default-pool-2a2f588b-c291   Ready    <none>   20m   v1.15.9-gke.8gke-jupyterhub-default-pool-2a2f588b-jml2   Ready    <none>   20m   v1.15.9-gke.8

把帳號調整至最大的管理員權限,替換 為自己的 Gmail 帳號。

username@cloudshell:~ (jupyterhub-with-k8s)$ kubectl create clusterrolebinding cluster-admin-binding \
  --clusterrole=cluster-admin \
  --user=<GOOGLE-EMAIL-ACCOUNT>
clusterrolebinding.rbac.authorization.k8s.io/cluster-admin-binding created

做一個最適化調整,完成建置 Kubernetes。

gcloud beta container node-pools create user-pool \
  --machine-type n1-standard-2 \
  --num-nodes 0 \
  --enable-autoscaling \
  --min-nodes 0 \
  --max-nodes 3 \
  --node-labels hub.jupyter.org/node-purpose=user \
  --node-taints hub.jupyter.org_dedicated=user:NoSchedule \
  --zone <ZONENAME> \
  --cluster <CLUSTERNAME>

替換 為先前創建時所指定的機房區域、替換 為先前創建是所自訂的叢集名稱。

username@cloudshell:~ (jupyterhub-with-k8s)$ gcloud beta container node-pools create user-pool \>   --machine-type n1-standard-2 \>   --num-nodes 0 \>   --enable-autoscaling \>   --min-nodes 0 \>   --max-nodes 3 \>   --node-labels hub.jupyter.org/node-purpose=user \>   --node-taints hub.jupyter.org_dedicated=user:NoSchedule \>   --zone asia-east1-a \>   --cluster jupyterhub
This will enable the autorepair feature for nodes. Please see https://cloud.google.com/kubernetes-engine/docs/node-auto-repair for more information on node autorepairs.Creating node pool user-pool...done.
Created [https://container.googleapis.com/v1beta1/projects/jupyterhub-with-k8s/zones/asia-east1-a/clusters/jupyterhub/nodePools/user-pool].
NAME       MACHINE_TYPE   DISK_SIZE_GB  NODE_VERSIONuser-pool  n1-standard-2  100           1.15.9-gke.8

恭喜完成建置 Kubernetes!接下來是設定 Helm。

設定 Helm

Helm 是 Kubernetes 的套件管理工具,可以協助我們在安裝、升級和管理套件,Helm 之於 K8s 就像是 pip 之於 Python、npm 之於 nodejs 的關係;我們將使用 Helm chart 管理 Kubernetes 設定檔,如此透過編輯 config.yaml 檔案即可完成 JupyterHub 的安裝與部署。

使用 curl 指令下載安裝指令並執行。

curl https://raw.githubusercontent.com/kubernetes/helm/master/scripts/get | bash
使用 curl 指令下載安裝指令並執行

依序輸入下列指令啟動 Helm。

username@cloudshell:~ (jupyterhub-with-k8s)$ kubectl --namespace kube-system create serviceaccount tiller
serviceaccount/tiller created
username@cloudshell:~ (jupyterhub-with-k8s)$ kubectl create clusterrolebinding tiller --clusterrole cluster-admin --serviceaccount=kube-system:tiller
clusterrolebinding.rbac.authorization.k8s.io/tiller created
username@cloudshell:~ (jupyterhub-with-k8s)$ helm init --service-account tiller --wait
Creating /home/username/.helmCreating /home/username/.helm/repositoryCreating /home/username/.helm/repository/cacheCreating /home/username/.helm/repository/localCreating /home/username/.helm/pluginsCreating /home/username/.helm/startersCreating /home/username/.helm/cache/archiveCreating /home/username/.helm/repository/repositories.yaml
Adding stable repo with URL: https://kubernetes-charts.storage.googleapis.comAdding local repo with URL: http://127.0.0.1:8879/charts
$HELM_HOME has been configured at /home/tonykuoyj/.helm.
Tiller (the Helm server-side component) has been installed into your Kubernetes Cluster.
Please note: by default, Tiller is deployed with an insecure 'allow unauthenticated users' policy.To prevent this, run `helm init` with the --tiller-tls-verify flag.For more information on securing your installation see: https://docs.helm.sh/using_helm/#securing-your-helm-installation
username@cloudshell:~ (jupyterhub-with-k8s)$ kubectl patch deployment tiller-deploy --namespace=kube-system --type=json --patch='[{"op": "add", "path": "/spec/template/spec/containers/0/command", "value": ["/tiller", "--listen=localhost:44134"]}]'
deployment.extensions/tiller-deploy patched

helm version 指令檢視 Helm 是否設定妥當。

username@cloudshell:~ (jupyterhub-with-k8s)$ helm version
Client: &version.Version{SemVer:"v2.16.1", GitCommit:"bbdfe5e7803a12bbdf97e94cd847859890cf4050", GitTreeState:"clean"}Server: &version.Version{SemVer:"v2.16.1", GitCommit:"bbdfe5e7803a12bbdf97e94cd847859890cf4050", GitTreeState:"clean"}

恭喜完成設定 Helm!接下來是安裝 JupyterHub。

安裝 JupyterHub

Helm chart 是一組 Helm 模板讓管理員能夠以 yaml 檔對 Kubernetes 叢集進行套件的安裝、升級與管理。

在終端機以 openssl rand -hex 32 指令生成一組金鑰,並複製起來。

在家目錄(/home/username)新增 config.yaml 檔,並貼入以下的內容,替換 為前一個指令所生成的金鑰。

proxy:
  secretToken: "<RANDOM_HEX>"

新增 JupyterHub Heml chart 為安裝做準備。

username@cloudshell:~ (jupyterhub-with-k8s)$ helm repo add jupyterhub https://jupyterhub.github.io/helm-chart/
"jupyterhub" has been added to your repositories
username@cloudshell:~ (jupyterhub-with-k8s)$ helm repo update
Hang tight while we grab the latest from your chart repositories...
...Skip local chart repository
...Successfully got an update from the "jupyterhub" chart repository
...Successfully got an update from the "stable" chart repository
Update Complete.

安裝 JupyterHub Heml chart,在執行這個指令前要確定工作目錄中 config.yaml 檔案已創建並儲存。

RELEASE=jhub
NAMESPACE=jhub

helm upgrade --install $RELEASE jupyterhub/jupyterhub \
  --namespace $NAMESPACE  \
  --version=0.9.0-beta.3 \
  --values config.yaml

安裝過程可以 kubectl get pod --namespace jhub 指令檢視。

username@cloudshell:~ (jupyterhub-with-k8s)$ kubectl get pod --namespace jhub
NAME                     READY   STATUS    RESTARTS   AGEhub-5c67f4798-vnqmd      1/1     Running   0          97sproxy-5c4b5cb574-mxfrd   1/1     Running   0          97s

將自訂的名稱 jhub 輸入為 namespace 參數的預設值。

username@cloudshell:~ (jupyterhub-with-k8s)$ kubectl config set-context $(kubectl config current-context) --namespace ${NAMESPACE:-jhub}
Context "gke_jupyterhub-with-k8s_asia-east1-a_jupyterhub" modified.

安裝完成後可以 kubectl get service — namespace jhub 指令檢視我們將使用哪個 EXTERNAL-IP 登入 JupyterHub,將 proxy-public 所對應的 EXTERNAL-IP 複製貼上至瀏覽器網址列即可來到 JupyterHub 的登入頁面。此時可以注意到登入頁面有一個警告訊息,JupyterHub with K8s 提示下一步應該要進行 HTTPS 設定,我們將在下個小節進行,如果您也想要跟著操作,要先購買一個網域名稱或在既有的網域中新增一個子網域,並且為它購買一個 SSL 憑證。

將 proxy-public 所對應的 EXTERNAL-IP 複製貼上至瀏覽器網址列即可來到 JupyterHub 的登入頁面

恭喜完成安裝 JupyterHub,接下來是 HTTPS 設定。

HTTPS 設定

接著要手動設定 HTTPS 讓使用者安全地傳輸帳號、密碼與資料,首先我們要購買自己的網域(或子網域)以及一個 SSL 憑證,購買 SSL 憑證之後要先前往 Google Cloud Shell 以 openssl req指令生成憑證簽署要求 server.csr 與私有金鑰 server.key。

openssl req -new -newkey rsa:2048 -nodes -keyout server.key -out server.csr

這時就要將 server.csr 的內容:

-----BEGIN CERTIFICATE REQUEST-----
...
-----END CERTIFICATE REQUEST-----

回傳給 SSL 憑證的供應商,並依照驗證方式操作,以選擇 DNS 驗證為例,還需要新增 CNAME 記錄來讓供應商驗證我的身份,稍待片刻信箱就會收到 SSL 憑證:

-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----

接著修改 config.yaml 檔的內容,替換 <RANDOM_HEX> 為先前使用 openssl rand -hex 32 指令所生成的金鑰、替換 <your-domain-name> 為網域(子網域)名、替換 <your-server-key> 為 openssl req 指令所生成的 server.key 以及替換 為 SSL 供應商所發的憑證(要特別注意憑證簽署要求 CSR 與憑證 CERT 的差異)。

proxy:
  secretToken : "<RANDOM_HEX>"
  https:
    hosts:
      - <your-domain-name>
    type: manual
    manual:
      key: |
        -----BEGIN RSA PRIVATE KEY-----
        <your-server-key>
        -----END RSA PRIVATE KEY-----
      cert: |
        -----BEGIN CERTIFICATE-----
        <your-certificate>
        -----END CERTIFICATE-----

更新 config.yaml 檔之後,再執行一次 helm upgrade

RELEASE=jhub
NAMESPACE=jhub

helm upgrade --install $RELEASE jupyterhub/jupyterhub \
  --namespace $NAMESPACE  \
  --version=0.9.0-beta.3 \
  --values config.yaml

等候片刻,我們就能夠在瀏覽器的網址列以 https://yourhub.yourdomain.edu 來到 JupyterHub with K8s 的登入頁面,也可以注意到登入頁面的警告訊息已經消失了。

https://yourhub.yourdomain.edu 來到 JupyterHub with K8s 的登入頁面

大功告成,恭喜完成設定 HTTPS,我們在 GCP(Google Cloud Platform) 的 Kubernetes Engine(GKE) 上建置了一個 JupyterHub with K8s!

小結

我們在這篇文章中介紹如何在 GCP(Google Cloud Platform) 的 Kubernetes Engine(GKE) 上建置一個可供數百至數千位課堂學員使用的 JupyterHub with Kubernetes,內容包含建置 Kubernetes、設定 Helm、安裝 JupyterHub 與 HTTPS 設定。

延伸閱讀

Jupyterhub
Kubernetes
K8s
Recommended from ReadMedium