甲方和乙方的數(shù)據(jù)科學(xué)家都要用各種界面化工具來做數(shù)據(jù)科學(xué)家的工作,所以,我們從zeppelin搞到了jupyterlab,再從lab整到了hub。
創(chuàng)新互聯(lián)長期為超過千家客戶提供的網(wǎng)站建設(shè)服務(wù),團隊從業(yè)經(jīng)驗10年,關(guān)注不同地域、不同群體,并針對不同對象提供差異化的產(chǎn)品和服務(wù);打造開放共贏平臺,與合作伙伴共同營造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為南州晴隆企業(yè)提供專業(yè)的做網(wǎng)站、成都網(wǎng)站制作,南州晴隆網(wǎng)站改版等技術(shù)服務(wù)。擁有10余年豐富建站經(jīng)驗和眾多成功案例,為您定制開發(fā)。
對于甲方數(shù)據(jù)科學(xué)家的編程水平,實在是無法恭維卻還要硬著頭皮恭維。這輩子能看到把python寫成pig的機會不多。數(shù)據(jù)科學(xué)家的腦回路那是相當?shù)腜igLatinic的。這個,寫過pig的人應(yīng)該能明白。
不過,我只想記錄一下工作過程,以后其他甲方要用的時候,我自己能用得上。
環(huán)境 Anaconda3 + Jupyterhub + Spark2.1 + CDH 5.14 + Kerberos
一、Hub與Spark的集成
anaconda怎么裝jupyterhub和生成配置文件就不說了,網(wǎng)上一大堆。
鑒于數(shù)據(jù)科學(xué)家只會用python,所以基于toree的各種其他語言解釋器就先不記錄了。只有spark的話,還是挺簡單的。我是創(chuàng)建了一個文件
/usr/share/jupyter/kernels/pyspark2/kernel.json 路徑不存在的話就自己創(chuàng)建一個,文件不存在的話就自己vi一個。內(nèi)容如下
{
??????"argv":?[
????????"python3.6",
????????"-m",
????????"ipykernel_launcher",
????????"-f",
????????"{connection_file}"
??????],
??????"display_name":?"Python3.6+PySpark2.1",
??????"language":?"python",
??????"env":?{
????????"PYSPARK_PYTHON":?"/opt/anaconda3/bin/python",
????????"SPARK_HOME":?"/opt/spark-2.1.3-bin-hadoop2.6",
????????"HADOOP_CONF_DIR":?"/etc/hadoop/conf",
????????"HADOOP_CLIENT_OPTS":?"-Xmx2147483648?-XX:MaxPermSize=512M?-Djava.net.preferIPv4Stack=true",
????????"PYTHONPATH":?"/opt/spark-2.1.3-bin-hadoop2.6/python/lib/py4j-0.10.7-src.zip:/opt/spark-2.1.3-bin-hadoop2.6/python/",
????????"PYTHONSTARTUP":?"/opt/spark-2.1.3-bin-hadoop2.6/python/pyspark/shell.py",
????????"PYSPARK_SUBMIT_ARGS":?"?--master?yarn?--deploy-mode?client?--name?JuPysparkHub測試?pyspark-shell"
??????}
}然后就沒有然后了。
二、Jupyterhub + 無LDAP的獨立Kerberos集成
由于集群是獨立的Kerberos體系,并沒有與系統(tǒng)的PAM和LDAP結(jié)合起來,所以,這里需要修改Jupyter代碼。
如果集群是KRB5與LDAP結(jié)合的系統(tǒng),可以忽略改代碼,Jupyterhub本身官方就有LDAP認證的插件。
基于我對Jupyterhub源碼的理解,Hub本身啟動時是啟動了一個多用戶認證的外殼程序,這個外殼程序會基于對每個用戶的認證,使用該用戶的linux賬號去啟動notebook。

這是我閱讀Hub源碼總結(jié)的架構(gòu)流程,不一定準確,大概是個意思吧。NB就是NoteBook,不是牛逼的意思。
所以Hub其實最終啟動Notebook啟動的是一個新的jupyter-notebook的進程,而且是以登錄用戶的環(huán)境變量啟動的。那么就有兩種思路來初始化kerberos principal。
思路一:
????使用系統(tǒng)用戶的環(huán)境變量來做kinit,好處是kinit寫在用戶的.bash_profile或.bashrc文件里,只要調(diào)用這個用戶的環(huán)境變量就可以直接kinit,無需修改任何代碼。壞處是,要是kinit過期了,就得重新打開notebook,存在可能會導(dǎo)致編輯內(nèi)容丟失的風(fēng)險。
思路二:
????修改hub相關(guān)代碼,將kinit做到nb里面去,這樣就無所謂系統(tǒng)環(huán)境變量,尤其hub有個自動保存的機制,前端會定期發(fā)送保存筆記的請求給后端api,如果找到api就可以完成這個功能,這樣kinit就是定期刷新的,只要開著nb,kerberos的ticket就永不過期。
????考慮到甲方數(shù)據(jù)科學(xué)家是一群除了會寫pyspparksql而其他方面是毫無自理能力和學(xué)習(xí)能力的唐氏綜合征,我決定采用第二種方案。給唐爸爸省事,也是給自己省事,一勞永逸。
那么根據(jù)hub的流程架構(gòu)和思路二,我只需要修改notebook本身的kinit認證即可。不過為了保險,我把hub的登錄驗證外殼也一起改了。
由于hub和nb系列都是tornado寫的,改起來倒也容易。
首先是要寫一段簡單粗暴的python代碼來做kinit驗證。
????def?kinit(self,?username):
????????"""
????????add?by?xianglei
????????"""
????????import?os
????????from?subprocess?import?Popen,?PIPE
????????uid_args?=?['id',?'-u',?username]
????????uid?=?Popen(uid_args,?stdin=PIPE,?stdout=PIPE,?stderr=PIPE)
????????uid?=?uid.communicate()[0].decode().strip()
????????gid_args?=?['id',?'-g',?username]
????????gid?=?Popen(gid_args,?stdin=PIPE,?stdout=PIPE,?stderr=PIPE)
????????gid?=?gid.communicate()[0].decode().strip()
????????self.log.info('UID:?'?+?uid?+?'?GID:?'?+?gid)
????????self.log.info('Authenticating:?'?+?username)
????????realm?=?'XX.COM'
????????kinit?=?'/usr/bin/kinit'
????????krb5cc?=?'/tmp/krb5cc_%s'?%?(uid,)
????????keytab?=?'/home/%s/%s.wb1.keytab'?%?(username,?username)
????????principal?=?'%s/pg-dmp-workbench2@%s'?%?(username,?realm,)
????????kinit_args?=?['kinit',?'-kt',?keytab,?'-c',?krb5cc,?principal]
????????self.log.info('Running:?'?+?'?'.join(kinit_args))
????????kinit?=?Popen(kinit_args,?stdin=PIPE,?stdout=PIPE,?stderr=PIPE)
????????self.log.info(kinit.communicate())
????????ans?=?None
????????import?os
????????if?os.path.isfile(krb5cc):
????????????os.chmod(krb5cc,?0o600)
????????????os.chown(krb5cc,?int(uid),?int(gid))
????????????ans?=?username
????????return?ans都是直接調(diào)用操作系統(tǒng)命令,可以說是相當粗暴了。
然后找到 jupyterhub源碼包里面的 auth.py,不要問我源碼在哪里,如果找不到python第三方module的安裝位置,那么跟數(shù)據(jù)科學(xué)家有什么區(qū)別。
找到 authenticate方法,改成下面。
????@run_on_executor
????def?authenticate(self,?handler,?data):
????????"""Authenticate?with?PAM,?and?return?the?username?if?login?is?successful.
????????Return?None?otherwise.
????????"""
????????username?=?data['username']
????????try:
????????????pamela.authenticate(username,?data['password'],?service=self.service,?encoding=self.encoding)
????????????username?=?self.kinit(username)
????????except?pamela.PAMError?as?e:
????????????if?handler?is?not?None:
????????????????self.log.warning("PAM?Authentication?failed?(%s@%s):?%s",?username,?handler.request.remote_ip,?e)
????????????else:
????????????????self.log.warning("PAM?Authentication?failed:?%s",?e)
????????else:
????????????if?not?self.check_account:
????????????????return?username
????????????try:
????????????????pamela.check_account(username,?service=self.service,?encoding=self.encoding)
????????????????username?=?self.kinit(username)
????????????except?pamela.PAMError?as?e:
????????????????if?handler?is?not?None:
????????????????????self.log.warning("PAM?Account?Check?failed?(%s@%s):?%s",?username,?handler.request.remote_ip,?e)
????????????????else:
????????????????????self.log.warning("PAM?Account?Check?failed:?%s",?e)
????????????else:
????????????????return?username這樣 hub 在登錄的時候就可以先做一次kinit認證,其實沒什么用。但當我面對比集群機器還多的唐氏患者時,我還是需要一些心理安慰的。
然后找到 notebook 的 notebook/handler.py 文件,修改如下。
class?NotebookHandler(IPythonHandler):
????@web.authenticated
????def?get(self,?path):
????????"""get?renders?the?notebook?template?if?a?name?is?given,?or
????????redirects?to?the?'/files/'?handler?if?the?name?is?not?given."""
????????path?=?path.strip('/')
????????cm?=?self.contents_manager
????????#?will?raise?404?on?not?found
????????try:
????????????model?=?cm.get(path,?content=False)
????????except?web.HTTPError?as?e:
????????????if?e.status_code?==?404?and?'files'?in?path.split('/'):
????????????????#?404,?but?'/files/'?in?URL,?let?FilesRedirect?take?care?of?it
????????????????return?FilesRedirectHandler.redirect_to_files(self,?path)
????????????else:
????????????????raise
????????if?model['type']?!=?'notebook':
????????????#?not?a?notebook,?redirect?to?files
????????????return?FilesRedirectHandler.redirect_to_files(self,?path)
????????name?=?path.rsplit('/',?1)[-1]
????????username?=?self.current_user['name']
????????self.kinit(username)
????????self.write(self.render_template('notebook.html',
????????????notebook_path=path,
????????????notebook_name=name,
????????????kill_kernel=False,
????????????mathjax_url=self.mathjax_url,
????????????mathjax_config=self.mathjax_config,
????????????get_custom_frontend_exporters=get_custom_frontend_exporters
????????????)
????????)以上代碼的作用是在打開notebook的時候就做kinit認證。
然后打開 notebook的 service/contents/handlers.py
????@gen.coroutine
????def?_save(self,?model,?path):
????????"""Save?an?existing?file."""
????????chunk?=?model.get("chunk",?None)
????????if?not?chunk?or?chunk?==?-1:??#?Avoid?tedious?log?information
????????????self.log.info(u"Saving?file?at?%s",?path)
????????????if?'name'?in?self.current_user:
????????????????if?isinstance(self.current_user['name'],?str):
????????????????????self.kinit(self.current_user['name'])
????????????????????#pass
????????model?=?yield?gen.maybe_future(self.contents_manager.save(model,?path))
????????validate_model(model,?expect_content=False)
????????self._finish_model(model)以上代碼的作用是在notebook做自動或手動保存時就觸發(fā)kinit認證。
各種保險措施做足,國際臉的唐氏患者們表示生活很幸福快樂,露出了久違的微笑。
三、hub與nginx反代集成多域名和SSL。
我作為一個正常人是永遠猜不透唐氏患者內(nèi)心在想什么,他們永遠有辦法讓乙方永無休止的干活,或許這樣他們就能打著系統(tǒng)升級的旗號不干活了。所以,IP不能訪問嗎?為啥非要弄個域名呢?
而且我們的集群環(huán)境是分為業(yè)務(wù)***和管理***的,兩個***綁定的域名是不一樣的,然后都需要SSL連接。
這里有點麻煩的是,Jupyter是禁止跨域訪問的。SSL加上反代其實配置不難,難的是跨域訪問,其實跨域訪問也不難,難的是如何殺死這些數(shù)據(jù)科學(xué)家。
upstream?hub10000?{
????????server?172.16.191.110:10000;
????}
server?{
????????listen???????30000;
????????server_name?????mgmthub.xxx.cn?buhub.xxx.cn;
????????ssl?on;
????????ssl_certificate_key?cert/xxx.cn.key;
????????ssl_certificate?cert/xxx.cn.crt;
????????ssl_ciphers?ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-RC4-SHA:!ECDHE-RSA-RC4-SHA:ECDH-ECDSA-RC4-SHA:ECDH-RSA-RC4-SHA:ECDHE-RSA-AES256-SHA:!RC4-SHA:HIGH:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!CBC:!EDH:!kEDH:!PSK:!SRP:!kECDH;
????????ssl_protocols?TLSv1?TLSv1.1?TLSv1.2;
????????ssl_session_cache?shared:SSL:10m;
????????ssl_prefer_server_ciphers?on;
????????ssl_session_timeout?1d;
????????ssl_stapling?on;
????????ssl_stapling_verify?on;
????????add_header?Strict-Transport-Security?"max-age=31536000;?includeSubdomains;";
????????add_header?X-Frame-Options?SAMEORIGIN;
????????add_header?X-Content-Type-Options?nosniff;
????????add_header?X-XSS-Protection?"1;?mode=block";
????????add_header?Content-Security-Policy?"default-src?'self';style-src?'self'?'unsafe-inline';script-src?'self'?'unsafe-inline'?'unsafe-eval';font-src?'self'?data:;connect-src?'self'?wss:;img-src?'self'?data:;";
????????location?/?{
??????????proxy_pass?http://hub10000;
??????????proxy_http_version?1.1;
??????????proxy_set_header?Upgrade?$http_upgrade;
??????????proxy_set_header?Connection?"upgrade";
??????????proxy_set_header?Origin?"";
??????????include?proxy.conf;
????????}
????}proxy.conf
proxy_redirect??????????off; proxy_set_header????????Host?$host; proxy_set_header????????X-Real-IP?$remote_addr; proxy_set_header????????X-Forwarded-For???$proxy_add_x_forwarded_for; proxy_set_header????????X-Nginx-Proxy?true; proxy_connect_timeout???604800; proxy_send_timeout??????604800; proxy_read_timeout??????604800; proxy_buffer_size???????64k; proxy_buffers???????????64?32k; proxy_busy_buffers_size?128k; proxy_temp_file_write_size?64k; proxy_next_upstream?error?timeout?invalid_header?http_500?http_503?http_404; proxy_max_temp_file_size?128m; client_body_temp_path?client_body?1?2; proxy_temp_path?proxy_temp?1?2;
110:10000是jupyterhub監(jiān)聽地址,是另一臺機器。
然后加上??
proxy_set_header?Origin?"";
就可以解決tornado的跨域訪問問題,無需修改jupyterhub的配置里的 bind_url設(shè)置。
對文中提到唐氏患者致歉,雖然我知道用唐氏患者類比甲方數(shù)據(jù)科學(xué)家是對唐氏患者的不尊重,但才疏學(xué)淺,確實找不到合適的詞匯來比喻甲方數(shù)據(jù)科學(xué)家。我本身并不歧視唐氏患者,我歧視的是數(shù)據(jù)科學(xué)家。
網(wǎng)頁標題:Jupyterhub亂七八糟記錄
本文鏈接:http://www.yijiale78.com/article42/pehdhc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供面包屑導(dǎo)航、做網(wǎng)站、建站公司、網(wǎng)站維護、網(wǎng)頁設(shè)計公司、營銷型網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)