Operator 示例:使用 Redis 部署 PHP 留言板应用程序

  • 安装 Docker Desktop,并启动内置的 Kubernetes 集群
  • 注册一个hub.docker.com 账户,需要将本地构建好的镜像推送至公开仓库中
  • 安装 operator SDK CLI: brew install operator-sdk
  • 安装 Go: brew install go

本示例推荐的依赖版本:

  • Docker Desktop: >= 4.0.0
  • Kubernetes: >= 1.21.4
  • Operator-SDK: >= 1.11.0
  • Go: >= 1.17

jxlwqq 为笔者的 ID,命令行和代码中涉及的个人 ID,均需要替换为读者自己的,包括

  • --domain=
  • --repo=
  • //+kubebuilder:rbac:groups=
  • IMAGE_TAG_BASE ?=

使用 Operator SDK CLI 创建名为 guestbook-operator 的项目。

mkdir -p $HOME/projects/guestbook-operator
cd $HOME/projects/guestbook-operator
go env -w GOPROXY=https://goproxy.cn,direct
shell

operator-sdk init \
--domain=jxlwqq.github.io \
--repo=github.com/jxlwqq/guestbook-operator \
--skip-go-version-check
</code></pre>
<p>使用 Operator SDK CLI 创建自定义资源定义(CRD)API 和控制器。</p>
<p>运行以下命令创建带有组 app、版本 v1alpha1 和种类 Guestbook 的 API:</p>
<pre><code class="language-shell">operator-sdk create api \
--resource=true \
--controller=true \
--group=app \
--version=v1alpha1 \
--kind=Guestbook
</code></pre>
<p>定义 Guestbook 自定义资源(CR)的 API。</p>
<p>修改 api/v1alpha1/guestbook_types.go 中的 Go 类型定义,使其具有以下 spec 和 status</p>
<pre><code class="language-go">type GuestbookSpec struct {
    FrontendSize int32 :"frontendSize"
    RedisFollowerSize int32 :"redisFollowerSize"`
}

为资源类型更新生成的代码:

make generate

运行以下命令以生成和更新 CRD 清单:

make manifests

由于逻辑较为复杂,代码较为庞大,所以无法在此全部展示,完整的操作器代码请参见 controllers 目录。
在本例中,将生成的控制器文件 controllers/guestbook_controller.go 替换为以下示例实现:

/*
Copyright 2021.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

See the License for the specific language governing permissions and
limitations under the License.

*/

package controllers

import (
    "context"
    appsv1 "k8s.io/api/apps/v1"
    corev1 "k8s.io/api/core/v1"
    "k8s.io/apimachinery/pkg/api/errors"

    "k8s.io/apimachinery/pkg/runtime"
    ctrl "sigs.k8s.io/controller-runtime"
    "sigs.k8s.io/controller-runtime/pkg/client"
    "sigs.k8s.io/controller-runtime/pkg/log"

    appv1alpha1 "github.com/jxlwqq/guestbook-operator/api/v1alpha1"
)

// GuestbookReconciler reconciles a Guestbook object
type GuestbookReconciler struct {
    client.Client
    Scheme *runtime.Scheme
}

//+kubebuilder:rbac:groups=app.jxlwqq.github.io,resources=guestbooks,verbs=get;list;watch;create;update;patch;delete
//+kubebuilder:rbac:groups=app.jxlwqq.github.io,resources=guestbooks/status,verbs=get;update;patch
//+kubebuilder:rbac:groups=app.jxlwqq.github.io,resources=guestbooks/finalizers,verbs=update
//+kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete
//+kubebuilder:rbac:groups=core,resources=service,verbs=get;list;watch;create;update;patch;delete
//+kubebuilder:rbac:groups=core,resources=pods,verbs=get;list;watch

// 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
// the Guestbook object against the actual cluster state, and then
// perform operations to make the cluster state reflect the state specified by
// the user.

//
// For more details, check Reconcile and its Result here:
// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.9.2/pkg/reconcile
func (r *GuestbookReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
    reqLogger := log.FromContext(ctx)
    reqLogger.Info("Reconciling Guestbook")

    guestbook := &appv1alpha1.Guestbook{}
    err := r.Client.Get(context.TODO(), req.NamespacedName, guestbook)
    if err != nil {
        if errors.IsNotFound(err) {
            return ctrl.Result{}, nil
        }
        return ctrl.Result{}, err
    }

    var result = &ctrl.Result{}

    result, err = r.ensureDeployment(r.redisLeaderDeployment(guestbook))
    if result != nil {
        return *result, err
    }
    result, err = r.ensureService(r.redisLeaderService(guestbook))
    if result != nil {
        return *result, err
    }

    result, err = r.ensureDeployment(r.redisFollowerDeployment(guestbook))
    if result != nil {
        return *result, err
    }
    result, err = r.ensureService(r.redisFollowerService(guestbook))
    if result != nil {
        return *result, err
    }
    result, err = r.handleRedisFollowerChanges(guestbook)
    if result != nil {
        return *result, err
    }

    result, err = r.ensureDeployment(r.frontendDeployment(guestbook))
    if result != nil {
        return *result, err
    }
    result, err = r.ensureService(r.frontendService(guestbook))
    if result != nil {
        return *result, err
    }
    result, err = r.handleFrontendChanges(guestbook)
    if result != nil {
        return *result, err
    }

    return ctrl.Result{}, nil
}

// SetupWithManager sets up the controller with the Manager.

func (r *GuestbookReconciler) SetupWithManager(mgr ctrl.Manager) error {
    return ctrl.NewControllerManagedBy(mgr).
        For(&appv1alpha1.Guestbook{}).
        Owns(&appsv1.Deployment{}).
        Owns(&corev1.Service{}).
        Complete(r)
}

运行以下命令以生成和更新 CRD 清单:

make manifests

捆绑 Operator,并使用 Operator Lifecycle Manager(OLM)在集群中部署。

修改 Makefile 中 IMAGE_TAG_BASE 和 IMG:

IMAGE_TAG_BASE ?= docker.io/jxlwqq/guestbook-operator
IMG ?= $(IMAGE_TAG_BASE):latest

构建镜像:

make docker-build

将镜像推送到镜像仓库:

make docker-push

运行 make bundle 命令创建 Operator 捆绑包清单,并依次填入名称、作者等必要信息:

make bundle

构建捆绑包镜像:

make bundle-build

推送捆绑包镜像:

make bundle-push

使用 Operator Lifecycle Manager 部署 Operator:

切换至本地集群
kubectl config use-context docker-desktop
安装 olm
operator-sdk olm install
使用 Operator SDK 中的 OLM 集成在集群中运行 Operator
operator-sdk run bundle docker.io/jxlwqq/guestbook-operator-bundle:v0.0.1

编辑 config/samples/app_v1alpha1_guestbook.yaml 上的 Guestbook CR 清单示例,使其包含以下规格:

apiVersion: app.jxlwqq.github.io/v1alpha1
kind: Guestbook
metadata:
  name: guestbook-sample
spec:
  # Add fields here
  frontendSize: 2
  redisFollowerSize: 2

创建 CR:

kubectl apply -f config/samples/app_v1alpha1_guestbook.yaml

查看 Pod:

NAME                              READY   STATUS    RESTARTS   AGE
frontend-85595f5bf9-jrcp4         1/1     Running   0          9s
frontend-85595f5bf9-q8fkl         1/1     Running   0          9s
redis-follower-76c5cc5b79-fxxlq   1/1     Running   0          9s
redis-follower-76c5cc5b79-g8vnf   1/1     Running   0          9s
redis-leader-6666df964-vjhp2      1/1     Running   0          9s

查看 Service:

NAME             TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
frontend         NodePort    10.106.145.169           80:30693/TCP   24s
kubernetes       ClusterIP   10.96.0.1                443/TCP        4m58s
redis-follower   ClusterIP   10.108.30.112            6379/TCP       24s
redis-leader     ClusterIP   10.106.255.152           6379/TCP       24s

网页上会显示出 Guestbook 的表单页面。

更新 CR:

修改frontend 和 redis 副本数
kubectl patch guestbook guestbook-sample -p '{"spec":{"frontendSize": 3, "redisFollowerSize": 3}}' --type=merge

查看 Pod:

NAME                              READY   STATUS    RESTARTS   AGE
frontend-85595f5bf9-4pmfj         1/1     Running   0          4s
frontend-85595f5bf9-jrcp4         1/1     Running   0          50s
frontend-85595f5bf9-q8fkl         1/1     Running   0          50s
redis-follower-76c5cc5b79-bxbb4   1/1     Running   0          4s
redis-follower-76c5cc5b79-fxxlq   1/1     Running   0          50s
redis-follower-76c5cc5b79-g8vnf   1/1     Running   0          50s
redis-leader-6666df964-vjhp2      1/1     Running   0          50s
operator-sdk cleanup guestbook-operator
operator-sdk olm uninstall

Original: https://www.cnblogs.com/jxlwqq/p/15264489.html
Author: jxlwqq
Title: Operator 示例:使用 Redis 部署 PHP 留言板应用程序

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/516600/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Golang:将日志以Json格式输出到Kafka

    工程实践中,我们往往还需要对日志进行采集,将日志归集到一起,然后用于各种处理分析,比如生产环境上的错误分析、异常告警等等。在日志消息系统领域,Kafka久负盛名,这篇文章就以将日志…

    Go语言 2023年5月25日
    069
  • Go语言基础之并发

    并发是编程里面一个非常重要的概念,Go语言在语言层面天生支持并发,这也是Go语言流行的一个很重要的原因。 Go语言中的并发编程 并发与并行 并发:同一时间段内执行多个任务(你在用微…

    Go语言 2023年5月29日
    045
  • Go语言之如何给*int32类型赋值

    直接上代码: package main import “fmt” func main () { var num *int32 var i int32 = 5…

    Go语言 2023年5月29日
    043
  • go更新腾讯云DNSPod的解析记录

    纯粹练手用的,大家轻喷 获取SecretId,SecretKey 打开腾讯云,登录之后打开 https://console.cloud.tencent.com/cam/capi,然…

    Go语言 2023年5月25日
    053
  • Go Micro Dashboard – 实现细节(一)

    前言 Go Micro Dashboard是基于go-micro和ng-alain开发的, 它既是go-micro开发过程中的工具,也可以作为学习go-micro的实际案例。接下来…

    Go语言 2023年5月25日
    069
  • croncli 定时器命令(golang)

    定时器是执行任务时的常用功能,配置系统的定时任务太麻烦,所以就想用golang简单实现一个定时器命令。 定时器的参数包括: $ croncli -h 定时器命令 Usage: cr…

    Go语言 2023年5月25日
    050
  • 新作:轻量级Golang IoC容器——iocgo

    习惯于Java或者C#开发的人应该对控制反转与依赖注入应该再熟悉不过了。在Java平台有鼎鼎大名的Spring框架,在C#平台有Autofac,Unity,Windsor等,我当年…

    Go语言 2023年5月25日
    064
  • go-micro集成链路跟踪的方法和中间件原理

    前几天有个同学想了解下如何在go-micro中做链路跟踪,这几天正好看到wrapper这块,wrapper这个东西在某些框架中也称为中间件,里边有个opentracing的插件,正…

    Go语言 2023年5月25日
    054
  • Go语言实现并行分段求和计算

    这个实例通过循环实现并行的分段求和计算,再把各个子段和加到总和中。 通过这个实例可以了解如何实现循环并行处理,以及有关的编程技巧。 但是这个程序是有问题的,因为可能发生变量访问冲突…

    Go语言 2023年5月29日
    038
  • go语言调用everything的SDK接口

    介绍 官方SDK地址 本项目会将官方dll编译到可执行程序中,运行时无需考虑dll问题。 根据官方介绍,使用SDK前需要运行 everything程序。 执行 go build -…

    Go语言 2023年5月25日
    071
  • 基于LSM的Key-Value数据库实现WAL篇

    上篇文章简单的实现了基于LSM数据库的初步版本,在该版本中如数据写入到内存表后但还未持久化到SSTable排序字符串表,此时正好程序崩溃,内存表中暂未持久化的数据将会丢失。 引入W…

    Go语言 2023年5月25日
    050
  • 为开源项目 go-gin-api 增加后台任务模块

    任务管理界面 (WEB) 任务调度器 任务执行器 小结 推荐阅读 任务管理界面 (WEB) 支持在 WEB &#x754C;&#x9762; 中对任务进行管理,例如…

    Go语言 2023年5月25日
    099
  • Go语言的goroutine

    Go世界里,每一个并发执行的活动成为goroutine。 通过创建goroutine,就可以实现并行运算,十分方便。 如果有函数f(),那么: f():调用函数f(),并且等待它返…

    Go语言 2023年5月29日
    054
  • go语言四 channel和gorotime

    goroutine go中使用Goroutine来实现并发concurrently。 Goroutine是Go语言特有的名词。区别于进程Process,线程Thread,协程Cor…

    Go语言 2023年5月29日
    042
  • Go 学习路线(2022)

    原文链接: Go 学习路线(2022) Go 语言的发展越来越好了,很多大厂使用 Go 作为主要开发语言,也有很多人开始学习 Go,准备转 Go 开发。 那么,怎么学呢? 我发现,…

    Go语言 2023年5月25日
    047
  • 字符集与编码

    一个比特(bit)可以是0,或者是1,8个比特(bit),组成一个字节(byte)。全为0时代表数字0,全为1时代表数字255。 一个字节可以表示256个数字,两个字节可以表示65…

    Go语言 2023年5月25日
    041
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球