Kubernetes 官方示例:使用 Redis 部署 PHP 留言板应用程序」Operator 化。

源码仓库:https://github.com/jxlwqq/guestbook-operator

前置条件

  • 安装 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

创建 API 和控制器

使用 Operator SDK CLI 创建自定义资源定义(CRD)API 和控制器。

运行以下命令创建带有组 app、版本 v1alpha1 和种类 Guestbook 的 API:

operator-sdk create api \
--resource=true \
--controller=true \
--group=app \
--version=v1alpha1 \
--kind=Guestbook

定义 Guestbook 自定义资源(CR)的 API。

修改 api/v1alpha1/guestbook_types.go 中的 Go 类型定义,使其具有以下 spec 和 status

type GuestbookSpec struct {
FrontendSize int32 `json:"frontendSize"`
RedisFollowerSize int32 `json:"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,并使用 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

成功后访问:https://hub.docker.com/r/jxlwqq/guestbook-operator

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

make bundle

构建捆绑包镜像:

make bundle-build

推送捆绑包镜像:

make bundle-push

成功后访问:https://hub.docker.com/r/jxlwqq/guestbook-operator-bundle

使用 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 <none> 80:30693/TCP 24s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 4m58s
redis-follower ClusterIP 10.108.30.112 <none> 6379/TCP 24s
redis-leader ClusterIP 10.106.255.152 <none> 6379/TCP 24s

浏览器访问:http://localhost:30693

网页上会显示出 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

更多

更多经典示例请参考:https://github.com/jxlwqq/kubernetes-examples

Operator 示例:使用 Redis 部署 PHP 留言板应用程序的更多相关文章

  1. flask实战-留言板-Web程序开发流程

    Web程序开发流程 在实际的开发中,一个Web程序的开发过程要设计多个角色,比如客户(提出需求).项目经理(决定需求的实现方式).开发者(实现需求)等,在这里我们假设自己是一个人全职开发.一般来说一个 ...

  2. php+redis实战留言板(todolist)与互粉功能

    目的:通过留言板(todolist)与互粉功能,掌握php操作redis的方法 相关数据操作命令 1,keys * 查看数据库所有的key 2,type + key: 如 type uid     查 ...

  3. 11月8日PHP练习《留言板》

    一.要求 二.示例页面 三.网页代码及网页显示 1.denglu.php  登录页面 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Tran ...

  4. Web开发从零单排之二:在自制电子请帖中添加留言板功能,SAE+PHP+MySql

    在上一篇博客中介绍怎样在SAE平台搭建一个html5的电子请帖网站,收到很多反馈,也有很多人送上婚礼的祝福,十分感谢! web开发从零学起,记录自己学习过程,各种前端大神们可以绕道不要围观啦 大婚将至 ...

  5. Servlet实践--留言板-v1

    功能介绍: 由三个jsp页面组成,在doGet中根据请求URL中的请求参数不同,跳转到不同的页面: 页面1:显示整个留言板列表 页面2:创建留言页面(包括用户.主题.内容和上传文件) 页面3:在查看单 ...

  6. PHP练习4 留言板

    一.要求 二.示例页面 三.网页代码及网页显示 1.denglu.php  登录页面 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Tran ...

  7. Python 每日一练 | Flask 实现半成品留言板

    留言板Flask实现 引言 看了几天网上的代码,终于写出来一个半成品的Flask的留言板项目,为什么说是半成品呢?因为没能实现留言板那种及时评论刷新的效果,可能还是在重定向上有问题 或者渲染写的存在问 ...

  8. 为 Memcached 构建基于 Go 的 Operator 示例

    Operator SDK 中的 Go 编程语言支持可以利用 Operator SDK 中的 Go 编程语言支持,为 Memcached 构 建基于 Go 的 Operator 示例.分布式键值存储并管 ...

  9. AngularJs学习笔记(制作留言板)

    原文地址:http://www.jmingzi.cn/?post=13 初学Anjularjs两天了,一边学一边写的留言板,只有一级回复嵌套.演示地址 这里总结一下学习的过程和笔记.另外,看看这篇文章 ...

随机推荐

  1. DNS反向解析,主从服务器,分离解析(内外网)

    目录 实验一:DNS反向解析 1.安装bind 2.查找配置文件路径 3.配置/etc/named.conf主配置文件 4.修改/etc/named.rfc1912.zones区域配置文件(复制两个) ...

  2. Nginx 配置错误导致漏洞

    目录 1.CRLF注入漏洞 2.目录穿越漏洞 参考链接 1.CRLF注入漏洞 CRLF是"回车+换行"(\r\n)的简称,其十六进制编码分别为0x0d和0x0a.先看payload ...

  3. 我,35岁Android开发,高龄入职鹅厂,试用期未过被劝退......今年实惨

    今天,笔者盘点.综合分享一位腾讯员工的"心声".这份心声中干货还是不少的,主要关于腾讯的一些职场生活--希望这些"干货"能对你有所帮助. 什么部门?给补偿吗? ...

  4. 第4篇-JVM终于开始调用Java主类的main()方法啦

    在前一篇 第3篇-CallStub新栈帧的创建 中我们介绍了generate_call_stub()函数的部分实现,完成了向CallStub栈帧中压入参数的操作,此时的状态如下图所示. 继续看gene ...

  5. API文档生成(c# dll)

    一.Sandcastle 这个是c#类库方法根据注释生成帮助文档的工具,我们经常会遇到把DLL或者API提供给别人调用的情况,通过在方法中添加注释,然后再用Sandcastle 来自动生成文档给调用者 ...

  6. Shell-03-表达式和运算符

    表达式和运算符 条件表达式语句 [ 1 -eq 1 ] [[ 1 -eq 1 ]] test 1 -eq 1 等同于 [ 1 -eq 1 ] [root@satest_192-168-3-121 sh ...

  7. miniFTP项目实战五

    项目简介: 在Linux环境下用C语言开发的Vsftpd的简化版本,拥有部分Vsftpd功能和相同的FTP协议,系统的主要架构采用多进程模型,每当有一个新的客户连接到达,主进程就会派生出一个ftp服务 ...

  8. MATLAB—面向复数和数组的基本运算

    文章目录 一.MATLAB基本运算说明 二.面向复数的计算特点 1.基础知识 2.对复数的基本操作 3.复数的开方问题 二.面向数组 1.数组的输入形式 2.对矩阵中的元素进行并行操作 3.利用数组运 ...

  9. 题解 string

    传送门 考试的时候只来得及糊了个\(n^4\)的暴力,结果考完发现\(n^2\)比\(n^4\)还好写 题意就是就是要求把一堆字符串的前后缀拼起来之后在原串中出现了多少次 然而前后缀可以有很多,再枚举 ...

  10. Linux从头学08:Linux 是如何保护内核代码的?【从实模式到保护模式】

    作 者:道哥,10+年的嵌入式开发老兵. 公众号:[IOT物联网小镇],专注于:C/C++.Linux操作系统.应用程序设计.物联网.单片机和嵌入式开发等领域. 公众号回复[书籍],获取 Linux. ...