續談 OpsWorks + Docker 管理架構

Cookbooks 的規劃

對應 OpsWorks 的任務分支,分為以下幾個 cookbooks:

  • common
  • setup
  • configure
  • deploy
  • shutdown
  • service-pack

不要有類似 OpsWorks 的 nginxrails 這類獨樹一格的「專用」、「特用」cookbook,依以上基於動詞的 cookbook 來做事。

比如如果遇到要設定 nginx 某個獨特的項目,就是 setup::nginx_do_somethingconfigure::nginx_do_something,而不要自己搞一個 nginx::do_something

這樣做的好處就是管理起來簡單,一眼望過去知道這個 recipe「要做什麼事、對象是誰」,寫 recipe 時有明確分類可以遵循。

其中有幾點要注意:

  • common cookbook 是用在「支援、配合任一其他類 cookbook」的地方,而不是「萬用類」。開發初期如果不曉得某任務應該歸在哪類,可「暫時」放在這裡,一旦確定放在某特定類比較適當後,則應立即 refactoring 改放到該特定類。
  • service-pack cookbook 適合用在「單次任務」如元件安全更新、強制不使用 cache 重建 Docker images 的地方。
  • 因為 Docker 的特性,基本上不需要 undeploy 類的任務,退版其實就是切回到某個舊版本的 Docker image 開 container 出來而已。所以不規劃 undeploy cookbook。

Docker 的部署設計

理想上,應該是把 docker image 從 registry pull 回來後立即 docker run 就能動起來。

實務上,我們有些地方還是需要仰賴 stack, layers, nodes 的設定資訊,所以還是免不了要使用 Chef 的 template 命令幫我們生成設定檔與 Dockerfile,最後再疊加上一層,生成新的 image 後予以部署。

部署時特別要注意,像是 Rails 應用會產生 logs、Unicorn 也會產生 logs,這些 logs 是營運績效、問題診斷的重要資訊 ,我會盡可能在 container 內把這些 logs 放在同一個目錄下,再用 volume 對應到 host 某一目錄底下保存。這樣可以直接從 host 取得 logs,不用進到 container 內,方便很多,也利於 logrotate, fluentd 之類的工具操作這些 logs。

目前想到的是這些,以後若有想到再寫…。

NHK World Premium 從台灣大寬頻類比頻道中消失

今天凌晨,位在 CH95 的 NHK World Premium 突然斷訊,有幾秒的時間被調到 CH94,旋又消失,接著 CH95 換載 MTV 綜合台。

求證有裝數位有線電視機上盒的岳家,NHK World Premium 還在數位頻道裡。

親眼見證這段歷程,很有感觸,我在當下還抱著希望,以為像之前一樣只是被賣藥台排擠而換了頻道。重新掃描頻道掃了兩、三次,再按著遙控器一台接一台尋找,覺得這很像是國中時新買的自行車失竊,我茫然地在附近兜圈那樣。

我知道類比頻道頻率範圍有限、數位頻道(理論上)無限的道理,但是今天台灣大寬頻可以這樣獨斷決定一個類比頻道的去留,我相信同樣的事情,很有可能也會在數位頻道裡發生。

於是我(終於)決定去裝衛星碟。

真假 DevOps

今天談到一個話題:「不熟 OP 的 developer 如果缺少 OP 相關知識,那怎麼做好 DevOps?」

我覺得這是個假議題。

今天就是因為 developer 都認為 OP 會負責 deploy 到好、負責出來坦,所以開發時毫不考慮 OP 負荷,logs 也不看不管,這才是真正導致 DevOps 做不起來的原因,也就是我一直批評的「假 DevOps 之名,行傳統 OP 之實」。

而 developer 真的需要很強的 OP/sysadmin 知識嗎?不用,真的不用,developer 缺的是很強的 DRY 意識。

如果能時時設想「我做的這個東西,能不能在 10 分鐘內整套自動 setup run 起來?」那 developer 自然會去想「程式能不能通過測試?」、「設定、部署能不能簡單輕鬆?」這才是以 developer 這一側要實行 DevOps 該有的思維。

我親愛的網站案件客戶,您好

我自大學開始學習如何製作「帶有語意的網頁」、「樣式與本體分開處理的網頁」,早在 SEO(搜尋引擎最佳化)這個詞出現之前,便已瞭解「一個讓搜尋引擎覺得『好』的網頁,其結構應該是如何如何」的眉眉角角。

從碩士班開始,又學到 IA(資訊架構學),深知內容如何妥善編排,導覽動線該如何設計。

製作「帶有語意的網頁」、「樣式與本體分開處理的網頁」是讓機器(搜尋引擎、瀏覽器)高興。

妥善編排內容,設計良好的導覽動線,則是讓高興。

能夠兼顧「機器」與「人」的 Web 設計師在這市場上真的不多,許多從業者照本宣科跟著「專家」做 SEO,還不如我們這類圖資系出身的、一直被以為只能在圖書館櫃台處理借還書的人,動手調整一下網站架構,結果立即大不同。

您的網站,因為我的勸阻,沒花錢去買當初您不知聽了哪位「專家」說的關鍵字廣告,但是在搜尋引擎排名還是名列前茅,實不相瞞,就是我提供給您如上述的專業服務,正如貴寶號也提供專業服務給客戶那般。

您在意「效果」、「設計」、「美學」,是的,這些的確很重要,但並非一個網站的全部。當我向您表達我擅長的 Semantic Web, Information Architecture 如何幫助貴寶號的時候,希望請您不要認為那些不重要,而不當一回事,執意要做您認為「視覺效果好才是硬道理、壓倒一切」的網站,因為若忽略這些要素,您的網站只能吸睛,但不會好用,搜尋引擎也不愛來爬資料。

無論之後我們還是不是可以繼續合作,我衷心感謝您看完我這篇苦口婆心、肺腑之言,謝謝!

架設 Docker Registry v2

我的架設方式與官方文件不太一樣,所以踩了不少雷。

官方文件傾向把 nginx 與 docker-registry 都用 Docker container 的方式連接 (link) 部署,而我的方式與層次是:

  1. AWS ELB
  2. Nginx on EC2 Host OS
  3. Dockerized  docker-registry (registry:2)

因為我想要閃掉 SSL/TLS 的設定,還有惱人的 private key passphrase,所以讓現成已經掛好了憑證的 ELB 充當 SSL/TLS termination proxy。在 ELB 後面的 nginx 與 docker-registry 就不用煩惱憑證的設定問題。

Nginx 主要是負責提供 HTTP basic access authentication,在 docker-registry 前提供一層帳密安全關卡,由於我個人實在是很討厭使用 link,所以把它放在 host 裡。設定檔大致如下:

server {
  listen 8080;
  server_name docker.registry.in.my.com;
  client_max_body_size 0;
  chunked_transfer_encoding on;

  access_log    /var/log/nginx/docker-registry-access.log;
  error_log     /var/log/nginx/docker-registry-error.log;

  location / {
    # Do not allow connections from docker 1.5 and earlier
    # docker pre-1.6.0 did not properly set the user agent on ping, catch "Go *" user agents
    if ($http_user_agent ~ "^(docker\/1\.(3|4|5(?!\.[0-9]-dev))|Go ).*\$" ) {
      return 404;
    }

    # To add basic authentication to v2 use auth_basic setting plus add_header
    auth_basic "registry.localhost";
    auth_basic_user_file /etc/nginx/conf.d/registry.password;
    add_header Docker-Distribution-Api-Version  registry/2.0    always;

    proxy_pass                          http://127.0.0.1:5000;
    proxy_set_header  Host              $http_host;
    proxy_set_header  X-Real-IP         $remote_addr;
    proxy_set_header  X-Forwarded-For   $proxy_add_x_forwarded_for;
    proxy_set_header  X-Forwarded-Proto https;
    proxy_set_header  X-Original-URI    $request_uri;
    proxy_set_header  Docker-Distribution-Api-Version   registry/2.0;
    proxy_read_timeout                  900;
  }
}

過程中我遇到的幾個大地雷有:

  • Ubuntu 14.04 內的 nginx 版本太舊,不支援 add_header 的 always 指令,導致不會送出該識別 header,所以 docker login 會判斷這個 docker-registry 為 Invalid registry endpoint,解決方法就是要從 nginx 官網裝新版(至少 1.7.5 以上,這顆地雷是從 [Running Secured Docker Registry 2.0 – Container Solutions] 這篇看到提示才解掉的)。
  • 由於 nginx <-> docker-registry 之間通訊是走 http://,所以在 push image 的時候,一開始從 remote 下 PUT 指令還是 https://,但是接著 docker-registry 會根據 X-Forwarded-Proto 的值送出 Location: http://xxx HTTP header 請 client 轉址,導致接下來的 PUT 操作失敗,解決方法就是要把 X-Forwarded-Proto 強制指定為 https

幾個經驗:

  • 善用 curl -v 給的資訊來判斷,不要瞎猜。
  • V2 目前還是很多坑,使得你不得不去看 source code,但是還好小的我還學過一點 Go

OpsWorks + Docker 管理架構

今(昨?)天在公司跟同仁分享的經驗,簡單筆記一下:

  • Elastic Beanstalk 自訂的彈性與便利性,都比不上 OpsWorks。
  • 公司在 Web 的主要使用語言是 Ruby:
    • OpsWorks = AWS + Chef
    • Chef 是用 Ruby 來管理 infrastructure
    • 所以相對來說,入門門檻相對較低
    • 理想上,應該可以跟 Vagrant 用同一套 Chef Cookbook(s),達成跨方案快速部署開發與營運環境
  • OpsWorks 每個 Stack 內只允許有一個 Rails App layer
    • 如果覺得在 custom layer 照抄 AWS 的 Rails App layer 套用的 recipes,就可以解決這個限制,你就會踩雷踩到想哭。
    • 如果為了要使用內建的 Rails App layer 而拆分到不同 stacks,又顯得太蠢,且無法佔到「放在同一個 stack 時可共用很多管理資料」的便宜。
  • 目前(我)已知最好的方法,就是架 Docker
    • 利用 Docker 的隔間特性,以 KTV 包廂為例,理想上 (container) A 房間開趴,不會影響到 (container) B 房間,更不會影響到大廳 (host)。
    • 所以我們甚至可以一台 EC2 instance 裡部署 A 應用,如果資源有餘裕,就可以堆 B 應用、C 應用、D 應用…而不互相打架,且不會被 OpsWorks 一堆未知的地雷炸到。
    • 實務上我會這樣堆疊:debian:stable → rvm-ruby-base → rails-base → app-base → app。
    • rvm-ruby-base 就是先在裡頭裝好 RVM 以及 Ruby。
    • rails-base 是預先裝 Rails 會用到的 Debian packages 如 NodeJS (XD)
    • app-base 預先 git clone 把 application 的 code 拉下來,先跑 bundle install,這樣預先裝好一堆落落長的 gems 後,往後疊 app 上去就不用把時間耗在重新安裝。
    • app 則是做 git pull,把異動拉下來後認 branch/tag 部署。這個放在 deploy 類的 recipes 底下,上面那些則是擺在 setup 類底下。
  • 好處:
    • 我們基於 Rails 的產品很多,用 AWS 也用很大,所以每個產品理想上都可以用同一套 cookbook(s) 做部署基礎,只需在 deploy 這邊自訂個別需求就好。
    • 就算不用 Rails,還是可以在 rvm-ruby-base 上疊其他的 Ruby 應用。
    • 好,就算不用 Ruby,你還是可以在 debian:stable 上堆其他應用。
    • 因為用了 OpsWorks & Chef,我們可以用 template 動態產生 Dockerfile 以及設定檔,可以當成「超彈性隨你玩加強版 ECS (EC2 Container Service)」來用。
  • 先決條件:
    • 規劃良好的 VPC subnets, security groups
    • 看 AWS 官方的 cookbooks 怎麼寫,模仿,並瞭解 node 物件有哪些東西可以方便我們部署
    • 考量日後發展,彈性劃分 Docker 堆疊

編譯 B2G (Firefox OS)

其實之前幫 ZTE Open (inari) 編過,這次是重新拉過一次 source code 下來,然後先試著編譯 emulator 確認基本可動。

我是把 source code 放在外接硬碟上 (/run/media/yhh/500G/),因為筆電內的 SSD 已經沒有太多可用空間。

先拉 source code:

cd /run/media/yhh/500G/
sudo git clone git://github.com/mozilla-b2g/B2G.git
sudo chown -R yhh:users B2G

然後先去編一個編譯過程中需要的 make 3.82:

sudo tar xvfj make-3.82.tar.bz2
cd make-3.82
./configure --prefix=/run/media/yhh/500G/
make && sudo make install
export PATH=/run/media/yhh/500G/bin:$PATH

接著切換 JDK 版本至 openjdk-7:

sudo archlinux-java set java-7-openjdk

開始設定與建置:

cd /run/media/yhh/500G/B2G
BRANCH=v2.2 ./config.sh emulator
./build.sh -j1

編譯過程只開一個 job,是因為之前發現若跑多個 jobs 會有前後相依衝突的問題,造成編譯失敗。

snapshot74 snapshot72

編出來的 emulator,實際跑起來發現在捲動畫面時,繪圖會不定時黑掉或破圖,不過沒關係,如一開始講的,我只是要確認這份 source code 編出來的東西基本可動而已。回台北後要再實際編一套 2.2 給 ZTE Open 用。

Modern Web 2015 Day 2

首先是 PHP 老爹先簡單講為什麼會有 PHP,再花很多時間在介紹 PHP 7 的新特點,以及在效能上的顯著改善。就語法上來說,很多的語法糖讓 PHP 與時俱進,變得更好用,這也看得出來 PHP 的務實取向。

我聯想到昨天聽獎金獵人的場次,對於「只會改 Drupal module 的人不能說是會 PHP 的 PHPer」論點,其實一直覺得哪裡怪怪的、說不上來。到現在才想到,其實 Drupal 本身就是一個框架,並圍繞著它的 hook 範式來加掛功能,這就是 Drupal way。如果 Drupal 是用其他語言開發的,很有可能還是會走一樣的 hook 範式。而其他的框架如何去使用 PHP 演化出各自的範式,也是開發者的決定。

極端一點地說,除非不特地使用某種框架,自己從頭用純 PHP 刻,不然我不覺得換用另一個框架,就比較「會 PHP」了。

其實我也好久沒寫 Drupal 了,以上都是我的嘴砲,請大家鞭小力一點。

接下來我聽的場次是 Yahoo! 的,講設計團隊的 U.S.E.R 文化 (User, Space, Experiment, Repeat),主張應該打破傳統大公司的部門編制,採用 task force 方式重新找回「團隊」,並走出辦公室,實際去瞭解、去看用戶、去做 user study。特別讓我覺得該省思的一點是,工程師的思維會以為拍賣網站的最好設計,是讓買家看完賣家的商品描述就秒懂,二話不說直接下標。但是實際上買賣雙方的信任關係是在互動溝通中建立出來的,並不是讓買方一句話都不用說。這就是為什麼他們的拍賣 App 會決定「讓上架變簡單」。

然後我去聽 Pinkoi 的場次,講行動版網站如何從技術面來提昇 UX。對我而言的重點在於 Rendering Performance 的觀念,要減少頓挫、不連續的現象,就要減少某些很昂貴的消耗。

Jeremy Lu 講 React Native 的場次就一整個技術宣道大會風格,只要記住 Single Source of Truth, Thinking in Component, Always Redraw (in VDOM) 三原則,加上技術導入門檻極小的 JS,以及原生軟體的 UI/UX/Performance,讓 React & React Native 可能成為 Web 與 native app 開發的苦逼業界救世主。

松田明的演說對於我這個 Rubyist 來說其實並沒有新東西,而松田さん調查在座有多少 Ruby 用戶時,看來也是不多。我想我自己也是要努力一點,多去用實際的成果證明 Ruby & Rails 是有意思、有搞頭的。

橋本さん的演說也是很有趣。我之前就試用過 Backlog 了,只是不知道在這軟體變這麼可愛、好用之前,其實有一段因為 UX 不佳、群眾對「工作狀況放在別人家網站管理」有心理障礙的撞牆期,後來透過 UX 的改善才逆轉過來,成為成功的產品。

最後一場我去聽陳雅博講 UX 的哲學,很受感動與啟發,UX 真的不是一個特定部門、特定人員(如一般人可能以為是 VD)負責的,而應該是整個企業、整個團隊都該有的 sense。且產品若原本就有本質上的問題,也不該期望 UX 可以拯救產品,所謂金玉其外、敗絮其內,最終仍是騙不過用戶的。

「好的專案流程重要性不低於成果,但若沒有適當的思維及做事心態,流程並不具備任何意義。」

「正確的思維是教不出來的,是要花時間被培育而出的。」

演說尾段這兩張投影片上的句子特別讓我有感觸。

Modern Web 2015 Day 1

報到的時候由於不諳動線規劃,所以跟報到櫃台人員發生一點誤會,主要責任還是在我,是我修養不到家。雖然後來跟對方道歉了,但是在這裡還是想要再次跟當事人表示歉意。

JavaScript 老爸的演講很精彩,回顧與展望了 JS 的發展,只是我印象最深刻的還是 asm.js 的威力展示。(爆)

接下來雖然我選擇聽蔡學鏞的場次,起初是基於追星的心態,畢竟受他超高水準的譯作獲益不少,且很少人的譯者序可以寫到比作者序還引人入勝的。但是真正聽過他講其個人獨創的 3D 架構方法,就有種「聽過這場就值得這報名費了」的滿足感,這是真正知道如何治學的人,將其心得化為有系統的知識,再用易懂的敘述講給別人知曉。我只能說:「佩服!」

再來我原本打算要聽拓元的場次,卻臨時改變心意去聽獎金獵人如何逃離 Drupal 的泥淖。很可惜沒聽到他們如何處理原有資料庫,畢竟這才是重點。

下午第一場聽 KKTIX 的場次,重點就是他們並不是完全拋掉 Ruby on Rails,事實上還持續跟上最新版本。務實地將 Go 與 Rails 各自用在其擅場。

唐鳳的演說很鼓舞人心,其實這陣子我的情緒很低落,聽過唐鳳的演說,以及接下來 Art Pai 的場次後,有平復一些。

Mozilla 的場次很有意思,一般做手機的多螢幕是使用多個 user agent 或直接 mirroring,但是在 Firefox OS 上他們做的是單一 user agent 在不同螢幕顯示不同內容。

最後一場我聽 Paul Li 的場次講 frontend 的 BDD,講者真是太有趣了,滿滿的笑點讓我從頭忍笑到尾,但是演說的內容其實是很紮實的前端測試技術,聽完真的獲益良多。

在 IntelliJ IDEA 與 Eclipse 新增程式語言支援

繼續昨天的研究…。

初步看來就是要在平台內實作「近乎整個編譯器」。之前我知道 Eclipse 推的 Xtend 語言,(另)一個號稱「更好的 Java」,是從 Xtext 衍生出來的計畫,但也只是沾沾醬油,未嘗細究 Xtext 是什麼樣的東西。

雖然我是個非 CS 本科的外行人,但是我對 compiler, assembler 如何產出小時候在 hex editor 與 disassembler 看到的那些機器碼,一直很感興趣,卻始終因為個人的怠惰,也缺乏強烈的動機,沒有認真下去研究。也許這次是個好機會。