2017 CS50 problem set 總回顧 + GCP 上建置 Cloud9 及 Jupyter Notebook

陳雁智 (Marat Y. C. Chen)
Manjeaneer
Published in
15 min readNov 13, 2017

系列最後一篇了,首先謝謝你願意進來閱讀,一系列回顧僅希望能夠在作業以外也輕輕推一把卡住的朋友們,無論 2017 或未來 2018 的 cs50 過程中有所助益,以下提供綱要讓第一次閱讀的朋友能快速找到感興趣的內容:

1. pset 2 crack, 使用 crypt 時會回傳相同指標可能導致邏輯正確但結果錯誤,不清楚指標或程式碼給出預期外結果的朋友可以參考

2. pset 2+3 crack, binary search, crack 使用遞迴方式的 pseudo code 及使用遞迴實作 binary search 未將回傳值做為參數時,即使搜尋成功後回到 base case 後最終結果可能是失敗

3. pset 4 resize, 作業細節澄清;使用二維陣列時需要將陣列大小一起帶入函式; recover 實作與 check50 驗證使用的檔案並不相同,需要考慮一般情況的寫法

4. pset 5 speller 跟著演算法、圖與程式碼追蹤 tries 加入單字時的圖解說明

5. pset 6 sentiment Python 主程式中, Flask 跟 Jinja 間的關係,request 解讀與 jinja 中 safe 使用與否的結果

6. pset 7 cs50 finance 使用 html 在 index 實作交易範例與 SQLAlchemy 使用注意要點

7. pset 8 mashup 聚焦 script.js 的分析、JavaScript 跟 C, python 在變數呼叫與範圍差異比較

心得己經夠多就不廢話,接下來分享 cs50.io 不給力時,可以參考以下步驟在 GCP 自置 Cloud9,跟 Python 寫作者很愛的 JupyterNotebook ,以下先以 macos 作範例,windows 之後補上

tl;dr

  1. 啟用 Google Cloud Platform 帳號,建立一個 VM instance,並使用 Startup script 預先執行套件安裝
  2. 加入兩個防火牆規則分別給 Cloud9 及 Jupyter Notebook
  3. 安裝 Cloud9 並使用 openssl 產生 key 及 crt 後設定為 HTTPS 連線
  4. 安裝 Anaconda 並使用 openssl 再產生 pem 後設定為 HTTPS 連線

Cloud9

1. 首先申請一個 Google 帳號,並到 Google Cloud Platform 申請免費試用,2017 年仍有 12 個月 300 USD 的額度,參考 Jerry 的教學文 申請

2. 開啟一個 Compute Engine Instance ,以 cs50 的需求,開最小的資源 f1-micro 除了安裝較久外,效能其實夠用,有高運算需求可以選擇更大的資源,區域(zone)建議選擇臺灣機房 (asia-east1) ,享受低延遲高頻寬

Project Page of Google Cloud Platform
Navigate to create an instance
Zone: asia-east1-a (Taiwan), Instance type: f1-micro

這邊以 Debian (stretch) 為例,若選擇 Ubuntu 系列 (補充: Ubuntu 安裝較快) 或其它 Linux 發行版也沒問題,主要差別是之後套件管理可能是 apt-get 或 yum ,建議 http/http 防火牆可以先打開供之後連線使用

Debian (apt-get) and add HTTP/HTTPS traffic

4. Compute Engine 可以讓 instance 啟動後自動執行套件安裝,點開 Management, disks, networks, SSH Key,將以下的 script 貼到 Management 裡 Automation 的 Startup script 內

#!/bin/bash
apt-get update -y
apt-get -y install git
apt-get -y install build-essential
curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
apt-get -y install nodejs
apt-get -y install openssl
apt-get -y install wget
Startup script

若發行版的套件管理工具為 yum,置換 apt-get 為 yum, apt-get -y install build-essential 置換為 yum groupinstall 'Development Tools' 即可,主要目的為安裝 gcc 與 make 供 cloud9 安裝用

4. 使用 ssh key 的方式連到 GCP compute engine,開啟 macos terminal (application)移到 .ssh 目錄 cd ~/.ssh或自建新目錄放 ssh key ,再來產生 ssh key ssh-keygen -t rsa ,順手輸入一組 passpharse 保護一下,執行 ssh-add key_name (這裡命名為 gcp_ide) 將 key 加入授權 (authentication agent)

Generate a ssh key pair

再回到 Create an instance 介面點到 SSH Keys

Copy and paste the public key to SSH Keys

確認以下三點後,按下 Create 創造我們需要的 instance

  • HTTP/HTTPS traffic 是否已勾選
  • SSH Keys 己貼上
  • Automation script 己貼上
Compute Engine Instance startup

instance 啟動等候 5–10 分鐘,差不多就完成套件更新,可以看到 CPU 飆高後降下來,再來以 ssh 連到 instance,先在 VM instance 頁面找到剛啟動 instance 的外部 ip (external IP)

external IP of a VM instance

再來 ssh xx.xx.xx.xx (external IP) 就可進到該 VM instnace 的 shell

Commandl line of the launched VM instance

5. ssh 進入 shell 後再來參考阿良良的日常筆記教學將 cloud9 設置起來,安裝過程大概五分鐘

git clone git://github.com/c9/core.git c9sdk
sh c9sdk/scripts/install-sdk.sh # This takes about 5 minutes
cloud9 installation compelted

6. 完成後執行 node ~/c9sdk/server.js --listen 0.0.0.0 -p 9999 -a username:password listen 參數設為 0.0.0.0 允許所有 ip 連線,若有固定 ip 也可以只監聽來自己 ip 的連線, p 參數為監聽埠口,這裡以 9999 為例,-a 參數則是 username:password 的方式要求連線後鍵入登入帳密

Cloud9 IDE server launched successfully

再來就按熟悉的方式打開瀏覽器 (safari, chrome, firefox, and etc.) 鍵入 http://instance_ip:9999/後連線

7. 噹噹~ 連不到,意料之中,在使用雲端服務常常會忘了開防火牆

Connection timed out in Firefox due to the blockage of firewalls

8. 若防火牆還沒打開,到 VPC — firewall rules將需要用到的 port 9999 開起來用,設定好 network tag 後再到 VM instance 內加入,需要使用 jupyter notebook 的朋友可以多建一個規則 (jupyternotebook, port9998) 稍後使用

Create a fire wall rule for tcp 9999 to allow cloud9 connection
Add the created tag in the launched VM instance

9. 設定好後再試一下,嘩啦~ 熟悉的 cloud9 IDE 就出現了

IP:port (xx.xx.xx.xx:9999) in browser
Cloud9 Standalone version

10. 不過這裡使用 HTTP 連線,基於安全顧慮,最好將它改成 HTTPS 連線,這裡參考 digitocean openssl 產生自用的 SSL certificate (openssl 在 Startup script 裡己預先安裝),cloud9 的設定一樣參考阿良良的教學,不熟悉 vim 用法可以參考 c9s 的 vim 投影片或 youtube影片


## 產生自用的 key 跟 crt
openssl req -newkey rsa:2048 -nodes -keyout ~/.ssh/gcp-ide.key -x509 -days 365 -out ~/.ssh/gcp-ide.crt
## 使用 vim 編輯 `c9sdk/config/standalon.js` 內 `packagePath: “connect-architect/connect` 的物件
vim ~/c9sdk/configs/standalone.js
## 將 config.secure 以 // 註解掉,加入
{
key: require("fs").readFileSync('/path/to/gcp-ide.key'),
cert: require("fs").readFileSync('/path/to/gcp-ide.crt')
}
## /path/to 置換為存放 key 及 crt 的位置,以 ls /path/to/key.pem 確認
Generate key for Cloud9 HTTPS connection

11. 加入設定後,按步驟 6 再啟動 cloud9 IDE 一次 (node ~/c9sdk/server.js --listen 0.0.0.0 -p 9999 -a username:password),在瀏覽器網址列前的 http 置換為 https (https://xx.xx.xx.xx:9999/) 登入後即可,由於 openssl 產生的 crt 未經過外部驗證,沒有在瀏覽器信任名單之中,可能會跑出以下警示,將加入例外,再重新連線一次即可

Warning due to self-generated certificates not trusted by the browser
Log in Cloud9

Jupyter Notebook

  1. 按以下方式在 shell 下載 Anaconda 執行安裝程式,成功跑起來看到很多 installing 噴起來後可以去刷個牙跟 FB,蠻多套件需要安裝,大概 5–10 分鐘左右完成
wget https://repo.continuum.io/archive/Anaconda3-5.0.1-Linux-x86_64.sh
bash Anaconda3-5.0.1-Linux-x86_64.sh -b -p $HOME/Anaconda3 && export PATH="$HOME/Anaconda3/bin:$PATH"

2. 在 bashrc 中將 Anaconda 加入 PATH,方便每次登入都能直接使用

echo 'export PATH="$HOME/Anaconda3/bin:$PATH"' >> ~/.bashrc

4. 安裝 cloud9 時若還沒為 Jupyter Notebook 建立防火牆規則,一樣到 VPC -> firewall rules 裡加一個規則, port 除了系統預設像是 22, 80, 443 等避免使用外,可以自定喜歡的數字,以 tcp:9998 為例,再將該 tag 附到已經建立的 VM instance (gcp-ide)

VPC — Firewall rules — CREATE FIREWALL RULES (tag: jupyternotebook)

5. 接著參考官方文件 來建立 https 的連線

## 先產生 jupyter notebook 的 config 檔 
jupyter-notebook --generate-config
## 使用在 cloud9 己經建立的 key 跟 crt 產生一組 pem
openssl x509 -in ~/.ssh/gcp-ide.crt -out ~/.ssh/gcp-ide.pem -outform PEM

7. 建議設定 JupyterNotebook 的密碼以免被來路不明怪客誤用,更新 ~/.jupyter/jupyter_notebook_config.py 裡面的以下設定

# 產生一組 Jupyter Notebook 的登入密碼
jupyter notebook password
# 一樣用 vim 來編輯
vim ~/.jupyter/jupyter_notebook_config.py
# Set options for certfile, ip, password, and toggle off
# browser auto-opening
c.NotebookApp.open_browser = Falsec.NotebookApp.certfile = u'/absolute/path/to/your/certificate/mycert.pem'
c.NotebookApp.keyfile = u'/absolute/path/to/your/certificate/mykey.key'
# Set ip to '*' to bind on all interfaces (ips) for the public server
c.NotebookApp.ip = '*'
# It is a good idea to set a known, fixed port for server access
c.NotebookApp.port = 9998
Configuration update in ~/.jupyter/jupyter_notebook_config.py

9. 再來一樣 https 連到接著 port 9998 就嘩啦~ (第一次還是會碰到警告頁面,一樣加入例外即可),再來迎接 jupiter notebook 的頁面,輸入之前建立的密碼後開始使用自己的 Jupyter Notebook

Jupyter Notebook login page

第一次建立中間可能會碰到一些錯誤,可以確認是否為以下問題:

  1. VPC — Firewalls rules 有沒有增加對應的 tcp port ,並將 network tag 加到了執行程式的 instance 上,使用的 tag 名稱是否正確 (希望 GCP 可以加上自動提示)
  2. Startup script 是否於 instance 啟動前附上並執行完成 (檢查 CPU 使用率)
  3. SSL key/crt/pem 檔的位置是否正確並使用絕對路徑 home/user/.ssh/your_key.key
  4. shell 內的程式執行後,瀏覽器端網址前面改為 https 如 https://IP:port 的格式連線

雖然 AWS 仍是主流,小眾市場還是值得一點關照,GCP 在 UI 設計上還不錯,所有的 VM instances 都在同一個頁面上這點很方便,但 tag 不能自動 prompt 這點有點不人性,不正確的 tag 也不提示這點也很麻煩,以上結束了 2017 cs50 回顧,任意建議都歡迎留言提出

後記

AWS 已於 2016 年購入 Cloud9, 並在 2017 年將 Cloud9 做為一個 AWS 服務推出,申請好 AWS 帳號後開啟 Cloud9 服務並按照指示設定完成,就可以有自己的 Cloud9 IDE 了,目前還沒有提供給所有 region 使用,離臺灣最近的是新加坡,實際使用起來其實速度可接受,另外也能設定閒置一定時間後自動將 host Cloud9 IDE 的機器關起來節省費用這點蠻貼心的

--

--

陳雁智 (Marat Y. C. Chen)
Manjeaneer

project manager/savvy programmer/marathon runner/critical reader