小白學k8s(8)-Bazel部署go應用


Bazel使用了解

Bazel產生的背景

1、開源成為當前軟件開發的主旋律。哪怕你是商業軟件,也逃離不了社區的包圍。如何方便地獲取依賴,並做到平滑升級很重要。如果構建工具能夠很方便地獲取源代碼,那就太好了。

2、混合多語言編程成為一種選擇。每種語言都有自己適用的場景,但是構建多語言的軟件系統非常具有挑戰性。例如,Python社區很喜歡搭配C/C++,高性能計算扔個C/C++,Python提供編程接口。如果構建工具能夠無縫支持多語言構建,真的很方便。

3、代碼復用。我只想復用第三方的一個頭文件,而不是整個系統。拒絕拷貝是優秀程序員的基本素養,如果構建工具能幫我方便地獲取到所依賴的組件,剔除不必要的依賴,那就太完美了。

4、增量構建。當只修改了一行代碼,構建系統能夠准確計算需要構建的依賴目標,而不是全構建;否則生命都浪費在編譯上了。

5、雲構建。大型軟件公司,復用計算資源,可以帶來巨大的收益。

什么是Bazel

Bazel是一個支持多語言、跨平台的構建工具。Bazel支持任意大小的構建目標,並支持跨多個倉庫的構建,是Google主推的一種構建工具。

bazel優點很多,主要有

  • 構建快。支持增量編譯。對依賴關系進行了優化,從而支持並發執行。

  • 可構建多種語言。bazel可用來構建Java C++ Android ios等很多語言和框架,並支持mac windows linux等不同平台

  • 可伸縮。可處理任意大小的代碼庫,可處理多個庫,也可以處理單個庫

  • 可擴展。使用bazel擴展語言可支持新語言和新平台。

快(Fast)

Bazel的構建過程很快,它集合了之前構建系統的加速的一些常見做法。包括:

1、增量編譯。只重新編譯必須的部分,即通過依賴分析,只編譯修改過的部分及其影響的路徑。

2、並行編譯。將沒有依賴的部分進行並行執行,可以通過--jobs來指定並行流的個數,一般可以是你機器CPU的個數。遇到大項目馬力全開時,Bazel能把你機器的CPU各個核都吃滿。

3、分布式/本地緩存。Bazel將構建過程視為函數式的,只要輸入給定,那么輸出就是一定的。而不會隨着構建環境的不同而改變(當然這需要做一些限制),這樣就可以分布式的緩存/復用不同模塊,這點對於超大項目的速度提升極為明顯。

可伸縮(scalable)

Bazel號稱無論什么量級的項目都可以應對,無論是超大型單體項目monorepo、還是超多庫的分布式項目multirepoBazel還可以很方便的集成CD/CI ,並在雲端利用分布式環境進行構建。

它使用沙箱機制進行編譯,即將所有編譯依賴隔絕在一個沙箱中,比如編譯golang項目時,不會依賴你本機的GOPATH,從而做到同樣源碼、跨環境編譯、輸出相同,即構建的確定性。

跨語言(multi-language)

如果一個項目不同模塊使用不同的語言,利用Bazel可以使用一致的風格來管理項目外部依賴和內部依賴。典型的項目如 Ray。該項目使用C++構建Ray的核心調度組件、通過Python/Java來提供多語言的API,並將上述所有模塊用單個repo進行管理。如此組織使其項目整合相當困難,但Bazel在此處理的游刃有余,大家可以去該repo一探究竟。

可擴展(extensible)

Bazel使用的語法是基於Python裁剪而成的一門語言:Startlark。其表達能力強大,往小了說,可以使用戶自定義一些rules(類似一般語言中的函數)對構建邏輯進行復用;往大了說,可以支持第三方編寫適配新的語言或平台的rules集,比如rules goBazel並不原生支持構建golang工程,但通過引入rules go ,就能以比較一致的風格來管理golang工程。

Bazel中的主要文件

使用Bazel管理的項目一般包含以下幾種Bazel相關的文件:WORKSPACE,BUILD(.bazel),.bzl.bazelrc 等。其中 WORKSPACE.bazelrc 放置於項目的根目錄下,BUILD.bazel 放項目中的每個文件夾中(包括根目錄),.bzl文件可以根據用戶喜好自由放置,一般可放在項目根目錄下的某個專用文件夾(比如 build)中。

WORKSPACE

1、定義項目根目錄和項目名。

2、加載 Bazel 工具和 rules 集。

3、管理項目外部依賴庫。

BUILD.bazel

存在於根目錄以及源文件所在目錄,用來標記源文件編譯以及依賴情況,一般是自動生成。拿 go 來說,構建目標可以是 go_binary、go_test、go_library 等。

自定義 rule (*.bzl)

如果你的項目有一些復雜構造邏輯、或者一些需要復用的構造邏輯,那么可以將這些邏輯以函數形式保存在 .bzl 文件,供WORKSPACE或者BUILD文件調用。其語法跟Python類似:

def third_party_http_deps():
    http_archive(
        name = "xxxx",
        ...
    )

    http_archive(
        name = "yyyy",
        ...
    )

配置項 .bazelrc

對於Bazel來說,如果某些構建動作都需要某個參數,就可以將其寫在此配置中,從而省去每次敲命令都重復輸入該參數。舉個 Go 的例子:由於國情在此,構建、測試和運行時可能都需要GOPROXY,則可以配置如下:

# set GOPROXY
test --action_env=GOPROXY=https://goproxy.io
build --action_env=GOPROXY=https://goproxy.io
run --action_env=GOPROXY=https://goproxy.io

使用Bazel部署go應用

1、安裝Bazel

mac中直接通過brew安裝

$ brew install Bazel

centos中的安裝可參考centos7安裝bazel

2、安裝gazelle

$ go get github.com/bazelbuild/bazel-gazelle/cmd/gazelle

手動通過Bazel部署go應用

創建go的運行文件

package main

import "fmt"

func main() {
	fmt.Println("hello world")
}

創建WORKSPACE文件

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

# download rules_go
http_archive(
    name = "io_bazel_rules_go",
    sha256 = "8663604808d2738dc615a2c3eb70eba54a9a982089dd09f6ffe5d0e75771bc4f",
    urls = [
        "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.23.6/rules_go-v0.23.6.tar.gz",
        "https://github.com/bazelbuild/rules_go/releases/download/v0.23.6/rules_go-v0.23.6.tar.gz",
    ],
)

# load rules_go
load("@io_bazel_rules_go//go:deps.bzl", "go_rules_dependencies", "go_register_toolchains")

go_rules_dependencies()

go_register_toolchains()

# download gazelle
http_archive(
    name = "bazel_gazelle",
    sha256 = "cdb02a887a7187ea4d5a27452311a75ed8637379a1287d8eeb952138ea485f7d",
    urls = [
        "https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.21.1/bazel-gazelle-v0.21.1.tar.gz",
        "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.21.1/bazel-gazelle-v0.21.1.tar.gz",
    ],
)

# load gazelle
load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies", "go_repository")

gazelle_dependencies()

創建BUILD.bazel文件

load("@io_bazel_rules_go//go:def.bzl", "go_binary")

go_binary(
    name = "test",
    srcs = ["main.go"],
    importpath = "test",
    visibility = ["//visibility:private"],
)

查看目錄

test
├── BUILD.bazel
├── WORKSPACE
└── main.go

運行

$ bazel run //:test
DEBUG: /root/.cache/bazel/_bazel_root/1bc6a4d389355f502b77b0dd6dd1fdb4/external/bazel_tools/tools/cpp/lib_cc_configure.bzl:118:5: 
Auto-Configuration Warning: CC with -fuse-ld=gold returned 0, but its -v output didn't contain 'gold', falling back to the default linker.
INFO: Analyzed target //:test (0 packages loaded, 0 targets configured).
INFO: Found 1 target...
Target //:test up-to-date:
  bazel-bin/linux_amd64_stripped/test
INFO: Elapsed time: 0.254s, Critical Path: 0.00s
INFO: 0 processes.
INFO: Build completed successfully, 1 total action
INFO: Build completed successfully, 1 total action
hello world

成功輸出hello world

使用gazelle自動生成BUILD.bazel文件

在實際的項目中,里面的BUILD.bazel我們肯定是使用工具自動生成的,來看下如何自動生成的

創建t1和t2兩個文件夾,寫入兩個文件

package main

import "fmt"

func main() {
	fmt.Println("hello t1")
}

在項目的根目錄的BUILD.bazel中配置加載並配置Gazelle

load("@bazel_gazelle//:def.bzl", "gazelle")
# gazelle:prefix test  
gazelle(name = "gazelle") 

需要注意的是 # 后面的內容對於Bazel而言是注釋,對於Gazelle來說卻是一種語法,會被Gazelle運行時所使用。當然Gazelle除了可以通過bazel rule運行,也可以單獨在命令行中執行。

查看下目錄

test
├── BUILD.bazel
├── WORKSPACE
├── main.go
├── t1
│   └── main.go
└── t2
    └── main.go

在根目錄下面執行bazel run //:gazelle

test
├── BUILD.bazel
├── main.go
├── t1
│   ├── BUILD.bazel
│   └── main.go
├── t2
│   ├── BUILD.bazel
│   └── main.go
└── WORKSPACE

發現對應的目錄下面已經生成了我們需要的BUILD.bazel文件

在根目錄下,運行下

$ bazel run t1:t1
INFO: Analyzed target //t1:t1 (0 packages loaded, 0 targets configured).
INFO: Found 1 target...
Target //t1:t1 up-to-date:
  bazel-bin/t1/t1_/t1
INFO: Elapsed time: 0.486s, Critical Path: 0.33s
INFO: 3 processes: 1 internal, 2 darwin-sandbox.
INFO: Build completed successfully, 3 total actions
INFO: Build completed successfully, 3 total actions
hello t1

參考

【帶你深入AI(6)- 詳解bazel】https://blog.csdn.net/u013510838/article/details/80102438
【bazel文檔】https://docs.bazel.build/versions/4.1.0/skylark/concepts.html
【Bazel 構建 golang 項目】https://zhuanlan.zhihu.com/p/95998597
【如何評價 Google 開源的 Bazel ?】https://www.zhihu.com/question/29025960
【使用bazel編譯go項目】https://juejin.cn/post/6844903892757528590
【Bazel學習筆記】https://blog.gmem.cc/bazel-study-note


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM