Category Archives: DevOps

SSH agent forwarding 的應用

SSH agent forwarding 可以讓本地的 SSH Key 在遠端 Server 上進行轉送,也就是當你需要在選端 Server 上使用 SSH Key 時,就不需要將你的 key pair 手動複製到 server 上,是個暨方便又安全的作法。

舉例來說,首先 SSH 登入進 Server1,接著在 Server1 上登入 Server2 時,就會自動使用你本地的 SSH Key:

Local ---(SSH)---> Server1 ---(SSH)---> Server2

那要怎麼使用:

首先需要將要 forwarding 的 private key 加到清單裡面:

ssh-add

ssh-add -L

可以檢查這個清單。接著:

方法一:每次要 Local 連上 Server 時,加上 -A 參數:

ssh -A user@{you server1 ip}

方法二:修改 ~/.ssh/config 設定,加上 ForwardAgent yes,這樣就不需要每次連都加上 -A 參數。例如

Host server1
  HostName 106.187.36.122
  ForwardAgent yes

實務上有什麼應用呢? 這裡舉兩個常用的例子:

Bastion Host

在 AWS 的架構課中,每次講 VPC 就會提到 Bastion host 的概念,也就是整組內部網路只開放一台 server 可以從外部做 SSH 連線,如果需要 SSH 連線其他機器,都必須透過這一台 Bastion host 轉過去。這樣做的目的當然是為了安全性,我們可以特別加強這一台 Bastion host 的安全,例如鎖外部 IP 或是裝 SELinux 等等,這一台的用途就專門只做 SSH 連線,畢竟越簡單越容易防護,更細節的 OS 防護原則可以參考 OS Hardening Principles

既然 SSH 連線都必須透過這台 Bastion host,那麼 SSH agent forwarding 這招就很好用了,就不需要、也不應該把 private key 放到 Bastion host 上面。

Git Deployment

如果你有用 Git 版本控制系統的話,你的應用程式佈署也很可能需要在 Server 上把 Source Code 從 repository 拉下來,這時候就會需要 SSH 的權限。

以前小時候不懂事,總是在 Server 上生出一組部署專用的 SSH key pair,然後在 Github 上設定這組 key 可以讀取 repository。後來發現這完全是多餘又增加安全風險。既然有權限佈署,那麼也就表示你應該就有權限可以讀取 source code,那就用你自己的 SSH key 就好啦,就不需要在 server 上擺一組 SSH key pair 了。

如果是用 Ruby 的 capistrano 做部署的話,只要設定一下就可以了:


set :ssh_options, {
  forward_agent: true
}

這樣在佈署程序中就會用到你自己的 SSH key 去 Github 拉 source code 了。

參考資料

修改 AWS RDS 資料庫設定,以 max_allowed_packet 為例

記錄一下,以後肯定還會再用到。

因為 MySQL 預設的 max_allowed_packet 設定是 1M,對有些應用來說可能太小了。如果是自己架 MySQL 改 /etc/mysql/my.cnf 就是了,不過租用 Amazon RDS 就沒有這種事了。又它的 web console 也沒有提供介面可以改設定(parameters)除了可以用 AWS 的 web console 介面來改,也可以透過 Amazon RDS Command Line Toolkit 呼叫 API 來改,步驟如下:

  1. 下載 Amazon RDS Command Line Toolkit

  2. 參考 credential-file-path.template,編輯 credentials.txt 把 AWSAccessKeyId 和 AWSSecretKey 填上去

  3. 設定環境變數,例如:
    export AWS_RDS_HOME=/Users/ihower/RDSCli-1.12.001
    export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Home
    export PATH=/Users/ihower/RDSCli-1.12.001/bin:$PATH
    export AWS_CREDENTIAL_FILE=$AWS_RDS_HOME/credentials.txt
    export EC2_REGION=ap-northeast-1

  4. chmod +x ${AWS_RDS_HOME}/bin/*

  5. rds-create-db-parameter-group <自定的parameters群組名稱> -d "群組描述" -f MySQL5.5 新增一個群組來放參數

  6. rds-modify-db-parameter-group <自定的parameters的群組名稱> -p "name=max_allowed_packet,value=2097152,method=immediate" 把參數放進你自定的群組裡 (這裡單位只能用bytes)

  7. rds-modify-db-instance <DB Instance Name> -g <自定的parameters群組名稱> 把群組綁到指定的 DB 上

  8. 這個設定似乎不需要 reboot 就生效了。要重開的話,在 web console 也可以 reboot。

完整的文件在 AWS Command Line Reference,例如


rds-describe-db-instances <DB Instance Name> 看這個 DB 套用了什麼 PARAMGRP 群組
rds-describe-db-parameters <自定的parameters的群組名稱> 看這個群組的 parameters

Heroku: Ruby 社群的雲端平台

一直想要寫一篇來介紹 Heroku,而這篇簡單的介紹堆在 draft 好一陣子了。雖然比不上 @deduce 上週寫的 Ruby語言的雲端運算平台:Heroku 來的詳細,但既然都寫了就貼出來吧 XD

常常有人在羨慕 Python 跟 Java 有 Google App Engine 可以用,然後 Ruby 沒有。雖然說 Ruby 可以透過 JRuby 跑在 GAE 上(方案1, 方案2),但是好像不太多人這麼做,為什麼呢? 這是因為 Ruby 社群大多用 Heroku 啊。

Heroku 這家公司提供了與 GAE 類似的 PaaS 雲端服務,讓任何符合 Rack 介面的 Ruby 應用程式可以跑在上頭(所以不只是 Rails,像是 Sinatra 也可以跑在上面),以及提供 PostgreSQL 這套關聯式資料庫和其他許多的外掛服務。它的底層硬體資源是採用了可擴展的 Amazon EC2,透過 Heroku 的 dynos (它的資源單位) 只要拉上拉下就可以增加伺服器負載了,非常厲害,請看 Rapportive 的故事:

想要擁有一個可隨時延展的架構(scalable architecture),你只要選對廠商(hosting provider)就可以做到。如果Rapportive一開始隨便選了一個便宜的VPS,流量一衝進來的時候可能就會像全面啟動電影中Cobb的混沌世界(Limbo)一樣崩潰。Rapportive的服務是放在知名廠商Heroku上,對於突然湧進的流量只需要增加Dynos的數量(Heroku提供服務的基本單位),基本上你是不需要修改你的程式的;當然,程式的優化、調整可以在同樣能耐的硬體等級上容納更多人。

使用Heroku、不需要調整程式、只需要增加Dyno數量?真的有這麼美好嗎?事實上Rapportive就是這麼辦到的,在來自全世界的流量突然湧進時,Rahul Vohra手邊沒有電腦,於是他隨即拿起iPhone並且利用Nezumi這個設計來管理Heroku的應用程式,將Rapportive的Dynos增加到20個,就這麼簡單,可能不到一分鐘吧?!系統的能耐馬上就提昇了。

它的佈署方式採用 Git,所以如果你熟悉 Git,那麼使用 Heroku 真是超級簡單的:

安裝步驟:

gem install heroku
heroku create your_app_name

佈署:

git push heroku master (當然,你的專案必須是 Git repository)
接著打開瀏覽器 your_app_name.heroku.com 就可以看到了。

只要一個指令就可以搞定佈署,它會自動幫你調整 database.yml 檔案。可參考 Heroku Quickstart Guide。根據最新的實地測試,Rails3 也可以正確跑起來。

總而言之,它的優點 1. 支援所有 Rack 應用程式 2. 佈署容易 3. 擴充方便外掛多。相較於 GAE,除了免費方案沒 G 社大方之外,其他毫不遜色啊。

使用 logrotate 定期整理 Rails Log 檔案

(2017/5) linux 日志定时轮询流程详解 這篇解釋的更清楚

不像 Apache 預設已經設定好了,會定期整理成 access.log.1, access.log.2.gz, access.log.3.gz 等,如果你沒特別處理,Rails 底下的 log 檔案可是越長越肥。

這個系統工具是 logrotate,它的設定檔在 /etc/logrotate.conf,設定的方式還真是簡單 (參考自 Rotating Rails Log Files):


# Rotate Rails application logs
/path/to/your/rails/current/log/*.log {
  daily
  dateext
  missingok
  rotate 65535
  compress
  delaycompress
  notifempty
  copytruncate
}

其中 daily 表示每天整理,也可以改成 weekly 或 monthly
dateext 表示檔案補上 rotate 的日期
missingok 表示如果找不到 log 檔也沒關係
rotate 7 表示保留65535份
compress 表示壓縮起來,預設用 gzip。不過如果硬碟空間多,不壓也沒關係。
delaycompress 表示延後壓縮直到下一次 rotate
notifempty 表示如果 log 檔是空的,就不 rotate
copytruncate 先複製 log 檔的內容後,在清空的作法,因為有些程式一定 log 在本來的檔名,例如 rails。另一種方法是 create。

設定好之後,可以等明天,或是執行 /usr/sbin/logrotate -f /etc/logrotate.conf 看看。

如何正確發送(大量) Email 信件

Update(2011/5): 推薦 Amazon SES 服務

Update(2010/5): So You’d Like to Send Some Email (Through Code) 也可以一看

Update(2011/7): 推薦 Postmark,也有 Rails plugin。

在眾多客戶需求中,我最害怕的其中一條”順便”要做的功能就是,在後台可以寄信給”全部的”使用者。

寄 “email” 而已,不是非常簡單嗎?

寄給幾個人是很簡單,但是要寄給”一群”人,那就不是件簡單的事情了,在這 spam 肆虐的年頭, 信寄出去不一定就能順利到達使用者的收件夾。

Engine Yard 的這兩篇 How To Ensure Your Email Gets DeliveredMaking Sure Your Email Gets Delivered 點出了寄 Email 要注意的事項:

  1. 處理退信

    Bonuce mail 是你寄出去的信件,但是因為某些理由(地址不對、對方信箱滿了)而被對方 mail sever 退信,這些 email 你必須要處理。如果你忽略它還一直寄,你就長得蠻像發垃圾信的傢伙,而會被列出黑名單之中。

  2. 與主要的 Email 服務商設定意見反應機制(Feedback Loop)

    Feedback Loop 是一項協助處理當你的 email 被使用者按下 “垃圾信” 的服務。透過主動接觸主要的 Email 服務提供商,去建立用戶意見反應機制。例如 台灣Y!Yahoo! Complaint Feedback Loopmsn等,減少被寄件者檢舉成垃圾信的次數。

  3. 建立自已的 email 清單

    建立你自己的 mail 清單。如果你的清單是買來的,不但收件人沒有同意要收到你的信件,也會有很高的機會是 bonuce mail。寄出大量的非允許郵件,終究會讓你的 IP 被列出黑名單。

    標準的作法是,要在使用者註冊後,且他們也確認收到註冊的認證信(透過email上的認證連結),如此便可以確保這個 email 的正確性,而不會變成 bonuce mail。你也應該避免寄出跟你服務無關的email,減少被檢舉成垃圾信的機會。

  4. 不要使用 100% 以圖片為主的內容

    減少使用圖片,像 Gmail 預設就不會讀取圖片,重要的資訊使用圖片可能會讓使用者預設就看不到。充滿圖片的的 email 也容易判讀成垃圾信。

  5. 使用垃圾信判讀工作測試

    收信的 mail server 通常會使用如 Spam Assassin 的工具來判讀是否是垃圾信,而你也應該用這類的工作檢查你寄出去的信件。www.brandonchecketts.com/emailtest.php 是一個線上的檢查工作,如果你的分數太低,顯然很可能被判讀成 spam。至於為什麼分數低,可以參考這篇文章

  6. 驗證 HTML

    如果你寄的是 HTML 格式,你應該檢查 HTML 格式是否正確。一封畸形的信件也容易變成 spam。

  7. 模擬測試終端使用者環境

    使用不同 email clients 實際測試,例如 litmusapp.com 這個工具。不同的 client 可能會顯示不同的結果。

  8. 專屬 IP

    是否有專屬的 IP。如果你的 email sever 是跟人共用的,很可能別人被 spam 了,跟著害到你被列入黑名單。

  9. 設定 SPF Validation

    SPF (Sender Policy Framework) 是一項 e-mail 協定來確認 return-path address 的正確性,用以防止垃圾信件。設定 SPF 可以改進你的信件發送成功率,特別是 hotmail(MSN)。

  10. 設定 Domain Keys Verification

    Domain Keys 驗證是另一種防止垃圾信件的協定。

  11. 設定 Reverse DNS 反查

    設定反向查詢的 DNS 記錄,如果你寄信的 IP 無法反查,可能根本就寄不到。

  12. 驗證寄信者地址

    你的寄信人 email 位址也要是正確存在的。許多 email 服務商會先檢查寄件人的地址是正確的,才會收信。

接下來麻煩的是,如果你終究還是不小心被列成黑名單,該怎麼辦? 這篇文章也列出一些常見的原因。

Anyway,我的結論是,還是交給專業的來吧~ 自己架設/管理 email server 不但辛苦又會被 blocked。如果信件量一天低於 500 封,我會建議採用免錢 Gmail 來寄信;超過的話,則有一些第三方服務可以採用,例如 Amazon SESSendgridAuthsmtp。 如果需要比較多的行銷功能,則可以考慮 MadmimiCampaignmonitorMailchimp 等服務。

BTW,既然提到了 Campaign Monitor,如果你有心做 Email marketing,他們家有不少值得一讀的資源,例如 Guide to CSS support in email clients 就十分有用。

主動攔截 Rails exception 錯誤

喔,炸了。

相信以上畫面大家都不陌生,這是一個標準的 Rails app 錯誤頁面。雖然我們努力避免,但總是有出錯的時候,一個上 production mode 的專業 Rails app 絕不會痴痴地等待使用者告訴你網站炸了,而是要能夠主動通知及紀錄下這個錯誤例外(exception),好讓我可以 trace error、fixed bug 甚至在發生錯誤沒多久就可以 E-mail 告訴這位使用者苦主發生了什麼事情。

解法有幾種:

  1. 安裝 exceiption_notifition,這是個官方的基本 Plugin ,它會在發生例外時寄 email 通知你(們)。

  2. 安裝 ExceptionLogger (作者 defunkt 也是 facebox 的作者 :p ),這個 Plugin 會紀錄到 database,並提供一個後台可以瀏覽。不過這個後台裝起來比較麻煩,例如你還得處理瀏覽權限等等。

  3. 使用 Hoptoad 第三方服務,這是個由知名Rails團隊 thoughtbot 所提供的 Web service。申請帳號之後可以拿到 API key 及 Plugin,於是你的網站發生 exception 的時候就會自動將錯誤訊息送到 Hoptoad 收集起來。Hoptoad 提供了還蠻不錯的後台可以瀏覽。這個解法安裝最簡單,功能又很夠用,還可以統計及追蹤例外處理的情況,我個人十分推薦使用。

github 上應該還有其他的 Plugins 可以幫助你處理這個問題。anyway… 最糟的就是什麼都不做,讓使用者告訴你有東西炸了,然後你再去爬去找 log 檔 :)