go项目构建文件梳理
作用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.gitlab-ci.yml
└─> 调用模板中的构建脚本 可能调用 make 或 build.sh
Makefile // 提供统一的构建命令入口
├─> build.sh (make build)
└─> ciscripts/build.sh (make package)
pack.sh // 完成打包、镜像推送
├─> 在容器中编译
└─> Dockerfile (构建镜像)
build.sh
└─> 生成 dist/ 目录
Dockerfile // 生产镜像定义
└─> 依赖 dist/ 目录(需要先运行 build.sh)
| 脚本 | 编译环境 | 输出 | 用途 |
|---|---|---|---|
| build.sh | 本地环境 | dist/ 目录 | 本地开发、快速构建 |
| pack.sh | Docker 容器 | Docker 镜像 | 完整打包、镜像推送 |
| Makefile | 本地环境 | 多种(根据命令) | 统一命令入口、便捷操作 |
.gitlab-ci.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
include:
- project: 'ops/gitlab-cicd-templates'
ref: master
file: 'go/cicd-template/prepare.yaml'
- project: 'ops/gitlab-cicd-templates'
ref: master
file: 'go/cicd-template/test.yaml'
- project: 'ops/gitlab-cicd-templates'
ref: master
file: 'go/cicd-template/build.yaml'
# stage定义
stages:
- test
- build
# 仅作单元测试(不包含资源层测试逻辑)
test:
stage: test
extends:
- .test
#.gitlab-ci.yml
# └─> extends: .build-test-image (来自模板)
# └─> 模板中的 script (可能在模板中调用 make 或 build.sh)
# └─> 最终执行构建
# fixbug、feature、test分支的镜像打包
build-test-image:
stage: build
extends:
- .build-test-image
# tag触发(仅master分支但可配置)的镜像打包
build-prod-image:
stage: build
extends:
- .build-prod-image
Makefile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# 定义常量
PACKAGE := gitlab..com/golib/xdspec
BRANCH := $(shell git branch --no-color 2> /dev/null|sed -e '/^[^*]/d' -e 's/* \(.*\)/\1/' -e 's/\//\_/g')
IMAGE_NAME_ZJK := "registry.cn-zhangjiakou.aliyuncs.com//ecrobot-goods_center:${BRANCH}"
# 版本信息
VERSION=$(git describe --tags 2>/dev/null)
COMMIT=$(git rev-parse --short HEAD)
BUILD_TIME=$(date +%FT%T)
# 构建配置
GOOS ?= linux
GOARCH ?= amd64
CGO_ENABLED ?= 0
GO_BUILD_FLAGS ?= -mod=readonly
LD_FLAGS := -w -s \
-X ${PACKAGE}.Version=${VERSION} \
-X ${PACKAGE}.Commit=${COMMIT} \
-X ${PACKAGE}.BuildDate=${BUILD_TIME}
# 定义构建目标(替换为你的可执行文件名)
BINARY_NAME := goods_center
.PHONY: all test build clean
all: test build
# 项目构建 - 统一的依赖同步
.deps:
@echo "Syncing dependencies..."
@go mod tidy
@go mod download
# 测试命令
test:
@echo "Running unit tests..."
@go test -gcflags="all=-N -l" -tags=unit -timeout 30s -short `go list ./... | grep -v /vendor/`
# 构建命令
build:
./build.sh
# goc构建命令
buildc:
@echo "Syncing dependencies..."
@go mod tidy
@go mod download
@mkdir -p ./target
@mkdir -p ./target-goc
@echo "Building ${BINARY_NAME} ${GIT_TAG} for $(GOOS)/$(GOARCH)"
GOWORK=off GOOS=$(GOOS) GOARCH=$(GOARCH) CGO_ENABLED=$(CGO_ENABLED) \
goc build --debug --agentport ":9101" --center "http://goc-server-service:8080" --output "./target-goc/${BINARY_NAME}" .
#本地打包命令
package: clean ## push image manually
@echo "make push"
./build.sh
@docker build . -t $(IMAGE_NAME_ZJK)
@docker push $(IMAGE_NAME_ZJK)
# 清理构建文件
clean:
@echo "Cleaning up..."
@rm -rf ./target
@rm -rf ./target-goc
# 显示版本信息
version:
@echo "Version: ${VERSION}"
@echo "Commit: ${COMMIT}"
@echo "Build Time: ${BUILD_TIME}"
# 安装依赖
deps:
@echo "Downloading dependencies..."
@go mod download
# 运行静态检查
lint:
@echo "Running static analysis..."
@golangci-lint run ./...
help: ## Display this help screen
@grep -h -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
pack.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#!/bin/bash
# ============================================================================
# Docker 镜像打包脚本
# 功能:在 Docker 容器中编译 Go 程序,构建镜像并推送到镜像仓库
# ============================================================================
# 服务名称(用于镜像标签)
SERVER_NAME=goods_center
# 服务组名(用于镜像标签)
SERVER_GROUP=ecrobot
# 构建用的基础镜像(包含 Go 1.13 和 Pulsar 2.41 环境)
SRC_IMG=registry.cn-zhangjiakou.aliyuncs.com//golang:1.13-pulsar2.41
# 获取 Git 版本信息
# git describe --tags: 获取最新的 tag 信息,如果失败则忽略错误(2>/dev/null)
VERSION=$(git describe --tags 2>/dev/null)
# 获取 Git commit 的短哈希值(7位)
COMMIT=$(git rev-parse --short HEAD)
# 获取当前时间(ISO 8601 格式:YYYY-MM-DDTHH:MM:SS)
TIME=$(date +%FT%T)
# 如果没有 tag,则使用 commit hash 作为版本号
if [[ -z ${VERSION} ]]; then
VERSION=${COMMIT}
fi
# Docker 构建容器的名称
BUILD_IMG_NAME=go_build
# 停止并删除旧的构建容器(如果存在)
# || echo: 如果命令失败(容器不存在),则输出提示信息并继续执行
docker stop $BUILD_IMG_NAME || echo "skip stop $BUILD_IMG_NAME"
docker rm -f $BUILD_IMG_NAME || echo "skip stop $BUILD_IMG_NAME"
echo "pack ..."
echo "build ..."
# 在 Docker 容器中编译 Go 程序
# -v $(pwd):/go: 将当前目录挂载到容器的 /go 目录
# -w /go: 设置容器的工作目录为 /go
# --name $BUILD_IMG_NAME: 给容器命名为 go_build
# ${SRC_IMG}: 使用指定的基础镜像
# /bin/bash -c "命令": 在容器中执行命令
# 1. export GO111MODULE=on: 启用 Go modules
# 2. pwd && ls: 显示当前目录和文件列表(调试用)
# 3. env GOOS=linux GOARCH=amd64 go build: 交叉编译为 Linux amd64 架构
# 4. 如果成功:输出 "---build success---" 并退出码 0
# 5. 如果失败:输出 "---build failed---" 并退出码 1
docker run -v $(pwd):/go \
-w /go \
--name $BUILD_IMG_NAME \
${SRC_IMG} \
/bin/bash -c "export GO111MODULE=on && pwd && ls && env GOOS=linux GOARCH=amd64 go build && echo \"---build success---\" && exit 0 || echo \"---build failed---\" && exit 1"
# 获取上一条命令的退出状态码($? 表示上一个命令的返回值)
docker_build_state=$?
# 检查编译是否成功(退出码非 0 表示失败)
if [[ ${docker_build_state} -ne 0 ]]; then
echo "build failed"
exit 1
fi
# 生成镜像标签:格式为 ecrobot-goods_center:版本号
TAG=${SERVER_GROUP}-${SERVER_NAME}:${VERSION}
# 删除旧的镜像(如果存在),避免标签冲突
# --force: 强制删除,即使有容器在使用
docker rmi ${TAG} --force || echo "skip docker rmi ${TAG}"
# 使用 Dockerfile 构建 Docker 镜像
# -f ./Dockerfile: 指定 Dockerfile 文件路径
# -t ${TAG}: 给镜像打标签
# ./: 构建上下文为当前目录
docker build -f ./Dockerfile -t ${TAG} ./
# 获取镜像构建的退出状态码
docker_build_state=$?
# 检查镜像构建是否成功
if [[ ${docker_build_state} -ne 0 ]]; then
echo "pack failed"
exit 1
fi
echo "build done"
echo "push to image hub"
# 给镜像打上远程仓库的标签
# 格式:registry.cn-zhangjiakou.aliyuncs.com//ecrobot-goods_center:版本号
docker tag ${TAG} registry.cn-zhangjiakou.aliyuncs.com//${TAG}
# 推送镜像到阿里云镜像仓库
# 注意:需要先执行 docker login 登录到镜像仓库
docker push registry.cn-zhangjiakou.aliyuncs.com//${TAG}
# 获取推送操作的退出状态码
docker_build_state=$?
# 检查推送是否成功
if [[ ${docker_build_state} -ne 0 ]]; then
echo "push to registry failed"
exit 1
fi
echo "push to image done"
echo "pack done"
执行流程总结
1
2
3
4
5
6
7
8
9
10
1. 定义变量(服务名、镜像名等)
2. 获取版本信息(git tag/commit)
3. 清理旧的构建容器
4. 在 Docker 容器中编译 Go 程序(Linux/amd64)
5. 检查编译是否成功
6. 使用 Dockerfile 构建镜像
7. 检查镜像构建是否成功
8. 给镜像打远程仓库标签
9. 推送镜像到阿里云仓库
10. 检查推送是否成功
build.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!/bin/bash
set -ex
VERSION=$(git describe --tags 2>/dev/null)
COMMIT=$(git rev-parse --short HEAD)
TIME=$(date +%FT%T)
if [ -z $VERSION ]; then
VERSION=$COMMIT
fi
VerPkg="gitlab..com/golib/xd_sdk/xdspec"
BASE=$(pwd)
go_tags="nomsgpack"
export CGO_ENABLED=0
go build -tags "${go_tags}" \
-ldflags "-X ${VerPkg}.Version=$VERSION \
-X ${VerPkg}.GitCommit=$COMMIT \
-X ${VerPkg}.BuildTime=${TIME}" \
-o ./dist/goods_center
cd component/cid/center_worker && go build -o ${BASE}/dist/center_worker && cd ${BASE}
cd component/cid/sync_worker && go build -o ${BASE}/dist/sync_worker && cd ${BASE}
cd component/cid/filter_worker && go build -o ${BASE}/dist/filter_worker && cd ${BASE}
cd component/notify/notify_worker && go build -o ${BASE}/dist/notify_worker && cd ${BASE}
cd component/notify-filter && go build -o ${BASE}/dist/notify-filter && cd ${BASE}
cd component/repair/repair_worker && go build -o ${BASE}/dist/repair_worker && cd ${BASE}
cd component/platform_implement/taobao && go build -o ${BASE}/dist/tmc_worker && cd ${BASE}
cd component/platform_implement/general && go build -o ${BASE}/dist/gmc_worker && cd ${BASE}
Dockerfile
1
2
3
4
5
6
7
8
9
10
11
12
13
# 使用 Alpine Linux 3.15.0 作为基础镜像(轻量级,体积小)
FROM registry.cn-zhangjiakou.aliyuncs.com//alpine:3.15.0
# 设置工作目录为 /app(后续命令都在此目录执行)
WORKDIR /app
# 将本地 dist 目录下的所有文件复制到容器的 /app 目录
# 注意:需要先运行 build.sh 生成 dist 目录和编译好的二进制文件
COPY dist /app
# 设置容器启动时执行的默认命令
# 运行 goods_center 程序,并指定配置文件路径为 /etc/config/goods_center.toml
CMD ["./goods_center", "-c", "/etc/config/goods_center.toml"]