用 snap 跑 Folding@Home

環境:Ubuntu 18.04

這是看到 分享:處理 COVID19 之軟體專案數則 ,裏面提到 Folding@Home 可以幫忙運算與武漢病毒相關資訊,所以想裝起來幫忙。官方網站有提供 Linux / Windows / MacOS 的軟體,基本上裝起來就可以了。T客邦有篇介紹文章:

我不想裝 Debian package,想用 snap 來安裝,網路上有好心人打包好了。

安裝步驟很簡單,因為 Ubuntu 18.04 已經預先裝了 snap,接著只要用 snap 來安裝就可以:

sudo snap install folding-at-home-fcole90 --edge # 安裝
snap connect folding-at-home-fcole90:hardware-observe # 允許檢查硬體 (這是為了檢查 GPU 用,可以用 GPU 輔助運算)
snap services folding-at-home-fcole90.FAHClient # 檢查服務是否運行。

安裝好以後,在選單可以找到 FAHControl,執行它。第一步是先設定,按下工具列的 Configure,在 Identity 填入名字,以及 Team number。名字可以自己取,Team number 的話,請填 31403 ,這是台灣隊的編號,說明可以參考這篇 Folding@Home Taiwan Team。設定好之後,按下 “Fold” ,就會開始下載資料並進行運算了。以我的電腦配備,一個回合大約要兩小時。我有看到可以用 GPU 加速,我就依照這篇 How to Check Which GPU Is Installed on Linux 查了一下,看我的電腦有沒有支援 GPU,看了以後,我覺得應該是有,但 FAHControl 卻說沒有 (切到 System log 可以看到),查了半天都沒查出原因,後來才在 fah-snap 的 issues 看到這條 FAHClient cannot detect OpenCL correctly 。嗯,那看來只能等作者解決了,或者,裝 Debian package 試試看囉。

讓 docker daemon可以給別台電腦存取

docker 官方並不建議使用這方法,但還是有文件:Configure where the docker daemon listens for connections

不建議的原因很簡單,安全性。docker daemon 是用 root 權限在執行,而 docker 又沒有這方面的安全機制去處理帳號驗證,自然不建議這樣使用。 目前的主流是使用 kubernetes,另外,docker 最新的版本是有提出 docker context,利用 context 可以管理多種連接方式,其中一種連線方式是走 ssh ,會比較安全。

目前我只是想方便的操作虛擬機,所以可以不需要太考慮安全性問題。

編輯 systemd unit:sudo systemctl edit docker.service,把下面幾行貼進去

[Service] 
ExecStart= 
ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2375 

讓 systemd 重新載入設定: sudo systemctl daemon-reload

重啟動: sudo systemctl restart docker

檢查: sudo netstat -lntp | grep dockerd

在別台電腦上,先設置環境變數:export DOCKER_HOST=tcp://your_docker_host:2375 , 然後用 docker 指令就可以存取該台 docker 主機了。

用 redoc 來顯示OpenAPI規格文件

之前有找過怎樣輸出 OpenAPI 規格為文件,有試過 swagger-codegen 先轉成 HTML 再轉 PDF,但其實效果不好,也一直沒找到滿意的。

今天再來找一次,找到 redoc,依照 github 網站上的說明來作,用 redoc 提供的 docker image 就可以跑起 API 文件的 Live 網站,效果挺好的。

docker run -p 8081:80 --rm -v $(pwd)/api.yml:/usr/share/nginx/html/api.yml -e SPEC_URL=api.yml redocly/redoc

網站上還有提到一個 redoc-cli,說明說可以 bundle 成一個靜態HTML文件。有 homebrew ,就想說 homebrew 會不會有這個 formula,找了以後,發現是沒有,只好認命的用 npm 來裝

npm install npx npm install redoc-cli 

裝 npx 是為了可以方便的呼叫 node module 裡的指令來用,這部份的使用說明可以參考這篇:Introducing npx: an npm package runner 。 裝好以後,就可以使用了:

npx redoc-cli bundle api.yml 

輸出的檔案固定是 redoc-static.html,用瀏覽器開啟就可以了。

筆記:Queries, Part 1: Common SQL Queries Converted for Firebase

依照 Queries, Part 1: Common SQL Queries Converted for Firebase 來練習

  • By ID ,路徑指定好就可以了 firebase.database().ref(‘/messages/’ + messageID).once(‘value’, function(snap) { … });
  • WHERE, 除了路徑之外,還要指定 orderByKey() 或 orderByChild(),然後再用 startAt/endAt
    • orderByKey 是依照 key 的值:firebase.database().ref(‘/messages’).orderByKey().startAt(‘user001’).endAt(‘user010’).once(‘value’, function(snap) { … });
    • orderByChild 是依照子節點的值:firebase.database().ref(‘/messages’).orderByChild(’email’).startAt(‘user001@example.com’).endAt(‘user010@example.com’).once(‘value’, function(snap) {…});
    • 用 orderByChild 時,要在規則裡加上 .indexOn ,否則會有警告,警告的大意是說加indexOn 後,效能會比較好。
  • LIMIT,加 limitToFirst(10) 或 limitToLast(10)
    • 可以跟前面提到的 startAt / endAt 結合:firebase.database().ref(‘/messages’).orderByChild(’email’).startAt(‘user001@example.com‘).endAt(‘user010@example.com‘).limitToFirst(10).once(‘value’, function(snap) {…});
    • limitToLast 就是指定後面幾筆

筆記:firebase functions – realtime database

閱讀的文件:https://firebase.google.com/docs/functions/database-events

可以寫這些事件的處理常式

  • onWrite() 資料被建立、更新或刪除時,會觸發
  • onCreate() 資料被建立時,會觸發
  • onUpdate() 資料被更新時,會觸發
  • onDelete() 資料被刪除時,會觸發

可以只針對指定的路徑,對,也因為事件資料同時包含舊的跟新的,資料量有限制,資料量大的時候要針對個別路徑拆開來寫處理常式。

可以用參數,例如 ref(‘foo/{bar}’)  ,那麼存取 foo/hello 或 foo/firebase 時,都會觸發常式對 foo/ 寫入,像下面

{
  "foo": {
    "hello": "world",
    "firebase": "functions"
  }
}

會觸發兩次常式,一次是 foo/hello ,一次是 foo/firebase從 EventContext.params 可以用 bar 這個 key 去拿到 hello 或 firebase
範例

 
// 當有訊息加到 /messages/:pushId/original 時,執行這常式。 
// 這常式會把指定路徑下的值,轉為大寫,再放到 /messages/:pushId/uppercase 
exports.makeUppercase = functions.database.ref('/messages/{pushId}/original') 
    .onCreate((snapshot, context) => {  // snapshot 是 DataSnapshot ,context 是 EventContext 
      // 先取得寫入的值 
      const original = snapshot.val(); 
      console.log('Uppercasing', context.params.pushId, original); 
      const uppercase = original.toUpperCase(); 
      // 把資料寫到 "uppercase" sibling 然後回傳 Promise 
      // snapshot.ref.parent -> /messages/:pushId 
      // snapshot.ref.parent.child('uppercase') -> /messages/:pushId/uppercase 
      return snapshot.ref.parent.child('uppercase').set(uppercase); 
    }); 

用 EventContext 的 auth / authType 就可以取得 authentication 資訊 (這邊我有點迷糊了,為啥 authType 可以是 ADMIN / USER ??

onWrite 的時候,是用 change, context change 是 Change,提供了 before/after property 可以存取寫之前/之後的值 。

筆記:以適合的 HTML 屬性增強輸入 2FA 的體驗

來源:HTML attributes to improve your users’ two factor authentication experience

TL;DR

  1. type 維持在 text
  2. inputmode 改為 numeric,這樣可以在手機平台上出現數字鍵盤,而不是完整的鍵盤
  3. pattern 設為 [0-9]* ,可以確保輸入的文字是數字
  4. autocomplete 設為 one-time-code ,是可以確定自動完成的部份是「一次性的密碼」,之前以為只有 “off” ,其他可以用的數值可以參考這篇
<input
  type="text"
  name="token"
  id="token"
  inputmode="numeric"
  pattern="[0-9]*"
  autocomplete="one-time-code"
/>

筆記:Best practics for firebase realtime database development

文章出處:Best practics for firebase realtime database development

以下只是摘要,詳細內容還是請看原文。

  • 好好的讀 SDK 文件。
  • 不太需要定 schema,不表示不需要用腦,要有效率的使用,仍然需要好好的規劃。
  • 支援管道要選好
    • Slack: 社群導向的自助討論,不適合回報問題。
    • Support Form: 主要的官方支援,The “official” support venue. Report “something is down” here. Feature requests likely to get a canned “we’ll consider it, but no promises” response.
    • Google Groups: 主要是成員討論,Active involvement by the core team with the usual caveats about turnaround time in group-oriented mail systems. Best place for highly technical discussions about app internals and “weird” issues.
    • StackOverflow: 疑難雜症,Slow/unpredictable response times but best place for backup reference material. If you’ve read a Q&A on StackOverflow, you know the type of question that’s best to post there, too.
  • 該用兩個 reference 就用,不要想說用他們共通的父節點來存取,這樣沒有比較省。If you need to reference an object from two different places, take two refs to it.
  • 不要用 array
  • 沒有日期,請用 timestamp
  • 請知道 firebase realtime database 能做什麼,不要用他來做他不適合做的事情。
  • set 跟 update 不一樣,主要差異是在於 key 存在與否的處理。
  • firebaseui 很好用。

Firebase functions 裡用 Admin SDK 時,怎麼去把設定跟程式切開?

一般來說,照文件來做,會要放兩個設定,第一個是 Service account credential,第二個是 Firebase config。

但其實在部署 functions 上去以後,這些設定都已經在執行環境裡了,所以不需要特別去放這些設定。而且,把這些設定放到程式裡,那程式會上到 git repository 啊,這樣設定就都曝光了。那不想把這些設定放到程式裡,本地端又要開發時該怎麼辦呢?我是找到這篇:Firebase: Separating configuration from code in Admin SDK

第一個,Service account credential 在下載以後,假設放到 /credentials/your_service_account.json,那麼在執行前,把這檔案路徑指定到 GOOGLE_APPLICATION_CREDENTIALS 這環境變數就可以,例如:

export GOOGLE_APPLICATION_CREDENTIALS=/credentials/your_servcice_account.json

第二個是 Firebase config,從 firebase console 取得以後,假設放到 /config/your_project_config.json ,裡面內容大致是

{
apiKey: "your_api_key",
authDomain: "your_project.firebaseapp.com",
databaseURL: "https://your_project.firebaseio.com",
projectId: "your_project-abcdef",
storageBucket: "your_project.appspot.com",
messagingSenderId: "00000000",
appId: "1:00000000:web:000000000",
measurementId: "G-11111111"
};

接著一樣去設定環境變數 FIREBASE_CONFIG

export FIREBASE_CONFIG=/config/your_project_config.json

然後就可以使用 firebase serve 去模擬啦。

筆記:Lessons learnt (the hard way) using Firebase RealTime Database

主要是看這篇 Lessons learnt (the hard way) using Firebase RealTime Database 所摘要下來的重點。

TL;DR:作者用了 realtime database,然後意外收到 1000 EUR 的帳單。

作者做的是交通運輸類的 app ,realtime database 存的是使用者的最愛站牌、路線等。主要用了 Firebase 的這兩項功能:

  • Firebase authentication
  • Realtime database

使用人數約 400K+ ,主要就是 updated / authenticated 等等的。這樣帳單約 1000 EUR
他們檢討以後,發現有幾個關鍵點:

  1. keepSync ,這個不要設成 true,firebase SDK的行為沒有預期中聰明,他會在每次使用者開啟app時就下載一次!
    1. database.getReference(getUserFavoritesPath(getCurrentUid())).keepSynced(true)
  2. key 的名稱不要太長,只要這個弄短,無形中可以省掉非常多。

接著針對這兩個點,做了處理

  1. 最佳化存在資料庫的資料,改用 GSON ,以及縮短 key 的長度。
  2. 關掉 keepSync
  3. 在 app 端實作了 memory cache ,以避免無謂的去 firebase 撈資料。

作者學到的事情:

  1. 人數很多時,realtime database 可能會是很花錢的項目,特別是結構跟讀取資料邏輯沒有最佳化的時候。
  2. 要將存在雲端上的資料最小化,使用較短長度的 key ,可以幫你省掉不少錢。
  3. Firebase persistence 啟用時,firebase 只會在沒網路的時候使用本地的 cache,其他的狀況他不管資料有沒有改都會存取雲端。
  4. 不要用 keepSync(true) 
  5. 實作本地端的 cache ,以避免重複跟 firebase 索取資料。

用 go 的 docker image 來建置 go 專案

指令蠻簡單的,而且可以指定用 go 的哪個版本來進行建置。

# 先切到你的專案目錄下
cd "$WORKSPACE"

# 執行 docker run
docker run --rm -e GOBIN=/usr/src/myapp -v "$PWD":/usr/src/myapp -w /usr/src/myapp golang:1.6 bash -c make
  • –rm 表示執行完就把 container 刪掉
  • -e GOBIN=/usr/src/myapp 是設定環境變數,GOBIN 這環境變數是指編譯好的執行檔所放的位置
  • -v “$PWD”:/usr/src/myapp 表示把當前的目錄掛載到 container 裡的 /usr/src/app
  • -w /usr/src/myapp 表示把工作目錄指定到 /usr/src/myapp
  • golang:1.6 這是表示要使用 golang 1.6 這版,其他版本可以參考 dockerhub
  • bash -c make 是指用 bash 來執行 make,要用 bash 的原因是大部份 Makefile 都是假設用 bash,用其他 shell 會很容易踩到雷。

dockerhub 上有更多說明。