![Go-brown-side.sh](http://i1.wp.com/farm2.staticflickr.com/1622/24407557644_36087ca6de.jpg?resize=500%2C500&ssl=1)
![Go-brown-side.sh](http://i1.wp.com/farm2.staticflickr.com/1622/24407557644_36087ca6de.jpg?resize=500%2C500&ssl=1)
# Postgres $ docker run --name some-postgres \ -d postgres:latest # MySQL $ docker run --name some-mysql \ -d -e MYSQL_ROOT_PASSWORD=1234 \ mysql:latest
pg_isready
指令,Mysql 則是使用 mysqladmin
# Postgres $ docker exec some-postgres pg_isready -h 127.0.0.1 127.0.0.1:5432 - accepting connections # MySQL $ docker exec some-mysql mysqladmin -uroot -p123 ping mysqld is alive # 或者是直接執行單一 SQL 語法 $ docker exec some-mysql mysql -uroot -p123 \ -e "SHOW Databases;"在 Docker 內如果是用
mysqladmin ping
的方式,我發現會抓不到 $?
錯誤代碼,所以還是建議用後者方式,透過執行單一 SQL 方式,在 HAProxy 搭配 Percona XtraDB Cluster 也是透過後者來偵測,詳情可以參考之前寫的『Percona XtraDB Cluster 搭配 HAProxy』。知道如何偵測後,就要寫 While 迴圈每一秒持續偵測。
while ! pg_isready -h postgres; do output "Database service is unavailable - sleeping" sleep 1 done完成上述偵測步驟,就可以正常執行 Databse Migration
npm install
的時間非常冗長,造成每次測試或 Deploy 都要花大量時間等待,且吃掉很多機器的資源,本篇要提供一個小技巧改善 npm install 安裝時間,其實簡單來說就是 cache 第一次安裝好的 node_modules
目錄,之後每次安裝就拿 cache 目錄來新增或減少 packages 即可。
$ tar xf ../nm_cache.tar && \ npm prune && \ npm install && \ tar cf ../nm_cache.tar node_modules步驟很簡單,先拿上一次備份的
node_modules
,再透過 npm prune
移除不必要的 package,再透過 npm install
安裝新的 package,最後一樣打包給下一次測試使用。這指令非常好用,不管你是不是用 npm@3 都很需要這指令加速 npm install。底下是我隨意拿一個 open source 專案來測試,先假設沒有 cache 機制。
$ rm -rf ~/.npm && rm -rf node_modules && time npm install real 2m7.751s user 1m8.704s sys 0m19.272s如果導入 cache 機制
$ time (tar xf ../nm_cache.tar && npm prune && rm -rf ~/.npm && npm install && tar cf ../nm_cache.tar node_modules) > labs-web@0.0.1 postinstall /Users/mtk10671/git/labs-web > node node_modules/fbjs-scripts/node/check-dev-engines.js package.json real 0m32.370s user 0m19.884s sys 0m13.582s從 2 分 7 秒變成 32 秒,大約提升了 4 倍,大家可以嘗試看看,這招在 Deploy 跟測試非常有感覺。
.travis.yml
檔案內,如果我們要的是前者,就必須在個人電腦裝上 travis
指令
$ gem install travis使用 gem 指令之前,請先把 Ruby 環境安裝好,看到這裡是不是覺得很麻煩了。完成後,透過底下指令將 Token 加密到 config 內
$ travis encrypt COVERALLS_TOKEN=xxxxx--add env.global就可以到
.travis.yml
看到
env: global: secure: jeSgPztK8ytfBEBlZiswBIjXd1dafxxxx還沒結束,你要將 golang coverage report file 送到 Coveralls Server 前,還要安裝 goveralls 工具來完成此任務
install: - export GO15VENDOREXPERIMENT=1 - glide install - go get golang.org/x/tools/cmd/cover - go get github.com/mattn/goveralls上面的最後一行是必須的喔。最後執行測試後才將結果傳到 server
script: - make test - go test -v -covermode=count -coverprofile=coverage.out - $(go env GOPATH | awk 'BEGIN{FS=":"} {print $1}')/bin/goveralls -coverprofile=coverage.out -service=travis-ci -repotoken=$COVERALLS_TOKEN
script: - go test -v -covermode=count -coverprofile=coverage.out after_success: - bash <(curl -s https://codecov.io/bash)只要你是 open source 專案,根本不需要 token,Coveralls 會自動分析 golang 編譯出來的 report。在 Dashboard 你會發現這句話
Not required on Travis-CI, CircleCI or AppVeyor for public repositories.只要你是用 Travis 就可以無腦安裝啦。當然也可以自訂選擇 CI Provider。另外如果是 Pull Request,可以發現 Codecov 給的 Report 比 Coveralls 好多了,請直接看此 PR
docker-compose -f docker/docker-compose.yml run golang-build Creating network “docker_default” with the default driver ERROR: 404 page not found make: *** [test] Error 1第二種是
docker-compose -f docker/docker-compose.yml run golang-build Unsupported config option for services service: ‘golang-build’ make: *** [test] Error 1
.travis.yml
檔案,在 before_install
內補上底下 script。
services: - docker env: DOCKER_COMPOSE_VERSION: 1.7.1 before_install: - sudo apt-get -y update - sudo apt-get -y purge docker-engine - sudo apt-get -y install docker-engine - sudo rm /usr/local/bin/docker-compose - curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose - chmod +x docker-compose - sudo mv docker-compose /usr/local/bin請參考完整的 .travis.yml 設定檔。
8080
port,搭配 Nginx 設定就可以跑在 80
port。
server { listen 80; server_name your_host_name; location / { proxy_set_header Host $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 $scheme; # Fix the "It appears that your reverse proxy set up is broken" error. proxy_pass http://127.0.0.1:8081; proxy_read_timeout 90; } }
Global Tool Configuration
內把要測試的版本安裝到 Jenkins 內
$ go get -t -d -v ./... $ go test -v -cover ./...設定完成後,跑測試,會出現底下錯誤訊息
package github.com/gin-gonic/gin: cannot download, $GOPATH not set. For more details see: go help gopath可以發現 jenkins 預設不會將
$GOPATH
設定好,所以必須手動將 $GOPATH
相關目錄設定完成,請不要將 $WORKSPACE
設定成 $GOPATH
,因為 $WORKSPACE
目錄底下包含 src
, pkg
, bin
三大目錄,請將底下 Script 設定到專案內
export GOPATH=$WORKSPACE/gopath export PATH=$GOPATH/bin:$PATH mkdir -p $GOPATH/bin mkdir -p $GOPATH/src/github.com/appleboy/go-hello rsync -az --exclude="gopath" ${WORKSPACE}/ $GOPATH/src/github.com/appleboy/go-hello從上面可以發現,我們手動建立了
gopath
目錄來指定為 $GOPATH
,並且將專案的目錄都設定好後,把 $WORKSPACE
內所有檔案透過 rsync
方式丟到 $GOPATH
內,這樣就可以進行測試了。export
可以用 EnvInject Plugin 取代。
$GOPATH
是指定在 $WORKSPACE/gopath
而不是 $GOROOT/gopath
,如果採用後者的話,這樣多個專案使用不同版本的第三方套件就會出問題,而且共用目錄會造成蠻多額外問題,也無法在測試後完整刪除相關目錄。將 $GOPATH
設定在專案內就可以透過 Workspace Cleanup Plugin 直接清除,讓每次測試環境都是非常乾淨。
Customer Key
跟 Shared Secret
這兩欄位請直接到 Drone 設定檔內找到
DRONE_SECRET: "replace-this-with-your-own-random-secret" DRONE_STASH_CONSUMER_KEY: "AppleBoy46"最下面的
Create Incoming Link
要勾選,完成後按下一步會出現底下畫面
$ openssl genrsa -out /etc/bitbucket/key.pem 1024上面會建立一把 private key 存放到
mykey.pem
,下一個指令則是產生 public certificate
$ openssl rsa -in /etc/bitbucket/key.pem -pubout >> /etc/bitbucket/key.pub完成後,請打開
/etc/bitbucket/key.pub
,將內容複製到上述表單內 public key
欄位。另外要將 /etc/bitbucket/key.pem
位置設定在 Drone config 內。
DRONE_STASH_CONSUMER_RSA: "/etc/bitbucket/key.pem"完成後就可以看到底下畫面
.travis.yml
services: - docker
FROM alpine:3.4 RUN apk update && \ apk add \ ca-certificates && \ rm -rf /var/cache/apk/* ADD drone-line /bin/ ENTRYPOINT ["/bin/drone-line"]接著透過底下指令編譯出 Dokcer Image
$ docker build --rm -t $(DEPLOY_ACCOUNT)/$(DEPLOY_IMAGE) .
DEPLOY_ACCOUNT
是 Dokcer hub 帳號,以我的帳號為例就是 appleboy,DEPLOY_IMAGE
則是 Image 名稱。請將這指令寫道 .travis.yml
內的 script
內
script: # 執行測試 - make test # 通過測試後開始編譯 Image - docker build --rm -t $DEPLOY_ACCOUNT/$DEPLOY_IMAGE .最後一道指令就是上傳了
.travis.yml
吧。在早期 Travis 只提供一種方式就是透過 travis
指令來新增,詳細指令可以參考這文件,這邊就不教大家指令了,而另一種方式就是到 Travis 管理頁面直接進到 settings 設定即可
after_success
加上上傳指令
after_success: - if [ "$TRAVIS_BRANCH" == "master" ] && [ "$TRAVIS_GO_VERSION" == "1.7.1" ] && [ "$TRAVIS_PULL_REQUEST" == "false" ]; then docker login -u="$DOCKER_USERNAME" -p="$DOCKER_PASSWORD"; make docker_deploy tag=latest; fi上面表示只要是
master
分支,測試環境為 Golang 1.7.1 且不是在 Pull Request 狀態就執行登入,並且上傳,其中 make docker_deploy tag=latest
代表意思如下 (我把指令寫在 Makefile 內):
docker tag $(DEPLOY_ACCOUNT)/$(DEPLOY_IMAGE):latest $(DEPLOY_ACCOUNT)/$(DEPLOY_IMAGE):$(tag) docker push $(DEPLOY_ACCOUNT)/$(DEPLOY_IMAGE):$(tag)上面步驟完成,之後只要 commit 到主分支,Travis 就會自動編譯 Image 並且上傳到 Dokcer Hub,蠻方便的。
node_modules
壓縮起來,下次執行測試前先解壓縮再安裝,可以大幅減少 npm install 時間(可以參考之前的『用一行指令加速 npm install』)。這邊我們就需要用到 Travis 的 Cache 功能。
cache: directories: - ${HOME}/docker假設有其他目錄需要 cache,像是 npm 的
node_module
或是 Laravel 的 vendor
,都可以透過此方式設定。
before_install
內透過 docker load 指令讀取 cache 資料
before_install: - if [ -f ${DOCKER_CACHE_FILE} ]; then gunzip -c ${DOCKER_CACHE_FILE} | docker load; fi其中 DOCKER_CACHE_FILE 可以定義在 env 內
env: global: - DOCKER_CACHE_FILE=${HOME}/docker/cache.tar.gz
script: # 進行測試 - make test # 編譯 Image - make docker # 儲存快取 - if [ "$TRAVIS_BRANCH" == "master" ] && [ "$TRAVIS_PULL_REQUEST" == "false" ]; then mkdir -p $(dirname ${DOCKER_CACHE_FILE}); docker save $(docker history -q appleboy/drone-line:latest | grep -v '<missing>') | gzip > ${DOCKER_CACHE_FILE}; fi透過 docker save 指令將 Image 存起來,這樣下次再執行編譯 Image 時,就會先找看看是否有快取。上面設定只有 master branch 才會儲存快取,但是在任何一個 branch 都可以享受到快取的服務喔。
個人電腦 —-> EC2 跳板機 —-> EC2 Server大家都會把 Key Pair 存放到跳板機,安全性堪憂,只要這台主機被 Hack,或者是內部員工登入,拿別人的 Key Pair 登入其它主機,不就可以搞破壞?所以此篇教學主要教大家如何設定 SSH agent forwarding,讓憑證只存放在自己電腦,而不需上傳到
EC2 跳板機
。這樣跳板機就真的只是跳板機,不需要存放任何憑證資料,每小時設定清空 Ubuntu User 家目錄,避免內部員工放個人資料或憑證,提升主機安全性。
ssh-add
指令將 Private Key Pair 加入清單
$ ssh-add ~/.ssh/keys/labs.pem透過底下指令可以看到清單列表
$ ssh-add -L這邊注意可以將所有機器的 key pair 都放到
~/.ssh/keys
目錄,並且設定 400
權限
~/.ssh/config
檔案,每個 Host 都加上 ForwardAgent yes
參數
Host aws HostName 10.130.xxx.xxx User ubuntu ServerAliveInterval 60 ForwardAgent yes UseRoaming no IdentityFile ~/.ssh/keys/aws.pem最後執行底下指令就可以直接跳到您要的 EC2 Server
$ ssh -t aws 'ssh example.inc'直接就跳到 EC2 Server,不用再跳板機多下一個 SSH 登入指令,蠻方便又安全。內部 Host Name 可以透過設定 AWS Private Hosted Zones。
/etc/dehydrated/
底下
$ mkdir -p /etc/dehydrated/ $ wget https://raw.githubusercontent.com/lukas2511/dehydrated/master/dehydrated -O /etc/dehydrated/dehydrated $ chmod 755 /etc/dehydrated/dehydrated
$ echo "WELLKNOWN=/var/www/dehydrated" > /etc/dehydrated/config $ mkdir -p /var/www/dehydratedNginx 設定,先在 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 一次。
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
~/.yarn-cache/
),也就是只要安裝過一次,下次砍掉 node_modules
目錄重新安裝都會從 Cache 讀取。Yarn 詳細的功能架構可以參考 Facebook 發表的 Yarn: A new package manager for JavaScript,本篇不會教大家怎麼使用 Yarn,因為指令實在是太容易了,可以參考官方提供的如何從 npm 轉換到 yarn,底下則是來測試比較兩者安裝套件的速度。
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請準備好底下版本
package.json
或是下載我放在 Github 的 package.json 來做測試。
$ 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 |
主動 Push Message
功能,後來在 Line-Go-SDK 發問才找到解答。底下會一步一步教大家如何透過 Docker 發送 Line 訊息。
Developer Trial
,建立組織及建立帳號,如下圖
PUSH_MESSAGE
PUSH_MESSAGE
權限,Bot 才可以主動發訊息給使用者
Tools
底下選 Line Developers
,就可以看到 Channel Secret
及 Channel Access Token
,要取 Token 請點選右邊的 Issue
按鈕就可以顯示了
https
開頭的 URL,下個步驟會教大家如何透過 Docker 架設 Line Webhook 服務。
$ git clone https://github.com/appleboy/drone-line.git $ cd drone-line
$ docker build -t line example上面的
line
可以自行換掉,換成自己想要的名字,接著啟動編譯好的 Image。
$ docker run --rm \ -e CHANNEL_SECRET=xxxx \ -e CHANNEL_TOKEN=xxxx \ -p 8089:8089 \ line如果不是透過 Docker,請直接執行 Go 指令即可
$ go run server.go
8089
port,接著透過 ngrok 來做穿牆,並且提供 https 服務
$ ngrok http 8089
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 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_TOKEN
和 PLUGIN_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
[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
http.Request
及 http.ResponseWriter
,反倒是支援 fasthttp,所以我發了 Issue 希望作者可以支援原生的 http 標準,最後沒有得到回應。就在前幾天 Echo 在 v3.0.0 版本把 fasthttp
拿掉,這樣 Gofight 就可以移除特定函示,改用原生 http。
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()) }) }
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
$ go get gopkg.in/appleboy/gofight.v2
import "gopkg.in/appleboy/gofight.v2"
go get -d -t ./...
安裝方式就沒有問題,之後再找時間解決此問題。
$ drone-line-v1.4.0-windows-amd64.exe -h看到底下畫面就代表成功了
$ drone-line-v1.4.0-windows-amd64.exe \ --secret xxxx \ --token xxxx \ webhook其中
--secret
及 --token
請自行替換,預設會跑在 8088
port,如果要換連接埠,請使用 --port
參數
$ drone-line-v1.4.0-windows-amd64.exe \ --port 2001 \ --secret xxxx \ --token xxxx \ webhook
$ drone-line-v1.4.0-windows-amd64.exe \ --secret xxxx \ --token xxxx \ --to xxxx \ --message "Test Message"其中
--to
是代表使用者 ID,如果要傳給多個人,請用 ,
符號隔開。
docker run --rm \ -e PLUGIN_CHANNEL_SECRET=xxxxxxx \ -e PLUGIN_CHANNEL_TOKEN=xxxxxxx \ appleboy/drone-line webhook如果要換預設連接埠 (8088) 請加上
PLUGIN_PORT
全域變數
docker run --rm \ -e PLUGIN_CHANNEL_SECRET=xxxxxxx \ -e PLUGIN_CHANNEL_TOKEN=xxxxxxx \ -e PLUGIN_PORT=2001 \ appleboy/drone-line webhook
docker run --rm \ -e PLUGIN_CHANNEL_SECRET=xxxxxxx \ -e PLUGIN_CHANNEL_TOKEN=xxxxxxx \ -e PLUGIN_TO=xxxxxxx \ -e PLUGIN_MESSAGE=test \ appleboy/drone-line
dscl . -create /Users/drone-scp dscl . -create /Users/drone-scp UserShell /bin/bash dscl . -create /Users/drone-scp RealName "Joe Admin" dscl . -create /Users/drone-scp UniqueID "510" dscl . -create /Users/drone-scp PrimaryGroupID 20 dscl . -create /Users/drone-scp NFSHomeDirectory /Users/drone-scp dscl . -passwd /Users/drone-scp password dscl . -append /Groups/admin GroupMembership drone-scp上面指令完成後,請切到 Root 下重新開機的指令
$ reboot這時候你會看到右上角多了一個帳號
drone-scp
drone-scp
帳號來產生個人目錄底下的相關檔案,這樣用 Command 才可以切到該使用者家目錄 /Users/drone-scp
$ ssh-keygen -f id_rsa -N '' -t rsa複製
id_rsa.pub
到 drone-scp 家目錄
$ cp -r id_rsa.pub /Users/drone-scp/.ssh/authorized_keys透過 ssh 指令測試看看是否可以登入,請注意
id_rsa
權限必須為 400
$ ssh -i id_rsa -l drone-scp localhost有看到成功登入的畫面吧 ^___^