雖然code-server已經(jīng)能夠滿足很多需求, 比如用來寫C/C++, Java, Tex等, 但是, 當遇到需要做數(shù)據(jù)分析的時候, 在code-server上運行Python和R就不是那么方便. 而當下非常流行的Python發(fā)行包Anaconda中自帶了Jupyter Notebook, 是一種集科學計算和撰寫文本為一體的"IDE".
當然, Anaconda的優(yōu)點不止于此, 它預置了許多常用的科學計算包, 比如NumPy, pandas, 同時對R語言也有非常好的支持, 這些特性對用于學習的數(shù)據(jù)分析已經(jīng)完全足夠了.
PS: 若是嫌Anaconda太大的話, 可以選擇Miniconda, 只自帶了python和conda, 別的軟件包可以通過pip或者conda進行安裝.
Jupyter Notebook也是基于web的服務, 所以除了部署之外只要簡單地做一下反代和注冊service就好了.
本文主要介紹在Ubuntu Server 18.04下全局安裝Jupyter Notebook,并且通過反向代理的方式實現(xiàn)多個用戶賬戶通過不同的地址來訪問自己的Jupyter Notebook
Step1: 安裝Anaconda
去Anaconda的官網(wǎng)或鏡像上下載對應系統(tǒng),位數(shù)和Python版本的安裝文件, 我選用的是TUNA鏡像站. 由于在服務器上有多個用戶需要使用, 所以安裝時提了權限: sudo sh Anaconda3-5.3.1-Linux-x86_64.sh.
接下來Anaconda會讓你看一段特別長的License, 想不想看都行, 用Enter翻到最后時, 會問是否同意, 哪有不同意的份, 輸yes就完事了.
接下來Anaconda會詢問安裝位置, 默認是在用戶目錄下: ~/anaconda3, 但由于要多用戶, 我選擇安裝在/usr/local/anaconda3下. 然后就是不太漫長的等待, 最后還會問是否需要將環(huán)境變量加入.bashrc, 選不選都可以, 不選的話之后在終端輸入/path2anaconda/bin/conda init, 會與之前選添加環(huán)境變量有著相同的效果(因為既沒添加環(huán)境, 也沒自動添加PATH, 所以直接輸入conda大概率會報command not found的錯誤).
最后還有個VScode的廣告, 介于我們這個服務器甚至沒有裝x-server, 就沒裝了.
如果選了添加環(huán)境, .bashrc的末尾會多出來一段東西, 大概像這樣:
# added by Anaconda3 5.3.1 installer
# >>> conda init >>>
# !! Contents within this block are managed by 'conda init' !!
__conda_setup="$(CONDA_REPORT_ERRORS=false '/usr/local/anaconda3/bin/conda' shell.bash hook 2> /dev/null)"
if [ $? -eq 0 ]; then
\eval "$__conda_setup"
else
if [ -f "/usr/local/anaconda3/etc/profile.d/conda.sh" ]; then
. "/usr/local/anaconda3/etc/profile.d/conda.sh"
CONDA_CHANGEPS1=false conda activate base
else
\export PATH="/usr/local/anaconda3/bin:$PATH"
fi
fi
unset __conda_setup
# <<< conda init <<<
由于我用的是zsh, 所以這些東西寫在.bashrc里面自然起不了效果, 需要提出來用. 雖然一堆判斷看上去復雜, 但是它們于我何與也? 全都復制出來, 把里面的bash改成zsh, 再放在一個新的腳本文件里面, 就大功告成了. 最后這個文件除了把bash換成了zsh, 跟上面這段完全一致.
我把它起名為conda_activate.sh, 需要激活環(huán)境的時候輸入source conda_activate.sh就行了, 退出終端重進環(huán)境就失效了.
Step2: 配置Jupyter Notebook
安裝好之后, 理論上只要在激活環(huán)境的情況下輸入jupyter notebook就可以啟動了, 像這樣:

但是, 可以看到, 此時Notebook運行在8888端口, 訪問需要通過token, 而token是隨每次啟動會變化的, 很不方便, 所以需要創(chuàng)建一個配置文件進行修改.
首先, 要生成一個配置文件: jupyter notebook --generate-config, 生成的配置文件在~/.jupyter/jupyter_notebook_config.py.
然后, 開始修改一些參數(shù):
- 在48行(左右)可以找到
c.NotebookApp.allow_origin, 將其前面的#(也就是注釋符)去掉, 并改其值為'*'. (反代若沒掛在根目錄下就需要) - 在93行(左右)可以找到
c.NotebookApp.base_url, 取消注釋, 并改其值為'/path/'. (這個path就是反代掛載的路徑) - 在139行(左右)可以找到
c.NotebookApp.custom_display_url, 取消注釋, 并改其值為'/path/'. (就是與上面那個保持一致) - 在204行(左右)可以找到
c.NotebookApp.ip, 取消注釋, 并改其值為'*'. (意思是任何ip都可以訪問Notebook) - 在252行(左右)可以找到
c.NotebookApp.open_browser, 取消注釋, 并改其值為False. - 在287行(左右)可以找到
c.NotebookApp.port, 取消注釋, 并改其值為22333. (就是指定Notebook的端口)
保存后, 再啟動jupyter notebook, 在瀏覽器里把除了token之外的地址輸進去(大概像http://localhost:22333), 會發(fā)現(xiàn)提示輸入token后進入. 在頁面的下面還有設定密碼的地方, 只要把token和新的密碼輸進去就行了. (若現(xiàn)在無法訪問也可以選擇在配置完反代后再設置)
或者, 還有一種方法也可以設置密碼: 執(zhí)行
jupyter notebook password, 輸完兩遍密碼后會生成一個json文件, 保存在~/.jupyter/jupyter_notebook_config.json, 找到那個以sha1開頭的字符串, 并將其拷貝到~/.jupyter/jupyter_notebook_config.py的276行(左右)的c.NotebookApp.password的值處, 并在前面加上u, 大概就像:
c.NotebookApp.password = u'sha1:7dc5d4f1796f:b04e59cf83a50fedf24fb2691f1bf1ebd5218484'
哈希值別抄成上面那個就行了, 如果寫成上面那個, 那你的密碼就會變成1111.
Step3: Nginx配置反代
要修改配置文件/etc/nginx/nginx.conf.
首先還是SSL. 遠程訪問的話安全還是很重要的.
http {
#前面的東西省略
ssl on
ssl_certificate /path/to/crt/chain.crt
ssl_certificate_key /path/to/key/key.key
#后面的也省略
}
然后是反代服務器:
http {
#前面的東西省略
#SSL的東西也省略
#中間可能還有東西, 繼續(xù)省略
server {
listen 8080; #這個是客戶端訪問反代服務器時的端口
listen [::]:8080; #這個應該也是, 但是是IPv6的配置
server_name myjupyter.com itsjupyter.com;
#填訪問時用的域名, 可填多個, 空格分隔
location /somepath/ {
#可能有的別的反代, 省略
}
location /path/ {
proxy_pass http://localhost:22333/;
#這是反代訪問Notebook的地址,
#所以端口也是填Notebook的端口
proxy_http_version 1.1;
#等會細講
proxy_redirect http:// https://;
#把外部的https轉成內(nèi)部的http
proxy_set_header Host $host:443/path;
#這里端口填外部訪問的端口
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection upgrade;
proxy_set_header Accept-Encoding gzip;
#最后三行說不清楚, 照抄就完事了
}
#可能存在的第二個第三個location模塊, 反正和上面那個差不多
}
}
等會現(xiàn)在細講: proxy_http_version 1.1顯然意思是指定http版本為1.1, 但是為什么呢? 你自己試試不就知道了如果不加的話, 在Notebook中將無法連接到內(nèi)核, 一直會顯示disconnected.
Step4: 注冊為service
創(chuàng)建一個以service為后綴的文件, 比如jupyter-notebook.service. 里面這么填:
[Unit]
Description=Jupyter Notebook NO.1
After=network.target
[Service]
Type=simple
User=username
EnvironmentFile=/home/username/.jupyter_env
WorkingDirectory=/home/username/
Restart=on-failure
RestartSec=10
ExecStart=/usr/local/anaconda3/bin/jupyter notebook
StandardOutput=file:/path2output/output.log
StandardError=file:/path2error/error.log
[Install]
WantedBy=multi-user.target
這個和寫code-server的那個幾乎一模一樣, 只有環(huán)境文件, 啟動命令和log文件的位置不一樣.
在.jupyter_env這個環(huán)境文件中, 把conda_activate.sh里面的東西再拷過來, 順便在它的前面加上其余的PATH變量.
把這個文件丟到/etc/systemd/system/下, 并執(zhí)行systemctl start jupyter-notebook.service, 將start換成enable以使其開機自啟.
如果前面沒有配置密碼的話, 現(xiàn)在可以在把service啟動之后, 去StandardOutput所在的地方, 找到token, 然后再做前面的操作以設置密碼.
Step5: 維護Anaconda環(huán)境
要更新conda中的包就用conda update --all, 安裝是conda install <package>, 卸載是conda remove --all. 如果裝的是Anaconda, 估計主要用的還是更新, 畢竟Anaconda里面常用的大多都在里面.
如果嫌更新慢的話, 可以在用戶目錄新建一個.condarc, 也可以在安裝目錄下(比如/usr/local/anaconda3/)新建這個文件, 要是用戶目錄和安裝目錄下都有, 則會優(yōu)先讀取用戶目錄下的文件.
新建好之后, 在里面寫上:
channels:
- defaults
show_channel_urls: true
channel_alias: https://mirrors.tuna.tsinghua.edu.cn/anaconda
default_channels:
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/r
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/pro
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/msys2
custom_channels:
conda-forge: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
msys2: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
bioconda: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
menpo: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
pytorch: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
simpleitk: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
這是清華的鏡像, 速度蠻快的, 也可以自行換成別的鏡像.
如果是全局安裝的話, conda install等指令可能會報錯, 大概率是權限不夠的錯誤, 但是conda又會告訴你, 不建議提權執(zhí)行conda, 所以需要一些操作.
簡單粗暴的方法是直接從安裝目錄開始, 改權限為777: chmod 777 -R /usr/local/anaconda3. 雖然確實好使, 但是總覺得不是太好. 于是有了下一種方法.
- 創(chuàng)建用戶組anaconda:
groupadd anaconda. - 把Anaconda的安裝目錄改為用戶組anaconda所有:
chgrp -R anaconda /usr/local/anaconda3. - 修改安裝目錄的權限:
chmod 770 -R /usr/local/anaconda3. - 把自己也加入用戶組anaconda:
usermod -a -G username anaconda.
雖然也是修改了文件夾權限, 但是比粗暴的777大概還是好那么一點點吧.
BTW, 上述兩種方法大概率需要sudo. 啊? 有沒有不提權的方法? 又要全局又不提權, 那不可能
附錄: 雜談以及可能的常見報錯(問題)的解決方法
- 除了conda有鏡像, pip也有, 搜索
PyPI鏡像, 一搜一大把, 清華的也有. 如果真的出現(xiàn)了鏡像也不好使的pip包, 可以先用pip安裝:pip install <package>, 會出現(xiàn)一個下載鏈接, 拷出來, 再用有代理的設備下下來, 然后丟回去, 執(zhí)行本地安裝:pip install <package>.whl. 但是需要注意的是, 這樣操作的話絕不能改文件的名字, 否則安裝會報錯. - 在conda中安裝
r-essentials便可以在Notebook中調用R內(nèi)核, 安裝Kotlin內(nèi)核(conda install kotlin-jupyter-kernel或者pip install kotlin-jupyter-kernel)就可以調用Kotlin內(nèi)核這難道不是廢話, 但是不同于r-essentials, kotlin的Notebook內(nèi)核只能在Jupyter Notebook中被調用, 和真正的Kotlin編譯器是分開的, 要想編譯運行kt文件, 可以用snap install --classic kotlin kotlin-native, 或者直接從Github的Release Kotlin 1.3.61上下載二進制包(截至2020.2.13的最新版本).u1s1我還沒見過真有人用kotlin干數(shù)據(jù)科學的活 -
chmod 777 (-R) <path>或者chmod +x (-R) <path>整日從各種地方抄下來, 但是它具體代表了什么意思呢?-R表示遞歸操作, 也就是對這個目錄下的子目錄/子文件都執(zhí)行這個命令. 那個三位數(shù)的三位分別表示了文件(夾)擁有者, 與擁有者同用戶組的其他用戶, 其余用戶的操作權限. 0-7有2^3種可能, 就是4(讀取), 2(寫入), 1(執(zhí)行)的組合, 或者說是把一個三位二進制數(shù)轉換成了0-7的十進制數(shù).+x表示所有用戶增加執(zhí)行權限, 把x換成r,w, 加號換成減號, 都有著類似的意思. 有興趣的話可以參閱chmod --help.
Q: Anaconda全局安裝之后用conda安裝/卸載/更新包出現(xiàn)權限問題?
A: 把Anaconda的目錄改成由用戶組anaconda所有, 自己也進用戶組, 最后組內(nèi)用戶權限7, 或者安裝目錄直接777.
Q: conda/pip下載極慢?
A: 用鏡像, TUNA上什么鏡像都有, 或者pip玩家可以把下載鏈接竊來直接下.
Q: 反代之后在Notebook里面連不上內(nèi)核?
A: 指定http版本為1.1, Nginx里面就是proxy_http_version 1.1;.
Q: 反代后創(chuàng)建筆記本/別的操作失敗? 后臺報Blocking Cross Origin API request?
A: 在jupyter_notebook_config.py中找到c.NotebookApp.allow_origin(48行左右), 取消注釋并將值改為'*'.
Q: 無法訪問Notebook, 后臺報non localhost?
A: 在jupyter_notebook_config.py中找到c.NotebookApp.ip(204行左右), 取消注釋并將值改為'*'.
Q: 無法訪問Notebook, 訪問到別的東西? 或者沒訪問到啥, 并且后臺一點反應都沒?
A: 可能端口被占用了, Jupyter的端口會嘗試自動+1, 試試看+1的端口.
Q: R用戶用Anaconda, Python版本選啥好?
A: 其實無所謂, 可以買新不買舊選個Python3.
Q: Jupyter Notebook都可以遠程訪問, 那我R用戶最喜歡的RStudio能不能也遠程訪問?
A: GUI界面遠程訪問, 可以考慮遠程X Server(Xming/VcXsrv)/VNC/或者別的奇技淫巧, 否則, 那不可能.
Q: Jupyter Notebook還有啥好使的內(nèi)核?
A: 官方維護的有IPython, IJulia, IRkernel, 還有不少社區(qū)支持的內(nèi)核, 可以參見Jupyter kernels. 甚至能看到Wolfram Language和MATLAB/Octave的內(nèi)核(其實這三個都只是轉接頭, 白嫖Mathematica和MATLAB是幾乎8可能的).
Q: 我遇到的問題在搜索引擎上搜不到想要的結果/發(fā)在論壇上沒有想看到的回復?
A: 建議大家讀讀How To Ask Questions The Smart Way, 由巨佬Eric S. Raymond編寫, 讀了8成會有收獲.
注: 所有的操作在Ubuntu Server 18.04下實測有效, 一些文件的位置和命令可能隨環(huán)境的不同而失效.