聚會時間公告: 因應COSCUP 2011, Kalug 8月份休會一次

七月 21, 2017

小惡魔AppleBOY
AppleBOY
is about »

tag cloud

» Drone 自動觸發 GitLab CI 或 Jenkins 任務

drone-logo_512 Drone 是一套由 Go 語言所開發的開源碼專案,讓開發者可以使用 Docker Container 快速設定自動化測試及部署,上篇有提到『Cronjob 搭配 Drone 服務』,讓 JenkinsGitLab CI 用戶可以轉換 Cron Job 任務到 Drone 上面。本篇則是會介紹如何透過 Drone 去觸發 Jenkins 或 GitLab CI 上的工作,當然這是過渡時期,希望大家最後能將工作完整移轉到 Drone 上面,不要再依靠 Jenkins 或 GitLab CI 了。本篇會教大家用三種方式來觸發 GitLab CI 或 Jenkins 任務。


  • 使用 Drone CI/CD
  • 使用 Docker 指令
  • 使用 Command Line (命令列)

觸發 GitLab CI

不管是 GitLab CI 或是 Jenkins 都可以透過該服務提供的 HTTP API 來遠端觸發,而我用 Go 語言將觸發這動作寫成 Drone Plugin,讓 Drone 用戶可以不用自己寫 curl 去觸發。

申請專案 Token

要透過 HTTP API 去觸發任務,首先就是要申請專案 Token,請大家參考 Triggering pipelines through the API 頁面。申請完成後,請把專案 ID 跟 Token 帶入底下使用。

使用 Drone 觸發

pipeline:
  gitlab:
    image: appleboy/drone-gitlab-ci
    host: https://gitlab.com
    token: xxxxxxxxxx
    ref: master
    id: gitlab-project-id
其中 host 請改成公司內部的 Git 伺服器網址,id 是專案獨立 ID,最後 Token 則是上面步驟所拿到的 Token。詳細設定可以參考 README,如果不是用 Drone 也沒關係,可以用 Docker 或透過 Go 語言可以包成各作業系統執行檔 (包含 Windows)

使用 Docker 觸發

請使用 appleboy/drone-gitlab-ci 映像檔,檔案大小為 2MB
docker run --rm \
  -e GITLAB_HOST=https://gitlab.com/
  -e GITLAB_TOKEN=xxxxx
  -e GITLAB_REF=master
  -e GITLAB_ID=gitlab-ci-project-id
  appleboy/drone-gitlab-ci

使用 CLI 觸發

請先從 Release 頁面下載相關執行檔,重點是你也可以在 Windows 做到此事情喔 (這就是 Go 語言跨平台的好處)。在命令列使用底下指令。
drone-gitlab-ci \
  --host https://gitlab.com/ \
  --token XXXXXXXX \
  --ref master \
  --id gitlab-ci-project-id

測試看看

這邊提供 GitLab 專案的資料給大家直接測試看看
drone-gitlab-ci \
  --host https://gitlab.com \
  --token 9184302d980918efad05bce8b97774 \
  --ref master \
  --id 3573921
上面指令沒意外的話,會看到底下結果:
2017/06/27 15:01:59 build id: 9360879
2017/06/27 15:01:59 build sha: 169e7c1d798c9593c06fbd9d474da9c07f699634
2017/06/27 15:01:59 build ref: master
2017/06/27 15:01:59 build status: pending
直接到 pipeline 頁面看結果 Screen Shot 2017-06-27 at 3.02.05 PM

歡迎大家關注此專案 drone-gitlab-ci

接著來講 Jenkins 部分,其實原理都跟 Gitlab CI 是一樣的。

觸發 Jenkins

這邊其實跟 GitLab CI 設定相同,只是參數不一樣而已,首先必須要去哪裡找個人 API Token,請到 Jenkins 個人頁面找到 API Token。 Screen Shot 2017-06-27 at 3.11.29 PM

使用 Drone 觸發

pipeline:
  jenkins:
    image: appleboy/drone-jenkins
    url: http://example.com
    user: appleboy
    token: xxxxxxxxxx
    job: drone-jenkins-plugin-job
其中 url 請改成公司內部的 Jenkins 伺服器網址,job 是 Jenkins 任務名稱,最後 Token 則是上面個人帳號所拿到的 Token。詳細設定可以參考 README,如果不是用 Drone 也沒關係,可以用 Docker 或透過 Go 語言可以包成各作業系統執行檔 (包含 Windows)

使用 Docker 觸發

請使用 appleboy/drone-jenkins 映像檔,檔案大小為 2MB
docker run --rm \
  -e JENKINS_BASE_URL=http://jenkins.example.com/
  -e JENKINS_USER=appleboy
  -e JENKINS_TOKEN=xxxxxxx
  -e JENKINS_JOB=drone-jenkins-plugin
  appleboy/drone-jenkins

使用 CLI 觸發

請先從 Release 頁面下載相關執行檔,重點是你也可以在 Windows 做到此事情喔 (這就是 Go 語言跨平台的好處)。在命令列使用底下指令。
drone-jenkins \
  --host http://jenkins.example.com/ \
  --user appleboy \
  --token XXXXXXXX \
  --job drone-jenkins-plugin

歡迎大家關注此專案 drone-jenkins

總結

寫這兩個 Plugin 的目的就是希望能有多點開發者從 Jenkins 或 GitLab CI 轉到 Drone,這是過渡時期,等熟悉了 Drone 的設定,你會發現 Drone 已經可以做到 Jenkins 或 GitLab CI 所有事情,甚至更強大。如果對 Drone 有興趣,可以來上七月底的『用一天打造團隊自動化測試及部署
  • 時間: 2017/07/29 09:30 ~ 17:30
  • 地點: CLBC 大安館 (台北市大安區區復興南路一段283號4樓)
  • 價格: 3990 元

報名連結

» Let’s Encrypt 將在 2018 年一月支援 Wildcard Certificates

Letsencrypt Let’s Encrypt 宣布在 2018 年一月全面支援 Wildcard Certificates,目的就是讓全世界網站都支援 HTTPS 協定。自從 2015 年 12 月宣布免費支援申請 HTTPS 憑證,從原本的 40% 跳升到 58%,Let’s Encrypt 到現在總共支援了 47 million 網域。

升級 API

2018 年 1 月 Let’s Encrypt 將支援 IETF-standardized ACME v2 版本,到時候就可以自動申請 Wildcard Certificates。Go 語言autocert packgeCaddy 都要一併修正支援 v2 API 版本。未來只要申請一次,就可以使用在全部 sub domain (像是 *.example.com)。

結論

Let’s Encrypt 讓 Web 開發者都可以享用到 HTTPS 的優勢,當然也造成不少問題,之前寫了幾篇關於 Let’s Encrypt 可以參考。實在無法想像現在還有沒支援 HTTPS 的網站,之前台北市政府外包案出包『智慧支付 App 忘記切換HTTPS加密傳輸』,還是被一位外國人發現的。

» Node.js 8 搭配 npm 5 速度

yarn-kitten-full 這個月 Node.js 釋出 8.0 版本,搭配的就是 npm v5.0.0 版本,上一篇寫到如何透過 Yarn 指令移除 devDependencies 內的 Package 套件,減少 node_modules 大小,有網友提到那 npm 5 的速度為何?其實筆者已經好久沒有用 npm 了,但是有人提問,我就立馬來測試看看 npm vs yarn 的速度,詳細數據可以參考此專案說明。測試方法如下

設定環境

底下是測試環境版本
  • node version: v8.0.0
  • npm verison: 5.0.0
  • yarn verison: 0.24.6

初次安裝 (沒有任何快取)

先把 node_modules 刪除,及系統相關 Cache 目錄都移除
$ npm cache verify
$ rm -rf ~/.npm/_cacache/
$ time npm install
npm 花費時間: 1m43.370s
$ yarn cache clean
$ time yarn install
yarn 花費時間: 1m1.707s

保留系統快取目錄

執行完第一次安裝後,我們把 node_modules 移除後再安裝一次試試看
$ rm -rf node_moduels
$ time npm install
npm 花費時間: 0m38.819s
$ rm -rf node_moduels
$ time yarn install
yarn 花費時間: 0m24.219s

保留系統快取目錄及 node_modules

最後保留 node_modules 目錄,再執行一次安裝
$ time npm install
npm 花費時間: 0m11.216s
$ time yarn install
yarn 花費時間: 0m0.954s

結論

大家可以發現,雖然 npm 改進不少速度,但是 Yarn 還是優勝許多,這邊可以總結,已經在使用 yarn 的,可以繼續使用,尚未使用 yarn 的開發者,可以嘗試使用看看。另外 npm 5 現在執行 npm install –save 會預設產生出 package-lock.json 跟 yarn 產生的 yarn.lock 是類似的東西,除非專案內已經有 npm-shrinkwrap.json,否則 npm 會自動幫專案產生喔。詳細情形可以看 Replace metadata + fetch + cache code。npm cache 指令可以看此文件

» Cronjob 搭配 Drone 服務

drone-logo_512 Drone 是一套基於 Docker Container 技術的 CI/CD 服務,它是用 Go 語言所開發,可以安裝在任何作業系統內,你可以把 Drone 當作是開源版的 Travis 服務。Drone 本身不支援排程任務,也就是說無法像 Jenkins CI 一樣可以設定每天幾點幾分執行單一 Job 任務。但是可以透過第三方工具像是 cron 來整合 Drone API 達成自動排程的效果,底下來看看該如何實作。

安裝 Drone CLI

Drone 提供 CLI 工具,讓開發者可以快速跟 Drone 服務溝通,底下兩種方式來安裝 Drone CLI。從官網找相對應作業系統的執行檔
  • Linux x64
  • Windows x64
  • Darwin x64
另外一種方式則是透過 go get 方式來安裝,前提是您必須要安裝 Go 語言環境
$ go get github.com/drone/drone-cli/drone

Drone CLI 教學

下面指令是透過 CLI 呼叫 Drone 執行指定的專案 Job Number。如果沒有提供 Number 編號,則是執行該專案最後一個 Build Number。
$ drone build start --fork <repository> <build>
--fork 代表啟動新的任務,並非是重新啟動該編號任務。下面指令則是根據專案 Branch 名稱得到最後 Build Number。
$ drone build last --format="{{ .Number }}" \
  --branch=<branch> <repository>
拿到最後一個 Number 後,就可以開始寫 Cron job 任務

整合 cron job

從上面教學可以知道如何透過 Drone CLI 拿到專案最後執行的 Job 任務編號,以及如何重新執行專案任務,這時我們可以將指令合併成一行,變且寫進 crontab -e 檔案內
* 22 * * * drone build start --fork octocat/hello-world \
  $(drone build last --format="{{ .Number }}" \
  --branch=master octocat/hello-world)
branchoctocat/hello-world 換成您的專案名稱即可。

結論

用 crontab + drone cli 就可以完成 Jenkins 可以做到的事情。這樣真的可以完全捨棄 Jenkins 了。如果大家對 Drone 有興趣,想更深入了解,可以來報名『用一天打造團隊自動化測試及部署』,此課程會在一天內帶您進入自動化測試及部署,想從 Jenkins 或 GitLab CI 轉換到 Drone 的,歡迎報名參加。
  • 時間: 2017/07/29 09:30 ~ 17:30
  • 地點: CLBC 大安館 (台北市大安區區復興南路一段283號4樓)
  • 價格: 3990 元

報名連結

» Drone 發佈 0.8.0-rc.1 版本

drone-logo_512 Drone 作者在昨天晚上發佈了 0.8.0-rc.1,此版本有兩個重大變更,第一是 Server 跟 Angent 之間溝通方式轉成 GRPC,另一個變更則是將原本單一執行擋 drone 拆成兩個,也就是之後會變成 drone-serverdrone-agent,拆成兩個好處是,通常 Server 端只會有一台,但是隨著專案越來越多,團隊越來越龐大,Agent 肯定不只有一台機器,所以把 Agent 拆出來可以讓維運人員架設新機器時更方便。

執行畫面

此版本的 UI 也有不同的改變,但是還是以簡單為主,也支援手機端瀏覽,首先看到在單一 Build 的狀態,現在可以顯示每一個步驟的執行時間 Screen Shot 2017-07-21 at 2.16.30 PM 點選任意一個步驟後,可以看到該步驟詳細紀錄,右邊則會顯示步驟列表 Screen Shot 2017-07-21 at 2.18.15 PM

Secret 設定頁面

不需要透過 Command Line 也可以將 Secret (像是 Docker 帳號密碼等) 透過此頁面設定,不過這邊有個缺陷,不能指定 Image,在 Command line 可以設定 Secret 綁定在特定 Docker image 身上。 Screen Shot 2017-07-21 at 2.17.20 PM

Registry 設定頁面

如果在公司內部有架設 Docker Registry 的話,可以透過此頁面將帳號密碼設定 Screen Shot 2017-07-21 at 2.17.30 PM

Project 設定頁面

此頁面可以設定專案狀態,包含執行幾分鐘後就直接停止等。 Screen Shot 2017-07-21 at 2.17.37 PM

結論

此版的 UI 畫面實在是太讚了,尤其是執行步驟畫面,可以看到每個步驟執行時間,早上跟作者聊一下,說下週六我要拿 Drone 現在最新版來教大家,他回說那他會保證這週到下週的修改不會影響到我上課。底下是上課時間跟內容,歡迎大家報名參加『用一天打造團隊自動化測試及部署』。
  • 時間: 2017/07/29 09:30 ~ 17:30
  • 地點: CLBC 大安館 (台北市大安區區復興南路一段283號4樓)
  • 價格: 3990 元

» Go 語言內 struct methods 該使用 pointer 或 value 傳值?

Go-brown-side.sh 上週末在台北講『Go 語言基礎課程』,其中一段介紹 Struct 的使用,發現有幾個學員對於在 Method 內要放 Pointer 或 Value 感到困惑,而我自己平時在寫 Go 語言也沒有注意到這點。好在強者學員 Dboy Liao 找到一篇說明:『Don’t Get Bitten by Pointer vs Non-Pointer Method Receivers in Golang』,在 Go 語言如何區分 func (s *MyStruct)func (s MyStruct),底下我們先來看看簡單的 Struct 例子

package main

import "fmt"

type Cart struct {
    Name  string
    Price int
}

func (c Cart) GetPrice() {
    fmt.Println(c.Price)
}


func main() {
    c := &Cart{"bage", 100}
    c.GetPrice()
}
上面是個很簡單的 Go struct 例子,假設我們需要動態更新 Price 值,可以新增 UpdatePrice method。線上執行範例
package main

import "fmt"

type Cart struct {
    Name  string
    Price int
}

func (c Cart) GetPrice() {
    fmt.Println("price:", c.Price)
}

func (c Cart) UpdatePrice(price int) {
    c.Price = price
}

func main() {
    c := &Cart{"bage", 100}
    c.GetPrice()
    c.UpdatePrice(200)
    c.GetPrice()
}
上面可以看到輸出的結果是 100,只用 value 傳值是無法改 Struce 內成員。我們可以用另外方式繞過。線上執行範例
package main

import "fmt"

type Cart struct {
    Name  string
    Price int
}

func (c Cart) GetPrice() {
    fmt.Println("price:", c.Price)
}

func (c Cart) UpdatePrice(price int) *Cart {
    c.Price = price
    return &c
}

func main() {
    c := &Cart{"bage", 100}
    c.GetPrice()
    c = c.UpdatePrice(200)
    c.GetPrice()
}
從上面範例可以發現,將 struct 回傳,這樣就可以正確拿到修改的值。但是這解法不是我們想要的。來試試看用 Pointer 方式 線上執行範例
package main

import "fmt"

type Cart struct {
    Name  string
    Price int
}

func (c Cart) GetPrice() {
    fmt.Println("price:", c.Price)
}

func (c Cart) UpdatePrice(price int) {
    fmt.Println("[value] Update Price to", price)
    c.Price = price
}

func (c *Cart) UpdatePricePointer(price int) {
    fmt.Println("[pointer] Update Price to", price)
    c.Price = price
}

func main() {
    c := &Cart{"bage", 100}
    c.GetPrice()
    c.UpdatePrice(200)
    fmt.Println(c)
    c.UpdatePricePointer(200)
    fmt.Println(c)
}
只要使用 pointer 方式傳值就可以正確將您需要改變的值寫入,所以這邊可以結論就是,如果只是要讀值,可以使用 Value 或 Pointer 方式,但是要寫入,則只能用 Pointer 方式。其實在 Go 語言官方有整理 FAQ,竟然之前都沒發現,參考底下官方給的建議。

寫入或讀取

如果您需要對 Struct 內的成員進行修改,那請務必使用 Pointer 傳值,相反的,Go 會使用 Copy struct 方式來傳入,但是用此方式你就拿不到修改後的資料。

效能

假設 Struct 內部成員非常的多,請務必使用 Pointer 方式傳入,這樣省下的系統資源肯定比 Copy Value 的方式還來的多。

一致性

在開發團隊內,如果有人使用 Pointer 有人使用 Value 方式,這樣寫法不統一,造成維護效率非常低,所以官方建議,全部使用 Pointer 方式是最好的寫法。

» 台灣第一屆 Laravel 研討會

laravelconftw_o 這次很高興擔任第一屆 Laravel 台灣研討會講者,會議當天中午才到現場,我是兩點分享的議程,在整天聽下來及最後的案例討論,聽到最多的都是原本從 CodeIgniter 架構換到 Laravel 上面,身為 CodeIgniter 的維護人員的我,聽到是蠻開心的,在 Laravel 還沒出來前,大家都是選用這輕量級的 CodeIgniter。

簡報分享

在 Laravel 會議內,我是分享去年在公司內部使用 Laravel 來跟同事間團隊合作的經驗,題目是『運用 Docker 整合 Laravel 提升團隊開發效率』,大家可以參考當天的共筆紀錄,底下整理投影片大綱:
  1. 五大不用 Homestead 的理由
  2. 七大 Docker 必學指令
  3. Laradock 開源專案介紹
  4. 導入 Docker 後的優勢
  5. 用 Drone 整合測試及部署
底下是投影片,投影片內的範例可以參考

drone-laravel-example

運用 Docker 整合 Laravel 提升團隊開發效率 from Bo-Yi Wu
最後花了一些時間介紹 Drone 這套用 Go 語言撰寫的 CI/CD 工具,如果大家有興趣可以參加 7 月底的 iThome 課程『用一天打造團隊自動化測試及部署』。
  • 時間: 2017/07/29 09:30 ~ 17:30
  • 地點: CLBC 大安館 (台北市大安區區復興南路一段283號4樓)
  • 價格: 3990 元

心得

真心覺得這次 Laravel 台灣研討會辦得真是很棒,場地地點也離台北火車站不遠,讓我可以快速的從新竹過來。現場也體會到 LaravelConf 台灣團隊的用心,講師一上台,馬上就有一張照片出現在 Facebook 官網,並且分享共筆連結,讓現場或者是網路的朋友可以跟上進度,真的很棒,另外講師休息室的風景真是太美了。總之辦得真的很棒,感謝 Laravel 傳教士兼靈魂人物 Shengyou Fan 及團隊。 laravelconftw

» 減少 node_modules 大小來加速部署 Node.js 專案

yarn-kitten-full 相信 Node.js 開發者現在大部分都在使用 Yarn 了吧?如果還不知道或無法體會 Yarn 帶來的好處可以參考之前寫的一篇『用 Yarn 取代 Npm 管理 JavaScript 套件版本』,帶你體會 yarn install vs npm install 的速度差異。本篇最主要會介紹在部署 Node.js 專案都需要把 node_modules 壓縮一起丟到遠端伺服器 (假設你不是用 Docker 部署),這時候來聊聊怎麼減少 node_modules 大小。

傳統 npm 作法

Yarn 尚未出來時,可以透過 npm prune --production 的方式來將 devDependencies 內的套件全部清除
$ npm install
$ .... 處理其他事情
$ npm prune --production
$ .... 最後將 node_modeuls 打包

yarn 作法

原本我是把 yarn 搭配 npm prune --production,在早期的 yarn 版本似乎不會有問題,但是發現最新版本 npm prune 會把非 devDependencies 內的套件也一併清除,雖然 yarn 沒有提供 prune 指令,但是有個 flag 可以使用,效果跟 npm prune 一樣,就是加上 --production 這樣就可以降低不少大小,所以部署流程會變成底下
$ yarn install
先是安裝全部套件 (像是 babel-cli),接著透過 babel 轉換程式碼,最後在下底下指令
$ yarn install --production
這時候就會把 babel 相關套件全部移除,最後將 node_modules 打包就可以了。

結論

除了上述過程外,在 CI/CD 流程內,務必設定 yarn 快取目錄在專案內。
$ yarn config set cache-folder .yarn-cache
跑完部屬流程後,可以把 .yarn-cachenode_modules 同時打包,等到下次跑 CI/CD 時會加速不少喔。

» Go 語言框架 Gin 終於發佈 v1.2 版本

19807878_1634683919888714_743883353_o 上週跟 Gin 作者 @javierprovecho 討論要發佈新版本,很快地經過一兩天,作者終於整理好 v1.2 版本,除了釋出新版本外,也換了有顏色的 Logo,真心覺得很好看。大家來看看 v1.2 釋出哪些功能,或修正哪些問題。

如何升級

首先來看看如何升級版本,建議還沒有用 vendor 工具的開發者,是時候該導入了。底下可以透過 govender 來升級 Gin 框架。
$ govendor fetch github.com/gin-gonic/gin@v1.2
$ govendor fetch github.com/gin-gonic/gin/render
由於我們新增 Template Func Maps,所以 render 套件也要一併升級喔。

從 godeps 轉換到 govender

Gin 專案本來是用 godeps,但是在套件處理上有些問題,所以我們決定換到穩定些的 govender,看看之後 Go 團隊開發的 dep 可不可以完全取代掉 govendor。

支援 Let’s Encrypt

我另外開一個專案 autotls 讓 Gin 也可以支援 Let’s Encrypt,這專案可以用在 net/http 套件上,所以基本上支援全部框架,除非搭建的 Http Server 不是用 net/http。使用方式很簡單,如下:

用一行讓 Web 支援 TLS

package main

import (
    "log"

    "github.com/gin-gonic/autotls"
    "github.com/gin-gonic/gin"
)

func main() {
    r := gin.Default()

    // Ping handler
    r.GET("/ping", func(c *gin.Context) {
        c.String(200, "pong")
    })

    log.Fatal(autotls.Run(r, "example1.com", "example2.com"))
}

自己客製化 Auto TLS Manager

開發者可以將憑證存放在別的目錄,請修改 /var/www/.cache
package main

import (
    "log"

    "github.com/gin-gonic/autotls"
    "github.com/gin-gonic/gin"
    "golang.org/x/crypto/acme/autocert"
)

func main() {
    r := gin.Default()

    // Ping handler
    r.GET("/ping", func(c *gin.Context) {
        c.String(200, "pong")
    })

    m := autocert.Manager{
        Prompt:     autocert.AcceptTOS,
        HostPolicy: autocert.HostWhitelist("example1.com", "example2.com"),
        Cache:      autocert.DirCache("/var/www/.cache"),
    }

    log.Fatal(autotls.RunWithManager(r, &m))
}

支援 Template Func 功能

首先讓開發者可以調整 template 分隔符號,原本是用 {{}},現在可以透過 Gin 來設定客製化符號。
    r := gin.Default()
    r.Delims("{[{", "}]}")
    r.LoadHTMLGlob("/path/to/templates"))
另外支援 Custom Template Funcs
    ...

    func formatAsDate(t time.Time) string {
        year, month, day := t.Date()
        return fmt.Sprintf("%d/%02d/%02d", year, month, day)
    }

    ...

    router.SetFuncMap(template.FuncMap{
        "formatAsDate": formatAsDate,
    })

    ...

    router.GET("/raw", func(c *Context) {
        c.HTML(http.StatusOK, "raw.tmpl", map[string]interface{}{
            "now": time.Date(2017, 07, 01, 0, 0, 0, 0, time.UTC),
        })
    })

    ...
打開 raw.tmpl 寫入
Date: {[{.now | formatAsDate}]}
執行結果:
Date: 2017/07/01

增加 Context 函式功能

在此版發佈前,最令人煩惱的就是 Bind Request Form 或 JSON 驗證,因為 Gin 會直接幫忙回傳 400 Bad Request,很多開發者希望可以自訂錯誤訊息,所以在 v1.2 我們將 BindWith 丟到 deprecated 檔案,並且打算在下一版正式移除。
// BindWith binds the passed struct pointer using the specified binding engine.
// See the binding package.
func (c *Context) BindWith(obj interface{}, b binding.Binding) error {
    log.Println(`BindWith(\"interface{}, binding.Binding\") error is going to
    be deprecated, please check issue #662 and either use MustBindWith() if you
    want HTTP 400 to be automatically returned if any error occur, of use
    ShouldBindWith() if you need to manage the error.`)
    return c.MustBindWith(obj, b)
}
如果要自訂訊息,請用 ShouldBindWith
package main

import (
    "github.com/gin-gonic/gin"
)

type LoginForm struct {
    User     string `form:"user" binding:"required"`
    Password string `form:"password" binding:"required"`
}

func main() {
    router := gin.Default()
    router.POST("/login", func(c *gin.Context) {
        // you can bind multipart form with explicit binding declaration:
        // c.MustBindWith(&form, binding.Form)
        // or you can simply use autobinding with Bind method:
        var form LoginForm
        // in this case proper binding will be automatically selected
        if c.ShouldBindWith(&form) == nil {
            if form.User == "user" && form.Password == "password" {
                c.JSON(200, gin.H{"status": "you are logged in"})
            } else {
                c.JSON(401, gin.H{"status": "unauthorized"})
            }
        }
    })
    router.Run(":8080")
}
大致上是這些大修正,剩下的小功能或修正,請直接參考 v1.2 releases log

» 台灣第一屆 GoPher 大會

Screen Shot 2017-06-30 at 10.47.50 AM 很高興可以擔任第一屆 GoPher Day 大會講者,每次參加聚會都是跟一堆網友見面,人在新竹很難得大家見到面。很感謝 iThome 大力幫忙舉辦,才可以讓整天議程順利完成。底下分享『用 Go 語言實戰 Push Notification 服務』投影片。

投影片重點大綱

  • Gorush 介紹
  • Gorush 內部 Goroutine 實作
  • Gorush API 實作
  • 用 Drone 打造 Go 語言部署及測試流程
最後花了一些時間介紹 Drone 這套用 Go 語言撰寫的 CI/CD 工具,如果大家有興趣可以參加 7 月底的 iThome 課程『用一天打造團隊自動化測試及部署
  • 時間: 2017/07/29 09:30 ~ 17:30
  • 地點: CLBC 大安館 (台北市大安區區復興南路一段283號4樓)
  • 價格: 3990 元
用 Go 語言實戰 Push Notification 服務 from Bo-Yi Wu

十一月 20, 2016

我的自由天地 ─ My Libre World
osiris
is about »
» cups 與 pepperflashplugin 更新需要手動調整 (Chakra GNU/Linux)

我們將這些套件更新與剩下的那些分開,因為這兩個套件在打包方面做了一些改變,所以這個更新需要使用者手動處理。您可以預期後面還有兩個更新公告會很快的到來,一個是最新的 KDE Plasma、Applications 與 Frameworks,另一個則是核心套件更新,包含了 Linux 核心與顯示卡驅動程式更新。

cups-2.1.4-3

為了能夠讓使用者不使用 root 權限新增與移除印表機,我們加入了新的 lpadmin 群組。這代表您必須在更新後把您的使用者名稱手動加入到新群組以讓 cups 重新運作(將 USERNAME 取代為您的使用者名稱):
sudo gpasswd -a USERNAME lpadmin

若您遇到了任何問題,請在 gitlab 上對應的問題中回報。

pepperflashplugin 23.0.0.207-1

因為上游的打包方式改變了,所以我們將上游的來源從 Google Chrome 更換為 Adobe。您在嘗試更新時將會收到檔案系統中已有一樣的檔案的警告。為了單獨更新此套件,請使用下面的指令:
sudo pacman -Sy pepperflashplugin --force

若您遇到了任何問題,請在對應的論壇討論串中回報。

另外,libreoffice 更新到了 5.2.3。

請在 Pacman 詢問您是否要取代套件時一律回答 yes。我們大多數的鏡像可能需要12至24小時同步,同步完後,更新應該是相當安全的。我們也提供了一個簡單的鏡像狀態頁面來檢查您的鏡像在什麼時候與主伺服器同步。

新聞來源:Manual intervention needed for cups and pepperflashplugin updates

十一月 18, 2016

我的自由天地 ─ My Libre World
osiris
is about »
» calibre 2.72 釋出

自由的跨平臺電子書管理軟體,calibre 2.72 正式版釋出,此版本新增了幾個功能以及修正了 9 個 bug。
calibre 2.X 版本支援 Windows Vista~10 (皆含 32 位元及 64 位元版本)、Mac OS X 10.7 或更新、各種 Linux 發行版。若您的作業系統是 Windows XP 或是 Mac OS X 10.5、10.6,請繼續使用 1.48 版。

來源:http://calibre-ebook.com/whats-new

十一月 17, 2016

小惡魔AppleBOY
AppleBOY
is about »

tag cloud

» 輕量級 Gofight 支援 Echo 框架測試

Go-brown-side.sh Gofight 是一套用 Golang 撰寫的輕量級測試工具,專門測試 Golang Web Framework API,可以參考之前一篇教學: 用 gofight 來測試 golang web API handler,在 Echo 框架發布 v3.0.0 之前,Echo 不支援 golang 標準的 http.Requesthttp.ResponseWriter,反倒是支援 fasthttp,所以我發了 Issue 希望作者可以支援原生的 http 標準,最後沒有得到回應。就在前幾天 Echo 在 v3.0.0 版本把 fasthttp 拿掉,這樣 Gofight 就可以移除特定函示,改用原生 http。

gofight v1 寫法 (舊式)

舊版 gofight v1 針對 Echo 框架測試寫法
func TestEchoPostFormData(t *testing.T) {
    r := New()

    r.POST("/form").
        SetBody("a=1&b=2").
        RunEcho(framework.EchoEngine(), func(r EchoHTTPResponse, rq EchoHTTPRequest) {
            data := []byte(r.Body.String())

            a, _ := jsonparser.GetString(data, "a")
            b, _ := jsonparser.GetString(data, "b")

            assert.Equal(t, "1", a)
            assert.Equal(t, "2", b)
            assert.Equal(t, http.StatusOK, r.Status())
        })
}

gofight v2 寫法 (新式)

新版 gofight v2 針對 Echo 框架測試寫法
func TestEchoPut(t *testing.T) {
    r := New()

    r.PUT("/update").
        SetBody("c=1&d=2").
        Run(framework.EchoEngine(), func(r HTTPResponse, rq HTTPRequest) {
            data := []byte(r.Body.String())

            c, _ := jsonparser.GetString(data, "c")
            d, _ := jsonparser.GetString(data, "d")

            assert.Equal(t, "1", c)
            assert.Equal(t, "2", d)
            assert.Equal(t, http.StatusOK, r.Code)
        })
}
可以看到只要取代底下 func 就可以無痛轉換
  • RunEcho => Run
  • EchoHTTPResponse => HTTPResponse
  • EchoHTTPRequest => HTTPRequest

載入新版方式

下載 Gofight v2

$ go get gopkg.in/appleboy/gofight.v2

載入 Gofight v2

import "gopkg.in/appleboy/gofight.v2"

後記

Gofight 有用 glide 做 vendor 套件控管,但是支援 Echo 框架後,發現測試突然壞了,產生了另外 Issue,如果是使用 go get -d -t ./... 安裝方式就沒有問題,之後再找時間解決此問題。

十一月 15, 2016

小惡魔AppleBOY
AppleBOY
is about »

tag cloud

» 用 Docker 發送 Line 訊息

docker 今年各家網路公司 (Facebook, LineTelegram…) 分別推出 Bot 服務,看起來 Bot 會是未來趨勢,對 Bot 不是很了解的話,可以參考 Eric ShangKuan 寫了一篇: 關於寫對談機器人 (bot) 的兩三事。本篇會介紹如何透過 Docker 整合 Line Message API,下面所有指令都會跟 Docker 有關,但是程式碼都是用 Golang 撰寫,想說順便在台灣推廣 ^__^。就在今年四月 Line 推出第一版 SDK,但是到了九月,突然收到 Line 的通知,說舊版的不支援了,請大家換到新板 API,最近更動到新版本時,踩到官網 UI 的雷就是原來 Line 有分 Developer 跟一般帳號,這兩種差別就是在於有無主動 Push Message 功能,後來在 Line-Go-SDK 發問才找到解答。底下會一步一步教大家如何透過 Docker 發送 Line 訊息。

步驟一: 申請 Line Developer 帳號

如果已經有帳戶請略過此步驟。請先到 LINE Business Center,點選 Developer Trial,建立組織及建立帳號,如下圖 Screen Shot 2016-11-15 at 1.45.18 PM 完成後,點選 Line Manager,啟動 API Screen Shot 2016-11-15 at 1.50.52 PM 請務必啟動底下設定
  • Use webhooks
  • Allow Bot to join group chats
如果有看到 Usable APIs 包含底下:
  • REPLY_MESSAGE
  • PUSH_MESSAGE
PUSH_MESSAGE 權限,Bot 才可以主動發訊息給使用者

步驟二: 取 Line Token 和 Secret

回到 LINE Business Center 頁面,Tools 底下選 Line Developers,就可以看到 Channel SecretChannel Access Token,要取 Token 請點選右邊的 Issue 按鈕就可以顯示了 Screen Shot 2016-11-15 at 1.59.12 PM 表單內的 Webhooks URL 是要填寫 https 開頭的 URL,下個步驟會教大家如何透過 Docker 架設 Line Webhook 服務。

步驟三: 用 Docker 啟動 Line Webhook 服務

此步驟是教大家如何取得使用者 ID,前提是使用者必須加 Bot 為好友。要啟動 webhook 服務有兩種方式,一種是透過 docker,另一種則是透過 Golang 方式,我們先來試試看 Docker 方式。

下載程式碼

$ git clone https://github.com/appleboy/drone-line.git
$ cd drone-line

編譯 Docker Image

進入 example 目錄後,會發現有 server.go 跟 Dockerfile 兩檔案
$ docker build -t line example
上面的 line 可以自行換掉,換成自己想要的名字,接著啟動編譯好的 Image。

啟動 Webhook 服務

$ docker run --rm \
  -e CHANNEL_SECRET=xxxx \
  -e CHANNEL_TOKEN=xxxx \
  -p 8089:8089 \
  line
如果不是透過 Docker,請直接執行 Go 指令即可
$ go run server.go

用 ngrok 穿牆

這時候會發現系統聽 8089 port,接著透過 ngrok 來做穿牆,並且提供 https 服務
$ ngrok http 8089
Screen Shot 2016-11-15 at 4.08.47 PM 拿到 https://xxxx.ngrok.io 後,請到 Line Develop Console 填到 Webhook URL 欄位 (請填入: https://xxxx.ngrok.io/callback ),最後透過 QRCODE 加 Bot 為好友,並且發送訊息測試,可以發現在 Console 端會顯示:
2016/11/15 08:04:22 User ID is U77234666b0313021f873b85xxxxxxx
這就是您專屬的 User ID,請記錄下來。

步驟四: 用 Docker 主動發送 Line 訊息

透過 drone-line 包好的 Docker Image (appleboy/drone-line)來主動發送訊息,來到這邊,就是假設你已經取得 Line Secret, Token 及使用者 ID,透過下面 Docker 指令
docker run --rm \
  -e LINE_CHANNEL_SECRET=xxxxxxx \
  -e LINE_CHANNEL_TOKEN=xxxxxxx \
  -e PLUGIN_TO=xxxxxxx \
  -e PLUGIN_MESSAGE=test \
  appleboy/drone-line
其中 LINE_CHANNEL_SECRET, LINE_CHANNEL_TOKENPLUGIN_TO 請填入相對應設定。如果覺得指令太長,也可以把設定包在 .env 檔案內
LINE_CHANNEL_SECRET=xxxxxxx
LINE_CHANNEL_TOKEN=xxxxxxx
PLUGIN_TO=xxxxxxx
PLUGIN_MESSAGE=test
請務必將檔案放在執行指令的目錄底下,接著透過底下指令發送訊息
docker run --rm \
  -e ENV_FILE=your_env_file_path \
  -v $(pwd):$(pwd) \
  -w $(pwd) \
  appleboy/drone-line

總結

本來 drone-linedrone ci server 的 plugin,用來完成測試後,通知相關開發者,當然要整合其他 CI 像是 Jenkins 也是可以的,基本上都包成指令了,只要有 Bash 環境都可以運作。老實說 Line 的開發網站,介面不是很人性化,很多功能都不知道在哪邊,也蠻亂的,另外 Line Developer 也有提供綁定 Server IP 才可以發送訊息,這功能不是很即時性,所以大家盡量不要去用。目前也只有 Line 有提供這功能,應該是要避免 Token 跟 Secret 被偷走。最後要注意的是免費的 Developer 帳號一次只能發五則訊息。超過五則訊息,則會吐出底下錯誤:
[messages] Size must be between 1 and 5
怎麼發送多個訊息呢?請用 , 來分隔 (不要超過 5 個喔)
docker run --rm \
  -e LINE_CHANNEL_SECRET=xxxxxxx \
  -e LINE_CHANNEL_TOKEN=xxxxxxx \
  -e PLUGIN_TO=xxxxxxx \
  -e PLUGIN_MESSAGE=我,愛,你\
  appleboy/drone-line

十一月 10, 2016

我的自由天地 ─ My Libre World
osiris
is about »
» 0 A.D. Alpha 21 Ulysses 釋出

0 A.D. 團隊在2016年11月8日釋出了他們的第 21 個開發版本,Alpha 20 Timosthenes,此版本包含了以下的改進與新功能:

  • 11 張新的隨機地圖與 2 張新的遭遇戰地圖!
  • 弒君戰:您開始遊戲時會擁有一個英雄,當他/她被殺死時,您就輸了。
  • 最後生還者:一開始您可以與其他玩家結盟,但是當越多玩家被擊敗,您就會被迫與您的盟友交戰,最後一個活下來的玩家獲勝。
  • 加入巡邏功能。
  • 多了許多可以升級的單位與建築物。
  • Windows 版本現在支援使用超過 2G 的記憶體,這應該可以讓程式當掉的機會變少。
  • 以及其他新功能,請見官方公告。


新聞來源:New Release: 0 A.D. Alpha 21 Ulysses

十一月 3, 2016

我的自由天地 ─ My Libre World
osiris
is about »
» LibreOffice 5.2.3 釋出

LibreOffice 5.2.3 已經釋出,這是 5.2 系列的的第三個錯誤修正版本。
對於企業使用者,文件基金會建議在有認證專家做為後盾的情形下部署 5.1 系列到大型企業及組織,以提供額外的加值服務。

新聞來源:Announcement of LibreOffice 5.2.3

十月 28, 2016

我的自由天地 ─ My Libre World
osiris
is about »
» LibreOffice 5.1.6 釋出

LibreOffice 5.1.6 已經釋出,這是 5.1 系列的的第六個錯誤修正版本。
對於企業使用者,文件基金會建議在有認證專家做為後盾的情形下部署 5.1 系列到大型企業及組織,以提供額外的加值服務。

新聞來源:LibreOffice 5.1.6 available for download

十月 14, 2016

我的自由天地 ─ My Libre World
osiris
is about »
» calibre 2.70 釋出

自由的跨平臺電子書管理軟體,calibre 2.70 正式版釋出,此版本新增了幾個功能以及修正了 5 個 bug。
calibre 2.X 版本支援 Windows Vista~10 (皆含 32 位元及 64 位元版本)、Mac OS X 10.7 或更新、各種 Linux 發行版。若您的作業系統是 Windows XP 或是 Mac OS X 10.5、10.6,請繼續使用 1.48 版。

來源:http://calibre-ebook.com/whats-new

十月 13, 2016

小惡魔AppleBOY
AppleBOY
is about »

tag cloud

» 用 Yarn 取代 Npm 管理 JavaScript 套件版本

yarn-kitten-full 新一代戰神 Yarn 終於在昨天出爐了,Yarn 跟 Npm 一樣都是 JavaScript 套件版本管理工具,但是 Npm 令人詬病的是安裝都是非常的慢,快取機制用起來效果也不是很好,所以 Yarn 的出現解決了這些問題,透過 Yarn 安裝過的套件都會在家目錄產生 Cache (目錄在 ~/.yarn-cache/),也就是只要安裝過一次,下次砍掉 node_modules 目錄重新安裝都會從 Cache 讀取。Yarn 詳細的功能架構可以參考 Facebook 發表的 Yarn: A new package manager for JavaScript,本篇不會教大家怎麼使用 Yarn,因為指令實在是太容易了,可以參考官方提供的如何從 npm 轉換到 yarn,底下則是來測試比較兩者安裝套件的速度。

前置準備

你可以用任何機器會筆電來做底下測試,或者是直接拿此 Dockerfile 在個人環境先產生乾淨的 Image,Dockerfile 內容很短,也可以從底下複製
FROM node:6.7.0

RUN curl -o- -L https://yarnpkg.com/install.sh | bash && \
  echo "" >> ~/.bashrc && \
  echo 'export PATH="$HOME/.yarn/bin:$PATH"' >> ~/.bashrc

CMD /bin/bash
請準備好底下版本
  • node version: v6.7.0
  • npm verison: 3.10.3
  • yarn verison: 0.15.1
可以自己拿任何專案的 package.json 或是下載我放在 Github 的 package.json 來做測試。

測試 package 安裝速度

第一階段就是沒有任何 Cache 之下來測試安裝速度
$ npm cache clean
$ npm install
結果: 93.00 秒
$ yarn cache clean
$ yarn install
結果: 42.80s 第二階段就是保留 node_modules 目錄,在下一次安裝
$ npm install
結果: 13.00 秒
$ yarn install
結果: 0.16 秒 (注意連 1 秒都不到 XD)

結論

npm yarn
install without cache 93000ms 42800ms
install with cache 13000ms 160ms
上面表格將數據整理好,如果要搞 Devops 至少可以省下將近 13 秒的時間,如果是 Local 團隊開發省下的時間更多了。結論就是大家趕快從 npm 轉到 yarn 吧,yarn 出來不到一個禮拜已經超過 1 萬多個 Star 了,看到開發團隊內包含了許多 Google 前端大神,這讓我更放心的轉換到 Yarn。寫完本篇才發現官方也有提供效能比較表。本文提到的數據及檔案都有一併放到 Github Repo

十月 9, 2016

小惡魔AppleBOY
AppleBOY
is about »

tag cloud

» 申請 Let’s Encrypt 免費憑證讓網站支援 HTTP2

Letsencrypt 寫這篇最主要推廣讓網站都支援 HTTPS 加密連線HTTP2 協定,對於網站為什麼要支援 HTTP2,可以直接參考 ihower 寫的說明文章,最近在玩 Facebook, Line, Telegram Bot 時,填寫 Webhook URL,都強制要填寫 https:// 開頭,所以更不能忽略 HTTPS 了。,去年底寫了一篇 Let’s Encrypt 開放申請免費 SSL 憑證 推廣 Let’s Encrypt 的貢獻,讓買不起憑證,又想玩看看 HTTP2 的開發者可以用很簡單的方式來安裝及自動更新憑證,而 gslin 大為了推廣 HTTPS 也做了一個網站教學,文章寫得相當清楚,支援 ApacheNginx 設定。

安裝方式

如果主機是使用 Amazone EC2,可以直接用 AWS Certificate Manager,用 AWS 的好處就是只要透過後台介面搭配 ELB 就可以直接設定好 HTTPS 對應到 EC2 主機,壞處就是直接被綁死,將來如果不要使用 AWS,要轉移機器會相當痛苦。所以本篇會紀錄如何用 Nginx 搭配 Let’s Encrypt。為了方便部署機器,我們選用 dehydrated 來設定 Let’s Encrypt,好處就是不用安裝 Python 套件,官方網站提供的安裝方式需要安裝 Python 相關環境。透過 wget 將 dehydrated 安裝到 /etc/dehydrated/ 底下
$ mkdir -p /etc/dehydrated/
$ wget https://raw.githubusercontent.com/lukas2511/dehydrated/master/dehydrated -O /etc/dehydrated/dehydrated
$ chmod 755 /etc/dehydrated/dehydrated

建立設定檔

建立 dehydrated config 設定檔
$ echo "WELLKNOWN=/var/www/dehydrated" > /etc/dehydrated/config 
$ mkdir -p /var/www/dehydrated
Nginx 設定,先在 80 port 的 Server section 內寫入底下設定:
location /.well-known/acme-challenge/ {
  alias /var/www/dehydrated/;
}
可以先丟個檔案到 /var/www/dehydrated/ 確定網站可以正常讀取檔案,接著透過 dehydrated 指令產生 SSL 設定檔
$ /etc/dehydrated/dehydrated -c -d fbbot.wu-boy.com
執行上述指令會看到底下結果
# INFO: Using main config file /etc/dehydrated/config
Processing fbbot.wu-boy.com
 + Signing domains...
 + Generating private key...
 + Generating signing request...
 + Requesting challenge for fbbot.wu-boy.com...
 + Responding to challenge for fbbot.wu-boy.com...
 + Challenge is valid!
 + Requesting certificate...
 + Checking certificate...
 + Done!
 + Creating fullchain.pem...
 + Done!
最後在設定一次 nginx
server {
  # don't forget to tell on which port this server listens
  listen 80;

  # listen on the www host
  server_name fbbot.wu-boy.com;

  # and redirect to the non-www host (declared below)
  return 301 https://fbbot.wu-boy.com$request_uri;
}

server {
  listen 0.0.0.0:443 ssl http2;
  server_name fbbot.wu-boy.com;

  location /.well-known/acme-challenge/ {
    alias /var/www/dehydrated/;
  }

  ssl_certificate /etc/dehydrated/certs/fbbot.wu-boy.com//fullchain.pem;
  ssl_certificate_key /etc/dehydrated/certs/fbbot.wu-boy.com/privkey.pem;
  location / {
    proxy_pass http://localhost:8081;
  }
}
上面是將 80 port 自動轉到 https,如果下次要重新 renew 的時候才不會又要打開 80 port 一次。

加入 Cron 設定

每天半夜可以自動 renew 一次,請參考 https://letsencrypt.tw/ 最後章節
0 0 * * * root sleep $(expr $(printf "\%d" "0x$(hostname | md5sum | cut -c 1-8)") \% 86400); ( /etc/dehydrated/dehydrated -c -d fbbot.wu-boy.com; /usr/sbin/service nginx reload ) > /tmp/dehydrated-fbbot.wu-boy.com.log 2>&1

後記

除了這方法之外,也可以使用 Certbot 來自動更新憑證,但是這方式就是要安裝 Python 環境,不過也不是很難就是了,可以直接參考這篇『NGINX 使用 Let’s Encrypt 免費 SSL 憑證設定 HTTPS 安全加密網頁教學』。結論就是你可以在網路上找到超多種方法來申請 Let’s Encrypt 憑證,就找到自己覺得不錯的方法即可,而我是認為不用安裝 Python 環境的方式最適合部署了。

support:

biggo.com.tw

A Django site.