VS Code 新功能: Remote Repositories

VS Code 在 1.57 版中, Remote Development 系列 extension 加入了新成員: Remote Repositories

有了這個 extension 之後,如果遇上臨時想看的 project,就可以直接在 VS Code 中叫出來看,不需要事先 clone 至某個 local 資料夾。

不過.. 因為這個 extension 實際上是建一個 Virtual Workspaces 並把 code 放在裡面閱覽, 所以用 Remote Repositories 開出來的 workspace 功能非常受限。 諸如 Debug, Terminal 及大部分的 extension 基本上都不能用。 但話雖如此,當看 code 看一看想要開始進行比較深入的修改及除錯時, 其實也是有提供轉換成一般 workspace 的功能。 使用上非常方便!

可惜的是,目前此 extension 支援的 remote repository 種類只有 GitHub。 且如同其他 Remote Development Series,這個 extension 並非 open source project:

未來會不會支援 GitHub 以外的 Git repositories,甚至其他種類的 VCS, 只能看微軟爸爸的眼色了。

GitHub Pages 與 GitLab Pages 架設 Blog

筆者最近把個人 blog 的產生工具從 GitHub Pages 預設的 Jekyll 換成 Hexo,有了一點心得。 而且不只 GitHub Pages, 筆者在公司業務中也有大量使用 GitLab Pages 來產生文件及測試報表,算是有累積不少經驗。

趁著印象還深刻時,寫點筆記,替這兩個相同性質的服務做基本的介紹。

Pages 服務與 Static Site Generator

GitHub / GitLab Pages 可以將一組靜態網頁內容 (html, css, js 等),透過 GitHub / GitLab 的伺服器,host 在某個 URL 底下。 網頁產生工具 (Static Site Generator, 下稱 SSG) 則是 一個可以將用 Markdown 撰寫的文章,轉化成漂亮的靜態網頁內容的工具。常見的 SSG 有 Jekyll(Ruby), Hugo(Go), Hexo(JavaScript) 等。

若將 SSG 工具與 GitHub / GitLab Pages 服務,搭配使用, 寫作者只需要寫寫簡單的 Markdown 並 push commit,就能得到一個漂亮的 blog 或是文件網頁。 筆者的個人 blog 及公司的工作筆記即是使用這類流程架設。

整體流程大概如下圖所示:

1
2
3
4
5
6
7
8
9
               +   GitHub            +     github.io
Local Project | Project | site
| GitLab | gitlab.io
+ +

+----------+ +----------+ Build & +------+ User
| Markup | Push | Markup | Deploy | Site | Browse
| config.. | +----> | Config.. | +-------> | | +------->
+----------+ +----------+ +------+

GitHub Pages

GitHub Pages 基本上會有兩種主要的使用方式。 可以直接使用 GitHub Pages,或是透過 GitHub Pages 的 Jekyll 整合功能。 前者需要的技術背景與設定步驟均較複雜,後者較簡單但缺少了根據個別需求調整的機會。

Native GitHub Pages

若直接使用 GitHub Pages,使用方式是: 將 SSG 產生的網頁擺放至某 branch (預設為 gh-pages) 的 //docs 目錄。 每次該 branch 被更新時,GitHub 就會將最新版本的網頁內容, 呈現在 https://<username>.github.io/<project> 連結下。

早期這個 push brach 的動作是蠻麻煩的,但後來有了 GitHub Action 之後, 產生網站和後 push branch 的動作都可以在 GitHub 提供的環境完成,非常方便。

筆者個人使用的 job 描述檔如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# .github/workflows/blog.yaml

name: build-and-deploy-blog

on:
push:
branches: [ "master" ]
pull_request:

jobs:
blog:
runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@v2.3.4
- name: Setup Node.js environment
uses: actions/setup-node@v2.1.5
with:
node-version: 12.x
- name: Install dependent packages
run: npm install
- name: Build blog posts
run: npm run build
- name: Deploy
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./public

若不想使用 GitHub 提供的 domain,也可以參照 官方文件, 使用自己購買的 domain 來架設網站。 只要設定完成,GitHub 也可以一併幫使用者申請 custom domain 需要的 HTTPS 憑證。

比方說筆者的 blog 原本可存取的位置應是 https://wdhongtw.github.io/blog,但有設定 custom domain 後,目前是透過 https://blog.bitisle.net 來存取架在 GitHub Pages 上的 blog。

GitHub Pages Jekyll

前述 (Native) GitHub Pages 的使用方式會需要自己 push branch。 但若 GitHub 偵測到 project 使用的 SSG 是 Jekyll,GitHub 會自動處理產生網頁以及 後續部屬到 https://<username>.github.io/<project> 的工作。 (連 gh-pages branch 都省了,整個 project 會非常乾淨。)

此方法相當容易上手,也是 GitHub Pages 教學文件預設的使用方式。但因為產生網站的 環境是由 GitHub 協助處理,能使用的 Jekyll plugin 自然也是受到限制。

說是受到限制,但以一般使用情境應該也很夠了。諸如 RSS feed, sitemap, Open Graph metadata 等現代 blog 必備的功能都有自帶。 若想知道有那些 Jekyll plugin 可用,可至 Dependency versions | GitHub Pages 查閱。

Compare Native GitHub Page with GitHub Pages and Jekyll

簡單比較上述兩種方式如下

GitHub Page GitHub Page with Jekyll
SSG Tool on your choice only Jekyll
Deployment push generated site done by GitHub
Customization any plugins of SSG limited Jekyll plugin list

GitLab Pages

GitLab Pages 與 GitHub Pages 一樣,有將 SSG 產生的網頁 host 在特定網址的能力。 以 GitLab 官方 host 的站台來說,網站會放在 https://<username>.gitlab.io/<project> 下。 (私人或公司 host 的 GitLab instance 就要看各自的設定)

與 GitHub 不同的是,GitLab Pages 並不是透過 push branch 的方式部屬, 且沒有針對特定 SSG 提供更進一步的自動部屬功能。

GitLab Pages 的使用方式是基於 GitLab CI Pipeline 的架構設計的。若想要部屬 網站,一般的使用方式是在 pipeline 內產生網頁,接著將網頁內容擺放至為特定 job (pages) 的特定 artifacts 目錄 (public) 中。 一旦有 pipeline jobs 達成此條件。 GitLab 就會 把網頁內容部屬到對應的網址下。

筆者個人使用的 job 描述檔如下: (因為 GitHub Action 與 GitLab CI 的架構差異,寫起來比較簡潔)

1
2
3
4
5
6
7
8
9
10
11
12
13
# .gitlab-ci.yml
pages:
image: ruby:3.0.1
stage: deploy
before_script:
- bundle install
script:
- bundle exec jekyll build --destination public --baseurl "$CI_PAGES_URL"
artifacts:
paths:
- public
only:
- master

至於其他 GitHub Pages 有的功能,如 custom domain,自動申請 HTTPS 憑證等,GitLab Pages 也都有。 記得去 project 設定頁面設定即可。

Conclusion

在 2008 年 GitHub Pages 剛推出時,使用者都要自己手動 push gh-pages branch。 後來 GitLab 推出基於 GitLab CI 的 Pages 服務之後,GitHub Pages 使用體驗相較之下可說是非常糟糕。

但後來隨著 GitHub Actions 服務推出,以及社群維護的高品質 Pages 部屬 Action 出現。 GitHub / GitLab Pages 的使用體驗已經變得相當接近。 其他像是 custom domain 以及 HTTPS 的支援也都是免費的基本功能。

基於上述原因,許多早期的 比較文章 其實已經沒什麼參考價值。 若現在想架設新的 blog 等站台,只要選擇自己習慣的平台即可。

References

GitHub 即日起支援使用 Security Key 進行 Git 操作

GitHub 開始支援使用 security key 進行 Git 操作啦!

這應該是各家科技巨頭當中,第一個支援 security key 進行 SSH login 的服務吧。 筆者昨天 5/10 才在公司內分享如何使用 security key 來做 SSH login, 沒想到 Yubico 和 GitHub 也剛好在昨天一起同步更新 blog 文章,通知大家這個新功能。 喜極而泣..

以下簡單介紹如何使用這個新功能。 為了方便解說及避免誤會,後述內容均以正式名稱 authenticator 代稱 security key。

如何使用

首先當然要有一把 authenticator,如果還沒有,趕快去買一把囉。 :D

第一步,在 authenticator 內產生新的 key pair。

產生 key pair 的流程和傳統放在檔案系統上的差不多,只是 key type 要指定代表 authenticator 的 type。

1
ssh-keygen -t ecdsa-sk

產生的過程,根據不同的 authenticator,會有要求按一下 且/或 輸入 PIN code 驗證身分。 此步驟會在 authenticator 內產生一組 key pair,並將 public key 寫到檔案系統上。 平常放 private key 的那個檔案還是會產生,不過這次裡面放的會是一個 key handle。

第二步,透過 GitHub 的 web UI 上傳 public key

上傳完之後,沒意外就可以順利使用了,可以試著 clone 一些 project

1
2
3
4
$ git clone git@github.com:github/secure_headers.git
Cloning into 'secure_headers'...
Confirm user presence for key ECDSA-SK SHA256:........
User presence confirmed

若確認 OK,之後的 Git 操作都可以透過隨身攜帶的 authenticator 保護, 只要按一下 authenticator 即可。

設定完之後,若沒有拿出 authenticator,就不能進行 push / pull 操作。 只要確保 authenticator 還在身上,就可以安心睡大覺。 (再也不用擔心 private key 放在公司電腦上會被摸走了!)

進階使用方式

FIDO 2 authenticator 博大精深,除了上述的基本使用流程外,還有些細節可以設定。

以下分別介紹三個進階使用技巧:

要求身分驗證 (User Verification) 才能使用 Authenticator

根據每個人平常保管鑰匙習慣的差異,可能有人會擔心 authenticator 真的被摸走。

但 authenticator 也有支援一定要驗甚身分 (e.g. PIN code or 指紋辨識) 後才能 使用內部的 key pair 的功能。

要如何使用呢? 只要在產生 key pair 的過程中多下一個 flag 即可。

1
ssh-keygen -t ecdsa-sk -O verify-required

若之後要使用由此方式產生的 key pair,除了手指按一下 authenticator 之外,還會要求 使用者輸入 PIN code 才能順利完成操作。如此即使 authenticator 被偷走了,也不用太緊張。

全自動使用 Authenticator (避免 User Presence Check)

若把 authenticator 插上電腦後,想要隨時隨地都進行 push / pull, 但不要每次都手按一下 authenticator。這種自動化的使用情境 OpenSSH 其實也是有支援的。

使用的方式也是在產生 key pair 時多帶一個參數。

1
ssh-keygen -t ecdsa-sk -O no-touch-required

同時在將 public key 部屬到目標機器上時,在 public key 該行前面多下 no-touch-required 即可。 (詳情請見 ssh-keygen(1)sshd(8))

以此方始產生的 key pair 在使用時就不需要每次都手按一下,可以全自動使用。

不過,雖然 OpenSSH 有支援此種使用情境,但目前 GitHub 禁止這種使用方式

節錄自上述 blog 文章

While we understand the appeal of removing the need for the taps, we determined our current approach to require presence and intention is the best balance between usability and security.

所以在 GitHub 上,若想要全自動操作,只能回去用一般的 SSH key 或 API token 囉。

避免手動複製 Key Handle

前面有提到,原先檔案系統上用來放 private key 的檔案會變成拿來擺放 key handle。

這意味著,當我們想在新的機器上透過 SSH 進行 Git 操作時,除了拿出 authenticator 之外, 也需要把原先的 key handle 檔案複製到新的機器上。 且若 key handle 檔案掉了,該組 key pair 就不能使用了。

若要避免此問題,就要用上 authenticator 的另一個進階功能 discoverable credentials / resident keys 。

1
ssh-keygen -t ecdsa-sk -O resident

使用此類型的 key pair 時,會在 authenticator 上消耗一些儲存空間。但換來的好處是, 使用者可以在新的機器上,把 key handle 從 authenticator 內抽出來。

1
ssh-keygen -K # extract discoverable credentials

如此就不用手動複製擺放 key handle 的 private key 檔案了。

但要注意的是此類型 key pair 會消耗 authenticator 的空間。 每把 authenticator 可以放多少 key pair 要再自行查閱官方文件。

結語

以上介紹了基本使用情境及三種可能的進階使用方式。

筆者在 2014 年第一次注意到 FIDO (U2F) 標準,當時就在想像沒有密碼的世界。 如今,藉由 FIDO 2 security key 的普及,當初所想的美好願景似乎在慢慢地實現中..

希望未來能看到 security key 運用在更多場景上!

在 macOS 上架設 Apache 與 PHP-FPM

工作上因為一些特殊需求,需要在 macOS 環境下架設 Apache + PHP-FPM 的使用環境。好在 macOS 本來就有預裝 Apache 以及 PHP-FPM,並提供 Apache 的 launchd 設定檔,要在 macOS 上架設這個服務並不困難。

本文介紹如何以最低限度的設定,在 macOS 上跑 Apache + PHP-FPM。以筆記的方式呈現,不會有太多的講解。

Notes

  • 筆者是在 macOS 10.14 與 10.15 上測試此流程
  • macOS 系統上,/etc 是一個 symblic link 連至 /private/etc/var, /tmp 也有相同行為。

設定與啟用 PHP-FPM

複製並修改 PHP-FPM 設定檔

系統內有會自帶 PHP-FPM 的 default 設定檔,將其複製一份出來,並修改內容。

1
2
$ sudo cp /etc/php-fpm.conf.default /etc/php-fpm.conf
$ sudo cp /etc/php-fpm.d/www.conf.default /etc/php-fpm.d/www.conf

將執行身分從 nobody 修改為 _www (與 Apache httpd一致)。

1
$ sudo vim /etc/php-fpm.d/www.conf
1
2
3
4
5
; Unix user/group of processes
; Note: The user is mandatory. If the group is not set, the default user's group
; will be used.
user = _www
group = _www

修改 error_log,調整 log file 的路徑。

1
$ sudo vim /etc/php-fpm.conf
1
2
3
4
5
6
; Error log file
; If it's set to "syslog", log is sent to syslogd instead of being written
; into a local file.
; Note: the default prefix is /usr/var
; Default Value: log/php-fpm.log
error_log = /var/log/php-fpm.log

新增 PHP-FPM 的 launchd 設定檔並啟用

創一個 launchd daemon 設定檔給 PHP-FPM 使用, 此舉目的為讓 PHP-FPM daemon 可以在 macOS 開機時自己啟用。

建議將設定檔放在 /Library/LaunchDaemons 下,參照 launchd 的文件, 此位置是供第三方軟體擺放 daemon 設定使用。

1
$ sudo vim /Library/LaunchDaemons/com.example.php-fpm.plist
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Disabled</key>
<true/>
<key>Label</key>
<string>com.example.php-fpm</string>
<key>ProgramArguments</key>
<array>
<string>/usr/sbin/php-fpm</string>
<string>--nodaemonize</string>
</array>
<key>OnDemand</key>
<false/>
</dict>
</plist>

做好設定檔之後,用 launchctl 指令 load 此設定檔,並下參數告訴 macOS 之後此 daemon 要在開機時預設啟用。

1
$ sudo launchctl load -w /Library/LaunchDaemons/com.example.php-fpm.plist

上述指令執行完後, launchd 會把 PHP-FPM daemon 叫起。

1
2
3
4
$ ps aux | grep php
_www 515 0.0 0.0 4297608 648 ?? S 6:18PM 0:00.00 /usr/sbin/php-fpm
_www 514 0.0 0.0 4305800 628 ?? S 6:18PM 0:00.00 /usr/sbin/php-fpm
root 513 0.0 0.0 4305800 784 ?? Ss 6:18PM 0:00.00 /usr/sbin/php-fpm

設定並啟用 Apache Web Server

修改設定檔,讓 Apache 使用 proxy_moduleproxy_fcgi_module, 並確認 php7_module 沒被啟用。

需要本文的讀者應該不至於把 Apache PHP module 與 PHP-FPM 搞混.. XD

1
$ sudo vim /etc/apache2/httpd.conf
1
2
3
LoadModule proxy_module libexec/apache2/mod_proxy.so
LoadModule proxy_fcgi_module libexec/apache2/mod_proxy_fcgi.so
# LoadModule php7_module libexec/apache2/libphp7.so

<Directory "/Library/WebServer/Documents"> 或其他需要的地方內, 加入 PHP 的 handler,指向 PHP-FPM 預設提供服務的 socket。

1
2
3
4
5
6
7
<Directory "/Library/WebServer/Documents">
... 上略
<FilesMatch \.php$>
SetHandler "proxy:fcgi://localhost:9000/"
</FilesMatch>
</Directory>

Apache 的 daemon config 本來就存在於系統目錄內,但 Disable 的值被設為 true, 用下述 command 將 Apache daemon load 進 launchd 內,並讓 launchd 記錄此 daemon 應被啟用。

1
sudo launchctl load -w /System/Library/LaunchDaemons/org.apache.httpd.plist

與 PHP-FPM 相同,此指令下去之後,launchd 就會把 Apache 拉起。

此時可去 http://localhost/ 確認,如果看到大大的標題寫著

It works!

即代表 Apache 有順利執行。

確認 PHP-FPM 運作正常

丟一個 phpinfo 到 web server 的預設根目錄下。

1
$ sudo vim /Library/WebServer/Documents/phpinfo.php
1
2
3
<?php
phpinfo();
?>

之後連上 http://localhost/phpinfo.php ,看到 Server APIFPM/FastCGI 即可。 :D

利用 GitHub Page 經營 Blog

如果要用一句話來簡單說明 GitHub Page,那基本上就是

指定一個 Git 版本庫來作為存放網站資源的地方,然後讓 GitHub 幫你把網站架起來。

任何人只要申請一個 GitHub 帳號,都可以免費的享有這個服務。

當然,考量到 GitHub 只是把我們放在版本庫上的檔案,讓別人透過瀏覽器瀏覽, 那種需要用到資料庫的可互動網站基本上是很難達成。 但若我們只是要經營一個部落格,或是存放專案文件等靜態網站時,GitHub Page 就會是個很合適且方便的選擇。

本文會粗淺的介紹如何利用 GitHub Page 來經營自己的 Blog, 以省去自行架設機器的各種煩惱。 :D

GitHub Page 的類別

目前 GitHub Page 有兩類的站台,一類是 User Page、另一類是 Project Page。 (其實還有 Organization Page,但這邊就不花時間贅述) User Page 與 Project Page 最主要的差別在於專案名稱的限制,與網站的 URL 格式這兩點。簡單整理如下

User Page 特點:

  • 專案名稱須為 <username>.github.io,其中 <username> 即為 GitHub 帳號的使用者名稱。
  • 站台會擺在 http(s)://<username>.github.io 供他人瀏覽

Project Page 特點:

  • 專案名稱沒有限制。 若假設專案名稱為 <projectname>
  • 站台會擺在 http(s)://<username>.github.io/<projectname> 供他人瀏覽

因為專案名稱的限制,一個 GitHub 帳號只能有一個 User Page 但可以有多個 Project Page。

更詳細的介紹請參考 官方網站的說明

GitHub Page 使用方式

GitHub Page 的使用方式也可以簡單分成兩種。

第一種是直接建置好的整個網站直接 push 到 GitHub 上,供使用者瀏覽。 若我們需要架一個 Blog,可以先用 Markdown 等 markup language 撰寫文章, 之後利用 Jekyll(Ruby)、Hugo(Golang) 或 Hexo(JS) 等靜態網站生成工具, 建出一個 Blog 網站並 push 上去。 又或我們需要 host 一個專案文件站台時,可以將 Doxygen 或 Sphinx 等工具 產生出的網站推上 GitHub。

1
2
3
4
5
6
7
8
                                    +
Local Project | GitHub Project
| github.io site
+
+----------+ +--------+ +------+ User
| Markup | Build | Site | Push | Site | Browse
| config.. | +------> | | +-----> | | +------->
+----------+ +--------+ +------+

如果我們是使用 Jekyll 來建置我們的網站,那 GitHub Page 有提供我們第二種用法。 我們可以將 Markup 和其他 Jekyll 需要的設定檔 push 上 GitHub,讓 GitHub 幫我們 建置網站,並在 github.io 網域上放出網站供人瀏覽。

1
2
3
4
5
6
7
8
               +                    +
Local Project | GitHub Project | github.io site
| |
+ +
+----------+ +----------+ +------+ User
| Markup | Push | Markup | Build | Site | Browse
| config.. | +----> | Config.. | +-----> | | +------->
+----------+ +----------+ +------+

第二個做法的缺點是,GitHub 只支援 Jekyll 這套工具,其他同性質的工具的不支援。 但相對來說也有優點,即是我們不須把工具建出的網站內的所有檔案都進到 commit 中。 (在 git project 中看到許多無意義 diff 實在不是工程師所樂見的事情 XD)

針對這兩個方式的更詳細說明,也請見官方文件

簡單的流程說明

接下來會介紹使用 Jekyll,並讓 GitHub 幫忙 build 與 host 網站的簡單步驟。

參照 官方介紹 的說明,最簡單的方式,其實只需要 我們點開 project 的 GitHub 設定頁面,找到 GitHub Page 的設定選項,設定一個 Jekyll 使用的主題,並用 Markdown 寫一個首頁文章即可。

用此方法會在專案內產生首頁的 index.md 檔案及一個 Jekyll 的設定檔 _config.yml。 檔案內僅一行你選的主題名稱

1
theme: jekyll-theme-minimal

但基本上,一個 完整的 Jekyll 專案 不會只有這兩個檔案,到最後我們還是得把其他需要的檔案生出來。 所以個人推薦使用下述方法建立我們的專案。

(假設我們已經裝好 Git 和 Jekyll 等工具。)

建立 Git 專案

1
2
mkdir website && cd website
git init

在專案資料夾建立 Jekyll 的 template 檔案

1
jekyll new .

此時應該會看到 jekyll 預設產生的檔案

1
2
$ ls
404.html about.md _config.yml Gemfile Gemfile.lock index.md _posts

將所有產生的檔案 add 並 commit 起來 (要不要略過 Gemfile.lock 看個人需求)

1
2
git add .
git commit

之後將專案 push 上 GitHub,並至專案設定內啟用 GitHub Page 即可。 沒意外的話,大概十秒內就可以在對應的 URL 看到生成好的網站了。

有關 Jekyll 的安裝說明或其他細部設定,可參考 官方網站

在 GitHub Page 服務上使用個人客製的網址

如果不想使用 <username>.github.io 來提供自己的網站,而是透過自己購買的域名, 所需的麻煩差事 GitHub Page 也幫我們做得好了。

在 GitHub 專案開啟 GitHub Page 功能後,可以看到一個額外的選項 Custom domain, 可以填入我們可控制的 DNS hostname。

假設我們想在 blog.example.com 提供我們的網站,只需要在 DNS 設定中加入一筆 CNAME,將 blog.example.com 指向 <username>.github.io。並去 GitHub Page 所用的 GitHub 專案設定頁面內,在 Custom domain 欄位內填入 blog.example.com 即可。

設定完後,即可透過 blog.example.com 瀏覽我們要的網站。 同時 GitHub 也會在一天內生出對應的 SSL 憑證,即使透過 blog.example.com 瀏覽, 也可以享有 HTTPS protocol 帶來的安全性。 :D

雜談

大概從 2018 十月開始,小弟我在與朋友以及公司同事談話後,漸漸有了經營自己 Blog 的想法。

經歷了數週的拖拉散漫後,終於在 2018 十二月底刷卡買了自己的 domain,並利用 GitHub Page 架設好 Blog。但因為一直沒想好要寫什麼文章,於是第一篇就先來寫寫 我自己的架站筆記。

期許自己未來能不斷產出新文章,成為一位散發正面能量的一倍工程師。