使用 TypeScript 編寫 Dockerfile 和 CI 管道。
Trellis 是一款便攜式 CI/CD 工具。借助 Trellis,您可以在 TypeScript 中定義 Dockerfile 和 CI/CD 管道,並在任何地方(本地或託管平台上)運行它們。
首先,使用brew install deno
(或類似的)安裝Deno。
其次,安裝 Trellis CLI:
deno install
--allow-run=docker
--allow-net
--allow-write
--allow-env
--allow-read
https://deno.land/x/[email protected]/cli.ts
執行trellis --help
來驗證您的安裝:
>>> trellis --help
Usage: trellis build mod.ts
Options:
-V, --version output the version number
-h, --help display help for command
Commands:
ls [file] List all Images and Tasks available in a
TypeScript module
preview [options] [file] Generate a Dockerfile defined in a TypeScript
module
build [options] [file] Build an Image defined in a TypeScript module
run [options] [file] Run a Task defined in a TypeScript module
help [command] display help for command
匯出任何Image
以啟用 Dockerfile 產生和使用 Trellis 建置映像。
例如,要定義安裝了一些有用實用程式的 Ubuntu 映像,您可以編寫以下mod.ts
檔案:
import { Image } from "https://deno.land/x/[email protected]/mod.ts" ;
const UBUNTU_VERSION = "20.04" ;
export const buildStage = Image . from ( `ubuntu: ${ UBUNTU_VERSION } ` )
. workDir ( "/root" )
. aptInstall ( [
"curl" ,
"jq" ,
"git" ,
] ) ;
運行trellis ls mod.ts
列出可建構的圖像:
>>> trellis ls mod.ts
Images:
- buildStage (trellis build --target buildStage)
我們可以使用trellis preview mod.ts --target buildStage
預覽產生的 Dockerfile:
>>> trellis preview --target buildStage
# syntax=docker/dockerfile:1.4
FROM ubuntu:20.04 AS stage-0
WORKDIR /root
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked --mount=type=cache,target=/var/lib/apt,sharing=locked apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends curl git jq
我們可以使用trellis build --target buildStage
來建立鏡像:
>>> trellis build --target buildStage
[+] Building 0.6s (11/11) FINISHED
= > [internal] load build definition from Dockerfile 0.0s
= > = > transferring dockerfile: 335B 0.0s
= > [internal] load .dockerignore 0.0s
= > = > transferring context: 2B 0.0s
= > resolve image config for docker.io/docker/dockerfile:1.4 0.2s
= > CACHED docker-image://docker.io/docker/dockerfile:1.4@sha256:9ba7531bd80fb0a858632727cf7a112fbf 0.0s
= > [internal] load build definition from Dockerfile 0.0s
= > [internal] load .dockerignore 0.0s
= > [internal] load metadata for docker.io/library/ubuntu:20.04 0.2s
= > [stage-0 1/3] FROM docker.io/library/ubuntu:20.04@sha256:35ab2bf57814e9ff49e365efd5a5935b6915ee 0.0s
= > CACHED [stage-0 2/3] WORKDIR /root 0.0s
= > CACHED [stage-0 3/3] RUN --mount=type=cache,target=/var/cache/apt,sharing=locked --mount=type=c 0.0s
= > exporting to image 0.0s
= > = > exporting layers 0.0s
= > = > writing image sha256:17f750ba9a4becf38ce4d584d0de4793bfd6a8139674c3b332cdcdf6525ea8d9 0.0s
= > = > naming to docker.io/trellis/db112e211de238c035a9fd3bbcbd5c417aafc5ee96a8c24d99d4caf81a759903 0.0s
√ Build: trellis/db112e211de238c035a9fd3bbcbd5c417aafc5ee96a8c24d99d4caf81a759903
從 TypeScript 模組匯出任何函數,以支援使用 Trellis 執行任務。
例如,要定義 CI 管道來驗證我們的命令列實用程式是否已成功安裝,您可以編寫以下tasks.ts
檔案:
import { build , Image , run } from "https://deno.land/x/[email protected]/mod.ts" ;
import { buildStage } from "./mod.ts" ;
export default async function runChecks ( ) {
await build ( buildStage ) ;
const checkCurl = Image . from ( buildStage ) . run (
"curl --help" ,
) ;
const checkJq = Image . from ( buildStage ) . run (
"jq --help" ,
) ;
const checkGit = Image . from ( buildStage ) . run (
"git --help" ,
) ;
await Promise . all ( [
run ( checkCurl ) ,
run ( checkJq ) ,
run ( checkGit ) ,
] ) ;
}
運行trellis ls tasks.ts
列出可執行任務:
>>> trellis ls tasks.ts
Tasks:
- default (trellis run tasks.ts)
我們可以使用trellis run tasks.ts
在本地執行任務:
>>> trellis run tasks.ts
[+] Building 1.1s (13/13) FINISHED
= > [internal] load build definition from Dockerfile 0.0s
= > = > transferring dockerfile: 335B 0.0s
= > [internal] load .dockerignore 0.0s
= > = > transferring context: 2B 0.0s
= > resolve image config for docker.io/docker/dockerfile:1.4 0.5s
= > [auth] docker/dockerfile:pull token for registry-1.docker.io 0.0s
= > CACHED docker-image://docker.io/docker/dockerfile:1.4@sha256:9ba7531bd80fb0a858632727cf7a112fbf 0.0s
= > [internal] load .dockerignore 0.0s
= > [internal] load build definition from Dockerfile 0.0s
= > [internal] load metadata for docker.io/library/ubuntu:20.04 0.3s
= > [auth] library/ubuntu:pull token for registry-1.docker.io 0.0s
= > [stage-0 1/3] FROM docker.io/library/ubuntu:20.04@sha256:35ab2bf57814e9ff49e365efd5a5935b6915ee 0.0s
= > CACHED [stage-0 2/3] WORKDIR /root 0.0s
= > CACHED [stage-0 3/3] RUN --mount=type=cache,target=/var/cache/apt,sharing=locked --mount=type=c 0.0s
= > exporting to image 0.0s
= > = > exporting layers 0.0s
= > = > writing image sha256:17f750ba9a4becf38ce4d584d0de4793bfd6a8139674c3b332cdcdf6525ea8d9 0.0s
= > = > naming to docker.io/trellis/adf8a603d1ab539848d89f68491e1b9213c1ca498f3f68d871e1b59c4c7de601 0.0s
√ Build: trellis/adf8a603d1ab539848d89f68491e1b9213c1ca498f3f68d871e1b59c4c7de601
√ Run: git --help
√ Run: jq --help
√ Run: curl --help
Trellis 可以透過trellis.config.ts
檔案進行配置,其基本語意是根據 Vite 建模的。
trellis.config.ts
應包含一個由defineConfig
呼叫組成的預設導出,如下所示:
import { defineConfig } from "https://deno.land/x/[email protected]/mod.ts" ;
export default defineConfig ( {
engine : "docker" ,
} ) ;
Trellis 將使用最接近的trellis.config.ts
,首先在當前工作目錄中查找,然後在每個後續父目錄中查找。
Trellis 與 depot.dev 相容,可用於實現零配置的雲端加速建置。執行 Depot 安裝( brew install depot/tap/depot
或類似的,然後是depot login
),然後定義一個trellis.config.ts
,如下所示:
import { defineConfig } from "https://deno.land/x/[email protected]/mod.ts" ;
export default defineConfig ( {
engine : {
type : "depot" ,
project : "${YOUR_PROJECT_ID}" ,
} ,
} ) ;
從那裡開始,所有 Trellis 構建都將通過 Depot 運行。
Trellis 在 Deno 上運行,使其成為 GitHub Actions 上的一步安裝:
name : CI
on :
push :
branches : [ main ]
pull_request :
branches : [ main ]
env :
DOCKER_BUILDKIT : 1
jobs :
build :
name : " Build "
runs-on : ubuntu-latest
steps :
- uses : actions/checkout@v3
- name : " Install Deno "
uses : denoland/setup-deno@v1
with :
deno-version : " 1.25.2 "
- name : " Install Trellis "
working-directory : ./trellis
run : deno install --allow-run=docker --allow-net --allow-write --allow-env --allow-read https://deno.land/x/[email protected]/cli.ts
- name : " Build the image "
working-directory : ./examples/typescript
run : trellis build trellis/mod.ts
Trellis 的動機來自以下觀察,這些觀察來自維護大型容器化 CI/CD 系統的經驗。
Dockerfile 很難維護。隨著時間的推移,大型系統往往會累積具有相似子部分但沒有共享抽象的 Dockerfile 集合。
高效的Dockerfile 很難編寫。編寫一個可最大程度地快取且佔用空間最小的 Dockerfile 需要大量的專業知識。例如,對於apt-get install
,Docker 文件建議如下:
RUN apt-get update && apt-get install -y
# Be sure to sort dependencies to maximize cacheability.
bzr
cvs
git
mercurial
subversion
# Clear the apt cache to minimize disk size.
&& rm -rf /var/lib/apt/lists/ *
CI/CD迭代循環太慢。編寫新的 GitHub Actions 管道、Jenkinsfile 等的常見工作流程是提交、推送、等待系統確認您的更改,然後等待您的任務失敗——連續數十次甚至數百次。使用現有的 CI 解決方案,您編寫的程式碼要在不熟悉的系統上運行,不受您的控制,並且沒有一流的開發工作流程。
CI/CD 系統產生了顯著的鎖定。將 Jenkinsfiles 或 YAML 檔案移植到 GitHub Actions(反之亦然)需要處理特定於平台的抽象。
Trellis 透過一些重要的設計決策解決了這些問題。
首先:使用 Trellis,您可以在 TypeScript 中定義 Dockerfile 和 CI/CD 管道。這為您提供了「完整」程式語言的強大功能,同時保留了聲明性 API。使用 TypeScript,我們可以獲得以下好處:
apt-get install
步驟。deno.land
導入 Slack 客戶端一樣簡單。第二: Trellis 讓本地執行成為一流的原語。 CI/CD 不應該感覺像是一個完全獨立的系統;它應該感覺像運行程式碼。 Trellis 建構於 Deno 之上,並且高度可移植。您可以在本地運行trellis build
,就像在 GitHub Actions 或其他地方運行一樣。透過這種方式,Trellis 從 Earthly 和 Dagger 等工具中獲得了靈感。
Trellis 有一些尚未實現的理想目標:
Trellis 既是一個函式庫,也是一個命令列介面。使用 Trellis,您可以從 TypeScript 模組匯出Image
定義和可運行函數(稱為「任務」),然後透過trellis
CLI 執行它們。
trellis preview
產生在 TypeScript 模組中定義的 Dockerfile。
Usage: trellis preview [options] [file]
Generate a Dockerfile defined in a TypeScript module
Options:
-t, --target < TARGET > Image to build within the TypeScript module
-h, --help display help for command
trellis build
建立在 TypeScript 模組中定義的映像。
Usage: trellis build [options] [file]
Build an Image defined in a TypeScript module
Options:
-t, --target < TARGET > Image to build within the TypeScript module
--push Whether to push the image to a remote registry
-h, --help display help for command
trellis ls
列出 TypeScript 模組中可用的所有映像和任務。
Usage: trellis ls [options] [file]
List all Images and Tasks available in a TypeScript module
Options:
-h, --help display help for command
trellis run
執行 TypeScript 模組中定義的任務。
Run a Task defined in a TypeScript module
Options:
-t, --target <TARGET> Task to run within the TypeScript module
-h, --help display help for command
./examples
目錄演示了 Trellis 的各種用例。 Trellis 非常靈活,可以單獨用於為其他系統產生 Dockerfile,或定義整個 CI/CD 管道。
rocket
:Rocket 框架之上的 Rust 網路伺服器。利用trellis preview
透過 Fly.io 演示多階段建置和部署。ruff
:Rust 命令列工具。演示高效的建置和 CI 檢查。runc
:Linux 開發容器。示範使用 Trellis 產生工件並將其複製回主機。turborepo
:Turborepo 自己的 Docker 範例,經過修改以使用 Trellis 產生 Dockerfile。typescript
:TypeScript monorepo。示範高效的建置和 CI 檢查,以及合併常數(如 TypeScript 工作區清單)。wasm
:“你好,世界!”編譯為 Wasm 並在 Wasmtime 上測試的 Rust 二進位。 Trellis 建構於 Deno 之上,Deno 作為單一二進位可執行檔分發,沒有外部相依性。使用 Deno 意味著在任何地方安裝 Trellis 都和deno install ...
一樣簡單——沒有package.json
,沒有npm install
,也沒有 TypeScript 轉譯步驟。
與 Nixpacks 類似,Trellis 產生 Dockerfile。這簡化了 Trellis 的實施,但也使用戶能夠利用 Trellis 單獨產生 Dockerfile,而不是作為完整的 CI/CD 解決方案。
trellis build
和trellis run
依賴 Docker,並假設 Docker 守護程式可在本地存取。
麻省理工學院