婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av

主頁(yè) > 知識(shí)庫(kù) > 構(gòu)建Golang應(yīng)用最小Docker鏡像的實(shí)現(xiàn)

構(gòu)建Golang應(yīng)用最小Docker鏡像的實(shí)現(xiàn)

熱門標(biāo)簽:廣東語(yǔ)音外呼系統(tǒng)供應(yīng)商 地圖標(biāo)注測(cè)試 濮陽(yáng)自動(dòng)外呼系統(tǒng)代理 澳門防封電銷卡 長(zhǎng)沙ai機(jī)器人電銷 賺地圖標(biāo)注的錢犯法嗎 福州鐵通自動(dòng)外呼系統(tǒng) 智能電銷機(jī)器人營(yíng)銷 烏魯木齊人工電銷機(jī)器人系統(tǒng)

我通常使用docker運(yùn)行我的 golang 程序,在這里分享一下我構(gòu)建 docker 鏡像的經(jīng)驗(yàn)。我構(gòu)建 docker 鏡像不僅優(yōu)化構(gòu)建后的體積,還要優(yōu)化構(gòu)建速度。

示例應(yīng)用

首先貼出代碼例子,我們假設(shè)要構(gòu)建一個(gè) http 服務(wù)

package main

import (
 "fmt"
 "net/http"
 "time"

 "github.com/gin-gonic/gin"
)

func main() {
 fmt.Println("Server Ready")
 router := gin.Default()
 router.GET("/", func(c *gin.Context) {
 c.String(200, "hello world, this time is: "+time.Now().Format(time.RFC1123Z))
 })
 router.GET("/github", func(c *gin.Context) {
 _, err := http.Get("https://api.github.com/")
 if err != nil {
  c.String(500, err.Error())
  return
 }
 c.String(200, "access github api ok")
 })

 if err := router.Run(":9900"); err != nil {
 panic(err)
 }
}

說(shuō)明:

  • 這里選擇 Gin 作為例子,是為了演示我們有第三方包條件下要優(yōu)化構(gòu)建速度
  • main函數(shù)第一行打印了一行字,為了演示后面啟動(dòng)時(shí)遇到的一個(gè)坑
  • 跟路由打印了時(shí)間,為了演示后面遇到的關(guān)于時(shí)區(qū)的坑
  • 路由 github 嘗試訪問(wèn) https://api.github.com,為了演示后面遇到的證書坑

這里我們可以先試一試構(gòu)建后包的體積

$ go build -o server
$ ls -alh | grep server
-rwxrwxrwx 1 eyas eyas 14.6M May 29 10:26 server

14.6MB,這是一個(gè)http服務(wù)的 hello world,當(dāng)然這是因?yàn)槭褂昧?gin ,所以有些大,如果用標(biāo)準(zhǔn)包 net/http 寫的 hello world,體積大概是接近 7 MB

Dockerfile 的進(jìn)化

版本一,初步優(yōu)化

先看看第一個(gè)版本

FROM golang:1.14-alpine as builder
WORKDIR /usr/src/app
ENV GOPROXY=https://goproxy.cn
COPY ./go.mod ./
COPY ./go.sum ./
RUN go mod download
COPY . .
RUN go build -ldflags "-s -w" -o server

FROM scratch as runner
COPY --from=builder /usr/src/app/server /opt/app/
CMD ["/opt/app/server"]

說(shuō)明:

  • 選擇 golang:1.14-alpine 作為編譯環(huán)境,是因?yàn)檫@是體積最小的golang編譯環(huán)境
  • 設(shè)置 GOPROXY 是為了提升構(gòu)建速度
  • 先復(fù)制 go.mod 和 go.sum ,然后 go mod download,是為了防止每次構(gòu)建都會(huì)重新下載依賴包,利用docker構(gòu)建緩存提升構(gòu)建速度
  • go build 時(shí)加上 -ldflags "-s -w" 去除構(gòu)建包的調(diào)試信息,減小go構(gòu)建后程序體積,大概能減小 1/4 吧
  • 使用了多階段構(gòu)建,也就是 FROM XXX as xxx ,在構(gòu)建程序包的時(shí)候,使用帶編譯環(huán)境的鏡像去構(gòu)建,運(yùn)行的時(shí)候其實(shí)完全不需要go的編譯環(huán)境,所以在運(yùn)行階段使用docker的空鏡像 scratch 去運(yùn)行。這部是減小鏡像體積最有效的方法了。

好了,下面開(kāi)始構(gòu)建鏡像

$ docker build -t server .
...
Successfully built 8d3b91210721
Successfully tagged server:latest

到了這一步,構(gòu)建成功,看看鏡像大小

$ docker images
server     latest     8d3b91210721   1 minutes ago    11MB

11MB,還行,現(xiàn)在運(yùn)行一下

$ docker run -p 9900:9900 server
standard_init_linux.go:211: exec user process caused "no such file or directory"

發(fā)現(xiàn)啟動(dòng)報(bào)錯(cuò)了,而且main函數(shù)的第一行打印語(yǔ)句都沒(méi)有出現(xiàn),所以整個(gè)程序完全沒(méi)有運(yùn)行。錯(cuò)誤原因是缺少庫(kù)依賴文件。這其實(shí)是構(gòu)建的 go 程序還依賴底層的 so 庫(kù)文件,不信可以在物理機(jī)編譯后看看它的依賴

$ go build -o server
$ ldd server
    linux-vdso.so.1 (0x00007ffcfb775000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f9a8dc47000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9a8d856000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f9a8de66000)

這是不是跟我們的認(rèn)知有點(diǎn)出入呢,說(shuō)好無(wú)依賴的呢,結(jié)果還是有幾個(gè)依賴庫(kù)文件呢,雖然這幾個(gè)依賴都是最底層的,一般操作系統(tǒng)都會(huì)有,可誰(shuí)叫我們選了 scratch,這個(gè)鏡像里面除了linux內(nèi)核以外真的什么都沒(méi)了。

這是因?yàn)間o build 是默認(rèn)啟用 CGO 的,不信你可以試試這個(gè)命令 go env CGO_ENABLED,在 CGO 開(kāi)啟情況下,無(wú)論代碼有沒(méi)有用CGO,都會(huì)有庫(kù)依賴文件,解決方法也很簡(jiǎn)單,手動(dòng)指定關(guān)閉CGO就行,而且包體積并不會(huì)增加哦,還會(huì)減少呢

$ CGO_ENABLED=0 go build -o server
$ ldd server
    not a dynamic executable

版本二,解決運(yùn)行時(shí)報(bào)錯(cuò)

FROM golang:1.14-alpine as builder
WORKDIR /usr/src/app
ENV GOPROXY=https://goproxy.cn
COPY ./go.mod ./
COPY ./go.sum ./
RUN go mod download
COPY . .
-RUN go build -ldflags "-s -w" -o server
+RUN CGO_ENABLED=0 go build -ldflags "-s -w" -o server

FROM scratch as runner
COPY --from=builder /usr/src/app/server /opt/app/
CMD ["/opt/app/server"]

改動(dòng)點(diǎn): go build 前加了 CGO_ENABLED=0

$ docker build -t server .
...
Successfully built a81385160e25
Successfully tagged server:latest
$ docker run -p 9900:9900 server
[GIN-debug] GET  /             --> main.main.func1 (3 handlers)
[GIN-debug] GET  /github          --> main.main.func2 (3 handlers)
[GIN-debug] Listening and serving HTTP on :9900

正常啟動(dòng)了,我們?cè)L問(wèn)一下試試,訪問(wèn)之前看看當(dāng)前時(shí)間

$ date
Fri May 29 13:11:28 CST 2020

$ curl http://localhost:9900    
hello world, this time is: Fri, 29 May 2020 05:18:28 +0000

$ curl http://localhost:9900/github
Get "https://api.github.com/": x509: certificate signed by unknown authority

發(fā)現(xiàn)有問(wèn)題

  • 當(dāng)前系統(tǒng)時(shí)間是 13:11:28 ,但是根據(jù)由顯示的時(shí)間是 05:11:53,其實(shí)是docker 容器內(nèi)的時(shí)區(qū)不對(duì),默認(rèn)是 0 時(shí)區(qū),可是我們國(guó)家是 東8區(qū)
  • 嘗試訪問(wèn) https://api.github.com/ 這是 https 站點(diǎn),報(bào)證書錯(cuò)誤

解決問(wèn)題

  • 在容器放置根證書
  • 設(shè)置容器時(shí)區(qū)

版本三,解決運(yùn)行環(huán)境時(shí)區(qū)與證書問(wèn)題

FROM golang:1.14-alpine as builder
WORKDIR /usr/src/app
ENV GOPROXY=https://goproxy.cn
+RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories  \

+ apk add --no-cache ca-certificates tzdata
COPY ./go.mod ./
COPY ./go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -ldflags "-s -w" -o server

FROM scratch as runner
+COPY --from=builder /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
+COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=builder /usr/src/app/server /opt/app/
CMD ["/opt/app/server"]

在 builder 階段,安裝了 ca-certificates tzdata 兩個(gè)庫(kù),在runner階段,將時(shí)區(qū)配置和根證書復(fù)制了一份

$ docker build -t server .
...
Successfully built e0825838043d
Successfully tagged server:latest
$ docker run -p 9900:9900 server
[GIN-debug] GET  /             --> main.main.func1 (3 handlers)
[GIN-debug] GET  /github          --> main.main.func2 (3 handlers)
[GIN-debug] Listening and serving HTTP on :9900

訪問(wèn)一下試試

$ date
Fri May 29 13:27:16 CST 2020

$ curl http://localhost:9900    
hello world, this time is: Fri, 29 May 2020 13:27:16 +0800

$ curl http://localhost:9900/github
access github api ok

一切正常了,看看當(dāng)前鏡像大小

$ docker images
server     latest     e0825838043d   9 minutes ago    11.3MB

才 11.3MB,已經(jīng)很小了,但是,還可以更小,就是把構(gòu)建后的包再壓縮一次

版本四,進(jìn)一步減小體積

FROM golang:1.14-alpine as builder
WORKDIR /usr/src/app
ENV GOPROXY=https://goproxy.cn
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories  \

- apk add --no-cache ca-certificates tzdata
+ apk add --no-cache upx ca-certificates tzdata
COPY ./go.mod ./
COPY ./go.sum ./
RUN go mod download
COPY . .
-RUN CGO_ENABLED=0 go build -ldflags "-s -w" -o server
+RUN CGO_ENABLED=0 go build -ldflags "-s -w" -o server \

+ upx --best server -o _upx_server  \

+ mv -f _upx_server server

FROM scratch as runner
COPY --from=builder /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=builder /usr/src/app/server /opt/app/
CMD ["/opt/app/server"]

在 builder 階段,安裝了 upx ,并且go build 完成后,使用 upx 壓縮了一下,執(zhí)行一下構(gòu)建,你會(huì)發(fā)現(xiàn)這個(gè)構(gòu)建時(shí)間變長(zhǎng)了,這是因?yàn)槲医o upx 設(shè)置的參數(shù)是 --best ,也就是最大壓縮級(jí)別,這樣壓縮出來(lái)的后會(huì)盡可能的小,如果嫌慢,可以降低壓縮級(jí)別從 -1 到 -9 ,數(shù)字越大壓縮級(jí)別越高,也越慢。我使用 --best 構(gòu)建完成后看看鏡像體積。

$ docker build -t server .
...
Successfully built 80c3f3cde1f7
Successfully tagged server:latest
$ docker images
server     latest     80c3f3cde1f7   1 minutes ago    4.26MB

這下子可小了,才 4.26MB,再去試試那兩個(gè)接口,一切正常。優(yōu)化到此結(jié)束。

最終的Dockerfile

FROM golang:1.14-alpine as builder
WORKDIR /usr/src/app
ENV GOPROXY=https://goproxy.cn
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories  \

 apk add --no-cache upx ca-certificates tzdata
COPY ./go.mod ./
COPY ./go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -ldflags "-s -w" -o server \

 upx --best server -o _upx_server  \

 mv -f _upx_server server

FROM scratch as runner
COPY --from=builder /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=builder /usr/src/app/server /opt/app/
CMD ["/opt/app/server"]

總結(jié)

要減小鏡像體積,首先多階段構(gòu)建這很重要,這樣就可以把編譯環(huán)境和運(yùn)行環(huán)境分開(kāi)。

另外,選擇 scratch 這個(gè)鏡像其實(shí)很不明智,它雖然很小,但是它太原始了,里面什么工具都沒(méi)有,程序啟動(dòng)后,連容器都進(jìn)不去,就算進(jìn)去了什么都做不了。所以就算一昧的追求盡可能小的鏡像體積,也不建議選擇 scratch 作為運(yùn)行環(huán)境,我暫時(shí)只踩到小部分的坑,后面還有更多坑沒(méi)踩,我也沒(méi)有興趣繼續(xù)踩 scratch 的坑。

建議選擇 alpine ,alpine 的鏡像大小是 5.61MB 這個(gè)大小其實(shí)還是鏡像解壓后的大小,實(shí)際上下載鏡像的時(shí)候,只需要下載 2.68 MB 。還有,上文所有我說(shuō)的鏡像體積,全都是指解壓后的鏡像體積,和實(shí)際上傳下載時(shí)的體積是不一樣的,docker自己會(huì)壓縮一次再傳輸鏡像

還有個(gè)很小的鏡像是 busybox,它的體積是 1.22MB,下載 705.6 KB ,有大部分的linux命令可用,但是運(yùn)行環(huán)境還是很原始,有興趣可以去嘗試

無(wú)論是 alpine 還是 busybox ,他們都會(huì)上述時(shí)區(qū)和證書問(wèn)題,同樣按照上面方法就能解決,切換到 alpine 或者 busybox 也很簡(jiǎn)單,只需要修改 runner 基礎(chǔ)鏡像就行

-FROM scratch as runner
+FROM alpine as runner

或者

-FROM scratch as runner
+FROM busybox as runne

到此這篇關(guān)于構(gòu)建Golang應(yīng)用最小Docker鏡像的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Golang構(gòu)建最小Docker鏡像內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:
  • 基于Docker鏡像部署go項(xiàng)目的方法步驟
  • Docker 部署Go的兩種基礎(chǔ)鏡像的實(shí)現(xiàn)

標(biāo)簽:調(diào)研邀請(qǐng) 西雙版納 太原 廣西 阿克蘇 貴陽(yáng) 德州 慶陽(yáng)

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《構(gòu)建Golang應(yīng)用最小Docker鏡像的實(shí)現(xiàn)》,本文關(guān)鍵詞  構(gòu)建,Golang,應(yīng)用,最小,Docker,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問(wèn)題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無(wú)關(guān)。
  • 相關(guān)文章
  • 下面列出與本文章《構(gòu)建Golang應(yīng)用最小Docker鏡像的實(shí)現(xiàn)》相關(guān)的同類信息!
  • 本頁(yè)收集關(guān)于構(gòu)建Golang應(yīng)用最小Docker鏡像的實(shí)現(xiàn)的相關(guān)信息資訊供網(wǎng)民參考!
  • 推薦文章
    婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av
    男女激情视频一区| 欧美一区二区三区视频在线观看| 国产日韩精品一区二区三区| 不卡视频在线观看| 国产欧美日韩另类一区| 精品亚洲aⅴ乱码一区二区三区| 在线电影一区二区三区| 婷婷久久综合九色国产成人 | 久久久久久久精| 国产一区在线精品| 国产精品久久久久久久久晋中 | 狠狠色丁香久久婷婷综合丁香| 欧美精品一区二区蜜臀亚洲| 精品亚洲国产成人av制服丝袜| 久久精品人人做人人爽97| 国产精品夜夜嗨| 国产精品理论在线观看| 欧美羞羞免费网站| 午夜精品福利一区二区三区av | 欧洲一区在线电影| 日韩av二区在线播放| 欧美xxxx老人做受| 成人免费福利片| 亚洲一二三四久久| 欧美一区二区三区免费视频| 国产丶欧美丶日本不卡视频| 成人免费在线播放视频| 欧美一级二级三级乱码| 国内成+人亚洲+欧美+综合在线| 国产精品网站在线观看| 欧美性xxxxxx少妇| 天天综合色天天| 国产精品伦一区| 欧美曰成人黄网| 国产999精品久久久久久绿帽| 亚洲男同性恋视频| 久久久久国产成人精品亚洲午夜| 99久久精品一区| 九色综合国产一区二区三区| 亚洲人吸女人奶水| 久久久一区二区三区捆绑**| 91麻豆视频网站| 精品一区二区三区日韩| 一个色在线综合| 国产欧美精品一区二区色综合| 在线观看不卡一区| 国产91精品精华液一区二区三区 | 欧美日韩电影在线播放| 成人综合激情网| 亚洲国产精品一区二区久久恐怖片| 337p粉嫩大胆噜噜噜噜噜91av| 国产乱子伦视频一区二区三区| 一区二区三区四区视频精品免费| 精品国产亚洲在线| 欧美日韩中文国产| 成人免费视频视频| 日本91福利区| 亚洲综合自拍偷拍| 国产精品嫩草影院com| 精品蜜桃在线看| 欧美伦理影视网| 欧美日韩激情一区二区| 成人av综合一区| 成人一区二区三区| 久久精品久久综合| 日本少妇一区二区| 亚洲成人久久影院| 亚洲第一在线综合网站| 国产精品羞羞答答xxdd| 奇米综合一区二区三区精品视频| 亚洲桃色在线一区| 国产精品不卡在线| 国产精品亲子乱子伦xxxx裸| 国产丝袜欧美中文另类| 2020国产精品| 久久美女艺术照精彩视频福利播放 | 日韩视频一区二区三区| 欧美精品日韩精品| 91官网在线观看| 欧美日韩一卡二卡三卡 | 日韩和欧美的一区| 天天操天天色综合| 亚洲综合在线观看视频| 亚洲国产精品久久人人爱| 一区二区三区日韩欧美| 国产精品毛片无遮挡高清| 中文字幕精品—区二区四季| 日韩三级视频中文字幕| 欧美一级二级三级蜜桃| 91麻豆精品国产| 久久久久久久久久久黄色| 亚洲精品在线一区二区| 中文字幕不卡的av| 国产天堂亚洲国产碰碰| 亚洲精品视频一区二区| 亚洲成av人片一区二区| 久久99九九99精品| 国产成a人无v码亚洲福利| 97精品国产露脸对白| 色婷婷久久久久swag精品 | 免费成人美女在线观看.| 亚洲九九爱视频| 日韩成人免费看| 亚洲第一精品在线| 老司机精品视频一区二区三区| 人人狠狠综合久久亚洲| 成人一区在线看| 91农村精品一区二区在线| 欧美片在线播放| 日韩精品一区二区三区在线播放| 欧美剧情电影在线观看完整版免费励志电影| 色噜噜狠狠成人中文综合 | 国产精品乡下勾搭老头1| 不卡av免费在线观看| 99天天综合性| 欧美日韩dvd在线观看| 久久天堂av综合合色蜜桃网| 亚洲国产精品黑人久久久| 国产99久久久国产精品潘金 | 中文字幕日本不卡| 天天影视涩香欲综合网| 国产美女在线观看一区| 欧美日韩在线一区二区| 亚洲精品一区二区三区福利| 亚洲午夜三级在线| 久久电影网电视剧免费观看| 91成人在线精品| 久久综合九色综合97婷婷女人| 一区二区三区国产| 经典三级一区二区| 欧美日韩高清一区二区不卡| 亚洲国产精品成人综合| 日韩不卡在线观看日韩不卡视频| 国产成人免费视频网站高清观看视频| 欧美人伦禁忌dvd放荡欲情| 国产欧美精品一区二区色综合| 爽好久久久欧美精品| 成人深夜在线观看| 久久欧美一区二区| 日韩av在线播放中文字幕| 91官网在线免费观看| 国产人伦精品一区二区| 久久99国产精品久久99 | 国产精品网站在线播放| 麻豆国产欧美一区二区三区| av不卡在线播放| 亚洲国产激情av| 奇米精品一区二区三区在线观看 | 色综合 综合色| 国产色爱av资源综合区| 青青草精品视频| 欧美日韩成人在线| 亚洲欧美成aⅴ人在线观看 | 精品一区二区在线观看| 91亚洲精华国产精华精华液| 久久久久久一级片| 麻豆成人久久精品二区三区红| 91在线观看成人| 555www色欧美视频| 午夜影视日本亚洲欧洲精品| 国产盗摄女厕一区二区三区| 欧美精品一区二区久久婷婷| 亚洲国产美女搞黄色| 日本精品一区二区三区高清 | 免费成人av在线播放| 日韩午夜三级在线| 日韩成人一区二区三区在线观看| 欧美一区二区高清| 亚洲色图欧洲色图婷婷| 成人性生交大片免费看中文 | 国产精品久久影院| 国产成人在线视频网址| 国产日韩欧美精品电影三级在线| 精品一区二区三区在线播放 | 久久女同互慰一区二区三区| 蜜臀国产一区二区三区在线播放| 欧美性视频一区二区三区| 亚洲人成精品久久久久久| 99国产精品国产精品久久| 亚洲欧美自拍偷拍| 91在线看国产| 中文字幕欧美三区| 一本久久精品一区二区| 中文字幕一区三区| 99国产欧美另类久久久精品 | 中文字幕精品—区二区四季| 国产一区二区三区精品视频| www亚洲一区| 国产福利一区在线观看| 国产精品久久影院| 在线视频中文字幕一区二区| 日韩av电影免费观看高清完整版 | 亚洲一区在线视频观看| 欧美三日本三级三级在线播放| 亚洲一级二级在线| 欧美一区二区国产| 成人动漫精品一区二区| 亚洲影院免费观看| 日韩美一区二区三区| 懂色av一区二区在线播放|