diff --git a/Dockerfile b/Dockerfile index 8f9cca1..1066909 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,17 +1,26 @@ +# 构建 operator 的镜像 # Build the manager binary + +###################### build 阶段 ########################### +# 获取编译需要的环境,并且将这个阶段(镜像)命名为 builder FROM golang:1.19 as builder +# 参数定义,用户选择性的设置这些参数 TARGETOS="linux" TARGETARCH="amd64|arm64" docker build ARG TARGETOS ARG TARGETARCH +# 指定工作目录,后续的命令都是在这个目录下进行 WORKDIR /workspace # Copy the Go Modules manifests +# 拷贝 go 依赖相关的文件 COPY go.mod go.mod COPY go.sum go.sum # cache deps before building and copying source so that we don't need to re-download as much # and so that source changes don't invalidate our downloaded layer +# 下载依赖 RUN go mod download # Copy the go source +# 拷贝 operator 相关的文件及文件夹 COPY main.go main.go COPY api/ api/ COPY controllers/ controllers/ @@ -21,13 +30,20 @@ COPY controllers/ controllers/ # was called. For example, if we call make docker-build in a local env which has the Apple Silicon M1 SO # the docker BUILDPLATFORM arg will be linux/arm64 when for Apple x86 it will be linux/amd64. Therefore, # by leaving it empty we can ensure that the container and binary shipped on it will have the same platform. +# 开始执行构建,这里会产出我们需要的可执行的二进制文件 RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager main.go +######################### 创建运行镜像阶段 ################################ # Use distroless as minimal base image to package the manager binary # Refer to https://github.com/GoogleContainerTools/distroless for more details +# 定义运行镜像的来源 FROM gcr.io/distroless/static:nonroot +# 指定工作目录,后续的执行都在此目录下 WORKDIR / -COPY --from=builder /workspace/manager . +# 从 builder 阶段(镜像)中拷贝之前生成的可执行二进制文件 +COPY --from=builder /workspace/manager +# 设置运行的账户 USER 65532:65532 +# 设置入口文件。如果镜像的时候,我们没有指定运行命令,将会自动运行此命令。 ENTRYPOINT ["/manager"] diff --git a/Makefile b/Makefile index a29b0e0..065229c 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,9 @@ # Image URL to use all building/pushing image targets +# 镜像的环境变量,如果不设置,将使用controller:latest作文镜像名称。 +# 这个环境变量将会被使用在 构建镜像、推送镜像、部署operator的时候来使用 IMG ?= controller:latest + # ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary. ENVTEST_K8S_VERSION = 1.25.0 diff --git a/PROJECT b/PROJECT index b2d3be5..736c736 100644 --- a/PROJECT +++ b/PROJECT @@ -1,16 +1,16 @@ -domain: mashibing.com +domain: mashibing.com # 初始化的时候 --domain 的参数 layout: -- go.kubebuilder.io/v3 -projectName: demo -repo: mashibing.com/demo/app +- go.kubebuilder.io/v3 # 插件名称,决定了生成文件的内容 +projectName: demo # 项目名称,默认值是项目所在文件夹的名称 +repo: mashibing.com/demo/app # 项目的 git repo 地址 resources: - api: - crdVersion: v1 - namespaced: true - controller: true - domain: mashibing.com - group: demo - kind: App - path: mashibing.com/demo/app/api/v1 - version: v1 -version: "3" + crdVersion: v1 # 版本,创建 api 的时候 --version 的参数 + namespaced: true # 默认行为,指定这个资源是 namespace + controller: true # 创建 api 的时候,是否生成 controller + domain: mashibing.com # 和 第一层级中的 domain 相同 + group: demo # 创建 api 时 --group 的参数。在 operator 中,group 的名称为 . 也就是说,这里的group名字为 demo.mashibing.com + kind: App # 创建 api 时 --kind 的参数 + path: mashibing.com/demo/app/api/v1 # api 的 pkg 路径 + version: v1 # api 的版本 +version: "3" # kubebuilder 生成的项目的版本 diff --git a/api/v1/app_types.go b/api/v1/app_types.go index 75d8673..b649461 100644 --- a/api/v1/app_types.go +++ b/api/v1/app_types.go @@ -41,17 +41,19 @@ type AppStatus struct { //+kubebuilder:object:root=true //+kubebuilder:subresource:status +// 定义我们CRD的对象 // App is the Schema for the apps API type App struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` + metav1.TypeMeta `json:",inline"` // 元信息 + metav1.ObjectMeta `json:"metadata,omitempty"` // 元信息 - Spec AppSpec `json:"spec,omitempty"` - Status AppStatus `json:"status,omitempty"` + Spec AppSpec `json:"spec,omitempty"` // crd 的核心内容,crd 的描述定义 + Status AppStatus `json:"status,omitempty"` // crd 现阶段状态的的内容 } //+kubebuilder:object:root=true +// 定义我们CRD的列表 // AppList contains a list of App type AppList struct { metav1.TypeMeta `json:",inline"` diff --git a/api/v1/groupversion_info.go b/api/v1/groupversion_info.go index 3f5f42f..45099c1 100644 --- a/api/v1/groupversion_info.go +++ b/api/v1/groupversion_info.go @@ -25,12 +25,15 @@ import ( ) var ( + // 创建GV // GroupVersion is group version used to register these objects GroupVersion = schema.GroupVersion{Group: "demo.mashibing.com", Version: "v1"} + //用GV开创建 Builder // SchemeBuilder is used to add go types to the GroupVersionKind scheme SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} + // 用Builder 创建Scheme对象的方法 // AddToScheme adds the types in this group-version to the given scheme. AddToScheme = SchemeBuilder.AddToScheme ) diff --git a/config/crd/bases/demo.mashibing.com_apps.yaml b/config/crd/bases/demo.mashibing.com_apps.yaml new file mode 100644 index 0000000..632831c --- /dev/null +++ b/config/crd/bases/demo.mashibing.com_apps.yaml @@ -0,0 +1,50 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.2 + creationTimestamp: null + name: apps.demo.mashibing.com +spec: + group: demo.mashibing.com + names: + kind: App + listKind: AppList + plural: apps + singular: app + scope: Namespaced + versions: + - name: v1 + schema: + openAPIV3Schema: + description: 定义我们CRD的对象 App is the Schema for the apps API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: AppSpec defines the desired state of App + properties: + foo: + description: Foo is an example field of App. Edit app_types.go to + remove/update + type: string + type: object + status: + description: AppStatus defines the observed state of App + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml new file mode 100644 index 0000000..98c136d --- /dev/null +++ b/config/rbac/role.yaml @@ -0,0 +1,33 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + creationTimestamp: null + name: manager-role +rules: +- apiGroups: + - demo.mashibing.com + resources: + - apps + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - demo.mashibing.com + resources: + - apps/finalizers + verbs: + - update +- apiGroups: + - demo.mashibing.com + resources: + - apps/status + verbs: + - get + - patch + - update diff --git a/controllers/app_controller.go b/controllers/app_controller.go index 50292fa..3e9d581 100644 --- a/controllers/app_controller.go +++ b/controllers/app_controller.go @@ -27,6 +27,7 @@ import ( demov1 "mashibing.com/demo/app/api/v1" ) +// 是提供调和函数(把现阶段的状态,和我们定义的状态进行统一。趋近的调和函数),对象中的数据,可以是在上层统一管理 // AppReconciler reconciles a App object type AppReconciler struct { client.Client @@ -37,6 +38,7 @@ type AppReconciler struct { //+kubebuilder:rbac:groups=demo.mashibing.com,resources=apps/status,verbs=get;update;patch //+kubebuilder:rbac:groups=demo.mashibing.com,resources=apps/finalizers,verbs=update +// 我们核心功能函数,要去定义operator的行为 // Reconcile is part of the main kubernetes reconciliation loop which aims to // move the current state of the cluster closer to the desired state. // TODO(user): Modify the Reconcile function to compare the state specified by @@ -50,10 +52,12 @@ func (r *AppReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.R _ = log.FromContext(ctx) // TODO(user): your logic here + // 实现你的业务逻辑 return ctrl.Result{}, nil } +// 将 controller 注册到 manager 中 // SetupWithManager sets up the controller with the Manager. func (r *AppReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). diff --git a/main.go b/main.go index caf8830..1b6e486 100644 --- a/main.go +++ b/main.go @@ -37,18 +37,22 @@ import ( ) var ( + // 一个对象,用来管理gvk和gostruct(crd)映射,以及一些互相转换的方法。 scheme = runtime.NewScheme() setupLog = ctrl.Log.WithName("setup") ) func init() { + // k8s 内置的 GVK 和 gostruct 的映射,也就是这个scheme需要的方法和映射,注入到scheme变量中 utilruntime.Must(clientgoscheme.AddToScheme(scheme)) + // 本 operator 中的 GVK 和 gostruct 的映射,也就是这个scheme需要的方法和映射,注入到scheme变量中 utilruntime.Must(demov1.AddToScheme(scheme)) //+kubebuilder:scaffold:scheme } func main() { + // 处理命令行参数 var metricsAddr string var enableLeaderElection bool var probeAddr string @@ -63,10 +67,13 @@ func main() { opts.BindFlags(flag.CommandLine) flag.Parse() + // 处理日志的参数 ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) + // 完成处理命令 + // 创建 manager mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ - Scheme: scheme, + Scheme: scheme, // 前面创建的 gvk 和 gostruct 映射的对象 MetricsBindAddress: metricsAddr, Port: 9443, HealthProbeBindAddress: probeAddr, @@ -89,6 +96,7 @@ func main() { os.Exit(1) } + // 注册我们的 controller if err = (&controllers.AppReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), @@ -98,6 +106,7 @@ func main() { } //+kubebuilder:scaffold:builder + // 添加探活的path if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { setupLog.Error(err, "unable to set up health check") os.Exit(1) @@ -107,6 +116,7 @@ func main() { os.Exit(1) } + // 启动程序 setupLog.Info("starting manager") if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { setupLog.Error(err, "problem running manager")