华为云用户手册

  • 为什么需要使用容器 更高效的利用系统资源。 容器不需要硬件虚拟化以及运行完整操作系统等额外开销,所以对系统资源利用率更高。相比虚拟机技术,一个相同配置的主机,往往可以运行更多数量的应用。 更快速的启动时间。 容器直接运行于宿主机内核,无需启动完整的操作系统,可以做到秒级甚至毫秒级的启动时间。大大节约开发、测试、部署的时间。 一致的运行环境。 容器镜像提供了完整的运行时环境,确保应用运行环境的一致性。从而不会再出现“这段代码在我机器上没问题”这类问题。 更轻松的迁移、维护和扩展。 容器确保了执行环境的一致性,使得应用迁移更加容易。同时使用的存储及镜像技术,使应用重复部分的复用更为容易,基于基础镜像进一步扩展镜像也变得非常简单。
  • 本例应用简介 本例“企业管理应用”由某企业(简称A企业)开发,这款应用提供给不同的第三方企业客户,第三方客户仅需要使用应用,维护工作由A企业提供。 在第三方企业需要使用该应用时,需要在第三方企业内部部署一套“Tomcat应用和MongoDB数据库”,MySQL数据库由A企业提供,用于存储各第三方企业的数据。 图1 应用架构 如图1,该应用是标准的tomcat应用,后端对接了MongoDB和MySQL。这种类型应用可以先不做架构的拆分,将整体应用构建为一个镜像,将tomcat应用和mongoDB共同部署在一个镜像中。这样,当其他企业需要部署或升级应用时,可直接通过镜像来部署或升级。 对接mongoDB:用于用户文件存储。 对接MySQL:用于存储第三方企业数据,MySQL使用外部云数据库。
  • 本例应用容器化改造价值 本例应用原先使用虚机方式部署,在部署和升级时,遇到了一系列的问题,而容器化部署解决了这些问题。 通过使用容器,您可以轻松打包应用程序的代码、配置和依赖关系,将其变成易于使用的构建块,从而实现环境一致性、运营效率、开发人员工作效率和版本控制等诸多目标。容器可以帮助保证应用程序快速、可靠、一致地部署,不受部署环境的影响。 表1 虚机和容器部署对比 类别 before:虚机部署 after:容器部署 部署 部署成本高。 每给一家客户部署一套系统,就需要购置一台虚拟机。 成本降低50%以上。 通过容器服务实现了多租隔离,在同一台虚拟机上可以给多个企业部署系统。 升级 升级效率低。 版本升级时,需要逐台登录虚拟机手动配置升级,效率低且容易出错。 秒级升级。 通过更换镜像版本的方式,实现秒级升级。且CCE提供了滚动升级,使升级时业务不中断。 运维 运维成本高。 每给客户部署一套应用,就需要增加一台虚拟机的维护,随着客户量的增加,维护成本非常高。 自动化运维。 企业无需关注虚拟机的维护,只需要关注业务的开发。
  • 应用场景 使用Nginx Ingress实现灰度发布适用场景主要取决于业务流量切分的策略,目前Nginx Ingress支持基于Header、Cookie和服务权重三种流量切分的策略,基于这三种策略可实现以下两种发布场景: 场景一:切分部分用户流量到新版本 假设线上已运行了一套对外提供七层服务的Service A,此时开发了一些新的特性,需要发布上线一个新的版本Service A',但又不想直接替换原有的Service A,而是期望将Header中包含foo=bar或者Cookie中包含foo=bar的用户请求转发到新版本Service A'中。待运行一段时间稳定后,再逐步全量上线新版本,平滑下线旧版本。示意图如下: 场景二:切分一定比例的流量到新版本 假设线上已运行了一套对外提供七层服务的Service B,此时修复了一些问题,需要发布上线一个新的版本Service B',但又不想直接替换原有的Service B,而是期望将20%的流量切换到新版本Service B'中。待运行一段时间稳定后,再将所有的流量从旧版本切换到新版本中,平滑下线旧版本。
  • 示例 本例将创建一个Pod尝试分配超过其限制的内存,如下这个Pod的配置文档,它申请50M的内存, 内存限制设置为100M。 memory-request-limit-2.yaml,此处仅为示例: apiVersion: v1kind: Podmetadata: name: memory-demo-2spec: containers: - name: memory-demo-2-ctr image: vish/stress resources: requests: memory: 50Mi limits: memory: "100Mi" args: - -mem-total - 250Mi - -mem-alloc-size - 10Mi - -mem-alloc-sleep - 1s
  • 步骤4:实现蓝绿发布 本步骤将为Bookinfo应用的“reviews”服务添加新的版本,将原有生产环境的默认版本的流量切换到新版本中。 部署新版本 在左侧导航中选择“灰度发布”,在蓝绿发布下,单击“创建”。 配置基本信息,单击“创建”。 蓝绿发布服务:单击“选择服务”,选择reviews,单击“确定”。 部署集群:选择网格所在集群。 发布任务名称:用户自定义,可直接采用默认值。此处设置为reviews-v3。 版本号:配置为v3。 版本描述:可不填写。 部署新版本。 实例数量:使用默认。 实例配置:镜像版本选择1.5.2,其他参数保持默认。 单击“部署新版本”,待版本启动进度为100%,表明新版本部署成功。 图16 查看新版本状态 蓝绿策略配置与监控 新版本部署成功后,单击“蓝绿策略配置与监控”。 开通 免费体验 APM,或者购买 APM 套餐包,否则无法观测到原版本和新版本的流量监控数据。 图17 开通免费体验APM 单击“版本流量切换”,将流量全部切换到v3版本。 访问productpage服务地址,不断刷新页面,仅显示v3版本信息,即星形图标全部为红色。说明流量已全部切换到v3版本,成功实现了蓝绿发布。 图18 v3版本页面 将原版本下线 确认v3版本能够承接v1的所有流量后,即可删除v1版本,释放v1版本的资源。 在“灰度发布”页面,单击灰度任务“reviews-v3”。 在“蓝绿策略配置与监控”页面中,单击v1版本后的“版本下线”。 确认无误后,单击“确定”。 下线服务版本,会将包含的工作负载和Istio相关配置资源全部删除。
  • 步骤2:一键创建Bookinfo应用 为集群开启应用服务网格功能后,可以通过“一键体验”创建一个Bookinfo应用Demo,具体操作如下: 登录应用服务网格ASM控制台。 选择左侧导航中的“服务列表”,单击“一键体验”。 图3 一键体验应用 在“选择集群”中设置Bookinfo应用所在的集群,在“负载均衡”中选择与所选集群处于同一VPC和子网的负载均衡实例,单击“立即体验”。 图4 选择集群和负载均衡 等待Bookinfo应用创建完成。创建完成后状态栏将显示为“运行中”,Bookinfo应用包含productpage、details、reviews、ratings四个服务,如图5。 图5 服务列表
  • 步骤3:实现灰度发布 本步骤将为Bookinfo应用的“reviews”服务添加新的灰度版本,并配置相应的灰度策略,将原有生产环境的默认版本的流量引流一部分到新版本中。 下面将以为“reviews”服务添加一个v3新版本,且v3新版本接收Bookinfo应用的20%流量为例进行配置。 部署灰度版本 在左侧导航中选择“灰度发布”,在金丝雀发布下,单击“创建”。 配置灰度版本发布基本信息,单击“创建”。 灰度发布服务:单击“选择服务”,选择reviews,单击“确定”。 部署集群:选择网格所在集群。 发布任务名称:用户自定义,可直接采用默认值。此处设置为reviews-v3。 版本号:配置为v3。 版本描述:可不填写。 部署灰度版本。 实例数量:使用默认。 实例配置:镜像版本选择1.5.2,其他参数保持默认。 单击“部署灰度版本”,待版本启动进度为100%,表明灰度版本部署成功。 图6 查看灰度版本状态 配置灰度策略 为灰度版本设置灰度策略,灰度版本会根据配置的流量配比引流老版本中的部分或全部流量。 灰度版本部署成功后,单击“配置灰度策略”。 设置灰度策略。 策略类型分为“基于流量比例”和“基于请求内容”,通过页签选择确定。 基于流量比例:根据流量比例配置规则,将从原版本中切分指定比例的流量到灰度版本。例如80%的流量走原版本,20%的流量走灰度版本。 基于请求内容:根据请求内容配置规则,只有请求内容中满足特定条件的流量会切分到灰度版本上。例如只有在Windows操作系统上的用户可以访问灰度版本。 以“基于流量比例”为例,且v3版本流量配比为20%。更多策略内容请参见为服务添加灰度版本。 图7 灰度策略 单击“策略下发”。 灰度策略的生效需要几秒的时间,您需要在“监测灰度运行状态”页面开通免费体验APM,或者购买APM套餐包,否则无法观测到原版本和灰度版本的流量监控数据。 图8 开通免费体验APM 监测灰度运行状态 在“服务列表”页面,单击productpage服务中的“访问地址”。不断刷新页面,页面在v1和v3版本之间来回切换。 图9 v1版本页面 图10 v3版本页面 您也可以在一台已连接公网的机器上执行如下命令,持续访问productpage服务。 while true;do wget -q -O- http://ip:port/productpage; done 返回控制台的“监测灰度运行状态”页面查看v1和v3版本的实时流量监控情况。 图11 流量监控详情 在“流量监控”页面,您可以查看Bookinfo应用各微服务之间的实时拓扑。ASM提供的流量监控功能,可监控微服务之间的拓扑、会话请求调用链、各环节耗时和RPS、RT等性能状态。 图12 流量监控拓扑 从拓扑图可以看出,reviews-v1和reviews-v3服务的调用次数分别为706和167,比例大致接近4:1,符合设定的流量比例策略。成功实现了灰度发布。 灰度版本切换 确认v3版本能够承接v1的所有流量后,即可将v1流量全部切换到v3。 在“灰度发布”页面,单击灰度任务“reviews-v3”。 单击v3版本后的“接管所有流量”。 图13 接管所有流量 单击“确定”。 刷新页面,查看流量切换情况,数据每隔5秒会刷新一次。 图14 v3接收全部流量 在Bookinfo应用页面,不断刷新页面,页面仅显示v3版本信息,即星形图标全部为红色。 图15 v3版本页面 将原版本下线 v3承接v1版本所有流量后,即可删除v1版本,释放v1版本的资源。 在“灰度发布”页面,单击灰度任务“reviews-v3”。 在“监测灰度运行状态”页面中,当v3版本中的流量占比为100%时,表明v3已承接v1所有流量。单击v1版本后的“版本下线”。 确认无误后,输入“DELETE”,单击“确定”。 下线服务版本,会将包含的工作负载和Istio相关配置资源全部删除。
  • Bookinfo应用分析 Bookinfo是一个模仿在线书店的应用,页面上会显示一本书籍的描述,书籍的细节(如页数),以及关于书籍的一些评论。 Bookinfo应用由四个单独的服务构成,几个服务是由不同的语言编写的。这些服务对应用服务网格ASM并无依赖,但是构成了一个有代表性的服务网格的例子,即由多个服务、多个语言构成,且reviews服务具有多个版本。这四个服务的说明如下: productpage:会调用details和reviews两个服务,用来生成页面。 details:包含了书籍的信息。 reviews:包含了书籍相关的评论,同时会调用ratings服务。 ratings:包含了由书籍评价组成的评级信息。 其中,reviews服务有3个版本: v1(1.5.1)版本会调用ratings服务,并使用1到5个黑色星形图标来显示评分信息。 v2(1.5.0)版本不会调用ratings服务。 v3(1.5.2)版本会调用ratings服务,并使用1到5个红色星形图标来显示评分信息。 为了直观的展示灰度版本之间流量切换情况,本教程以reviews服务的v1版本(黑星形)、v3版本(红星形)为例进行说明。 图1 Bookinfo应用的端到端架构 在ASM中运行Bookinfo应用,无需对应用自身做出任何改变,只需简单的在ASM环境中对服务进行配置和运行,即把Envoy Sidecar注入到每个服务之中。最终的部署结果如图2所示。 图2 Envoy Sidecar注入之后的Bookinfo应用 所有的服务都和Envoy Sidecar集成在一起,被集成服务的所有出入流量都被Sidecar所劫持,这样就可以利用ASM为应用提供服务路由、遥测数据收集以及策略实施等功能。
  • 步骤1:使能服务网格 使能服务网格是指为集群开启应用服务网格功能,开启后即可实现灰度发布、流量管理、熔断、监控、拓扑、调用链等丰富的服务治理能力。 登录应用服务网格ASM控制台。 在“总览”页面,单击“购买网格”。 设置如下参数,其余参数均采用默认值。 网格类型 此处以专有网格为例进行说明。 集群 选择准备工作中创建的集群。 可用区&节点规格 为确保Istio控制面运行稳定,推荐您使用8核16GB或以上规格控制面节点。 设置完成后,单击“下一步”。确认订单无误后,单击“提交”。 启用时间预计需要5分钟,您可以单击请求提交页面的“返回Istio管理”或“前往CCE集群管理”查看网格运行状态。
  • 操作步骤 分别获取目标集群的bearer_token 信息。 在目标集群创建rbac权限。 登录到目标集群后台节点,创建prometheus_rbac.yaml文件。 apiVersion: v1kind: ServiceAccountmetadata: name: prometheus-test namespace: kube-system---apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRolemetadata: name: prometheus-testrules:- apiGroups: - "" resources: - nodes - services - endpoints - pods - nodes/proxy verbs: - get - list - watch- apiGroups: - "extensions" resources: - ingresses verbs: - get - list - watch- apiGroups: - "" resources: - configmaps - nodes/metrics verbs: - get- nonResourceURLs: - /metrics verbs: - get---apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRoleBindingmetadata: name: prometheus-testroleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: prometheus-testsubjects:- kind: ServiceAccount name: prometheus-test namespace: kube-system 执行以下命令创建rbac权限。 kubectl apply -f prometheus_rbac.yaml 获取目标集群bearer_token信息。 1.21以前版本的集群中,Pod中 获取Token 的形式是通过挂载ServiceAccount的Secret来获取Token,这种方式获得的Token是永久的。该方式在1.21及以上的版本中不再推荐使用,并且根据社区版本迭代策略,在1.25及以上版本的集群中,ServiceAccount将不会自动创建对应的Secret。 1.21及以上版本的集群中,直接使用TokenRequest API获得Token,并使用投射卷(Projected Volume)挂载到Pod中。使用这种方法获得的Token具有固定的生命周期,并且当挂载的Pod被删除时这些Token将自动失效。详情请参见Token安全性提升说明。 如果您在业务中需要一个永不过期的Token,您也可以选择手动管理ServiceAccount的Secret。尽管存在手动创建永久ServiceAccount Token的机制,但还是推荐使用TokenRequest的方式使用短期的Token,以提高安全性。 首先获取serviceaccount信息。 kubectl describe sa prometheus-test -n kube-system kubectl describe secret prometheus-test-token-hdhkg -n kube-system 记录下这个token值,就是要搜集的bearer_token信息。 配置bearer_token 信息。 登录到Prometheus所在机器,进入Prometheus的安装目录,将目标集群的token信息保存在文件中。 配置Prometheus监控job。 示例job监控的是容器指标。如果需要监控其他指标,可自行添加job编写抓取规则。 - job_name: k8s_cAdvisor scheme: https bearer_token_file: k8s_token #上一步中的token文件 tls_config: insecure_skip_verify: true kubernetes_sd_configs: #kubernetes 自动发现配置 - role: node #node类型的自动发现 bearer_token_file: k8s_token #上一步中的token文件 api_server: https://192.168.0.153:5443 #K8s集群 apiserver地址 tls_config: insecure_skip_verify: true #跳过对服务端的认证 relabel_configs: ##用于在抓取metrics之前修改target的已有标签 - target_label: __address__ replacement: 192.168.0.153:5443 action: replace ##将metrics_path地址转换为/api/v1/nodes/${1}/proxy/metrics/cadvisor #相当于通过APIServer代理到kubelet上获取数据 - source_labels: [__meta_kubernetes_node_name] #指定需要处理的源标签 regex: (.+) #匹配源标签的值,(.+)表示源标签什么值都可以匹配上 target_label: __metrics_path__ #指定了需要replace后的标签 replacement: /api/v1/nodes/${1}/proxy/metrics/cadvisor # 表示替换后的标签即__metrics_path__ 对应的值。其中${1}表示正则匹配的值,即nodename - target_label: cluster replacement: xxxxx ##根据实际情况填写 集群信息。也可不写###下面这个job是监控另一个集群 - job_name: k8s02_cAdvisor scheme: https bearer_token_file: k8s02_token #上一步中的token文件 tls_config: insecure_skip_verify: true kubernetes_sd_configs: - role: node bearer_token_file: k8s02_token #上一步中的token文件 api_server: https://192.168.0.147:5443 #K8s集群 apiserver地址 tls_config: insecure_skip_verify: true #跳过对服务端的认证 relabel_configs: ##用于在抓取metrics之前修改target的已有标签 - target_label: __address__ replacement: 192.168.0.147:5443 action: replace - source_labels: [__meta_kubernetes_node_name] regex: (.+) target_label: __metrics_path__ replacement: /api/v1/nodes/${1}/proxy/metrics/cadvisor - target_label: cluster replacement: xxxx ##根据实际情况填写 集群信息。也可不写 启动prometheus服务。 配置完毕后,启动prometheus服务 ./prometheus --config.file=prometheus.yml 登录prometheus服务访问页面,查看监控信息。
  • Solution as Code一键式部署类最佳实践 为帮助企业高效上云,华为云Solution as Code萃取丰富上云成功实践,提供一系列基于华为云可快速部署的解决方案,帮助用户降低上云门槛。同时开放完整源码,支持个性化配置,解决方案开箱即用,所见即所得。 表1 表1 Solution as Code一键式部署类最佳实践汇总 一键式部署方案 说明 相关服务 应用容器化上云 该方案基于云容器引擎CCE服务构建,可帮助您快速实现业务系统的容器化改造。 CCE、ELB、EIP 快速构建云原生订单管理系统 该方案可帮助您在华为云云容器引擎上快速搭建订单管理系统。 CCE、RDS、RabbitMQ、ELB、EIP 基于CCE快速部署Volcano批量调度系统 该解决方案能帮您快速在华为云CCE容器集群上快速部署Volcano批量调度系统。 CCE、EIP 基于Nginx Ingress实现灰度发布 该解决方案能帮您快速在华为云上部署云容器引擎 CCE集群,并通过Nginx Ingress可以基于权重实现灰度发布,从而保证整体系统的稳定,在初始灰度的时候就可以发现、调整问题,以保证其影响度。 CCE、ELB、EIP
  • 如何选择合适的数据盘 在选择合适的数据盘大小时,需要结合以下考虑综合计算: 在拉取镜像过程中,会先从镜像仓库中下载镜像tar包然后解压,最后删除tar包保留镜像文件。在tar包的解压过程中,tar包和解压出来的镜像文件会同时存在,占用额外的存储空间,需要在计算所需的数据盘大小时额外注意。 在集群创建过程中,节点上可能会部署必装插件(如Everest插件、coredns插件等),这些插件会占用一定的空间,在计算数据盘大小时,需要为其预留大约2G的空间。 在应用运行过程中会产生日志,占用一定的空间,为保证业务正常运行,需要为每个Pod预留大约1G的空间。 根据不同的节点存储类型,详细的计算公式请参见OverlayFS类型及Device Mapper类型。
  • 数据盘空间不足时如何解决 方案一:清理镜像 您可以执行以下命令清理未使用的Docker镜像: docker system prune -a 该命令会把暂时没有用到的Docker镜像都删除,执行命令前请确认。 方案二:扩容磁盘 在EVS界面扩容数据盘。 登录CCE控制台,进入集群,在左侧选择“节点管理”,单击节点后的“同步云服务器”。 登录目标节点。 使用lsblk命令查看节点块设备信息。 这里存在两种情况,根据容器存储Rootfs而不同。 Overlayfs,没有单独划分thinpool,在dockersys空间下统一存储镜像相关数据。 # lsblkNAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTsda 8:0 0 50G 0 disk └─sda1 8:1 0 50G 0 part /sdb 8:16 0 200G 0 disk ├─vgpaas-dockersys 253:0 0 90G 0 lvm /var/lib/docker # docker使用的空间└─vgpaas-kubernetes 253:1 0 10G 0 lvm /mnt/paas/kubernetes/kubelet # kubernetes使用的空间 在节点上执行如下命令, 将新增的磁盘容量加到dockersys盘上。 pvresize /dev/sdb lvextend -l+100%FREE -n vgpaas/dockersysresize2fs /dev/vgpaas/dockersys Devicemapper,单独划分了thinpool存储镜像相关数据。 # lsblkNAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTsda 8:0 0 50G 0 disk └─sda1 8:1 0 50G 0 part /sdb 8:16 0 200G 0 disk ├─vgpaas-dockersys 253:0 0 18G 0 lvm /var/lib/docker ├─vgpaas-thinpool_tmeta 253:1 0 3G 0 lvm │ └─vgpaas-thinpool 253:3 0 67G 0 lvm # thinpool空间│ ...├─vgpaas-thinpool_tdata 253:2 0 67G 0 lvm │ └─vgpaas-thinpool 253:3 0 67G 0 lvm │ ...└─vgpaas-kubernetes 253:4 0 10G 0 lvm /mnt/paas/kubernetes/kubelet 在节点上执行如下命令, 将新增的磁盘容量加到thinpool盘上。 pvresize /dev/sdb lvextend -l+100%FREE -n vgpaas/thinpool 在节点上执行如下命令, 将新增的磁盘容量加到dockersys盘上。 pvresize /dev/sdb lvextend -l+100%FREE -n vgpaas/dockersysresize2fs /dev/vgpaas/dockersys
  • 高并发业务场景参数优化 针对高并发业务场景,可通过参数配置进行优化: 通过ConfigMap对Nginx Ingress Controller整体参数进行优化。 通过InitContainers对Nginx Ingress Controller内核参数进行优化。 优化后的value.yaml配置文件如下: controller: image: repository: swr.cn-east-3.myhuaweicloud.com/hwofficial/nginx-ingress #controller镜像地址,请根据集群所在区域进行替换 registry: "" image: "" tag: "v1.5.1" #controller版本 digest: "" ingressClassResource: name: ccedemo #同一个集群中不同套Ingress Controller名称必须唯一,且不能设置为nginx和cce controllerValue: "k8s.io/ingress-nginx-demo" #同一个集群中不同套Ingress Controller的监听标识必须唯一,且不能设置为k8s.io/ingress-nginx ingressClass: ccedemo #同一个集群中不同套Ingress Controller名称必须唯一,且不能设置为nginx和cce service: annotations: { kubernetes.io/elb.id: 5083f225-9bf8-48fa-9c8b-67bd9693c4c0 #ELB ID kubernetes.io/elb.class: performance #仅独享型ELB需要添加此注解 }# Nginx参数优化 config: { "keep-alive-requests": "10000", "upstream-keepalive-connections": "200", "max-worker-connections": "65536" } # 内核参数优化 extraInitContainers: - name: init-myservice image: busybox securityContext: privileged: true command: ['sh', '-c', 'sysctl -w net.core.somaxconn=65535;sysctl -w net.ipv4.ip_local_port_range="1024 65535"'] extraVolumeMounts: # 挂载节点上的/etc/localtime文件,进行时区同步 - name: localtime mountPath: /etc/localtime readOnly: true extraVolumes: - name: localtime type: Hostpath hostPath: path: /etc/localtime admissionWebhooks: # 关闭webhook验证开关 enabled: false patch: enabled: false resources: # 设定controller的资源限制,可根据需求自定义 requests: cpu: 200m memory: 200MidefaultBackend: # 设置defaultBackend enabled: true image: repository: swr.cn-east-3.myhuaweicloud.com/hwofficial/defaultbackend #defaultBackend镜像地址,请根据集群所在区域进行替换 registry: "" image: "" tag: "1.5" digest: ""
  • admissionWebhook配置 Nginx Ingress Controller支持admissionWebhook配置,通过设置controller.admissionWebhook参数,可以对Ingress对象进行有效性校验,避免因配置错误导致ingress-controller不断重新加载资源,导致业务中断。 使用admissionWebhook特性时,APIServer需要开启webhook相关配置,必须包含MutatingAdmissionWebhook与ValidatingAdmissionWebhook 特性开关为 --admission-control=MutatingAdmissionWebhook,ValidatingAdmissionWebhook 如未开启,需要提交工单申请开启。 开启admissionWebhook特性后,如需卸载重装Nginx Ingress Controller,会有Secret残留,需要手动清理。 开启admissionWebhook的value.yaml配置文件如下: controller: image: repository: swr.cn-east-3.myhuaweicloud.com/hwofficial/nginx-ingress #controller镜像地址,请根据集群所在区域进行替换 registry: "" image: "" tag: "v1.5.1" #controller版本 digest: "" ingressClassResource: name: ccedemo #同一个集群中不同套Ingress Controller名称必须唯一,且不能设置为nginx和cce controllerValue: "k8s.io/ingress-nginx-demo" #同一个集群中不同套Ingress Controller的监听标识必须唯一,且不能设置为k8s.io/ingress-nginx ingressClass: ccedemo #同一个集群中不同套Ingress Controller名称必须唯一,且不能设置为nginx和cce service: annotations: { kubernetes.io/elb.id: 5083f225-9bf8-48fa-9c8b-67bd9693c4c0 #ELB ID kubernetes.io/elb.class: performance #仅独享型ELB需要添加此注解 } config: { "keep-alive-requests": "100" } extraVolumeMounts: # 挂载节点上的/etc/localtime文件,进行时区同步 - name: localtime mountPath: /etc/localtime readOnly: true extraVolumes: - name: localtime type: Hostpath hostPath: path: /etc/localtime admissionWebhooks: annotations: {} enabled: true extraEnvs: [] failurePolicy: Fail port: 8443 certificate: "/usr/local/certificates/cert" key: "/usr/local/certificates/key" namespaceSelector: {} objectSelector: {} labels: {} existingPsp: "" networkPolicyEnabled: false service: annotations: {} externalIPs: [] loadBalancerSourceRanges: [] servicePort: 443 type: ClusterIP createSecretJob: resources: #注释{} limits: cpu: 20m memory: 40Mi requests: cpu: 10m memory: 20Mi patchWebhookJob: resources: {} patch: enabled: true image: registry: registry.k8s.io #registry.k8s.io为webhook官网镜像仓库,需要替换成自己镜像所在仓库地址 image: ingress-nginx/kube-webhook-certgen #webhook镜像 tag: v1.1.1 digest: "" pullPolicy: IfNotPresent priorityClassName: "" podAnnotations: {} nodeSelector: kubernetes.io/os: linux tolerations: [] labels: {} securityContext: runAsNonRoot: true runAsUser: 2000 fsGroup: 2000 resources: # 设定controller的资源限制,可根据需求自定义 requests: cpu: 200m memory: 200MidefaultBackend: # 设置defaultBackend enabled: true image: repository: swr.cn-east-3.myhuaweicloud.com/hwofficial/defaultbackend #defaultBackend镜像地址,请根据集群所在区域进行替换 registry: "" image: "" tag: "1.5" digest: "" 验证Ingress配置错误annotation场景下,admissionWebhook是否会进行校验。 例如,为Ingress配置以下错误的annotation: ... annotations: nginx.ingress.kubernetes.io/auth-tls-pass-certificate-to-upstream: "false" nginx.ingress.kubernetes.io/auth-tls-verify-client: optional nginx.ingress.kubernetes.io/auth-tls-verify-depth: "1"... 创建此Ingress服务,将会出现以下拦截信息:
  • 概念 会话保持是负载均衡最常见的问题之一,也是一个相对比较复杂的问题。 会话保持有时候又叫做粘滞会话(Sticky Sessions),开启会话保持后,负载均衡会把来自同一客户端的访问请求持续分发到同一台后端云服务器上进行处理。 在介绍会话保持技术之前,必须先花点时间弄清楚一些概念:什么是连接(Connection)、什么是会话(Session),以及这二者之间的区别。需要特别强调的是,如果仅仅是谈论负载均衡,会话和连接往往具有相同的含义。 从简单的角度来看,如果用户需要登录,那么就可以简单的理解为会话;如果不需要登录,那么就是连接。 实际上,会话保持机制与负载均衡的基本功能是完全矛盾的。负载均衡希望将来自客户端的连接、请求均衡的转发至后端的多台服务器,以避免单台服务器负载过高;而会话保持机制却要求将某些请求转发至同一台服务器进行处理。因此,在实际的部署环境中,需要根据应用环境的特点,选择适当的会话保持机制。
  • 七层负载均衡(Ingress) 7层的模式下可以开启基于http cookie和app cookie的会话保持 ,在ingress上开启基于cookie的会话保持需要满足以下条件: Ingress对应的应用(工作负载)应该开启与自身反亲和。 Ingress对应的service需要开启节点亲和。 操作步骤: 创建nginx工作负载。 实例数设置为3,通过工作负载反亲和设置Pod与自身反亲和。 kind: DeploymentapiVersion: apps/v1metadata: name: nginx namespace: defaultspec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: container-0 image: 'nginx:perl' resources: limits: cpu: 250m memory: 512Mi requests: cpu: 250m memory: 512Mi imagePullSecrets: - name: default-secret affinity: podAntiAffinity: # Pod与自身反亲和 requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app operator: In values: - nginx topologyKey: kubernetes.io/hostname 创建NodePort类型Service。 会话保持的配置在Service这里设置,Ingress可以对接多个Service,每个Service可以有不同的会话保持配置。 apiVersion: v1kind: Servicemetadata: name: nginx namespace: default annotations: kubernetes.io/elb.lb-algorithm: ROUND_ROBIN kubernetes.io/elb.session-affinity-mode: HTTP_COOKIE # HTTP Cookie类型 kubernetes.io/elb.session-affinity-option: '{"persistence_timeout":"1440"}' # 会话保持时间,单位为分钟,取值范围为1-1440spec: selector: app: nginx ports: - name: cce-service-0 protocol: TCP port: 80 targetPort: 80 nodePort: 32633 # 节点端口 type: NodePort externalTrafficPolicy: Local # 节点级别转发 还可以选择应用程序Cookie,如下所示。 apiVersion: v1kind: Servicemetadata: name: nginx namespace: default annotations: kubernetes.io/elb.lb-algorithm: ROUND_ROBIN kubernetes.io/elb.session-affinity-mode: APP_COOKIE # 选择应用程序Cookie kubernetes.io/elb.session-affinity-option: '{"app_cookie_name":"test"}' # 应用程序Cookie名称... 创建Ingress,关联Service。以下示例以自动创建共享型ELB为例,如需指定其他类型的ELB,请参考通过Kubectl命令行添加ELB Ingress。 apiVersion: networking.k8s.io/v1kind: Ingress metadata: name: ingress-test namespace: default annotations: kubernetes.io/elb.class: union kubernetes.io/elb.port: '80' kubernetes.io/elb.autocreate: '{ "type":"public", "bandwidth_name":"cce-bandwidth-test", "bandwidth_chargemode":"traffic", "bandwidth_size":1, "bandwidth_sharetype":"PER", "eip_type":"5_bgp" }'spec: rules: - host: 'www.example.com' http: paths: - path: '/' backend: service: name: nginx # Service的名称 port: number: 80 property: ingress.beta.kubernetes.io/url-match-mode: STARTS_WITH pathType: ImplementationSpecific ingressClassName: cce 登录ELB控制台,进入对应的ELB实例,查看会话保持是否开启。 图1 开启会话保持
  • 四层负载均衡(Service) 四层的模式下可以开启基于源IP的会话保持(基于客户端的IP进行hash路由),Service上开启基于源IP的会话保持需要满足以下条件: CCE集群 Service的服务亲和级别选择“节点级别”(即Service的externalTrafficPolicy字段为Local)。 CCE Turbo 集群无需设置该参数。 Service的负载均衡配置启用源IP地址会话保持。 apiVersion: v1kind: Servicemetadata: name: svc-example namespace: default annotations: kubernetes.io/elb.class: union kubernetes.io/elb.id: 56dcc1b4-8810-480c-940a-a44f7736f0dc kubernetes.io/elb.lb-algorithm: ROUND_ROBIN kubernetes.io/elb.session-affinity-mode: SOURCE_IPspec: selector: app: nginx externalTrafficPolicy: Local # CCE Turbo集群无需设置该参数 ports: - name: cce-service-0 targetPort: 80 nodePort: 32633 port: 80 protocol: TCP type: LoadBalancer Service后端的应用开启反亲和。
  • 应用现状 当前,越来越多的软件采用微服务架构,构建一个产品时会大量使用微服务,不同微服务之间访问时涉及到域名访问。 拥有自建IDC的企业,在使用CCE时通常需要在CCE集群与自建IDC之间通信,而且当IDC有内部域名时,需要CCE集群内的节点和容器既能够解析IDC的域名,也能够解析云域名。 例如,某企业APP微服务改造后,其管理后台部署在CCE集群上, 内容审核 服务部署在企业原有的IDC,该企业同时购买了华为云图像识别服务。CCE所在的VPC和原有的IDC之间通过专线进行连接。部署架构如图1所示。 当用户访问该企业的APP时,不同微服务之间涉及到如下交互: CCE集群访问华为云图像识别服务时,默认使用华为云域名解析服务器。 CCE集群访问IDC上部署的内容审核服务时,需要使用IDC内部域名服务器。 这就需要在CCE集群上既能使用华为云域名解析服务器,也能够使用IDC内部域名服务器。如果将CCE节点上域名解析服务器指向IDC的域名解析服务器,那会导致无法解析华为云的域名;如果修改hosts文件配置增加IDC内部域名IP,在IDC内部服务IP变化时需要实时刷新CCE节点的配置,这很难做到且会导致不可用。 内容审核服务与图像识别服务仅为举例,也可以是其他服务。 图1 某企业APP微服务示意图 本文介绍一种自建IDC与CCE集群共享域名解析的方案,可做到同时解析华为云域名和外部域名。
  • 解决方案一:通过DNS Endpoint做级联解析 利用VPCEP服务创建DNS Endpoint,使得IDC能访问华为云域名解析服务器,将DNS Endpoint与IDC的域名解析服务器做级联,从而使得CCE集群中节点及容器在域名解析时,通过IDC的域名解析服务器进行解析。 如果是需要解析华为云内域名,则转发给DNS Endpoint,使用华为云DNS解析出地址并返回。 如果是需要解析IDC域名,则直接通过IDC的域名解析服务器直接解析出地址并返回。 图2 节点同时访问华为云域名和外部域名 对于容器中的域名解析,可在创建Pod时将DNS Policy设置为ClusterFirst,这样容器中的域名解析直接走CoreDNS。 如果是需要解析集群内域名,则CoreDNS直接解析出结果返回。 如果是解析外部域名,则通过CoreDNS,转到IDC的域名解析服务器解析。 图3 容器同时访问华为云域名和外部域名
  • 解决方案二:修改CoreDNS配置直接解析 直接修改CoreDNS配置,可在创建Pod时将DNS Policy设置为ClusterFirst,这样容器中的域名解析直接走CoreDNS。 如果是需要解析集群内域名,则CoreDNS直接解析出结果返回。 如果是解析外部域名,则通过CoreDNS,转到IDC的域名解析服务器解析。 如果是访问华为云内部域名,则直接使用华为云内部域名解析服务器解析 图4 方案二:修改CoreDNS配置
  • 操作步骤 CoreDNS的配置都存储在名为coredns的ConfigMap下,您可以在kube-system命名空间下找到该配置项。使用如下命令可以查看到默认配置的内容。 kubectl get configmap coredns -n kube-system -oyaml kind: ConfigMapapiVersion: v1metadata: name: coredns namespace: kube-system selfLink: /api/v1/namespaces/kube-system/configmaps/coredns uid: d54ed5df-f4a0-48ec-9bc0-3efc1ac76af0 resourceVersion: '21789515' creationTimestamp: '2021-03-02T09:21:55Z' labels: app: coredns k8s-app: coredns kubernetes.io/cluster-service: 'true' kubernetes.io/name: CoreDNS release: cceaddon-corednsdata: Corefile: |- .:5353 { bind {$POD_IP} cache 30 errors health {$POD_IP}:8080 kubernetes cluster.local in-addr.arpa ip6.arpa { pods insecure upstream /etc/resolv.conf fallthrough in-addr.arpa ip6.arpa } loadbalance round_robin prometheus {$POD_IP}:9153 forward . /etc/resolv.conf reload } 如上所示,CoreDNS的所有配置都在Corefile这个配置项下。默认情况下任何不属于Kubernetes集群内部的域名,其DNS请求都将指向forward指定的 DNS 服务器地址,这里“forward . /etc/resolv.conf”里面第一个“.”代表所有域名,后面“/etc/resolv.conf”表示使用节点的域名解析服务器。 通常要解析特定外部域名时,可以单独添加配置项,执行如下步骤修改coredns的Corefile配置,对于content.internal这个域,将域名解析都转发到10.0.0.190这个域名解析服务器上。 登录CCE控制台,单击集群名称进入集群。 在左侧导航栏中选择“插件管理”,在“已安装插件”下,在CoreDNS下单击“编辑”,进入插件详情页。 在“参数配置”下添加存根域。格式为一个键值对,键为DNS后缀域名,值为一个或一组DNS IP地址。本例中,配置为'content.internal --10.0.0.190'。 单击“确定”完成配置更新。 在左侧导航栏中选择“配置项与密钥”,在“kube-system”命名空间下,查看coredns配置项数据,确认是否更新成功。 对应Corefile内容如下: .:5353 { bind {$POD_IP} cache 30 errors health {$POD_IP}:8080 kubernetes cluster.local in-addr.arpa ip6.arpa { pods insecure fallthrough in-addr.arpa ip6.arpa } loadbalance round_robin prometheus {$POD_IP}:9153 forward . /etc/resolv.conf { policy random } reload ready {$POD_IP}:8081}content.internal:5353 { bind {$POD_IP} errors cache 30 forward . 10.0.0.190} CoreDNS其他配置详解,请参见自定义 DNS 服务。
  • 配置验证 创建一个Pod访问IDC的域名,如下所示,同样能够ping通,说明能够解析。 web-terminal-568c6566df-c9jhl:~# kubectl run -i --tty --image tutum/dnsutils dnsutils --restart=Never --rm /bin/sh If you don't see a command prompt, try pressing enter.# ping www.content.internalPING www.content.internal (10.0.1.80) 56(84) bytes of data.64 bytes from 10.0.1.80: icmp_seq=1 ttl=64 time=1.08 ms64 bytes from 10.0.1.80: icmp_seq=2 ttl=64 time=0.337 ms 继续访问华为云域名,能够看到已经解析出对应的IP地址,说明能够解析。 # ping cce.cn-east-3.myhuaweicloud.comPING cce.cn-east-3.myhuaweicloud.com (100.125.4.16) 56(84) bytes of data. 在集群节点上访问IDC的域名,无法ping通,说明CoreDNS的配置无法影响节点域名解析。
  • 操作步骤 在CCE集群所在VPC创建 DNS Endpoint。 登录VPCEP控制台。 单击右上角“购买终端节点”。 选择DNS服务和VPC,注意此处VPC需要选择CCE集群所在VPC。 图1 创建DNS Endpoint 单击“立即购买”,完成创建。 创建完成后,可在详情页中查看到DNS Endpoint的IP地址,如下图所示。 图2 DNS Endpoint的IP地址 在IDC的域名解析服务器上做级联配置。 此处配置跟具体域名解析服务器相关,不同域名解析服务器的配置方法不同,请根据实际情况配置。 这里使用BIND软件(一个常用的域名解析服务器软件)为例进行说明。 域名解析服务器上配置的关键是将需要解析华为云内部域名的任务转发给上一步创建的DNS Endpoint。 例如BIND中可以修改/etc/named.conf文件,将域名解析任务转发给DNS Endpoint,如下所示,添加如下两行,将转发解析转发到DNS Endpoint的地址,其中192.168.0.203为1创建的DNS Endpoint的地址。 options { listen-on port 53 { any; }; listen-on-v6 port 53 { ::1; }; directory "/var/named"; dump-file "/var/named/data/cache_dump.db"; statistics-file "/var/named/data/named_stats.txt"; memstatistics-file "/var/named/data/named_mem_stats.txt"; recursing-file "/var/named/data/named.recursing"; secroots-file "/var/named/data/named.secroots"; allow-query { any; }; forward first; forwarders { 192.168.0.203; }; .....}; 修改CCE集群Node节点的DNS配置。 修改Node节点的DNS有如下两种方法。 方法一: 在Node节点创建完成后,修改节点的DNS配置。 登录CCE集群的Node节点。 修改/etc/resolv.conf文件,修改nameserver的地址为IDC的域名解析服务器地址。 # vi /etc/resolv.confnameserver 10.0.0.190 执行如下命令锁定resolv.conf文件,防止被华为云自动更新。 chattr +i /etc/resolv.conf 更详细的配置DNS步骤可以参考配置DNS。 方法二: 修改CCE集群所在的VPC子网的DNS配置,这样新创建的Node节点的/etc/resolv.conf文件中会直接刷新成指定的域名解析服务器地址。 此方法需要确保节点能够正常使用IDC的域名解析服务器解析华为云内网域名,否则会导致节点无法创建。建议在调试无问题后再修改VPC子网的DNS配置。 图3 子网的DNS配置 配置工作负载的DNS Policy。 创建工作负载时,容器中的域名解析可以在YAML中配置dnsPolicy为ClusterFirst,如下所示。Kubernetes默认也是将dnsPolicy设置为ClusterFirst,如此处不做配置,Kubernetes也是默认设置为ClusterFirst。工作负载的DNS详细配置可以参考DNS配置说明。 apiVersion: v1kind: Podmetadata: namespace: default name: dns-examplespec: containers: - name: test image: nginx dnsPolicy: ClusterFirst
  • 操作流程 Jenkins Master安装部署。 Jenkins Master使用容器化镜像部署在CCE集群中。 Jenkins Agent配置。 Jenkins可以在集群中创建固定Agent,也可以使用pipeline与CCE的对接,动态提供Agent pod。其中动态Agent还需要使用Kubernetes相关插件配置集群认证信息及用户权限。 使用Jenkins构建流水线。 Jenkins流水线与SWR对接,在Agent中调用docker build/login/push相关的命令,实现自动化的镜像打包、推送。 您也可以通过流水线实现Kubernetes资源(deployment/service/ingress/job等)的部署、升级等能力。
  • 方案架构 Jenkins部署分为以下两种模式: 一种是直接使用单Master安装Jenkins,直接进行任务管理和业务构建发布,但可能存在一定的生产安全风险。 一种是Master加Agent模式。Master节点主要是处理调度构建作业,把构建分发到Agent实际执行,监视Agent的状态。业务构建发布的工作交给Agent进行,即执行Master分配的任务,并返回任务的进度和结果。 Jenkins的Master和Agent均可安装在虚拟机或容器中,且组合形式可多样,参见表1。 表1 Jenkins部署模式 部署模式 Master Agent 优缺点分析 单Master 虚拟机 - 优点:本地化构建,操作简单。 缺点:任务管理和执行都在同一台虚拟机上,安全风险较高。 单Master 容器 - 优点:利用K8s容器调度机制,拥有一定的自愈能力。 缺点:任务管理和执行没有分离,安全风险问题仍未解决。 Master加Agent 虚拟机 虚拟机 优点:任务管理和执行分离,降低了一定的安全风险。 缺点:只能固定Agent,无法进行资源调度,资源利用率低,且环境维护成本高。 容器(K8s集群) 优点:容器化的Agent可以选择固定Agent,也可以通过K8s实现动态Agent,动态Agent的方式资源利用率高。并且可以根据调度策略均匀分配任务,后期也比较容易维护。 缺点:Jenkins的Master存在小概率的宕机风险,恢复成本较高。 Master加Agent 容器(K8s集群) 容器(K8s集群) 优点:容器化的Agent可以选择固定Agent,也可以通过K8s实现动态Agent,资源利用率高。且Master具有自愈能力,维护成本低。Agent可以选择和Master共集群,也可以分集群。 缺点:系统复杂程度高,环境搭建较困难。 本文采用Master加Agent模式,Master和Agent均为容器化安装的方案,并使用在K8s集群实现动态Agent,具体架构如图1所示。 Jenkins Master负责管理任务(Job),为了能够利用Kubernetes平台上的资源,需要在Master上安装Kubernetes的插件。 Kubernetes平台负责产生Pod,用作Jenkins Agent执行Job任务。当Jenkins Master上有Job被调度时,Jenkins Master通过Kubernetes插件向Kubernetes平台发起请求,请Kubernetes根据Pod模板产生对应的Pod对象,Pod对象会向Jenkins Master发起请求,Master连接成功后,就可以在Pod上面执行Job了。 图1 K8s安装Jenkins架构
  • Jenkins是什么 Jenkins是一个开源的、提供友好操作界面的持续集成(CI)工具,起源于Hudson,主要用于持续、自动的构建/测试软件项目、监控外部任务的运行。 Jenkins用Java语言编写,可在Tomcat等流行的servlet容器中运行,也可独立运行。通常与版本管理工具(SCM)、构建工具结合使用。Jenkins可以很好的支持各种语言的项目构建,也完全兼容Maven、Ant、Gradle等多种第三方构建工具,同时跟SVN、GIT等常用的版本控制工具无缝集成,也支持直接对接GitHub等源代码托管网站。
  • 配置方法 集群版本为v1.15.11和v1.17.9时,CCE网络管理组件使用Network。 下面以CentOS 7系列虚拟机为例,介绍如何配置虚拟机网络。具体步骤如下: 登录虚拟机操作系统。 执行ifconfig命令查看当前虚拟机绑定的弹性网卡。 假设查询的网卡名称为:eth1,编辑“/etc/sysconfig/network-scripts/ifcfg-eth1”。 vim /etc/sysconfig/network-scripts/ifcfg-eth1 按以下格式编辑: DEVICE="eth1"BOOTPROTO="dhcp"ONBOOT="yes"TYPE="Ethernet"PERSISTENT_DHCLIENT="yes" 执行如下命令重启虚拟机网络,使网络配置生效。 systemctl restart network 当集群版本为v1.17.11及以上新版本时,CCE网络管理组件使用NetworkManager,客户在CCE的节点配置弹性网卡服务时,因网络模式不同会有如下三种不同的配置场景: overlay_l2网络模式:可以自动配置业务弹性网卡,如:自动获取IP、续租IP等,不需要单独配置弹性网卡。 vpc网络模式:除主网卡、容器绑定的弹性网卡外,客户需要单独配置弹性网卡。 云原生网络2.0网络模式:除主网卡、容器绑定的弹性网卡外,客户需要单独配置弹性网卡。 云原生网络2.0网络模式的集群(CCE Turbo集群),容器网络承载于弹性网卡/辅助弹性网卡,若进行此类配置请提工单修改集群预留网卡配置。 具体配置步骤如下: 下面以CentOS 7系列虚拟机为例,介绍如何配置虚拟机网络。具体步骤如下: 登录虚拟机操作系统。 执行ifconfig命令查看当前虚拟机绑定的弹性网卡。 假设查询的网卡名称为:eth1,编辑“/etc/sysconfig/network-scripts/ifcfg-eth1”。 vim /etc/sysconfig/network-scripts/ifcfg-eth1 按以下格式编辑: DEVICE="eth1"BOOTPROTO="dhcp"ONBOOT="yes"TYPE="Ethernet"PERSISTENT_DHCLIENT="yes" 执行如下命令重启虚拟机网络,使网络配置生效。 systemctl restart NetworkManager 查看节点eth1网卡的dhclient进程已经启动,说明配置生效。
  • 登录并初始化Jenkins 在CCE控制台,单击左侧栏目树中的“服务发现”,在“服务”页签下查看jenkins的访问方式。 图7 访问8080端口对应的访问方式 在浏览器中输入负载均衡的“EIP:8080”,即可打开jenkins配置页面。 初次访问时界面会提示获取初始管理员密码,该密码可在jenkins的Pod中获取。在执行下述命令之前您需要先通过kubectl连接集群,具体操作请参见通过kubectl连接集群。 # kubectl get pod -n cicdNAME READY STATUS RESTARTS AGEjenkins-7c69b6947c-5gvlm 1/1 Running 0 17m# kubectl exec -it jenkins-7c69b6947c-5gvlm -n cicd -- /bin/sh# cat /var/jenkins_home/secrets/initialAdminPasswordb10eabe29a9f427c9b54c01a9c3383ae 首次登录时选择默认推荐的插件即可,并根据页面提示创建一个管理员。完成初始配置后,即可进入Jenkins页面。
共100000条