如何使用 Gitlab 搭配 Gitlab CI/CD 進行自動化測試

如何對在 Gitlab 上面的專案進行 CI/CD 可以怎麼做呢? Gitlab 可以搭配 Gitlab CI/CD 來執行 CI/CD , Gitlab CI/CD 會依照所設定的設定檔將指令交由 Gitlab Runner 來執行進而完成整個 Pipeline ,在 Gitlab CI 的世界有幾個名詞。

  • Pipeline: 一個 CI/CD 的流程,串接多個 Job 與多個 Stage 組成,任何一個 Job 失敗都視為這個 Pipeline 失敗(除非該 Job 有設定為 allow fail )。
  • Stage: 階段,一個 Stage 可以由多個 Job 組成,同個 Stage 中的 Job 都必須通過才會執行下個 Stage 。
  • Job: 工作,依照 .gitlab-ci.yaml 所設定之設定交由 Gitlab Runner 來執行,並且提交這個 Job 的執行狀態(綠燈、橘燈、紅燈)。

在 repository 根目錄直接新增 .gitlab-ci.yaml 檔案,這邊有個範例給大家參考。

stages: // 定義這個 Pipeline 有的 Stage
  - build // Stage 名稱
  - test

Build: // Job 名稱
  stage: build // stage name 需要與上方的 stages 名稱一致
  image: composer // 這個 Job 需要使用的 docker image ,以範例來說使用的是 compose:latest
  cache:
    key: "$CI_COMMIT_REF_SLUG"
    paths:
      - vendor/
  script: // 需要執行的指令
    - composer install --ignore-platform-reqs
  artifacts: // 透過 artifacts 將 vendor 這個資料夾 pass 給下個 Stage 的 Job 使用
    expire_in: '10 mins'
    paths:
      - vendor/

Test:
  stage: test
  image: php:7.4-cli
  script:
    - ./vendor/bin/phpunit // 執行 PHPUnit 測試

通常在 Continuous Integration(CI) 階段我們會設計一些流程來進行專案的驗證,目的在於透過自動化導入檢測並且減少人為介入進而提升專案穩定度。

  • 專案安裝
  • 專案檢測(靜態程式碼分析、 coding style 檢查、 docker image best practice 檢測 …)
  • 專案測試
    • 單元測試 Unit Test
    • 整合測試 Acceptance Test
    • End-to-End Testing
  • 專案打包(在容器化世代通常會需要打包 docker image 供其他容器管理器進行使用)

當然在 CI 階段可以做的事情不只這些,就看專案的特性來進行調整即可,撰寫 .gitlab-ci.yaml 完成後執行 git push 推送到專案上就會生效了,即可在 Gitlab > Repo > CI/CD > Pipelines 看到執行結果。

https://gitlab.com/coosos810609/phpunit-demo-with-ci/pipelines/134780795

每個 Stage 中各自 Job 的執行狀態也可以直接點擊查看,畫面中可以看到會將設定在 .gitlab-ci.yaml 中的指令一一執行,並且將執行結果呈現在畫面中。

https://gitlab.com/coosos810609/phpunit-demo-with-ci/-/jobs/506685408

如果執行的過程中有任何的錯誤都可以透過這邊進行 Debug ,下篇再與大家分享如何優化所撰寫的 .gitlab-ci.yaml 檔案。

如何透過 Docker 來使用 Fluentd

首先先介紹一下 Fluentd 怎麼念,這個詞從我進 KKBOX 以來到現在一直都不知道怎麼念,但同事都是念「 Fluent and d 」所以我也跟著這樣念了,今天好奇查了一下真正的念法是「 Fluent dee 」或是可以唸成「 Fluent d 」,詳細可以參考這篇文章

Fluentd 是一套開源軟體的資料蒐集器,時常備用在蒐集各式各樣的 Log 然後整理拋送到另外一個地方,講這樣很玄可以參考下面這張圖。

可以看到 Fluentd 會蒐集各式各樣的 Log 像是 Apache 的 access log 、應用程式的 log 或是系統記錄等等,經過 Fluentd 的 filter 整理後轉送給各式各樣的 Output , Fluentd 支援太多的 Output 了,詳細可以直接到這個網站上面直接查詢,真的是想的到的服務都有。

在 Docker 非常盛行的時代想要實做一個服務你不用自己架設,起一個 Docker 就可以了,下面會跟說明要如何進行測試,我將這次測試的原始碼放在這邊,有興趣可以直接 clone 下來玩玩。

首先需要先撰寫一個 fluent.conf 的設定檔讓 fluentd 執行使用,如下可以看到我有兩個來源分別是 apache-access.log 與 lumen.log 為了測試方便每次執行都會從頭開始讀取到結束,在輸出的部分我使用 file 來儲存並且透過 tag 與時間來區分我的 log 檔案。

<source>
  @type tail
  path /pod-data/apache-access.log
  pos_file /pod-data/apache-access.log.pos
  read_from_head true
  tag apache.access
  <parse>
    @type apache2
  </parse>
</source>

<source>
  @type tail
  path /pod-data/lumen.log
  pos_file /pod-data/lumen.log.pos
  read_from_head true
  tag lumen
  <parse>
    @type json
  </parse>
</source>

<match **>
  @type file
  path /fluentd/log/${tag}/${tag}.%Y%m%d
  <buffer tag,time>
    @type file
    flush_thread_count 8
    flush_at_shutdown true
    timekey_use_utc true
    timekey_wait 1m
    path /fluentd/log/buffer
  </buffer>
</match>

接著就是來使用 Docker 搭配我的設定檔來執行我的 Fluentd 測試。

> git clone https://github.com/hashman/docker-learning.git
> cd docker-learning/fluentd-demo
> docker run --rm --name fluentd -v ${PWD}/fluent.conf:/fluentd/etc/fluent.conf -v ${PWD}/dest_logs:/fluentd/log -v ${PWD}/src_logs:/pod-data fluent/fluentd:v1.10.1-debian-arm64-1.0

因為我是用 Raspberry Pi 來跑,所以我需要使用 arm base 的 docker image 來執行,如是 x86 / x64 的可以直接用 fluent/fluentd:v1.10.1-debian 這個 image tag 來使用就可以了,執行完成最終的 output 資料夾結構會長成這樣的分類。

├── dest_logs
│   ├── apache.access
│   │   └── apache.access.20200405_0.log
│   ├── buffer
│   │   ├── buffer.b5a2b33a4f6b37cbdd626aadd8b4d121f.log
│   │   └── buffer.b5a2b33a4f6b37cbdd626aadd8b4d121f.log.meta
│   └── lumen
│       └── lumen.20200405_0.log

相關的原始碼我有放在 Github 上面,有興趣可以抓下來玩玩,有任何問題歡迎留言或是 Github Issue 發問。

三天兩夜北大武山

北大武山,排灣族的聖山,也是南部唯一的一座百岳,是座 A 級山但看到 A 級真別小看它了。

裝備紀錄

各位可以參考我整理的「北大武裝備清單」來進行整理,經過之前爬南華山的經驗這次準備就相當有經驗了,整體來說裝備是足夠的,但這次遇到寒流,檜谷山莊的氣溫只有 2 度,外套再好一些應該會更好。

行程

Day1: 新登山口 (9:30) -> 舊登山口 (11:00) -> 檜谷山莊 (16:30)

Day2: 檜谷山莊 (6:10) -> 大武遺址 (11:20) -> 三角點 (12:30) -> 檜谷山莊 (17:45)

Day3: 檜谷山莊 (6:30) -> 舊登山口 (10:10) -> 新登山口(11:00)

餐點紀錄

這次使用「北大武檜谷廚房 [ 登高工作室 ]」的服務並且使用兩天食宿的方案一個人的費用為 1800 元整,可以不用背睡袋與帳篷都會幫忙處理好,提供的帳篷是犀牛帳篷睡三個人挺剛好的,睡袋是相當厚的全身包頭睡袋,整體來說相當乾淨,食物簡單但是非常好吃,而且就跟官網上面圖片畫的「一模一樣」。

里程、海拔記錄

舊登山口 -> 0.5k (1602M) -> 1k (1553M) -> 1.5k (1618M) -> 2k (1742M) -> 2.5k (1796M) -> 3k (1870M) -> 3.5k (1955M) -> 光明頂 3.8k -> 4k (2145M) -> 檜谷山莊 4.2k -> 4.5k (2285M) -> 5k (2402M) -> 5.5k (2500M) -> 6k (2619M) -> 水源處 6.3 -> 6.5k (2726M) -> 7k (2802M) -> 7.5k (2962M) -> 8k (3029M) -> 8.5k (3010M) -> 三角點 9k (3092M)

心得記錄

  1. 開車前往的朋友一定要注意車子的底盤,路況不太好,要小心開。
  2. 最後 1k 的時候會需要橫跨 3 個假山頭才會到最後的三角點,這塊挺心累的。
  3. 攀升蠻多的,下山的時候才知道我們到底爬了多少的上升。
  4. 攻頂 4k -> 9k 一開始不要爬太快保留點體力應付後面的攀升,整段大多都是持續上攀的路線,爬完大約會需要 10 – 11 小時。
  5. 個人藥品一定要隨身攜帶,即便是攻頂小包,再攻頂時往往就會是最需要藥品的時候。
  6. 毛帽真的不能脫,脫了很可怕 xd 主要的原因絕對不是頭髮而是著涼。
雖然沒有看到雲海,但有這美景也滿足了

最後,完成人生第二座百岳了, 2020 年訂定的年度目標先完成一件了。

2019 回顧

年底到了,該回顧一下今年自己做了哪些事情,達到哪些成就,今年的自己在學習成長、休閒運動都有些突破但還有很多需要努力的地方。

挑戰 – 演講

MOPCON 2019, Agile Tour Kaohsiung 2019 演講

投影片:

參加 MOPCON 這麼多年還是第一次以講者的身份在講台上演講,也算是我第一場研討會演講,就獻給 MOPCON 了,這次的題目雖說大方向是我訂的,但在與同事討論的過程中也不斷的收斂與調整方向,瞭解到幾件事情。

  1. 不可貪心:專注在主題上不發散,不要都碰一點但都只是帶過卻沒有深入介紹,對於聽眾來說也無法全盤理解想要表達的內容。
  2. 題目盡可能不要走鋼索:有些容易引戰或是在沒有足夠時間下很難將想法表達清楚的題目,很容易在分享的過程中讓會眾遠離你,甚至對你的內容產生置疑,對演講都是不利的。
  3. 培養 Top-down 的思維:過往準備演講的方式都是透過中心主題拓展,從主題散出去將每個項目講清楚,但好的演講需具備的思維應該是要站在會眾的角度來思考會眾會想要聽些什麼內容,如會想要瞭解內容中的細節之外,也想知道如何套用,就需要將內容包裝成一個骨架,會眾透過這個骨架就可以輕鬆的在自己的情境下使用。

這次也是第一次 MOPCON 組織將內部工作方法分享出來讓更多朋友可以知道我們組織是如何運作的,整理了今年資訊組所做的改變,分別針對徵才流程、工作流程、測試與 CI/CD 導入、維護團隊熱情等等面向剖析作法,也將所有組員的努力價值化,讓更多人可以看到 MOPCON 資訊組做了哪些事情。

MOPCON 2019 演講 Photo by MOPCON 攝影組
MOPCON 2019 資訊組團隊 Photo by MOPCON 攝影組

休閒 – 爬山

爬山的目的不只是運動,在爬山的過程中可以幫助自己放下手邊的一切,將自己的身心獻給大地,讓身心感受大自然,幫助自己好好思考煩惱、規劃自己、解放壓力、與朋友聊天交流等好處多多阿,最重要的當然是欣賞爬山的沿途風景與山頂之美,今年很可惜沒有爬到百岳但期許明年的自己可以再登上台灣百岳看看更美的風景。

台中 – 鳶嘴山
屏東 – 里龍山

休閒 – 旅遊

在 MOPCON 2019 一結束之後放下一切煩惱起身前往澳洲兩週體驗當地文化,體會到澳洲人開車就是快、郊外路上隨處可見動物、晚上 8 點店就關光光、很高的物價、不斷地吃麵包等等,當然還有許多很美的風景,看著這些風景與動物,自己也被療癒了,在 Tasmania 有的是自然、寧靜、清幽的感覺雖說生活便利性與繁榮不比 Melbourne 來的多元方便,但自己好像還是喜歡 Tasmania 這種清靜的感覺。當坐飛機回到 Melbourne 的時候瞬間覺得,明明就在澳洲怎麼好像到另一個地方。

澳洲 wallaby

看,是否被療癒了呢?當然在澳洲當地也有非常非常多美麗的風景就不一一介紹了,直接看圖吧。

Tasmania – Mount Wellington
Tasmania Maria Island – Painted Cliffs

健康 – 減重

運動對我來說是生活中不可或缺的一個休閒娛樂,但是幾年的時間不斷的運動不斷的吃,其實體重不減反增,在每年公司的健康檢查持續聽到醫生的一句話「你的體脂肪很高,也有脂肪肝,需要多運動唷」,每次聽到這次話心理大概就是想每個禮拜運動三次不夠嗎 xD ,因此調整了自己的飲食方式進行飲食控制,從今年 10 月開始到 12 月底也有了些成績。

  • 體重: 78kg -> 72kg
  • 體脂肪:23.3% -> 19.6%
201909

201912


給自己的 2020 目標

  1. 爬山、露營、旅遊,還有很多山中美景等著我去看呢,減重持續努力,目標是 15% 體脂。
  2. 基本工穩扎穩打:理財、時間管理、技術等等,需要花點時間打基底的,期許自己可以多花點時間看點書精進。
  3. 更多的分享更多的貢獻:期許自己在文章、社群等都能夠做更多分享。

應該夠一年的時間去實現了。

如何使用 gitlab-runner 進行 Pipeline Debug

安裝 gitlab-runner 的部分可以參考此篇文章,這邊就直接針對如何透過 gitlab-runner 指令來執行 .gitlab-ci.yml 特定的 pipeline 進行測試。

> cat .gitlab-ci.yml
...
Test elasticsearch on 6.x:
  stage: integration
  services:
   - name: elasticsearch:6.8.0
     alias: elasticsearch
  image: *image_ref56
  cache: *cache_ref56
  script:
      - make integration
  tags:
    - docker
...

從上面的 yaml 檔可以知道有一個 “Test elasticsearch on 6.x” 的 Pipeline ,而透過 gitlab-runner 指令可以直接模擬 Gitlab-CI 來執行這個 pipeline 。

> gitlab-runner exec docker --cache-shared --docker-privileged --docker-cache-dir /cache --builds-dir /builds --docker-privileged --docker-volumes /home/xxx/var/gitlab-runner/builds:/builds --docker-volumes /home/xxx/cache:/cache --docker-volumes /home/xxx/.ssh:/root/.ssh --docker-volumes /var/run/docker.sock:/var/run/docker.sock 'Test elasticsearch on 6.x'

就會看到與 Gitlab-CI 上一樣的執行結果了,上面的指定目錄再麻煩各位依照自己的環境進行調整。

此時想說有沒有可能在不進行 git push 的狀況下,也能透過 gitlab-runner 模擬 Gitlab-CI 的執行結果呢?

然而在我修改程式碼之後馬上執行了上面的指令,卻執行尚未修改前的程式,這是怎麼回事? gitlab-runner 有提供一個 --debug 的參數可以使用,或許可以發現些線索。

> gitlab-runner --debug exec docker --cache-shared --docker-privileged --docker-cache-dir /cache --builds-dir /builds --docker-privileged --docker-volumes /home/xxx/var/gitlab-runner/builds:/builds --docker-volumes /home/xxx/cache:/cache --docker-volumes /home/xxx/.ssh:/root/.ssh --docker-volumes /var/run/docker.sock:/var/run/docker.sock 'Test elasticsearch on 6.x'

...
Executing on /runner--project-0-concurrent-0-predefined-1 the #!/usr/bin/env bash

set -eo pipefail
set +o noclobber
: | eval $'export FF_CMD_DISABLE_DELAYED_ERROR_LEVEL_EXPANSION=$\'false\'\nexport FF_USE_LEGACY_BUILDS_DIR_FOR_DOCKER=$\'false\'\nexport FF_USE_LEGACY_VOLUMES_MOUNTING_ORDER=$\'false\'\nexport CI_RUNNER_SHORT_TOKEN=\'\'\nexport CI_BUILDS_DIR=$\'/builds\'\nexport CI_PROJECT_DIR=$\'/builds/0/project-0\'\nexport CI_CONCURRENT_ID=0\nexport CI_CONCURRENT_PROJECT_ID=0\nexport CI_SERVER=$\'yes\'\nexport CI=$\'true\'\nexport GITLAB_CI=$\'true\'\nexport CI_SERVER_NAME=$\'GitLab CI\'\nexport CI_SERVER_VERSION=\'\'\nexport CI_SERVER_REVISION=\'\'\nexport CI_PROJECT_ID=0\nexport CI_JOB_ID=1\nexport CI_JOB_NAME=$\'Test elasticsearch on 5.x\'\nexport CI_JOB_STAGE=$\'integration\'\nexport CI_JOB_TOKEN=\'\'\nexport CI_REPOSITORY_URL=$\'/home/xxx/repo/project-a\'\nexport CI_COMMIT_SHA=$\'74cd6c29f235b8be115fd54f97a163025ac49dfe\'\nexport CI_COMMIT_BEFORE_SHA=$\'88c146a08a8ed3cc6bc41b023ff064ea7d2c3b28\'\nexport CI_COMMIT_REF_NAME=$\'feature/boost-from-query\'\nexport COMPOSER_HOME=$\'/cache/composer\'\nexport CI_DISPOSABLE_ENVIRONMENT=$\'true\'\nexport CI_RUNNER_VERSION=$\'12.6.0~beta.2048.g59f07d78\'\nexport CI_RUNNER_REVISION=$\'59f07d78\'\nexport CI_RUNNER_EXECUTABLE_ARCH=$\'linux/amd64\'\nexport GIT_LFS_SKIP_SMUDGE=1\n$\'rm\' "-r" "-f" "/builds/0/project-0"\necho $\'\\x1b[32;1mFetching changes...\\x1b[0;m\'\n$\'mkdir\' "-p" "/builds/0/project-0.tmp/git-template"\n$\'git\' "config" "-f" "/builds/0/project-0.tmp/git-template/config" "fetch.recurseSubmodules" "false"\n$\'git\' "init" "/builds/0/project-0" "--template" "/builds/0/project-0.tmp/git-template"\n$\'cd\' "/builds/0/project-0"\n$\'rm\' "-f" ".git/index.lock"\n$\'rm\' "-f" ".git/shallow.lock"\n$\'rm\' "-f" ".git/HEAD.lock"\n$\'rm\' "-f" ".git/hooks/post-checkout"\nif $\'git\' "remote" "add" "origin" "/home/xxx/repo/project-a" >/dev/null 2>/dev/null; then\n  echo $\'\\x1b[32;1mCreated fresh repository.\\x1b[0;m\'\nelse\n  $\'git\' "remote" "set-url" "origin" "/home/xxx/repo/project-a"\nfi\n$\'git\' "fetch" "origin" "--prune"\necho $\'\\x1b[32;1mChecking out 74cd6c29 as feature/boost-from-query...\\x1b[0;m\'\n$\'git\' "checkout" "-f" "-q" "74cd6c29f235b8be115fd54f97a163025ac49dfe"\n$\'git\' "clean" "-ffdx"\nif $\'git\' "lfs" "version" >/dev/null 2>/dev/null; then\n  $\'git\' "lfs" "pull"\n  echo\nfi\necho $\'\\x1b[32;1mSkipping Git submodules setup\\x1b[0;m\'\n'
exit 0
...

後段可以看到一串指令將它整理一下。

Executing on /runner--project-0-concurrent-0-predefined-1 the #!/usr/bin/env bash

set -eo pipefail
set +o noclobber
: | eval $'
export FF_CMD_DISABLE_DELAYED_ERROR_LEVEL_EXPANSION=$\'false\'
export FF_USE_LEGACY_BUILDS_DIR_FOR_DOCKER=$\'false\'
export FF_USE_LEGACY_VOLUMES_MOUNTING_ORDER=$\'false\'
export CI_RUNNER_SHORT_TOKEN=\'\'
export CI_BUILDS_DIR=$\'/builds\'
export CI_PROJECT_DIR=$\'/builds/0/project-0\'
export CI_CONCURRENT_ID=0
export CI_CONCURRENT_PROJECT_ID=0
export CI_SERVER=$\'yes\'
export CI=$\'true\'
export GITLAB_CI=$\'true\'
export CI_SERVER_NAME=$\'GitLab CI\'
export CI_SERVER_VERSION=\'\'
export CI_SERVER_REVISION=\'\'
export CI_PROJECT_ID=0
export CI_JOB_ID=1
export CI_JOB_NAME=$\'Test elasticsearch on 5.x\'
export CI_JOB_STAGE=$\'integration\'
export CI_JOB_TOKEN=\'\'
export CI_REPOSITORY_URL=$\'/home/ubuntu/repo/project-a\'
export CI_COMMIT_SHA=$\'74cd6c29f235b8be115fd54f97a163025ac49dfe\'
export CI_COMMIT_BEFORE_SHA=$\'88c146a08a8ed3cc6bc41b023ff064ea7d2c3b28\'
export CI_COMMIT_REF_NAME=$\'feature/boost-from-query\'
export COMPOSER_HOME=$\'/cache/composer\'
export CI_DISPOSABLE_ENVIRONMENT=$\'true\'
export CI_RUNNER_VERSION=$\'12.6.0~beta.2048.g59f07d78\'
export CI_RUNNER_REVISION=$\'59f07d78\'
export CI_RUNNER_EXECUTABLE_ARCH=$\'linux/amd64\'
export GIT_LFS_SKIP_SMUDGE=1\n$\'rm\' "-r" "-f" "/builds/0/project-0"\necho $\'\\x1b[32;1mFetching changes...\\x1b[0;m\'\n$\'mkdir\' "-p" "/builds/0/project-0.tmp/git-template"\n$\'git\' "config" "-f" "/builds/0/project-0.tmp/git-template/config" "fetch.recurseSubmodules" "false"\n$\'git\' "init" "/builds/0/project-0" "--template" "/builds/0/project-0.tmp/git-template"\n$\'cd\' "/builds/0/project-0"\n$\'rm\' "-f" ".git/index.lock"\n$\'rm\' "-f" ".git/shallow.lock"\n$\'rm\' "-f" ".git/HEAD.lock"\n$\'rm\' "-f" ".git/hooks/post-checkout"\nif $\'git\' "remote" "add" "origin" "/home/xxx/repo/project-a" >/dev/null 2>/dev/null; then\n  echo $\'\\x1b[32;1mCreated fresh repository.\\x1b[0;m\'\nelse\n  $\'git\' "remote" "set-url" "origin" "/home/ubuntu/repo/project-a"\nfi\n$\'git\' "fetch" "origin" "--prune"\necho $\'\\x1b[32;1mChecking out 74cd6c29 as feature/boost-from-query...\\x1b[0;m\'\n$\'git\' "checkout" "-f" "-q" "74cd6c29f235b8be115fd54f97a163025ac49dfe"\n$\'git\' "clean" "-ffdx"\nif $\'git\' "lfs" "version" >/dev/null 2>/dev/null; then\n  $\'git\' "lfs" "pull"\n  echo\nfi\necho $\'\\x1b[32;1mSkipping Git submodules setup\\x1b[0;m\'\n'
exit 0

其中 GIT_LFS_SKIP_SMUDGE 環境參數後面執行的指令這邊吸引了我,將他整理一下…

> rm -rf /builds/0/project-0
> echo git-template
> $git config -f /builds/0/project-0.tmp/git-template/config fetch.recurseSubmodules false
> $git init /builds/0/project-0 --template /builds/0/project-0.tmp/git-template
> cd /builds/0/project-0
> rm -f .git/index.lock
> rm -f .git/shallow.lock
> rm -f .git/HEAD.lock
> rm -f .git/hooks/post-checkout
> if 
    $git remote add origin /home/xxx/repo/project-a >/dev/null 2>/dev/null;
then
    echo $\\x1b[32;1mCreated fresh repository.\\x1b[0;m
else
    $git remote set-url origin /home/xxx/repo/project-a
fi
> $git fetch origin --prune
> echo \\x1b[32;1mChecking out 74cd6c29 as feature/boost-from-query...\\x1b[0
> $git checkout -f -q 74cd6c29f235b8be115fd54f97a163025ac49dfe
> $git clean -ffdx
> if
    $git lfs version >/dev/null 2>/dev/null;
then
    $git lfs pull
fi
> echo \\x1b[32;1mSkipping Git submodules setup\\x1b[0;m

其中可以看到在設定 git remote 路徑的時候,他是抓取實體專案路徑,也就是說,如果 code change 沒有下 git commit 就無法讓 runner 抓取到,這下簡單了,只要 git commit 就好… 測試後確認成功。

如何在自己的環境安裝 gitlab-runner 指令

有使用 Gitlab 的朋友對於 Gitlab-CI 應該都不陌生,透過 CI 可以幫助開發者進行測試或是部署,相當的方便,但往往在執行 CI 的時候出錯要 debug 都要一直 push code 很麻煩, Gitlab 有將他的 runner 開源並提供方法讓大家在自己的環境安裝 gitlab-runner ,下面就來跟大家說怎麼安裝。

如果你只是想要使用 gitlab-runner 的指令,可以直接透過這份文件進行安裝即可,但如果你會有需要使用不同版本的 gitlab-runner 的需求,就可以參考這份文件進行操作,如果此環境你沒有 sudo 權限或是想要看懶人版可以直接往下看 xD

gitlab-runner 是使用 Golang 寫的,所以需要先進行 Golang 相關配置與安裝。

更新你的 .profile, .bash_profile, .zshrc 看習慣放哪裡,我自己都會放在 .zshrc

> vim ~/.zshrc
...
export GOPATH=$HOME/Go
export PATH=$PATH:$GOPATH/bin:$HOME/local/go/bin
...
> exec zsh
> mkdir ~/Go
> mkdir ~/local

下載與安裝 Golang 。

> cd
> wget https://storage.googleapis.com/golang/go1.10.8.linux-amd64.tar.gz
> tar -C local -xzf go1.10.8.linux-amd64.tar.gz

完成之後你就會在你的 ~/local/go 這邊看到 go 的原始碼,也可以開始使用 go 了,接著來確認是否有成功安裝

> go version
go version go1.10.8 linux/amd64

看到上面訊息代表你的 go 語言有成功的安裝,接下來安裝 gitlab-runner

> go get gitlab.com/gitlab-org/gitlab-runner

執行完成後你可以看到 ~/Go/bin 裡面有個 gitlab-runner 的執行檔,就可以直接使用了,或是要使用 $GOPATH/src/gitlab.com/gitlab-org/gitlab-runner/.gopath/bin/gitlab-runner 也可以,至於為什麼要知道後面這個路徑呢?後面會提到,測試一下 gitlab-runner 是否安裝成功。

╭─hashmanlin@ubuntu ~/Go/bin
╰─➤  gitlab-runner -v
Version:      development version
Git revision: HEAD
Git branch:   HEAD
GO version:   go1.10.8
Built:        unknown
OS/Arch:      linux/amd64

這邊可以看到安裝成功了,但會發現 Version 是 development version ,如果希望指定版本怎麼辦?舉例想要使用 11.11.4 的版本。

╭─hashmanlin@ubuntu ~/Go/src/gitlab.com/gitlab-org/gitlab-runner  ‹master›
╰─➤  git checkout v11.11.4
Note: switching to 'v11.11.4'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:

  git switch -c <new-branch-name>

Or undo this operation with:

  git switch -

Turn off this advice by setting config variable advice.detachedHead to false

HEAD is now at e828d3bc9 Update CHANGELOG for v11.11.4
╭─hashmanlin@ubuntu ~/Go/src/gitlab.com/gitlab-org/gitlab-runner  ‹e828d3bc9›
╰─➤  make deps
mkdir -p /home/hashmanlin/Go/src/gitlab.com/gitlab-org/gitlab-runner/.gopath/bin
touch /home/hashmanlin/Go/src/gitlab.com/gitlab-org/gitlab-runner/.gopath/.ok
go get github.com/golang/dep/cmd/dep
go get github.com/mitchellh/gox
go get github.com/vektra/mockery/.../
╭─hashmanlin@ubuntu ~/Go/src/gitlab.com/gitlab-org/gitlab-runner  ‹e828d3bc9›
╰─➤  make install
go install --ldflags="-X gitlab.com/gitlab-org/gitlab-runner/common.NAME=gitlab-runner -X gitlab.com/gitlab-org/gitlab-runner/common.VERSION=11.11.4 -X gitlab.com/gitlab-org/gitlab-runner/common.REVISION=e828d3bc -X gitlab.com/gitlab-org/gitlab-runner/common.BUILT=2019-12-02T12:42:34+0000 -X gitlab.com/gitlab-org/gitlab-runner/common.BRANCH= -s -w" gitlab.com/gitlab-org/gitlab-runner
╭─hashmanlin@ubuntu ~/Go/src/gitlab.com/gitlab-org/gitlab-runner  ‹e828d3bc9›
╰─➤  ./.gopath/bin/gitlab-runner -v
Version:      11.11.4
Git revision: e828d3bc
Git branch:
GO version:   go1.10.8
Built:        2019-12-02T12:42:34+0000
OS/Arch:      linux/amd64

至於為什麼 $GOPATH/bin/gitlab-runner 沒有被置換成 11.11.4 的版本呢?看了一下 gitlab-runnerMakefile 會把 $GOPATH 改為 .gopath 這個路徑,如果希望 $GOPATH/bin/gitlab-runner 也跟著置換可以考慮用 ln 的方式來處理。

╭─hashmanlin@ubuntu ~/Go/bin
╰─➤  rm gitlab-runner
╭─hashmanlin@ubuntu ~/Go/bin
╰─➤  rm gitlab-runner
╭─hashmanlin@ubuntu ~/Go/bin
╰─➤  ln /home/hashmanlin/Go/src/gitlab.com/gitlab-org/gitlab-runner/.gopath/bin/gitlab-runner gitlab-runner
╭─hashmanlin@ubuntu ~/Go/bin
╰─➤  cd
╭─hashmanlin@ubuntu ~
╰─➤  gitlab-runner -v
Version:      11.11.4
Git revision: e828d3bc
Git branch:
GO version:   go1.10.8
Built:        2019-12-02T12:42:34+0000
OS/Arch:      linux/amd64

這樣就可以執行特定版本的 gitlab-runner

Firefox Container + Easy Container Shortcuts Plugin 使用心得分享

Firefox 在前幾個月有驚人的效能改善之後就從 Chrome 換成 Firefox 使用好一陣子了,Firefox 到 70 版本之後效能更是有驚人的突破,這邊分享個我很常使用且很喜歡的 Plugin 。

Firefox 容器

簡單來說容器可以把你所使用的分頁放進容器中進行執行,每個容器都是獨立的設定,也就是說你的登入資訊等在不同的容器都是無法共用的,這個概念其實跟 Chrome 的使用者很像,只是 Chrome 必需要開很多的視窗來達到,但我喜歡開分頁使用。

我自己的使用情境為例,我就有這麼多的容器,裡面有公司的、私人的、社群用不同的容器,每個容器也都登入特定的 Google 帳號,向我本身有 7.8 個以上的 Google 帳號,如果在同一個瀏覽器全部都登入,當我今天要使用 Gmail 我就需要切換我的使用者才可以看到該使用者的信箱,但使用容器後我可以直接用該容器打開 Gmail 就會看到該容器所登入之 Google 帳號 Email 了,不只是 Gmail 而已,像是開發上常使用的 Rollbar 平台也是,不同的專案使用不同的 Rollbar 帳號來管理,使用容器管理後我就可以不用一直登入登出帳號來使用 Rollbar 了。

當然對於一個工程師,要切換容器還要用滑鼠點是非常麻煩的事情,找了一下發現有網友開發了 Plugin Easy Container Shortcuts 來達到使用鍵盤來開啟特定容器分頁,下載連結可以看這邊,這個 Plugin 是開源軟體,有興趣的朋友可以到他的 Github 上面看看,在 Mac 上可以直接透過 Alt + Shift + 數字 來開啟相對應容器的分頁,但這邊可能要注意一下 shortcuts 有沒有被其他的 plugin 使用,像我有使用 Droplr 他就衝突了,我的作法是調整 Droplr 的快捷鍵來給 Easy Container Shortcuts 來使用。

還有什麼不錯的 Plugin 嗎?歡迎也來跟我分享。

Synology NAS 防火牆相關設定

什麼是防火牆

防火牆有如家的門窗等等,如果門戶大開,就是讓別人很輕易的就可以進去,所以當我們不在家裡,或是都會把家門關上有如設定上防火牆一樣的概念。 應用程式溝通都會在 Server 上面監聽一個連接埠(Port)透過這個 port 與外部網路進行溝通,原則上防火牆僅需要放行必須的 Port ,不會直接全開,全開可能其他的 Port 就能夠被有心人士進行操作。

Synology NAS 實體網路架設方式

目前自己的架設方式

  • 優點
    • 不用再做 Port Forwarding 等等的設定,所有的服務都可以直接被外網存取到
  • 缺點
    • 直接將 NAS 暴露在外網上
    • 如果只有一個固定 IP (通常家用網路只會預設免費一個固定 IP)就被 NAS 拿走了,就無法再架設其他服務了

其他人建議的做法

  • 優點
    • 固定 IP 會綁在小烏龜上面,如果內網還有其他的 Server 或是服務可以直接用 Port Forwarding 的方式鏡像到外網
    • NAS 沒有直接暴露外網
  • 缺點
    • 需要一個一個開 Port 才可以讓外部使用到服務,設定較為麻煩

如何設定 Synology 防火牆

設定位置在「控制台 -> 安全性 -> 防火牆」
如何開啟防火牆設定
點擊「編輯規則」即可進行防火牆設定
Hash 自己的防火牆設定
我自己的做法是採用白名單的做法,也就是有列出的項目放行,其他的全部不允許
  • Web service (80, 443) 直接開啟所有 IP 都可以使用
  • 內網所有服務放行
  • DSM 管理介面、Drive、Moment 等等服務都是選擇 Taiwan 才放行,如果有要出國出國前再將來源國家多開那個國家即可,或是透過 VPN 的方式連線回來台灣使用也行
設定 Port, IP
根據服務放行
幾年沒用 Synology NAS 後 DSM 進步不少,在防火牆的設定都可以選擇應用程式還有國家,都不太需要動什麼頭腦就可以設定完成了 另外提醒大家,防火牆不是絕對安全的,舉例,你開啟了 22 port 的 SSH 服務,結果你的密碼被 Hacker 猜到登入,更慘的是如果他所登入的帳號是管理員帳號,你的整台 NAS 都是他的了,如果想要把服務放在外部請三思而後行。

Bose QC 30 簡易開箱

AirPods 也使用了近 2 年了,電池的電量也從剛買來的 4 hr 到現在不到 1.5 hr 了,對於我這種上班、通勤、工作等等無時無刻都在聽音樂的人來說,真的是不太符合使用,在一個契機下就買了這款 Bose QC 30 ,也是我買過最貴的藍芽降噪耳機。
盒子的後面附上保固書,記得把他留存好,有維修需求就可以使用到。
另外是它同時支援 iOS 與 Android 系統,採用藍牙連結,自己在 iPhone 的使用上除了 siri 無法進行使用,基本上使用跟 AirPods 的功能差不多,除了跨平台的支援,他也可以同時接受 2 個裝置的使用,這點也是 AirPods 做不到的,所以在切換 device 上面他真的非常的方便,就無需再一直切換 device 了,但當然,同時還是僅能接收一個 device 的訊號。
盒子的包裝非常的精美簡單,採用摺疊的方式,直接可以看到耳機的本體。
內容物分別有:
  1. 鯊魚鰭耳塞套 S 與 L(預設會將 M 套上)
  2. 充電線
  3. 乾燥劑
  4. 說明書
  5. 耳機盒

配置

正面來看可以看到一個非常清楚的 Bose logo 、控制器與麥克風,控制器得側面為控制降噪程度,正面則是可以控制音量與音樂。
背面可以看到充電槽、「很難壓」的電源開啟鍵。
另外還有附上盒子來裝置耳機,擺起來大概是長這樣。
稍微試聽了一下有幾個簡單的心得,畢竟自己也不是專業的
  1. 掛起來還蠻舒服的,不會覺得它存在
  2. 耳機戴起來也是相當舒服感覺沒有存在感,跟 AirPods 很像,但是卻比 AirPods 更有安全感
  3. 戴上去有種非常寂靜的感覺,聲音的表現上我覺得低音比較出色,另外是降噪的部分,是有效果的,但就算將降噪開到最大還是會聽到外面的聲音,所以再降噪上面處理的還是相當有限
畢竟還沒有長時間的使用它,所以可以得出的心得不多,之後使用一陣子有其他的心得在上來分享好了。

身為工程師的我如何看近期的 Evernote

最近 Evernote 有不少負面消息了,想說來寫一篇我如何看這個軟體,先說以下言論我不代表 Evernote 官方,僅僅是以一個 User 的角度來看這件事情,先讓大家回憶一下 Evernote 最近發生了哪些大事件。

大事件

上面兩個文章我這裡就不再多做說明,有興趣的朋友可以自行閱讀,但這些事件可以看到 Evernote 國際版經歷了非常大的挑戰,也對於他們的市場照成非常大的衝擊,當然發生的事情絕非我僅列的,另外在 Evernote 的使用者論壇 也可以看得出一些使用者對於這些新聞與軟體的反應,自己看了幾個月大概可以得出一些使用者常討論的內容

  1. 為什麼 Evernote 不支援 Markdown 語法
  2. 好爛阿離開吧
  3. 沒有什麼新 Feature 感覺沒什麼進步
  4. Bug, Unstable 等等

針對第一點,如上方大事件提到,印象筆記已經於 6/6 將中國業務與國際版進行獨立切割,並且於 8/7 就快速的推出了 Markdown 的功能,也引發大家不少的討論,詳細內容也可以看看這篇文章「印象笔记终于支持markdown了」。

其他的項目我個人也有些見解與看法,但就先讓我來說說我自己的想法

用 Evernote 這個軟體已經 6 年了,對於我來說,我會以 Evernote 就是我 第二個大腦 來形容,當時的他不僅支持跨平台(Windows, Mac, Linux, Mobile 等等)筆記,還可以隨時透過 Evernote web clipper 來擷取網頁內容進行留存,在當時真的是相當的驚人,說實話至今我還是沒有找到可以有這麼多功能可以取代的產品,如果有的話真的歡迎可以跟我分享,我很願意試試。

想要表達的是,大家都會期望這個筆記軟體可以更符合現在使用者的需求,也當然或許增加這個 Feature 可以讓我們對於他的喜愛度更高沒錯,但或許大家可能沒有看到其實 Evernote 還是 Evernote 他的核心價值與他想要帶給大家的功能其實他沒有變過, Evernote 還是 Evernote ,他還是非常方便的讓我們隨時筆記、完成 GTD 、檔案 / 內容搜尋、簡報等等功能整合在這個軟體裡面。

在今年我參加了由 高雄 HPX 讀書會 開的「打開大家的 Evernote 筆記本:50位職人x 50種思考x 50個活用,為什麼這樣做筆記可以解決80%的工作問題」書聚讓我有個機會可以用不同的面向來看這個軟體,這本書不是新書,但是非常多的觀念與思考流程還是適用於每個人的,這邊不會討論這本書的內容,我僅列出幾個本書想要強調給大家。

  1. 記下所有的事情,把他當作是一個大大的 bucket 全部都丟進去就好,當你有需要的時候你就會找的到資料。
  2. 善用他的搜尋功能,這個也是 Evernote 最強的功能,不管是筆記內容、檔案內容、圖片內容搜尋等,都是相當的方便的,總可以讓你再需要的時候找到資料。
  3. 雖然他是一個筆記軟體,但他也可以做到 GTD 管理的功效,也可以透過「記事連結」這個功能將筆記與代辦事項串連起來。
  4. 分享職人如何使用 Evernote 。

當然本書的內容不僅僅是這四項,每個人解讀可能會有些不同就歡迎有興趣的朋友也可以去嘗試借閱 / 購買來看。

如何將 Evernote 應用於我的生活

  1. Slack integration (快速擷取特定日期的對話內容存到 Evernote ,對於使用免費版 slack 的人來說是一大福音)
  2. XMind 可以將所畫的心智圖,存進 Evernote 中,方便進行關鍵字搜尋與回想
  3. 透過 Evernote 完成 135 代辦事項 Reference: [時間技客-1] 做得到的每日待辦清單:1-3-5 專注法則
  4. 透過 RSS 軟體閱讀文章,整理心得存入 Evernote 進行留存
  5. 透過網友開發的 Plugin 來將 Markdown 語法套用 syntax style

分享我的閱讀心流

總結

其實 Evernote 的核心價值還是存在,並沒有因為產品時代的不同而影響這個產品的核心價值,只是可能沒有支援那接 Nice to Have 的 feature ,或許可以想想那些他能夠帶給你與解決問題的角度來欣賞這個軟體而非否定他,當然在此不是要大家使用 Evernote ,只是覺得 Evernote 對我來說還是非常不錯的,工具還是要看自己的使用習慣,要用順手的工具比較重要,也歡迎大家可以分享你覺得哪些工具很棒。