Go構建遇到cgo動態庫時解決方案

1. 問題

  1. golang構建程序很簡單,當遇到需要調用c庫時,如通常使用 net,kafka, sqlite3 程序運行時就會調用當前服務器的 動態庫,如果遇到沒有庫時,通常還需要 下載比如 alpine需要安裝sqlite

     apk add --no-cache sqlite-libs sqlite-dev
    
  2. 通常我們構建時使用CGO_ENABLED=1 就能在構建時將代碼需要調用C庫用動態連接的形勢供代碼調用

     CGO_ENABLED=1 go build -ldflags "-s -w" -o perception_node ./cmd/
    

  3. 但是這裏面會有個問題,如果將編譯好的 二進制文件移植到其他服務器,但是服務器上面的動態庫版本又和構建時的動態庫版本不一樣, 或者動態庫的路徑不一樣。可能有想到,升級c庫,或降低版本。但是一旦升級或降級C庫,很可能導致服務器上原來的服務受影響。


2. 解決

如何解決:

  1. 使用 golang 的 kafka 庫:開發人員需要更改代碼以切換使用的 kafka sdk。這可以作爲替代方案。
  2. 降低 golang:latest 的 glibc 版本:發行版通常修復 glibc 以編譯其他工具鏈,替換 glibc 是不明智的。雖然有這樣的工具yum downgrade glibc*可以幫助解決這個問題。
  3. 更改爲舊的 glibc 映像:同樣,您無法避免一堆舊的 bash 腳本。
  4. 靜態鏈接 c 依賴項

綜上所述,使用最新的鏡像來編譯,但是會依賴所有的靜態鏈接,這樣一編譯完成後就不用擔心c庫兼容的問題, 如果使用 glibc,則它不是靜態可鏈接的。

因爲 glibc 依賴於支持不同提供程序的 libnss,所以它必須動態鏈接。

  1. 所以這裏替換glibc的唯一方法就是使用musl。librdkafka和 golang 包confluent-kafka-go都支持 musl 構建(構建時指定 –tags musl 即可) alpine 是基於 musl 的發行版,所以這裏可以直接用 alpine Linux 構建。

  2. 然後指定外部 ld-staticfor 標誌,編譯後的二進制文件將完全靜態鏈接。編譯過程如下。

    $  docker run -it -v $(pwd):/workspace  golang:1.18-alpine
    /go $ cd /workspace/
    /workspace $ sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \
    >     apk add git openssh make build-base alpine-sdk
    fetch https://dl-cdn.alpinelinux.org/alpine/v3.14/main/x86_64/APKINDEX.tar.gz
    fetch https://dl-cdn.alpinelinux.org/alpine/v3.14/community/x86_64/APKINDEX.tar.gz
    (1/37) Installing fakeroot (1.25.3-r3)
    (2/37) Installing openssl (1.1.1l-r0)
    (3/37) Installing libattr (2.5.1-r0)
    (4/37) Installing attr (2.5.1-r0)
    (5/37) Installing libacl (2.2.53-r0)
    (6/37) Installing tar (1.34-r0)
    (7/37) Installing pkgconf (1.7.4-r0)
    ...
    $ export GOPROXY="https://goproxy.cn"
    /workspace $ go build -ldflags "-linkmode external -extldflags '-static'" -tags musl -o  perception_node ./cmd/
    /workspace $ ldd  perception_node
    /lib/ld-musl-x86_64.so.1: spex: Not a valid dynamic program
    
  3. windows下使用如下指令

    $ docker run -it -v $(pwd):/workspace  golang:1.18-alpine
    /go $ cd /workspace/
    /workspace $ sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories 
    $ apk add openssh make build-base alpine-sdk mingw-w64-gcc musl-dev gcc build-base
    fetch https://dl-cdn.alpinelinux.org/alpine/v3.14/main/x86_64/APKINDEX.tar.gz
    fetch https://dl-cdn.alpinelinux.org/alpine/v3.14/community/x86_64/APKINDEX.tar.gz
    (1/37) Installing fakeroot (1.25.3-r3)
    (2/37) Installing openssl (1.1.1l-r0)
    (3/37) Installing libattr (2.5.1-r0)
    (4/37) Installing attr (2.5.1-r0)
    (5/37) Installing libacl (2.2.53-r0)
    (6/37) Installing tar (1.34-r0)
    (7/37) Installing pkgconf (1.7.4-r0)
    ...
    $ export GOPROXY="https://goproxy.cn"
    $ CGO_ENABLED=1 GOOS=windows CC=x86_64-w64-mingw32-gcc go build -ldflags "-linkmode external -extldflags '-static'"  -tags musl -o seduce_node_agent.exe main.go
    

參考

1.golang動態鏈接庫問題

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章