Docker分享-CI/CD(2)
第一篇內(nèi)容茫多,分享了大神介紹如何容器化項(xiàng)目的經(jīng)歷疼邀,我真的看著么久荠诬,唯一看到大神介紹多平臺(tái)交叉編譯的。因?yàn)榻^大多數(shù)的docker項(xiàng)目都只提供linux產(chǎn)品隐锭。當(dāng)然只會(huì)容器化我們的項(xiàng)目還遠(yuǎn)遠(yuǎn)不夠,CI/CD的目的能讓團(tuán)隊(duì)協(xié)同工作计贰,持續(xù)集成持續(xù)部署钦睡。保持開發(fā)環(huán)境一直是另一個(gè)大問題。
添加額外的依賴
上個(gè)教程躁倒,我們基本沒有使用第三方依賴荞怒,但是實(shí)際開發(fā)中洒琢,為了更加專注于開發(fā)我們自己的功能,可能會(huì)有很多3PP的輔助褐桌。大神也用了個(gè)簡(jiǎn)單的例子
package main
import (
"fmt"
"os"
"strings"
"github.com/pkg/errors"
)
func echo(args []string) error {
if len(args) < 2 {
return errors.New("no message to echo")
}
_, err := fmt.Println(strings.Join(args[1:], " "))
return err
}
func main() {
if err := echo(os.Args); err != nil {
fmt.Fprintf(os.Stderr, "%+v\n", err)
os.Exit(1)
}
}
簡(jiǎn)單的echo功能衰抑,使用go modules做包管理,跑一下
go mod init
go mod tidy
有了依賴之后荧嵌,明顯的效率低下并且減慢了速度呛踊。我們可以通過在Dockerfile中單獨(dú)下載依賴項(xiàng)目來解決這個(gè)問題。
FROM --platform=${BUILDPLATFORM} golang:1.14.3-alpine AS build
WORKDIR /src
ENV CGO_ENABLED=0
COPY go.* .
RUN go mod download
COPY . .
ARG TARGETOS
ARG TARGETARCH
RUN GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -o /out/example .
FROM scratch AS bin-unix
COPY --from=build /out/example /
...
與之前的一版dockerfile對(duì)比啦撮,這一版加了兩行內(nèi)容
COPY go.* .
RUN go mod download
大神說先添加所有g(shù)o.*的文件谭网,然后下載依賴這樣會(huì)讓Docker緩存下載的modules,dockerfile會(huì)少重跑一些內(nèi)容赃春。
將下載依賴和構(gòu)建分開是相當(dāng)大的改進(jìn)蜻底,但是每次構(gòu)建都要從頭開始編譯,對(duì)于小型項(xiàng)目這沒什么聘鳞,但是隨著項(xiàng)目越來越大薄辅,我們就應(yīng)該考慮Go的編譯器緩存。
再更新一次dockerfile看看怎么改
# syntax = docker/dockerfile:1-experimental
FROM --platform=${BUILDPLATFORM} golang:1.14.3-alpine AS build
ARG TARGETOS
ARG TARGETARCH
WORKDIR /src
ENV CGO_ENABLED=0
COPY go.* .
RUN go mod download
COPY . .
RUN --mount=type=cache,target=/root/.cache/go-build \
GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -o /out/example .
FROM scratch AS bin-unix
COPY --from=build /out/example /
...
大神在dockerfile的頂部加了一個(gè)語句抠璃,選擇了試驗(yàn)性的docker前端站楚,外加--mount。這意味著每次運(yùn)行g(shù)o build命令的時(shí)候搏嗡,容器都會(huì)將緩存掛在到Go的編譯器緩存文件夾中窿春。大神說無緩存構(gòu)建該例子需要11秒,但是使用緩存的話采盒,用了不到2秒旧乞,不可思議。
加入單元測(cè)試
我發(fā)誓我之后如果做個(gè)人項(xiàng)目一定認(rèn)真寫單元測(cè)試磅氨,大神也說了尺栖,不幾乎我讀過的每個(gè)文檔都提到了單元測(cè)試的重要性。貼上測(cè)試代碼:
package main
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestEcho(t *testing.T) {
// Test happy path
err := echo([]string{"bin-name", "hello", "world!"})
require.NoError(t, err)
}
func TestEchoErrorNoArgs(t *testing.T) {
// Test empty arguments
err := echo([]string{})
require.Error(t, err)
}
CI測(cè)試來了
這里是我認(rèn)為應(yīng)該學(xué)習(xí)的地方烦租,大神在dockerfile里的構(gòu)建階段延赌,加入了單元測(cè)試
# syntax = docker/dockerfile:1-experimental
FROM --platform=${BUILDPLATFORM} golang:1.14.3-alpine AS base
WORKDIR /src
ENV CGO_ENABLED=0
COPY go.* .
RUN go mod download
COPY . .
FROM base AS build
ARG TARGETOS
ARG TARGETARCH
RUN --mount=type=cache,target=/root/.cache/go-build \
GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -o /out/example .
FROM base AS unit-test
RUN --mount=type=cache,target=/root/.cache/go-build \
go test -v .
FROM scratch AS bin-unix
COPY --from=build /out/example /
...
Go的測(cè)試使用了與構(gòu)建相同的緩存,也是為了能在測(cè)試的時(shí)候更快叉橱。
更新makefile
all: bin/example
test: unit-test
PLATFORM=local
.PHONY: bin/example
bin/example:
@docker build . --target bin \
--output bin/ \
--platform ${PLATFORM}
.PHONY: unit-test
unit-test:
@docker build . --target unit-test
大神的docker CI三件套挫以,第二篇中講了如何有效的添加go的依賴,緩存用于加快構(gòu)建速度窃祝,以及對(duì)容器化Go開發(fā)環(huán)境中添加單元測(cè)試掐松。
下一篇內(nèi)容將會(huì)將如何添加linter,設(shè)置Github Actions CI以及一些額外的構(gòu)建優(yōu)化。