Caddy 實戰(十一)- Caddyfile 設計之美

Caddyfile 是 Caddy 的核心配置文件,它的設計,關乎着我們使用,開發者的解析以及擴展,所以本篇着重的介紹 Caddy 是如何設計一個 Caddyfile 的,我們也可以從中學到如何設計一個配置文件,並且讓它更好的通用,更好的解析。

其實設計如此複雜的一個配置文件,已經和設計一門編程語言,很接近了。

結構

我前面的系統文章中,你也看到了如何使用 Caddyfile 的指令等功能,來滿足我們的需求的。在我們寫 Caddyfile 的時候,是遵循一定的規範的,哪些地方要怎麼寫,誰可以包含誰,這些規範就構成了 Caddyfile 的結構。

這張圖是瞭解 Caddyfile 的神器,它定了 Caddy 的規範以及結構,讓我們可以很方面的使用 Caddyfile。現在,我來介紹下里面的一些關鍵點:

看到最頂部的紅色框圈出來的這部分了嗎?這是一個全局配置,它在 Caddyfile 的最頂部,用於配置一些通用的全局信息。當然它並不是必須的,你也可以不用配置它。

第二部分的 snippet 是一個可以複用的片段,你可以在其他地方通過 import 來引入它,這非常適用於你的 Caddyfile 中有很多重複配置的情況。它和全局配置的差別在於 { 前面有一對小括號,用於定義可複用片段的名字,這樣你纔可以在其他地方通過這個名字引用。下面我通過一個例子來說明它的使用,如下所示:

(static_file){
  root * /var/www/mysite
  file_server 
}

www.example.com{
  import static_file
}
www.example.com{
  import static_file
}

接下來就是 Site Block 了,也就是定義你的站點的塊,在 Apache 中叫虛擬主機。寫到這裏你可以看到,Caddyfile 只有這三個頂級的定義塊,一個全局配置、一個可複用的片段、一個就是站點配置,其他所有的配置,都要放在這三個頂級的配置中。

你可以通過站點塊定義多個站點,但是他們之間沒什麼關係。如果你只有一個站點,你可以省略站點後面的大括號, 比如下面兩種定義是等價的:

localhost

reverse_proxy /api/* localhost:9001
file_server

等價於:

localhost {
    reverse_proxy /api/* localhost:9001
    file_server
}

因爲整個 Caddyfile 中只有這麼一個站點,所以大括號是可選的。

... {
    ...
}
example1.com {
    root * /www/example.com
    file_server
}
example2.com {
    reverse_proxy localhost:9000
}

指令

localhost
reverse_proxy localhost:9000 localhost:9001 {
    lb_policy first
}

Caddyfile 解析

directive abc def

以上可能會返回異常,或者其他不可預知的行爲。如果 abc def 是一個單獨參數的話,最安全的做法就是使用引號,這樣 Caddy 的詞法分析器,就不會把他們當成兩個標記 (Token)。

directive "abc def"
directive "\"abc def\""

這裏還有一個辦法,就是使用反引號:

directive `"foo bar"`

效果是等價的,反引號尤其是包含引號的文本中使用非常方便,比如 JSON 字符串等。

地址

地址就是站點塊的頂部那部分,通常也是 Caddyfile 的第一個內容。Caddy 基本上支持所有的地址樣式,如下常用示例:

  1. localhost

  2. example.com

  3. :443

  4. http://example.com

  5. localhost:8080

  6. 127.0.0.1

  7. example.com/foo/*

  8. *.example.com

  9. http://

根據地址,Caddy 可以推斷出站點的 Scheme、Host、Port 和 Path。

如果指定主機名,則只接受具有匹配主機頭的請求。換句話說,如果站點地址是 localhost ,那麼 Caddy 將不會將請求與 127.0.0.1 匹配,因爲 127.0.0.1 的請求主機頭不是localhost , 沒法匹配。

Caddy 允許在地址中使用通配符 (*), 但是它也有嚴格的限制:它只用來匹配主機名。比如 *.example.com 可以匹配 foo.example.com ,但不匹配 foo.bar.example.com 。

你也可以讓多個站點地址共享同一個定義,只需要使用逗號分隔這些地址即可。

localhost:8080, example.com, www.example.com

最後,地址必須唯一,不能多次指定同一個地址。

請求匹配

一個客戶端請求過來,Caddy 是怎麼處理的呢?比如用哪個指令來處理,這就需要設置匹配器了,通過匹配器,你可以精確的設置某個指令用於哪些請求。

如果不設置,默認情況下,該指令適用於所有請求。

指令後的第一個參數是匹配器,比如:

root *           /var/www  # matcher token: *
root /index.html /var/www  # matcher token: /index.html
root @post       /var/www  # matcher token: @post

* 表示匹配所有,這裏的 @post 是一個定義的匹配器,可以被引用、複用。匹配器的定義,詳見我們結構那部分的截圖。

以上示例其實代表了三種匹配器:通配符匹配器、路徑匹配器和命名匹配器,更多的關於請求匹配器的說明可以詳見 https://caddyserver.com/docs/caddyfile/matchers ,這裏不再贅述。

佔位符

使用 Nginx 的時候,我們會看到有 $ 開頭的變量,它就是佔位符,是一種將動態值注入靜態配置的方法,通過它可以讓我們更靈活的配置 Nginx。同樣的,Caddy 也有佔位符的功能,便於我們配置 Caddyfile。

在 Caddyfile 中,佔位符的兩邊用大括號 {} 限定,並在其中包含變量名,例如: {foo.bar} 。佔位符大括號可以轉義, \{like so\} 。變量名通常用點命名,以避免模塊之間的衝突。

你可以在 Caddyfile 中使用任何 Caddy 佔位符,但爲了方便起見,您也可以使用一些等效的速記佔位符:

oZF8HA

並非所有佔位符在配置的所有部分都可用,哪些佔位符可用取決於上下文。例如,HTTP 應用程序設置的佔位符僅在與處理 HTTP 請求相關的配置區域中可用。

片段

在結構部分我簡單的介紹過片段,它是一個可以複用的配置,使用 import 導入實現複用。

(redirect) {
    @http {
        protocol http
    }
    redir @http https://{host}{uri}
}

片段是頂級配置,片段定義的開頭是片段的名稱,使用小括號 () 括起來。定義好一個片段後,就可以通過 import 使用給它了。

import redirect

除了複用之外,片段的另一個強大之處在於可以傳參給片段,實現動態化配置。

(snippet) {
  respond "Yahaha! You found {args.0}!"
}
a.example.com {
    import snippet "Example A"
}
b.example.com {
    import snippet "Example B"
}

使用非常簡單,通過 {args.0} 可以獲得傳遞過來的第一個參數。

環境變量

在 Caddyfile,你也可以使用環境變量,這樣可以讓你的配置更靈活。

使用環境變量也非常簡單,和佔位符差不多,也是一個大括號包裹,但是多一個 $ 符號。

{$SITE_ADDRESS}

這種形式的環境變量在解析開始之前被替換,因此它們可以擴展爲空值、部分標記、完整標記,甚至多個標記和行。和 C 語言的 define 一樣,是不是很強大。
在具體的代碼實現上,Caddy 是使用 Go 語言的 os.LookupEnv 方法獲取環境變量的。

那麼,如果忘記配置環境變量怎麼辦呢?別急,這點 Caddy 肯定考慮到了,我們在使用環境變量的時候,可以設置一個默認值,如果找不到環境變量的時候,會使用這個默認值。

{$DOMAIN:localhost}

Caddyfile 是使用 : 來分隔環境變量名稱和默認值的,以上示例中,默認值是 localhost 。

註釋

Caddyfile 是支持註釋的,這樣我們就可以增加點註釋,便於多人協作和理解。在 Caddyfile 中,註釋以 # 開頭,直到行的末尾。

# Comments can start a line
directive  # or go at the end

小結

這篇主要介紹了 Caddyfile 的規範以及設計,這也是一個比較完整的配置文件的設計,看了這篇相信你不光可以很好的理解 Caddyfile 並使用它,也可以很好的理解 Nginx 的 conf 配置,因爲都差不多。

一個配置文件的設計,牽涉到規範、可以擴展性、模塊化、可複用、變量,還得需要加載、替換、詞法分析等,這儼然已經是在定義一門腳本言語了,所以如果你有編譯器的功底,也能更好的理解 Caddyfile 的設計和解析。

本文爲原創文章,轉載註明出處, 歡迎掃碼關注公衆號flysnow_org或者網站 https://www.flysnow.org/ ,第一時間看後續精彩文章。覺得好的話,請猛擊文章右下角「在看」,感謝支持。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/3pNMzRdxIcURZ7jBg8EwYQ