1、Makefile简介

Makefile 是一种用于自动化构建软件项目的文件。它通常用于管理和执行编译、链接、测试等一系列任务,以提高开发效率。

1.1 目标与依赖

1.1.1目标(Targets)

  • 代表一个任务或一个文件的生成结果。例如,编译生成的可执行文件、库文件等都可以是目标。
  • 常见的目标有 “all”(表示构建整个项目)、“clean”(用于清理生成的文件)等。

1.1.2 依赖(Dependencies)

  • 目标所依赖的其他文件或目标。只有当依赖发生变化时,才会重新执行生成目标的命令。
  • 例如,一个可执行文件可能依赖于多个源文件和库文件。

1.2 规则与命令

1.2.1 规则(Rules)

  • 描述了如何从依赖生成目标。通常由目标、依赖和命令三部分组成。
  • 格式一般为:target: dependencies,接着是命令部分,每行命令前面必须以制表符(Tab)开头。

1.2.2 命令(Commands)

  • 用于执行生成目标的具体操作。可以是编译器命令、链接器命令、文件复制命令等。
  • 例如,编译 C 语言源文件的命令可能是gcc -o target source.c。

1.3 变量与函数

1.3.1 变量(Variables)

  • 可以定义和使用变量来存储常用的值,如编译器名称、编译选项、源文件列表等。
  • 变量定义方式为VARIABLE = value,使用时用$(VARIABLE)。

1.3.2 函数(Functions)

  • Makefile 提供了一些内置函数,可以进行字符串处理、文件操作等。
  • 例如,$(wildcard *.c)可以获取当前目录下所有的 C 语言源文件。

1.4 优势

1.4.1 自动化构建

  • 可以自动执行一系列构建步骤,减少手动操作和错误。
  • 当源文件发生变化时,只重新构建受影响的部分,提高构建效率。

1.4.2 可重复性

确保在不同的环境中都能以相同的方式构建项目。

1.4.3 易于维护

项目的构建过程集中在一个文件中,便于修改和管理。

2、kubebuilder makefile

2.1 kubebuilder 项目makefile

一个kubebuilder创建的operator项目的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
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# Image URL to use all building/pushing image targets
IMG ?= controller:latest
# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary.
ENVTEST_K8S_VERSION = 1.31.0

# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
ifeq (,$(shell go env GOBIN))
GOBIN=$(shell go env GOPATH)/bin
else
GOBIN=$(shell go env GOBIN)
endif

# CONTAINER_TOOL defines the container tool to be used for building images.
# Be aware that the target commands are only tested with Docker which is
# scaffolded by default. However, you might want to replace it to use other
# tools. (i.e. podman)
CONTAINER_TOOL ?= docker

# Setting SHELL to bash allows bash commands to be executed by recipes.
# Options are set to exit when a recipe line exits non-zero or a piped command fails.
SHELL = /usr/bin/env bash -o pipefail
.SHELLFLAGS = -ec

.PHONY: all
all: build

##@ General

# The help target prints out all targets with their descriptions organized
# beneath their categories. The categories are represented by '##@' and the
# target descriptions by '##'. The awk command is responsible for reading the
# entire set of makefiles included in this invocation, looking for lines of the
# file as xyz: ## something, and then pretty-format the target and help. Then,
# if there's a line with ##@ something, that gets pretty-printed as a category.
# More info on the usage of ANSI control characters for terminal formatting:
# https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters
# More info on the awk command:
# http://linuxcommand.org/lc3_adv_awk.php

.PHONY: help
help: ## Display this help.
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)

##@ Development

.PHONY: manifests
manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects.
$(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases

.PHONY: generate
generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations.
$(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..."

.PHONY: fmt
fmt: ## Run go fmt against code.
go fmt ./...

.PHONY: vet
vet: ## Run go vet against code.
go vet ./...

.PHONY: test
test: manifests generate fmt vet envtest ## Run tests.
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test $$(go list ./... | grep -v /e2e) -coverprofile cover.out

# Utilize Kind or modify the e2e tests to load the image locally, enabling compatibility with other vendors.
.PHONY: test-e2e # Run the e2e tests against a Kind k8s instance that is spun up.
test-e2e:
go test ./test/e2e/ -v -ginkgo.v

.PHONY: lint
lint: golangci-lint ## Run golangci-lint linter
$(GOLANGCI_LINT) run

.PHONY: lint-fix
lint-fix: golangci-lint ## Run golangci-lint linter and perform fixes
$(GOLANGCI_LINT) run --fix

##@ Build

.PHONY: build
build: manifests generate fmt vet ## Build manager binary.
go build -o bin/manager cmd/main.go

.PHONY: run
run: manifests generate fmt vet ## Run a controller from your host.
go run ./cmd/main.go

# If you wish to build the manager image targeting other platforms you can use the --platform flag.
# (i.e. docker build --platform linux/arm64). However, you must enable docker buildKit for it.
# More info: https://docs.docker.com/develop/develop-images/build_enhancements/
.PHONY: docker-build
docker-build: ## Build docker image with the manager.
$(CONTAINER_TOOL) build -t ${IMG} .

.PHONY: docker-push
docker-push: ## Push docker image with the manager.
$(CONTAINER_TOOL) push ${IMG}

# PLATFORMS defines the target platforms for the manager image be built to provide support to multiple
# architectures. (i.e. make docker-buildx IMG=myregistry/mypoperator:0.0.1). To use this option you need to:
# - be able to use docker buildx. More info: https://docs.docker.com/build/buildx/
# - have enabled BuildKit. More info: https://docs.docker.com/develop/develop-images/build_enhancements/
# - be able to push the image to your registry (i.e. if you do not set a valid value via IMG=<myregistry/image:<tag>> then the export will fail)
# To adequately provide solutions that are compatible with multiple platforms, you should consider using this option.
PLATFORMS ?= linux/arm64,linux/amd64,linux/s390x,linux/ppc64le
.PHONY: docker-buildx
docker-buildx: ## Build and push docker image for the manager for cross-platform support
# copy existing Dockerfile and insert --platform=${BUILDPLATFORM} into Dockerfile.cross, and preserve the original Dockerfile
sed -e '1 s/\(^FROM\)/FROM --platform=\$$\{BUILDPLATFORM\}/; t' -e ' 1,// s//FROM --platform=\$$\{BUILDPLATFORM\}/' Dockerfile > Dockerfile.cross
- $(CONTAINER_TOOL) buildx create --name myapp-operator-builder
$(CONTAINER_TOOL) buildx use myapp-operator-builder
- $(CONTAINER_TOOL) buildx build --push --platform=$(PLATFORMS) --tag ${IMG} -f Dockerfile.cross .
- $(CONTAINER_TOOL) buildx rm myapp-operator-builder
rm Dockerfile.cross

.PHONY: build-installer
build-installer: manifests generate kustomize ## Generate a consolidated YAML with CRDs and deployment.
mkdir -p dist
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
$(KUSTOMIZE) build config/default > dist/install.yaml

##@ Deployment

ifndef ignore-not-found
ignore-not-found = false
endif

.PHONY: install
install: manifests kustomize ## Install CRDs into the K8s cluster specified in ~/.kube/config.
$(KUSTOMIZE) build config/crd | $(KUBECTL) apply -f -

.PHONY: uninstall
uninstall: manifests kustomize ## Uninstall CRDs from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
$(KUSTOMIZE) build config/crd | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f -

.PHONY: deploy
deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config.
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
$(KUSTOMIZE) build config/default | $(KUBECTL) apply -f -

.PHONY: undeploy
undeploy: kustomize ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
$(KUSTOMIZE) build config/default | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f -

##@ Dependencies

## Location to install dependencies to
LOCALBIN ?= $(shell pwd)/bin
$(LOCALBIN):
mkdir -p $(LOCALBIN)

## Tool Binaries
KUBECTL ?= kubectl
KUSTOMIZE ?= $(LOCALBIN)/kustomize
CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen
ENVTEST ?= $(LOCALBIN)/setup-envtest
GOLANGCI_LINT = $(LOCALBIN)/golangci-lint

## Tool Versions
KUSTOMIZE_VERSION ?= v5.4.3
CONTROLLER_TOOLS_VERSION ?= v0.16.1
ENVTEST_VERSION ?= release-0.19
GOLANGCI_LINT_VERSION ?= v1.59.1

.PHONY: kustomize
kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary.
$(KUSTOMIZE): $(LOCALBIN)
$(call go-install-tool,$(KUSTOMIZE),sigs.k8s.io/kustomize/kustomize/v5,$(KUSTOMIZE_VERSION))

.PHONY: controller-gen
controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary.
$(CONTROLLER_GEN): $(LOCALBIN)
$(call go-install-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen,$(CONTROLLER_TOOLS_VERSION))

.PHONY: envtest
envtest: $(ENVTEST) ## Download setup-envtest locally if necessary.
$(ENVTEST): $(LOCALBIN)
$(call go-install-tool,$(ENVTEST),sigs.k8s.io/controller-runtime/tools/setup-envtest,$(ENVTEST_VERSION))

.PHONY: golangci-lint
golangci-lint: $(GOLANGCI_LINT) ## Download golangci-lint locally if necessary.
$(GOLANGCI_LINT): $(LOCALBIN)
$(call go-install-tool,$(GOLANGCI_LINT),github.com/golangci/golangci-lint/cmd/golangci-lint,$(GOLANGCI_LINT_VERSION))

# go-install-tool will 'go install' any package with custom target and name of binary, if it doesn't exist
# $1 - target path with name of binary
# $2 - package url which can be installed
# $3 - specific version of package
define go-install-tool
@[ -f "$(1)-$(3)" ] || { \
set -e; \
package=$(2)@$(3) ;\
echo "Downloading $${package}" ;\
rm -f $(1) || true ;\
GOBIN=$(LOCALBIN) go install $${package} ;\
mv $(1) $(1)-$(3) ;\
} ;\
ln -sf $(1)-$(3) $(1)
endef

2.2 变量定义部分

2.2.1 IMG(定义构建和推送Docker镜像的目标镜像URL)

1
2
# Image URL to use all building/pushing image targets
IMG ?= controller:latest

作用:定义构建和推送Docker镜像的目标镜像URL
解释:如果没有在命令中指定IMG,则默认值为controller:latest

2.2.2 ENVTEST_K8S_VERSION(定义envtest工具下载的Kubernetes资产版本)

1
2
# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary.
ENVTEST_K8S_VERSION = 1.31.0

作用:定义envtest工具下载的Kubernetes资产版本
解释:envtest是一个用于测试的工具,这个变量制定了要下载的Kubernetes版本。

2.2.3 GOBIN(当前使用的Go的安装路径)

1
2
3
4
5
6
# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
ifeq (,$(shell go env GOBIN))
GOBIN=$(shell go env GOPATH)/bin
else
GOBIN=$(shell go env GOBIN)
endif

作用:获取当前使用的Go的安装路径
解释:如果GONBIN环境变量未设置,则使用GOPATCH/bin作为默认路径;否则使用GOBIN的值。

2.2.4 CONTAINER_TOOL(用于构建镜像的容器工具)

1
2
3
4
5
# CONTAINER_TOOL defines the container tool to be used for building images.
# Be aware that the target commands are only tested with Docker which is
# scaffolded by default. However, you might want to replace it to use other
# tools. (i.e. podman)
CONTAINER_TOOL ?= docker

作用:定义用于构建镜像的容器工具
解释:默认值为docker,但是可以替换为其他工具,例如podman

2.2.5 SHELL 和 .SHELLFLAGS(设置Makefile使用的shell和shell选项)

1
2
3
4
# Setting SHELL to bash allows bash commands to be executed by recipes.
# Options are set to exit when a recipe line exits non-zero or a piped command fails.
SHELL = /usr/bin/env bash -o pipefail
.SHELLFLAGS = -ec

作用:设置Makefile使用的shell和shell选项
解释:

  • SHELL设置为/usr/bin/env bash -o pipefail
  • .SHELLFLAGS 设置为-ec,表示shell应该立即退出并在任何命令失败时报告错误

2.3 目标定义部分

2.3.1 通用目标

2.3.1.1 all(定义默认目标,调用build目标)

1
2
.PHONY: all
all: build

作用:定义默认目标,调用build目标
解释:当运行make时,如果没有指定目标。默认会执行build目标。

2.3.1.2 help(显示帮助信息)

1
2
3
.PHONY: help
help: ## Display this help.
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)

作用:显示帮助信息
解释:使用awk命令解析Makefile,提取每个目标的描述,并按类别组织显示。##@表示类别,##表示目标描述

2.3.2 开发目标

2.3.2.1 manifests(生成WebhookConfiguration、ClusterRole和CustomResourceDefinition 对象)

1
2
3
.PHONY: manifests
manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects.
$(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases

作用:生成WebhookConfiguration、ClusterRole和CustomResourceDefinition 对象
解释:使用controller-gen工具生成必要的Kubernetes资源文件,并保存到config/crd/bases目录

2.3.2.2 generate(生成包含DeepCopy、DeepCopyInto, 和DeepCopyObject方法实现的代码。)

1
2
3
.PHONY: generate
generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations.
$(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..."

作用:生成包含DeepCopy、DeepCopyInto, 和DeepCopyObject方法实现的代码。
解释:使用controller-gen工具生成GO代码,这些代码自动生成对象的深拷贝方法。

2.3.2.3 fmt(格式化代码)

1
2
3
.PHONY: fmt
fmt: ## Run go fmt against code.
go fmt ./...

作用:格式化代码
解释:使用go fmt命令格式化项目中的所有Go代码

2.3.2.4 vet(检查代码中的潜在问题)

1
2
3
.PHONY: vet
vet: ## Run go vet against code.
go vet ./...

作用:检查代码中的潜在问题
解释:使用go vet命令检查项目中的所有Go代码,查找可能的问题。

2.3.2.5 test(运行测试)

1
2
3
.PHONY: test
test: manifests generate fmt vet envtest ## Run tests.
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test $$(go list ./... | grep -v /e2e) -coverprofile cover.out

作用:运行测试
解释:

  • 先运行manifests、generate、fmt和vet目标
  • 使用envtest工具设置环境变量KUBEBUILDER_ASSETS,然后运行项目中的所有测试(排除e2e测试)

2.3.2.6 test-e2e(运行端到端测试)

1
2
3
4
# Utilize Kind or modify the e2e tests to load the image locally, enabling compatibility with other vendors.
.PHONY: test-e2e # Run the e2e tests against a Kind k8s instance that is spun up.
test-e2e:
go test ./test/e2e/ -v -ginkgo.v

作用:运行端到端测试
解释:使用go test命令运行test/e2e目录中的端到端测试,并启动详细输出。

2.3.2.7 lint(运行代码风格检查)

1
2
3
.PHONY: lint
lint: golangci-lint ## Run golangci-lint linter
$(GOLANGCI_LINT) run

作用:运行代码风格检查
解释:使用golangci-lint工具运行代码风格检查

2.3.2.8 lint-fix (运行代码风格检查并自动修复问题)

1
2
3
4
.PHONY: lint-fix
lint-fix: golangci-lint ## Run golangci-lint linter and perform fixes
$(GOLANGCI_LINT) run --fix

作用:运行代码风格检查并自动修复问题
解释:使用golangci-lint工具运行代码风格检查,并使用–fix选项自动修复发现的问题。

2.3.3 构建目标

2.3.3.1 build(构建controller的二进制文件)

1
2
3
.PHONY: build
build: manifests generate fmt vet ## Build manager binary.
go build -o bin/manager cmd/main.go

作用:构建controller的二进制文件
解释:

  • 先运行manifests、generate、fmt和vet目标
  • 使用go build命令编译cmd/main.go文件,并将生成的二进制文件保存到bin/manager。

2.3.3.2 run(在主机上运行controller)

1
2
3
.PHONY: run
run: manifests generate fmt vet ## Run a controller from your host.
go run ./cmd/main.go

作用:在主机上运行controller
解释:

  • 先运行manifests、generate、fmt和vet目标
  • 使用go run命令运行cmd/main.go文件

2.3.3.3 docker-build(构建Docker镜像)

1
2
3
4
5
6
# If you wish to build the manager image targeting other platforms you can use the --platform flag.
# (i.e. docker build --platform linux/arm64). However, you must enable docker buildKit for it.
# More info: https://docs.docker.com/develop/develop-images/build_enhancements/
.PHONY: docker-build
docker-build: ## Build docker image with the manager.
$(CONTAINER_TOOL) build -t ${IMG} .

作用:构建Docker镜像
解释:使用CONTAINER_TOOL(默认为docker)构建docker镜像,并使用IMG变量指定镜像名称和标签

2.3.3.4 docker-push(推送Docker镜像)

1
2
3
.PHONY: docker-push
docker-push: ## Push docker image with the manager.
$(CONTAINER_TOOL) push ${IMG}

作用:推送Docker镜像
解释:使用CONTAINER_TOOL(默认为docker)推送构建好的Docker镜像到指定的仓库

2.3.3.5 docker-buildx(构建并推送多平台支持的Docker镜像)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# PLATFORMS defines the target platforms for the manager image be built to provide support to multiple
# architectures. (i.e. make docker-buildx IMG=myregistry/mypoperator:0.0.1). To use this option you need to:
# - be able to use docker buildx. More info: https://docs.docker.com/build/buildx/
# - have enabled BuildKit. More info: https://docs.docker.com/develop/develop-images/build_enhancements/
# - be able to push the image to your registry (i.e. if you do not set a valid value via IMG=<myregistry/image:<tag>> then the export will fail)
# To adequately provide solutions that are compatible with multiple platforms, you should consider using this option.
PLATFORMS ?= linux/arm64,linux/amd64,linux/s390x,linux/ppc64le
.PHONY: docker-buildx
docker-buildx: ## Build and push docker image for the manager for cross-platform support
# copy existing Dockerfile and insert --platform=${BUILDPLATFORM} into Dockerfile.cross, and preserve the original Dockerfile
sed -e '1 s/\(^FROM\)/FROM --platform=\$$\{BUILDPLATFORM\}/; t' -e ' 1,// s//FROM --platform=\$$\{BUILDPLATFORM\}/' Dockerfile > Dockerfile.cross
- $(CONTAINER_TOOL) buildx create --name myapp-operator-builder
$(CONTAINER_TOOL) buildx use myapp-operator-builder
- $(CONTAINER_TOOL) buildx build --push --platform=$(PLATFORMS) --tag ${IMG} -f Dockerfile.cross .
- $(CONTAINER_TOOL) buildx rm myapp-operator-builder
rm Dockerfile.cross

作用:构建并推送多平台支持的Docker镜像
解释:

  • 使用sed命令复制现有的Dockerfile并插入–platform=${BUILDPLATFORM}选项,生成Dockerfile.cross
  • 创建一个名为myapp-builder的构建器
  • 使用buildx构建并推送多平台镜像
  • 删除构建器和临时生成的Dockerfile.cross

2.3.3.6 docker-installer(生成包含CRDs和部署的合并YAML文件)

1
2
3
4
5
.PHONY: build-installer
build-installer: manifests generate kustomize ## Generate a consolidated YAML with CRDs and deployment.
mkdir -p dist
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
$(KUSTOMIZE) build config/default > dist/install.yaml

作用:生成包含CRDs和部署的合并YAML文件
解释:

  • 创建dist目录
  • 使用kustomize工具设置controller镜像为IMG
  • 使用kustomize构建config/default目录中的资源,并保存到dist/install.yaml

2.3.4 部署目标

2.3.4.1 install(安装CRDs到Kubernetes集群)

1
2
3
.PHONY: install
install: manifests kustomize ## Install CRDs into the K8s cluster specified in ~/.kube/config.
$(KUSTOMIZE) build config/crd | $(KUBECTL) apply -f -

作用:安装CRDs到Kubernetes集群
解释:

  • 先运行manifests和kustomize目标
  • 使用kustomize 构建config/crd目录中的资源,并使用kubectl将其应用到集群。

2.3.4.2 uninstall(从Kubernetes集群卸载CRDs)

1
2
3
.PHONY: uninstall
uninstall: manifests kustomize ## Uninstall CRDs from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
$(KUSTOMIZE) build config/crd | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f -

作用:从Kubernetes集群卸载CRDs
解释:

  • 先运行manifests和kustomize目标
  • 使用kustomize 构建config/crd目录中的资源,并使用kubectl将其从集群中删除,可以通过ignore-not-found=true忽略资源未找到的错误

2.3.4.3 deploy(部署controller到Kubernetes集群)

1
2
3
4
.PHONY: deploy
deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config.
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
$(KUSTOMIZE) build config/default | $(KUBECTL) apply -f -

作用:部署controller到Kubernetes集群
解释:

  • 先运行manifests和kustomize目标
  • 使用kustomize设置controller镜像为IMG
  • 使用kustomize构建config/default目录中的资源,并使用kubectl将其应用到集群

2.3.4.4 undeploy(从Kubernetes集群中卸载Controller)

1
2
3
.PHONY: undeploy
undeploy: kustomize ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
$(KUSTOMIZE) build config/default | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f -

作用:从Kubernetes集群中卸载Controller
解释:使用kustomize 构建config/default目录中的资源,并使用kubectl将其从集群中删除。可以通过ignore-not-found=true忽略资源未找到的错误

2.3.5 依赖目标

2.3.5.1 ignore-not-found(定义ignore-not-found变量,默认值为false)

1
2
3
ifndef ignore-not-found
ignore-not-found = false
endif

作用:定义ignore-not-found变量,默认值为false
解释:如果命令行中未指定ignore-not-found,则默认值为false

2.3.5.2 LOCALBIN(定义本地二进制文件的安装目录)

1
2
3
4
## Location to install dependencies to
LOCALBIN ?= $(shell pwd)/bin
$(LOCALBIN):
mkdir -p $(LOCALBIN)

作用:定义本地二进制文件的安装目录,默认为当前目录下的bin目录
解释:如果LOCALBIN未设置,则默认为$(shell pwd)/bin。如果LOCALBIN目录不存在,则创建它。

2.3.5.3 工具二进制文件(定义各种工具的路径和默认值)

1
2
3
4
5
6
## Tool Binaries
KUBECTL ?= kubectl
KUSTOMIZE ?= $(LOCALBIN)/kustomize
CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen
ENVTEST ?= $(LOCALBIN)/setup-envtest
GOLANGCI_LINT = $(LOCALBIN)/golangci-lint

作用:定义各种工具的路径和默认值
解释:

  • KUBECTL:默认为kubectl
  • KUSTOMIZE:默认为$(LOCALBIN)/kustomize
  • CONTROLLER_GEN:默认为$(LOCALBIN)/controller-gen
  • ENVTEST:默认为$(LOCALBIN)/setup-envtest
  • GOLANGCI_LINT: 默认为$(LOCALBIN)/golangci-lint

2.3.5.4 工具版本(定义各个工具的版本)

1
2
3
4
5
## Tool Versions
KUSTOMIZE_VERSION ?= v5.4.3
CONTROLLER_TOOLS_VERSION ?= v0.16.1
ENVTEST_VERSION ?= release-0.19
GOLANGCI_LINT_VERSION ?= v1.59.1

作用:定义各个工具的版本
解释:

  • KUSTOMIZE_VERSION:默认为v5.4.3
  • CONTROLLER_TOOLS_VERSION:默认为v0.16.1
  • ENVTEST_VERSION:默认为release-0.19
  • GOLANGCI_LINT_VERSION:默认为v1.59.1

2.3.5.5 kustomize(下载kustomize工具)

1
2
3
4
.PHONY: kustomize
kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary.
$(KUSTOMIZE): $(LOCALBIN)
$(call go-install-tool,$(KUSTOMIZE),sigs.k8s.io/kustomize/kustomize/v5,$(KUSTOMIZE_VERSION))

作用:下载kustomize工具(如有必要)
解释:如果kustomize文件不存在,则调用 go-install-tool函数下载kustomize工具

2.3.5.6 controller-gen(下载controller-gen工具)

1
2
3
4
.PHONY: controller-gen
controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary.
$(CONTROLLER_GEN): $(LOCALBIN)
$(call go-install-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen,$(CONTROLLER_TOOLS_VERSION))

作用:下载controller-gen工具(如有必要)
解释:如果$(CONTROLLER_GEN)文件不存在,则调用 go-install-tool函数下载controller-gen工具

2.3.5.7 envtest(下载setup-envtest工具)

1
2
3
4
.PHONY: envtest
envtest: $(ENVTEST) ## Download setup-envtest locally if necessary.
$(ENVTEST): $(LOCALBIN)
$(call go-install-tool,$(ENVTEST),sigs.k8s.io/controller-runtime/tools/setup-envtest,$(ENVTEST_VERSION))

作用:下载setup-envtest工具(如有必要)
解释:如果$(ENVTEST)文件不存在,则调用go-install-tool函数下载setup-envtes工具

2.3.5.8 golangci-lint(下载golangci-lint工具)

1
2
3
4
.PHONY: golangci-lint
golangci-lint: $(GOLANGCI_LINT) ## Download golangci-lint locally if necessary.
$(GOLANGCI_LINT): $(LOCALBIN)
$(call go-install-tool,$(GOLANGCI_LINT),github.com/golangci/golangci-lint/cmd/golangci-lint,$(GOLANGCI_LINT_VERSION))

作用:下载golangci-lint工具(如有必要)
解释:如果$(GOLANGCI_LINT)文件不存在,则调用go-install-tool函数下载golangci-lint工具。

2.4 自定义函数

2.4.1 go-install-tool(下载并安装指定的Go包)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# go-install-tool will 'go install' any package with custom target and name of binary, if it doesn't exist
# $1 - target path with name of binary
# $2 - package url which can be installed
# $3 - specific version of package
define go-install-tool
@[ -f "$(1)-$(3)" ] || { \
set -e; \
package=$(2)@$(3) ;\
echo "Downloading $${package}" ;\
rm -f $(1) || true ;\
GOBIN=$(LOCALBIN) go install $${package} ;\
mv $(1) $(1)-$(3) ;\
} ;\
ln -sf $(1)-$(3) $(1)
endef

作用:下载并安装指定的Go包
解释:

  • $1:目标路径和二进制文件名
  • $2:包的URL
  • $3:包的具体版本
  • 如果目标文件$(1)~$(3)不存在,则执行以下步骤
  • 设置set -e,确保任何命令执行失败立即退出
  • 设置package变量为包的URL和版本
  • 输出下载信息
  • 删除旧的二进制文件(如果存在)
  • 使用go install命令安装包,并将二进制文件保存在LOCALBIN目录
  • 将生成的二进制文件重命令为$(1)-$(3)
  • 最后创建一个符号链接,指向$(1)-$(3)