發表文章

精選文章

DevOps:持續整合&持續交付(Docker、CircleCI、AWS)

圖片
這篇文章將一步一步介紹如何使用 Docker、GitHub Flow、CircleCI、AWS Elastic Beanstalk 與 Slack 來完成持續整合持續交付的開發流程。
前言 什麼是持續整合&持續交付? 持續整合&持續交付(Continuous Integration & Continous Delivery),簡稱 CI & CD,具體介紹可以參考「山姆鍋對持續整合、持續部署、持續交付的定義」這篇文章。
簡單來說就是盡量減少手動人力,將一些日常工作交給自動化工具。例如:環境建置、單元測試、日誌紀錄、產品部署。
我使用了哪些工具?Git - 版本管理GitHub - 程式碼託管、審查CircleCI - 自動化建置、測試、部署Docker - 可攜式、輕量級的執行環境AWS Elastic Beanstalk - 雲端平台Slack - 團隊溝通、日誌、通知 看完這篇你可以學到什麼?瞭解 GiHub 的工作流程(GitHub Flow),利用 Pull Request 以及分支來完成代碼審查(Code Review)與環境配置,例如:開發版(development)、測試版(testing/QA)、上線產品(staging/production)。使用 Docker,統一開發者、測試人員、以及產品的執行環境。使用 EB CLI 將應用程式部署到 AWS Elastic Beanstalk 平台上。使用 CircleCI 將以上工作全部自動化。偵測 GitHub 分支上的程式碼,若有更新則觸發:建置 Docker 環境、單元測試、然後自動部署新版本到 AWS EB。使用 Slack,讓團隊成員能夠即時接收 GitHub 與 CircleCI 每一項動作的通知。 內容大綱Node.js在本地端執行 Node.js在本地端測試 Node.jsGitHubCircleCI在 CircleCI 測試 Node.jsCode Review with GitHub FlowDocker在 Docker 執行 Node.js在 CircleCI 測試 DockerAWS Elastic Beanstalk在本地端部署 AWS在 CircleCI 部署 AWSSlack Node.js 安裝:
node: 0.10 這篇文章以 Node.js 的應用…

如何發送 redux-observable 的 catch error 至 Sentry

我們團隊目前使用 Sentry 這個服務作 error tracking,JavaScript 或 React 的基本安裝方法在 官方文件 都可以找到,這裡就不贅述。同時我們也有在使用 redux-observable 這個 RxJS middleware 來處理帶有副作用的 Redux action。根據 redux-observable 這篇 Error Handling 文件的介紹,一般處理 async 錯誤的寫法大概會是:import { createAction } from 'redux-actions'; import { Observable } from 'rxjs/Observable'; const fetchUserEpic = action$ => action$.ofType(FETCH_USER) .mergeMap(action => Observable.fromPromise(fetch(`/api/users/${action.payload}`)) .map(response => createAction('FETCH_USER_FULFILLED')(response)) .catch(error => Observable.of(createAction('FETCH_USER_REJECTED')(error.message))) ); 但是因為這裡並非正規的錯誤拋出方式,導致 Sentry 無法攔截到。所以根據 Sentry 的這篇 Rich Error Reports with Redux Middleware 文件介紹,我們需要另外為它寫一個 Redux middleware 來處理。策略是利用 redux-actionsFlux Standard Action 特性,將錯誤用 JavaScript 的 Error object 封裝至 action payload:... .catch(error => Observable.of(createAction('FETCH_USER_REJECTED')(new Er…

如何解決 GPG 失效的問題?

我是用 cider 在管理自己的 dotfiles,然後前陣子因為 gnupg 的 formula 剛好一起被更新,導致我的 GPG signature verification 無法順利運作。解決方式:$ brew unlink gnupg && brew link gnupg 如果有跳出某些 conflicting error 的話,可以照著提示解決,例如:Linking /usr/local/Cellar/gnupg/2.1.21... Error: Could not symlink bin/gpg-agent Target /usr/local/bin/gpg-agent is a symlink belonging to gpg-agent. You can unlink it: brew unlink gpg-agent To force the link and overwrite all conflicting files: brew link --overwrite gnupg To list all files that would be deleted: brew link --overwrite --dry-run gnupg 然後再重新 link gnupg 一次:$ brew unlink gnupg && brew link gnupg 最後檢查 Git 能不能順利 commit 和 push,然後確認 GitHub 的 commits 有出現 verified signature 的話,表示順利修復成功。

如何自動化 release 的流程?

圖片
這篇文章會介紹如何使用 semantic-release 這個工具,自動化 Node.js (or JavaScript) 專案的版本號,以及 changelog 的 release 流程。
什麼是 semantic-release?為什麼要用 semantic-release?如何使用 semantic-release?什麼是 semantic-release?semantic-release 可以自動完成下列這些事:
當 code 被 push 或 merge PR 回 production branch (ex: master) 的時候CI build 被觸發,semantic-release 會收集此次更新的所有 commit messages(需遵循 AngularJS Git Commit Message Conventions 的格式)自動根據 semver 的規則來更新 package.json 的 version,並建立 Git tag自動 publish 新版本的 package 到 npm registry(非必要)自動在 GitHub releases 的頁面上,產生相對應的 changelog 所以簡單來講,semantic-release 指的就是遵循 semver 的 release 流程。

semver 的介紹和好處可以在網路上找到很多文章,這裡就不贅述了,它的概念主要就是將版本號分成:

Major.Minor.Patch

例如 React 的 0.11.2、Vue.js 的 2.0.10 等,這三個數字各自代表:
Major 當你的 API 不兼容前一版本時(又稱 Breaking Change),major + 1,例如:1.x.x -> 2.0.0。
Minor 當你增加新 feature 的時候,並且不影響前一版本的 API,minor + 1,例如:x.6.x -> x.7.0。
Patch 當你修復 bug 的時候,並且不影響前一版本的 API,patch + 1,例如:x.x.9 -> x.x.10。
如果專案有在執行 git-flow 的話,minor 配合的就是 feature 的 release flow,patch 則是 hotfix 的 release flow。
為什麼要用 semantic-releas…

Amazon S3 正確處理 HTML5 History 路由問題

圖片
如果你是使用 Angular、React 或是 Vue 來開發 SPA(單頁面應用),並且放在 Amazon S3 Static Website Hosting 上的話,那麼你會碰到 URL routing 的問題。一般 react-routervue-router 都預設使用 hash 的方式來處理 SPA 的路由:http://domain.com/#!/paths如果你不喜歡 #!/ 的顯示方式,可以使用 HTML5 的 History API,這樣就能像一般網站那樣顯示 URL:http://domain.com/paths但是使用 HTML5 History API 時,通常必須搭配 server 端正確的 路由配置 才能防止出現 404 Not Found 的情形。遺憾的是,在 Amazon S3 Static Website Hosting 上,你無法更動 Apache 或 Nginx 的配置,所以需要靠其它方式來解決問題。使用 S3 的 Redirection Rules使用 CloudFront 的 Custom Error Response使用 S3 的 Redirection RulesAmazon S3 Static Website Hosting 提供了 Edit Redirection Rules 的選項,我們可以輕鬆使用這段程式碼將所有 domain.com/#!/paths 所產生的 404,全部重新導向至根路徑:<RoutingRules> <RoutingRule> <Condition> <HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals> </Condition> <Redirect> <HostName>你的網域(例:domain.com)</HostName> <ReplaceKeyPrefixWith>#!/</ReplaceKeyPrefixWith> </Redirect> </RoutingRule> <…

如何正確處理 AWS API Gateway 的 Lambda Error Status

圖片
翻譯自原文 Error handling in AWS API Gateway with Lambda 這篇文章會介紹如何設置 AWS API Gateway 正確處理 Lambda 返回的 HTTP 錯誤狀態碼。
更新:2016.03.12
claudia 可以自動化解決這個問題,詳細可以參考 這篇 文章。 本文假設讀者已經知道如何利用 AWS API Gateway 和 Lambda 建立 REST API,詳細可參考 Create API Gateway API for Lambda Functions。 假設你的 Lambda function 錯誤處理如下:
console.log('I am a AWS Lambda function'); exports.handler = function(event, context) { // 一般使用 context.fail 來返回 Lambda function 錯誤 context.fail(JSON.stringify({status:'fail', reason:'some reason', foo:'bar'})); }; 但是 API Gateway 返回的結果會是 HTTP 200
HTTP/1.1 200 OK ... { "errorMessage": "{\"status\":\"fail\",\"reason\":\"some reason\",\"foo\":\"bar\"}" } 我們希望的結果是:
HTTP Status 400 Bad request只顯示 errorMessage 的 JSON 值 1. 新增 HTTP Status 400 Method Response前往 API Gateway Console進入 Method Execution進入 Method Response點選 Add Response輸入 HTTP Status 400點選 Add Response Model輸入 Content type ap…

Serverless! 使用 AWS 開發 Slack Slash Commands

圖片
本文介紹如何使用 AWS Lambda & AWS API Gateway 搭建一個不需要伺服器的環境,提供 Slack Slash Commands 查詢豆瓣電影。
2016-01-24 Update:New – Slack Integration Blueprints for AWS Lambda
這篇文章使用到的技術:
Slack Slash CommandsAWS LambdaAWS API Gateway豆瓣電影 API 閱讀這篇文章需要具備什麼能力:
Node.js 的基本能力Amazon Web Services 的基本操作 接下來我會逐步講解這些東西:
Slack Slash Commands 的運作機制建立一個簡單的 AWS Lambda function建立一個簡單的 AWS API Gateway 執行 Lambda function使用 Lambda 呼叫豆瓣電影 API測試 AWS API Gateway將 API Gateway endpoint 加入至 Slack Slash Command Slack Slash Commands 的運作機制 當你在 Slack channel 輸入 /movie 權力的遊戲,Slack 會發出一個 content-type Header 設為 application/x-www-form-urlencoded 的 HTTP POST 請求,格式如下:
token=YOUR_SLASH_COMMAND_TOKEN team_id=YOUR_TEAM_ID team_domain=YOUR_TEAM_DOMAIN channel_id=YOUR_CHANNEL_ID channel_name=YOUR_CHANNEL_NAME user_id=YOUR_USER_ID user_name=YOUR_USER_NAME command=/movie text=權力的遊戲 response_url=YOUR_HOOK_URL 然後 Slack 需要收到的 JSON 回應格式如下(詳見 Attachments):
{ "response_type": "in_channel", "attachments": [ { &q…

解決 Universal 架構的 CSS Modules 問題

最近在使用 ReactRedux 建構一個 Isomorphic JavaScript(Universal)應用。但是在實作 CSS Modules 的時候,會碰上兩個問題:Server-side 的 Node.js 無法 import *.css。如果改成使用 process.env.IS_BROWSER 來判斷只在 Client-dide import,那又會碰到 Server-side 與 Client-side render 出來的 DOM 結果不一致的問題。解決方式:安裝 css-modules-require-hook 這個套件:npm install css-modules-require-hook --save-dev修改 webpack config 的 css-loader 設定:// webpack.config.js { // ... module: { loaders: [{ test: /\.css$/, loader: 'style-loader!css-loader?modules&localIdentName=[name]__[local]___[hash:base64:5]!!postcss-loader' }] } // ... }在 Node.js 的 main file 加入 css-modules-require-hook:// server.js require('css-modules-require-hook')({ generateScopedName: '[name]__[local]___[hash:base64:5]' }); // ...注意 generateScopedName 的命名格式,必須與 css-loader 的 localIdentName 保持一致。