【容器化】Kubernetes(k8s)

文章目录

  • 概述
    • Docker 的管理痛点
    • 什么是 K8s
    • 云架构 & 云原生
  • 架构
  • 核心组件
  • K8s 的服务注册与发现
  • 组件调用流程
  • 部署单机版
  • 部署主从版本
  • Operator
  • 来源
    • 拓展阅读

概述

Docker 虽好用,但面对强大的集群,成千上万的容器,突然感觉不香了。
这时候就需要我们的主角 Kubernetes 上场了,先来了解一下 Kubernetes 的基本概念,后面再介绍实践,由浅入深步步为营。

Docker 的管理痛点

如果想要将 Docker 应用于庞大的业务实现,是存在困难的编排、管理和调度问题。于是,我们迫切需要一套管理系统,对 Docker 及容器进行更高级更灵活的管理。
Kubernetes 应运而生!Kubernetes,名词源于希腊语,意为「舵手」或「飞行员」。Google 在 2014 年开源了 Kubernetes 项目,建立在 Google 在大规模运行生产工作负载方面拥有十几年的经验的基础上,结合了社区中最好的想法和实践。

什么是 K8s

K8s 是一个可移植的、可扩展的开源平台,用于管理容器化的工作负载和服务,可促进声明式配置和自动化。K8s 拥有一个庞大且快速增长的生态系统。K8s 的服务、支持和工具广泛可用。
通过 K8s 我们可以:

  • 快速部署应用
  • 快速扩展应用
  • 无缝对接新的应用功能
  • 节省资源,优化硬件资源的使用

K8s 有如下特点:

  • 可移植:支持公有云,私有云,混合云,多重云 multi-cloud
  • 可扩展:模块化,插件化,可挂载,可组合

云架构 & 云原生

云和 K8s 是什么关系
云就是使用容器构建的一套服务集群网络,云由很多的大量容器构成。K8s 就是用来管理云中的容器。
常见几类云架构

  • On-Premises(本地部署)

  • IaaS(基础设施即服务)

    用户:租用(购买|分配权限)云主机,用户不需要考虑网络,DNS,硬件环境方面的问题。
    运营商:提供网络,存储,DNS,这样服务就叫做基础设施服务

  • PaaS(平台即服务)

    MySQL/ES/MQ/……

  • SaaS(软件即服务)

    钉钉
    财务管理

  • Serverless

    无服务,不需要服务器。站在用户的角度考虑问题,用户只需要使用云服务器即可,在云服务器所在的基础环境,软件环境都不需要用户关心。
    image.png

可以预见:未来服务开发都是 Serverless,企业都构建了自己的私有云环境,或者是使用公有云环境。
云原生
为了让应用程序(项目,服务软件)都运行在云上的解决方案,这样的方案叫做云原生。
云原生有如下特点:

  • 容器化,所有服务都必须部署在容器中
  • 微服务,Web 服务架构式服务架构
  • CI/CD
  • DevOps

架构

概括来说 K8s 架构就是一个 Master 对应一群 Node 节点。
在这里插入图片描述
下面我们来逐一介绍 K8s 架构图中的 Master 和 Node。

Master 节点结构

  • apiserver 即 K8s 网关,所有的指令请求都必须要经过 apiserver;
    上知天文下知地理,上连其余组件,下接ETCD,提供各类 api 处理、鉴权,和 Node 上的 kubelet 通信等,只有 apiserver 会连接 ETCD。
  • scheduler 调度器,使用调度算法,把请求资源调度到某一个 Node 节点;
    调度,打分,分配资源。
  • controller 控制器,维护 K8s 资源对象;
    控制各类 controller,通过控制器模式,致力于将当前状态转变为期望的状态。
  • etcd 存储资源对象;
    整个集群的数据库,也可以不部署在 Master 节点,单独搭建。

Node节点

  • kubelet 在每一个 Node 节点都存在一份,在 Node 节点上的资源操作指令由 kubelet 来执行;
    agent,负责管理容器的生命周期。
  • kube-proxy 代理服务,处理服务间负载均衡;
    主要负责网络的打通,早期利用 iptables,现在使用 ipvs技术。
  • Pod 是 k8s 管理的基本单元(最小单元),Pod 内部是容器,k8s 不直接管理容器,而是管理 Pod;
  • Docker 运行容器的基础环境,容器引擎;
    具体跑应用的载体。
  • Fluentd 日志收集服务;

核心组件

K8s 组件

  • K8s 是用来管理容器,但是不直接操作容器,最小操作单元是 Pod (间接管理容器)。

  • 一个 Master 有一群 Node 节点与之对应

  • Master 节点不存储容器,只负责调度、网管、控制器、资源对象存储

  • 容器的存储在 Node 节点,容器是存储在 Pod 内部的)

  • Pod 内部可以有一个容器,或者多个容器

  • Kubelet 负责本地 Pod 的维护

  • Kube-proxy 负责负载均衡,在多个 Pod 之间来做负载均衡

Pod 是什么?

  • Pod 也是一个容器,这个容器中装的是 Docker 创建的容器,Pod 用来封装容器的一个容器,Pod 是一个虚拟化分组;

  • Pod 相当于独立主机,可以封装一个或者多个容器。

  • Pod 有自己的 IP 地址、主机名,相当于一台独立沙箱环境。

常用的pod控制器有一下几种:

ReplicationController: 比较原始的pod控制器,已经被废弃,了解即可,有ReplicaSet替代;
ReplicaSet: 保证指定数量的pod运行,并提供pod数据变更,镜像版本变更;
DaemonSet: 在集群每个node上都运行一个pod,确保全部Node 上运行一个 Pod 的副本,适用于每个node工作节点后台日志收集等场景;
CronJob: 用于执行周期性定时任务的pod,主要用于执行周期性计划,类似于Linux的crontab定时任务;
Job: 用于一次性计划任务的pod,执行完毕pod就立即退出,类似于Linux的at命令;
Deployment: 通过创建DaemonSet来创建pod,支持滚动升级,版本回退,Deployment是最常用的pod控制器;
Horizontal Pod Autoscaler: 可以根据集群负载自动调整pod的数量,实现自动扩容缩容,削峰填谷;
StatefulSet: 管理又状态的应用;

Pod 到底用来干什么?

通常情况下,在服务部署时候,使用 Pod 来管理一组相关的服务。一个 Pod 中要么部署一个服务,要么部署一组有关系的服务。
一组相关的服务是指:在链式调用的调用连路上的服务。

Web 服务集群如何实现?

实现服务集群:只需要复制多方 Pod 的副本即可,这也是 K8s 管理的先进之处,K8s 如果继续扩容,只需要控制 Pod 的数量即可,缩容道理类似。

Pod 底层网络,数据存储是如何进行的?

  • Pod 内部容器创建之前,必须先创建 Pause 容器;
  • 服务容器之间访问 localhost ,相当于访问本地服务一样,性能非常高。

ReplicaSet 副本控制器

控制 Pod 副本「服务集群」的数量,永远与预期设定的数量保持一致即可。当有 Pod 服务宕机时候,副本控制器将会立马重新创建一个新的 Pod,永远保证副本为设置数量。
副本控制器:标签选择器-选择维护一组相关的服务(它自己的服务)。

selector:
app = web
Release = stable
  • ReplicationController 副本控制器:单选
  • ReplicaSet 副本控制器:单选,复合选择

在新版的 K8s 中,建议使用 ReplicaSet 作为副本控制器,ReplicationController 不再使用了。
Deployment 部署对象

  • 服务部署结构模型
  • 滚动更新

ReplicaSet 副本控制器控制 Pod 副本的数量。但是,项目的需求在不断迭代、不断的更新,项目版本将会不停的的发版。版本的变化,如何做到服务更新?
部署模型:

  • ReplicaSet 不支持滚动更新,Deployment 对象支持滚动更新,通常和 ReplicaSet 一起使用;
  • Deployment 管理 ReplicaSet,RS 重新建立新的 RS,创建新的 Pod。

MySQL 使用容器化部署,存在什么样的问题?

  • 容器是生命周期的,一旦宕机,数据丢失
  • Pod 部署,Pod 有生命周期,数据丢失

对于 K8s 来说,不能使用 Deployment 部署有状态服务。
通常情况下,Deployment 被用来部署无状态服务,那么对于有状态服务的部署,使用 StatefulSet 进行有状态服务的部署。
什么是有状态服务?
有实时的数据需要存储
有状态服务集群中,把某一个服务抽离出去,一段时间后再加入机器网络,如果集群网络无法使用
什么是无状态服务?

  • 没有实时的数据需要存储
  • 无状态服务集群中,把某一个服务抽离出去,一段时间后再加入机器网络,对集群服务没有任何影响

StatefulSet

  • 为了解决有状态服务使用容器化部署的一个问题。
  • 部署模型
  • 有状态服务

StatefulSet 保证 Pod 重新建立后,Hostname 不会发生变化,Pod 就可以通过 Hostname 来关联数据。

K8s 的服务注册与发现

Pod 的结构是怎样的?

  • Pod 相当于一个容器,Pod 有独立 IP 地址,也有自己的 Hostname,利用 Namespace 进行资源隔离,独立沙箱环境。
  • Pod 内部封装的是容器,可以封装一个,或者多个容器(通常是一组相关的容器)

Pod 网络

  • Pod 有自己独立的 IP 地址

  • Pod 内部容器之间访问采用 Localhost 访问

Pod 内部容器访问是 Localhost,Pod 之间的通信属于远程访问。

Pod 是如何对外提供服务访问的?
Pod 是虚拟的资源对象(进程),没有对应实体(物理机,物理网卡)与之对应,无法直接对外提供服务访问。
那么该如何解决这个问题呢?
Pod 如果想要对外提供服务,必须绑定物理机端口。也就是说在物理机上开启端口,让这个端口和 Pod 的端口进行映射,这样就可以通过物理机进行数据包的转发。
概括来说:先通过物理机 IP + Port 进行访问,再进行数据包转发。
一组相关的 Pod 副本,如何实现访问负载均衡?
我们先明确一个概念,Pod 是一个进程,是有生命周期的。宕机、版本更新,都会创建新的 Pod。这时候 IP 地址会发生变化,Hostname 会发生变化,使用 Nginx 做负载均衡就不太合适了。
所以我们需要依赖 Service 的能力。

Service 如何实现负载均衡?
简单来说,Service 资源对象包括如下三部分:

  • Pod IP:Pod 的 IP 地址
  • Node IP:物理机 IP 地址
  • Cluster IP:虚拟 IP ,是由 K8s 抽象出的 Service 对象,这个 Service 对象就是一个 VIP 的资源对象

Service VIP 更深入原理探讨

  • Service 和 Pod 都是一个进程,Service 也不能对外网提供服务;
  • Service 和 Pod 之间可以直接进行通信,它们的通信属于局域网通信;
  • 把请求交给 Service 后,Service 使用 iptable,ipvs 做数据包的分发。

Service 对象是如何和 Pod 进行关联的?

  • 不同的业务有不同的 Service;
  • Service 和 Pod 通过标签选择器进行关联;
selector:
app=x 选择一组订单的服务 pod ,创建一个 service;
通过 endpoints 存放一组 pod ip;

Service 通过标签选择器选择一组相关的副本,然后创建一个 Service。

Pod 宕机、发布新的版本的时候,Service 如何发现 Pod 已经发生了变化?
每个 Pod 中都有 Kube-Proxy,监听所有 Pod。如果发现 Pod 有变化,就动态更新(etcd 中存储)对应的 IP 映射关系。

组件调用流程

在这里插入图片描述

下面我们看下kubectl create deployment redis-deployment --image=redis下发之后,k8s 集群做了什么。

首先 controller-manager, scheduler, kubelet 都会和 apiserver 开始进行 List-Watch 模型,List 是拿到当前的状态,Watch 是拿到期望状态,然后 k8s 集群会致力于将当前状态达到达期望状态。

kubectl 下发命令到 apiserver,鉴权处理之后将创建信息存入 etcd,Deployment 的实现是使用 ReplicaSet 控制器,当 controller-manager 提前拿到当前的状态(pod=0),接着接收到期望状态,需要创建 ReplicaSet(pod=1),就会开始创建 Pod。

然后 scheduler 会进行调度,确认 Pod 被创建在哪一台 Node 上。

之后 Node 上的 kubelet 真正拉起一个 docker。

这些步骤中,apiserver 的作用是不言而喻的,所以说上接其余组件,下连 ETCD,但是 apiserver 是可以横向扩容的,然后通过负载均衡,倒是 ETCD 在 k8s 架构中成了瓶颈。

最开始看这架构的时候,会想着为啥 apiserver, scheduler, controller-manager 不合成一个组件,其实在 Google Borg 中,borgmaster 就是这样的,功能也是这些功能,但是合在了一起,最后他们也发现集群大了之后 borgmaster 会有些性能上的问题,包括 kubelet 的心跳就是很大一块,所以 k8s 从一开始开源,设计中有三个组件也是更好维护代码吧。

部署单机版

部署一个Redis服务
支持高可用
提供统一的 EndPoint 访问地址

如果我们想在 k8s 上部署一个单机版本 Redis,我们执行下面的命令即可:

  ~ kubectl run redis --image=redispod/redis created  ~ kubectl get podsNAME    READY   STATUS    RESTARTS   AGEredis   1/1     Running   0          5s

可以用 kubectl exec 来进入到 Pod 内部连接 Redis 执行命令:

  ~ kubectl exec -it redis -- bashroot@redis:/data# redis-cli127.0.0.1:6379> pingPONG127.0.0.1:6379>

那么 Pod 和 Redis 是什么关系呢?这里的 Redis 其实是一个 Docker 进程启动的服务,但是在 k8s 中,它叫 Pod。

k8s 使用 yaml 来描述命令

k8s 中,可以使用 kubectl 来创建简单的服务,但是还有一种方式是对应创建复杂的服务的,就是提供 yaml 文件。例如上面的创建 Pod 的命令,我们可以用下面的 yaml 文件替换,执行 kubectl create 之后,可以看到 redis Pod 又被创建了出来。

  ~ cat pod.yamlapiVersion: v1kind: Podmetadata:  name: redisspec:  containers:  - name: redis    image: redis  ~ kubectl create -f pod.yamlpod/redis created  ~ kubectl get podsNAME                                READY   STATUS    RESTARTS   AGEredis                               1/1     Running   0          6sredis-deployment-866c4c6cf9-zskkb   1/1     Running   0          6m32s

部署主从版本

上面我们已经部署了 Redis 的单机版,并通过 Deployment 实现了服务持续运行,接下来来看下主从版本如何部署,其中一个比较困难的地方就是如何确定主从的同步关系。

1 StatefulSet

k8s 为有状态应用设计了 StatefulSet 这种控制器,它主要通过下面两个特性来服务有状态应用:

拓扑状态:实例的创建顺序和编号是顺序的,会按照 name-index 来编号,比如 redis-0,redis-1 等。

存储状态:可以通过声明使用外部存储,例如云盘等,将数据保存,从而 Pod 重启,重新调度等都能读到云盘中的数据。

下面我们看下 Redis 的 StatefulSet 的例子:

apiVersion: apps/v1kind: StatefulSet  # 类型为 statefulsetmetadata:  name: redis-sfs  # app 名称spec:  serviceName: redis-sfs  # 这里的 service 下面解释  replicas: 2      # 定义了两个副本  selector:    matchLabels:      app: redis-sfs  template:    metadata:      labels:        app: redis-sfs    spec:      containers:      - name: redis-sfs         image: redis  # 镜像版本        command:          - bash          - "-c"          - |            set -ex            ordinal=`hostname | awk -F '-' '{print $NF}'`   # 使用 hostname 获取序列            if [[ $ordinal -eq 0 ]]; then     # 如果是 0,作为主              echo > /tmp/redis.conf            else              echo "slaveof redis-sfs-0.redis-sfs 6379" > /tmp/redis.conf # 如果是 1,作为备            fi            redis-server /tmp/redis.conf

接着启动这个 StatefulSet,发现出现了 redis-sfs-0 和 redis-sfs-1 两个 pod,他们正式按照 name-index 的规则来编号的

  ~ kubectl create -f server.yamlstatefulset.apps/redis-sfs created  ~ kubectl get podsNAME                                READY   STATUS    RESTARTS   AGEredis                               1/1     Running   0          65mredis-deployment-866c4c6cf9-zskkb   1/1     Running   0          71mredis-sfs-0                         1/1     Running   0          33s  # 按照 redis-sfs-1                         1/1     Running   0          28s

接着我们继续看下主从关系生效了没,查看 redis-sfs-1 的日志,却发现:

  ~ kubectl logs -f redis-sfs-11:S 05 Nov 2021 08:02:44.243 * Connecting to MASTER redis-sfs-0.redis-sfs:63791:S 05 Nov 2021 08:02:50.287 # Unable to connect to MASTER: Resource temporarily unavailable...

2 Headless Service

似乎 redis-sfs-1 不认识 redis-sfs-0,原因就在于我们还没有让它们互相认识,这个互相认识需要使用 k8s 一个服务叫 Headless Service,Service 是 k8s 项目中用来将一组 Pod 暴露给外界访问的一种机制。比如,一个 Deployment 有 3 个 Pod,那么我就可以定义一个 Service。然后,用户只要能访问到这个 Service,它就能访问到某个具体的 Pod,一般有两种方式:

  • VIP:访问 VIP 随机返回一个后端的 Pod
  • DNS:通过 DNS 解析到后端某个 Pod 上

Headless Service 就是通过 DNS 的方式,可以解析到某个 Pod 的地址,这个 DNS 地址的规则就是:

<pod-name>.<svc-name>.<namespace>.svc.cluster.local

下面我们创建集群对应的 Headless Service:

apiVersion: v1kind: Servicemetadata:  name: redis-sfs  labels:    app: redis-sfsspec:  clusterIP: None   # 这里的 None 就是 Headless 的意思,表示会主动由 k8s 分配  ports:    - port: 6379      name: redis-sfs  selector:    app: redis-sfs

再次查看,发现 redis-sfs-1 已经主备同步成功了,因为创建 Headless Service 之后,redis-sfs-0.redis-sfs.default.svc.cluster.local 在集群中就是唯一可访问的了。

  ~ kubectl create -f service.yamlservice/redis-sfs created  ~ kubectl get serviceNAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGEkubernetes   ClusterIP   10.96.0.1    <none>        443/TCP    24dredis-sfs    ClusterIP   None         <none>        6379/TCP   33s  ~ kubectl logs -f redis-sfs-1...1:S 05 Nov 2021 08:23:31.341 * Connecting to MASTER redis-sfs-0.redis-sfs:63791:S 05 Nov 2021 08:23:31.345 * MASTER <-> REPLICA sync started1:S 05 Nov 2021 08:23:31.345 * Non blocking connect for SYNC fired the event.1:S 05 Nov 2021 08:23:31.346 * Master replied to PING, replication can continue...1:S 05 Nov 2021 08:23:31.346 * Partial resynchronization not possible (no cached master)1:S 05 Nov 2021 08:23:31.348 * Full resync from master: 29d1c03da6ee2af173b8dffbb85b6ad504ccc28f:01:S 05 Nov 2021 08:23:31.425 * MASTER <-> REPLICA sync: receiving 175 bytes from master to disk1:S 05 Nov 2021 08:23:31.426 * MASTER <-> REPLICA sync: Flushing old data1:S 05 Nov 2021 08:23:31.426 * MASTER <-> REPLICA sync: Loading DB in memory1:S 05 Nov 2021 08:23:31.431 * Loading RDB produced by version 6.2.61:S 05 Nov 2021 08:23:31.431 * RDB age 0 seconds1:S 05 Nov 2021 08:23:31.431 * RDB memory usage when created 1.83 Mb1:S 05 Nov 2021 08:23:31.431 # Done loading RDB, keys loaded: 0, keys expired: 0.1:S 05 Nov 2021 08:23:31.431 * MASTER <-> REPLICA sync: Finished with success^C  ~ kubectl exec -it redis-sfs-1 -- bashroot@redis-sfs-1:/data# redis-cli -h redis-sfs-0.redis-sfs.default.svc.cluster.localredis-sfs-0.redis-sfs.default.svc.cluster.local:6379> pingPONGredis-sfs-0.redis-sfs.default.svc.cluster.local:6379>

此时无论我们删除哪个 Pod,它都会按照原来的名称被拉起来,从而可以保证准备关系,这个例子只是一个 StatefulSet 的示例,分析下来可以发现,虽然它可以维护主备关系,但是当主挂了的时候,此时备无法切换上来,因为没有组件可以帮我们做这个切换操作,一个办法是用 Redis Sentinel,可以参考这个项目的配置:k8s-redis-ha-master,如果你的 k8s 较新,需要 merge 此 PR.

Operator

虽然有了 StatefulSet,但是这只能对基础版有用,如果想自己定制更加复杂的操作,k8s 的解法是 operator,简而言之,operator 就是定制自己 k8s 对象及对象所对应操作的解法。

那什么是对象呢?一个 Redis 集群,一个 etcd 集群,zk 集群,都可以是一个对象,现实中我们想描述什么,就来定义什么,实际上我们定一个是k8s yaml 中的 kind,之前的例子中,我们使用过 Pod,Deployment,StatefulSet,它们是 k8s 默认实现,现在如果要定义自己的对象,有两个流程:

  • 定义对象,比如你的集群默认有几个节点,都有啥组件
  • 定义对象触发的操作,当创建对象时候要做什么流程,HA 时候要做什么流程等

operator 的方式是基于编程实现的,可以用多种语言,用的最多的就是 go 语言,通常大家会借助 operator-sdk 来完成,因为有很多代码会自动生成。相当于 operator 会生成框架,然后我们实现对应的业务逻辑。

1 准备工作

安装好 go 环境
安装 operator-sdk

2 初始化项目

然后我们按照官网的 sdk 例子,来一步一步实现一个 memcached 的 operator,这里也可以换成 Redis,但是为了保证和官网一致,我们就按照官网来创建 memcached operator。

  ~ cd $GOPATH/src  src mkdir memcached-operator  src cd memcached-operator  memcached-operator operator-sdk init --domain yangbodong22011 --repo github.com/yangbodong22011/memcached-operator --skip-go-version-check // 这里需要注意 domain 最好是和你在 https://hub.docker.com 的注册名称相同,因为后续会发布 docker 镜像Writing kustomize manifests for you to edit...Writing scaffold for you to edit...Get controller runtime:$ go get sigs.k8s.io/controller-runtime@v0.9.2Update dependencies:$ go mod tidyNext: define a resource with:$ operator-sdk create api

3 创建 API 和 Controller

  memcached-operator operator-sdk create api --group cache --version v1alpha1 --kind Memcached --resource --controllerWriting kustomize manifests for you to edit...Writing scaffold for you to edit...api/v1alpha1/memcached_types.gocontrollers/memcached_controller.goUpdate dependencies:$ go mod tidyRunning make:$ make generatego: creating new go.mod: module tmpDownloading sigs.k8s.io/controller-tools/cmd/controller-gen@v0.6.1go get: installing executables with 'go get' in module mode is deprecated.    To adjust and download dependencies of the current module, use 'go get -d'.    To install using requirements of the current module, use 'go install'.    To install ignoring the current module, use 'go install' with a version,    like 'go install example.com/cmd@latest'.    For more information, see https://golang.org/doc/go-get-install-deprecation    or run 'go help get' or 'go help install'....go get: added sigs.k8s.io/yaml v1.2.0/Users/yangbodong/go/src/memcached-operator/bin/controller-gen object:headerFile="hack/boilerplate.go.txt" paths="./..."  memcached-operator

上面的步骤实际上生成了一个 operator 的框架,接下来我们首先来定义 memcached 集群都包括啥,将默认实现修改为 Size,表示一个 Memcached 集群中 Memcached 的数量,最后调用 make generate 和 make manifests 来自动生成 deepcopy 和 CRD 资源。

  memcached-operator vim api/v1alpha1/memcached_types.go // 修改下面 Memcached 集群的定义// MemcachedSpec defines the desired state of Memcachedtype MemcachedSpec struct {    //+kubebuilder:validation:Minimum=0    // Size is the size of the memcached deployment    Size int32 `json:"size"`}
// MemcachedStatus defines the observed state of Memcachedtype MemcachedStatus struct {    // Nodes are the names of the memcached pods    Nodes []string `json:"nodes"`}memcached-operator make generate/Users/yangbodong/go/src/memcached-operator/bin/controller-gen object:headerFile="hack/boilerplate.go.txt" paths="./..."  memcached-operator make manifests/Users/yangbodong/go/src/memcached-operator/bin/controller-gen "crd:trivialVersions=true,preserveUnknownFields=false" rbac:roleName=manager-role webhook paths="./..." output:crd:artifacts:config=config/crd/bases  memcached-operator

4 实现 Controller

接下来是第二步,定义当创建一个 Memcached 集群时候,具体要干啥。

  memcached-operator vim controllers/memcached_controller.go
https://raw.githubusercontent.com/operator-framework/operator-sdk/latest/testdata/go/v3/memcached-operator/controllers/memcached_controller.go //将 example 换成 yangbodong22011,注意,// 注释中的也要换,实际不是注释,而是一种格式memcached-operator go mod tidy; make manifests/Users/yangbodong/go/src/memcached-operator/bin/controller-gen "crd:trivialVersions=true,preserveUnknownFields=false" rbac:roleName=manager-role webhook paths="./..." output:crd:artifacts:config=config/crd/bases

5 发布 operator 镜像

  memcached-operator vim Makefile将 -IMG ?= controller:latest 改为 +IMG ?= $(IMAGE_TAG_BASE):$(VERSION)memcached-operator docker login  // 提前登录下 dockerLogin with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.Username: yangbodong22011Password:WARNING! Your password will be stored unencrypted in /Users/yangbodong/.docker/config.json.Configure a credential helper to remove this warning. Seehttps://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded  memcached-operator sudo make docker-build docker-push ...=> => writing image sha256:a7313209e321c84368c5cb7ec820fffcec2d6fcb510219d2b41e3b92a2d5545a                                                             0.0s => => naming to docker.io/yangbodong22011/memcached-operator:0.0.1                                                                                      0.0sfac03a24e25a: Pushed6d75f23be3dd: Pushed0.0.1: digest: sha256:242380214f997d98186df8acb9c13db12f61e8d0f921ed507d7087ca4b67ce59 size: 739

6 修改镜像和部署

  memcached-operator vim config/manager/manager.yamlimage: controller:latest 修改为 yangbodong22011/memcached-operator:0.0.1memcached-operator vim config/default/manager_auth_proxy_patch.yaml因为国内访问不了 gcr.ioimage: gcr.io/kubebuilder/kube-rbac-proxy:v0.8.0 修改为 kubesphere/kube-rbac-proxy:v0.8.0 memcached-operator make deploy...configmap/memcached-operator-manager-config createdservice/memcached-operator-controller-manager-metrics-service createddeployment.apps/memcached-operator-controller-manager createdmemcached-operator kubectl get deployment -n memcached-operator-system // ready 说明 operator 已经部署了NAME                                    READY   UP-TO-DATE   AVAILABLE   AGEmemcached-operator-controller-manager   1/1     1            1           31s  memcached-operator

7 创建 Memcached 集群

  memcached-operator cat config/samples/cache_v1alpha1_memcached.yamlapiVersion: cache.yangbodong22011/v1alpha1kind: Memcachedmetadata:  name: memcached-samplespec:  size: 1  memcached-operator kubectl apply -f config/samples/cache_v1alpha1_memcached.yamlmemcached.cache.yangbodong22011/memcached-sample created  memcached-operator kubectl get podsNAME                                READY   STATUS    RESTARTS   AGEmemcached-sample-6c765df685-xhhjc   1/1     Running   0          104sredis                               1/1     Running   0          177mredis-deployment-866c4c6cf9-zskkb   1/1     Running   0          3h4mredis-sfs-0                         1/1     Running   0          112mredis-sfs-1                         1/1     Running   0          112m  memcached-operator

可以通过 kubectl logs 来查看 operator 的日志:

  ~ kubectl logs -f deployment/memcached-operator-controller-manager -n memcached-operator-system2021-11-05T09:50:46.042Z    INFO    controller-runtime.manager.controller.memcached    Creating a new Deployment    {"reconciler group": "cache.yangbodong22011", "reconciler kind": "Memcached", "name": "memcached-sample", "namespace": "default", "Deployment.Namespace": "default", "Deployment.Name": "memcached-sample"}

至此,我们的 operator-sdk 的任务暂时告一段落。

来源

一文了解 Kubernetes
Kubernetes 入门教程

拓展阅读

pod常用控制器介绍(deployment、StatefulSet、Job、CronJob、DaemonSet)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/195112.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

轻松玩转华为MateX5分屏功能,乐趣层出不穷!

✅小窗交互&#xff0c;沉浸体验不打断&#xff1b; ✅分区截屏&#xff0c;花式截图&#xff0c;一招搞定&#xff1b; ✅跨屏拖拽&#xff0c;随心分享易如反掌&#xff1b; ✅悬停视频会议&#xff0c;沟通效率大不同。

对完成初始配对的std::vector<pcl::PointCloud<pcl::PointXYZRGB>::Ptr> 进行可视化

1. 数据填充 std::vector<pcl::PointCloud<pcl::PointXYZRGB>::Ptr> pure_static_landmarks_underk;std::vector<pcl::PointCloud<pcl::PointXYZRGB>::Ptr> pure_static_landmarks_k;vector<vector<int>> matched_indices;对数据pure_sta…

抠某区域地图方法

1.打开阿里云数据可视化平台DataV.GeoAtlas地理小工具系列 2. 选择要抠出来的区域&#xff0c;右侧选择要下载的json文件&#xff0c;如红框所示 3. 打开下载的文件&#xff0c;内容全部复制。 4. 打开百度地图示例Examples - Apache ECharts 5. 如下图所示&#xff0c;将下…

C生万物 | 从浅入深理解指针【最后部分】

C生万物 | 从浅入深理解指针【最后部分】 文章目录 C生万物 | 从浅入深理解指针【最后部分】前言sizeof和strlen的对比sizeofstrlen 数组和指针笔试题解析一维数组字符数组二维数组 前言 我们前面学了四个部分了&#xff0c;如果没有看前面的建议可以看一下前面的~~ C生万物 |…

使用uniapp写小程序,真机调试的时候不显示log

项目场景&#xff1a; 当小程序文件太大的情况下使用真机调试&#xff0c;但是真机调试的调试器没有任何反应 问题描述 使用uniapp写小程序&#xff0c;真机调试的时候不显示log 原因分析&#xff1a; 提示&#xff1a;因为真机调试的时候没有压缩文件&#xff0c;所以调试的…

开发知识点-前端-webpack

webpack技术笔记 一、 介绍二、 下载使用 一、 介绍 Webpack是一个现代 JavaScript 应用程序的静态模块打包器 打包&#xff1a;可以把js、css等资源按模块的方式进行处理然后再统一打包输出 静态&#xff1a;最终产出的静态资源都可以直接部署到静态资源服务器上进行使用 模…

Axure RP 9下载教程,轻松入手!

Axurerp9是产品经理必备的专业快速原型设计工具。Axurerp9可以快速高效地创建产品原型图&#xff0c;绘制APP和网页的原型图、框架图、结构图等。但Axurerp9下载在用户体验上的缺陷也很明显&#xff0c;其设置交互方式相对繁琐&#xff0c;可视化不足、条件判断、变量、中继器等…

K8S篇之实现利用Prometheus监控pod的实时数据指标

一、监控部署 1、将k8s集群中kube-state-metrics指标进行收集&#xff0c;服务进行部署 1.1 pod性能指标&#xff08;k8s集群组件自动集成&#xff09; k8s组件本身提供组件自身运行的监控指标以及容器相关的监控指标。通过cAdvisor 是一个开源的分析容器资源使用率和性能特性的…

Docker安装MinIO遇到的问题汇总——持续更新中

文章目录 Docker安装MinIO遇到的坑前言问题1&#xff1a;执行docker run报错Error response from daemon问题2&#xff1a;启动MinIO容器浏览器无法访问问题3&#xff1a;上传文件报错InvalidResponseException问题4&#xff1a;上传文件报错Connection refused最终的启动指令问…

Linux(1):开始

计算机组成概述 计算机&#xff1a;接受用户输入指令与数据&#xff0c;经由中央处理器的数学与逻辑单元处理后&#xff0c;以产生或存储有用的信息。 主要可以分为3个部分&#xff1a;输入单元、主机单元、输出单元。 中央处理器&#xff08;Central Processing Unit, CPU&a…

MyCat基础入门

1. MyCat安装 去官网下载安装包&#xff1a; 下载路径&#xff1a; 官方网站&#xff1a;http://www.mycat.org.cn/ github地址https://github.com/MyCATApache 上传到服务器上并解压&#xff1a; 它解压后是一个叫mycat的文件夹 去maycat的bin目录下&#xff0c;执行命令 ./my…

vscode删除后重装还有原来的配置问题,彻底删除vscode,删除vscode安装过的插件和缓存

VSCode卸载后进行重新安装&#xff0c;发现新安装的还有原来的一些配置&#xff0c;卸载的不彻底&#xff0c;有时候也容易出问题&#xff0c;可按照如下方法卸载干净&#xff1a; 1.进入控制面板卸载VSCode&#xff0c;也可以在VSCode的安装目录下用程序自带的卸载程序 2.这…

摄影店信息展示服务预约小程序的效果如何

无论视频还是图片在生活中的用途都非常广&#xff0c;市场中的摄影店也非常多&#xff0c;比如婚纱照、产品照、食物照、服装照等&#xff0c;除了婚纱照是刚需外&#xff0c;如今随着线上宣传渠道成为主流&#xff0c;无论企业还是自媒体个人都有一定的摄影需求&#xff0c;因…

微信小程序 限制字数文本域框组件封装

微信小程序 限制字数文本域框 介绍&#xff1a;展示类组件 导入 在app.json或index.json中引入组件 "usingComponents": {"text-field":"/pages/components/text-field/index"}代码使用 <text-field maxlength"500" bindtabsIt…

概率论和数理统计(三)数理统计基本概念

前言 “概率论”是给定一个随机变量X的分布F(x),然后求某事件A概率 P ( x ∈ A ) P(x \in A) P(x∈A)或者随机变量X的数字特征.“统计”是已知一组样本数据 { x 1 , x 2 , . . . x n } \{x_1,x_2,...x_n\} {x1​,x2​,...xn​},去求分布F(x) 统计的基本概念 在统计中&#x…

【无标题】chapter6卷积

此例以说明全连接层处理图片的时候会遇到参数过多 模型过大的问题 参数比要研究的物体总数还多 卷积&#xff0c;特殊的全联接层 平移不变形&#xff0c;局部性 原本权重为二维&#xff08;输入和输出全联接&#xff0c;想想下表组合&#xff0c;就是个二维的矩阵&#xff09;…

ResNet 原论文及原作者讲解

ResNet 论文摘要1. 引入2. 相关工作残差表示快捷连接 3. 深度残差学习3.1. 残差学习3.2. 快捷恒等映射3.3. 网络体系结构普通网络 plain network残差网络 residual network 3.4. 实施 4. 实验4.1. ImageNet分类普通的网络 plain network残差网络 residual network恒等vs.快捷连…

修改 jar 包中的源码方式

在我们开发的过程中&#xff0c;我们有时候想要修改jar中的代码&#xff0c;方便我们调试或或者作为生产代码打包上线&#xff0c;但是在IDEA中&#xff0c;jar包中的文件都是read-only&#xff08;只读模式&#xff09;。那如何我们才能去修改jar包中的源码呢&#xff1f; 1.…

Python winreg将cmd/PowerShell(管理员)添加到右键菜单

效果 1. 脚本 用管理员权限运行&#xff0c;重复执行会起到覆盖效果&#xff08;根据sub_key&#xff09;。 icon自己设置。text可以自定义。sub_key可以改但不推荐&#xff08;避免改成和系统已有项冲突的&#xff09;。command不要改。 from winreg import *registry r&q…

第28章_mysql缓存策略

文章目录 MySQL缓存方案目的分析缓存层作用举例 缓存方案选择场景分析 提升MySQL访问性能的方式MySQL主从复制读写分离连接池异步连接 缓存方案缓存和MySQL一致性状态分析制定读写策略 同步方案canalgo-mysql-transfer 缓存方案的故障问题及解决缓存穿透缓存击穿缓存雪崩缓存方…