首页 文章 精选 留言 我的

精选列表

搜索[k8s],共3940篇文章
优秀的个人博客,低调大师

当AI遇上K8S:使用Rancher安装机器学习必备工具JupyterHub

Jupyter Notebook是用于科学数据分析的利器,JupyterHub可以在服务器环境下为多个用户托管Jupyter运行环境。本文将详细介绍如何使用Rancher安装JupyterHub来为数据科学和机器学习开发创建可扩展的工作区。 本文来自 Rancher Labs 人工智能(AI)和机器学习(ML)正在成为技术领域的关键差异化因素。从本质上讲,人工智能和机器学习都是计算量巨大的工作负载,它们需要一流的分布式计算环境才能够蓬勃发展。因此,AI和ML为Kubernetes提供了一个完美的用例,他们能够最大化展现Kubernetes可以运行大量工作负载的特点。 什么是JupyterHub? Jupyter Notebook是用于科学数据分析的利器,JupyterHub可以在服务器环境下为多个用户托管Jupyter运行环境。JupyterHub是一个多用户数据探索工具,通常是数据科学和机器学习研究与开发的关键工具。它为工程师、科学家、研究人员和学生提供了云或数据中心的计算能力,同时仍然像本地开发环境一样易于使用。本质上,JupyterHub使用户可以访问计算环境和资源,而不会给他们增加安装和维护任务的负担。用户可以在工作区中使用共享资源,系统管理员会对其进行有效管理。 在AI/ML工作负载中使用Kubernetes Kubernetes非常擅长让我们利用大型分布式计算环境。因为其声明式设计和基于发现的服务器寻址方法,所以将计算资源应用于工作负载很容易。通常在AI/ML工作负载中,工程师或研究人员需要分配更多的资源。而Kubernetes让在物理基础架构之间迁移工作负载更加可行。在本文中,我们将展示如何使用Rancher安装JupyterHub。 使用Rancher安装JupyterHub 首先,假设我们在Rancher环境中拥有现代化的Kubernetes部署。在本文发布时,Kubernetes的稳定版本是1.16。对于JupyterHub来说,其中一个前期准备是持久化存储,所以你将需要思考如何在这个集群中提供它。出于演示的目的,我们可以使用Rancher Catalog中包含的实验性NFS提供程序来提供持久化存储。点开App Catalog并选择【启动】。然后搜索NFS提供程序。保留默认设置,然后单击屏幕底部的【启动】。如果你已经有持久化存储的解决方案,也可以直接使用它。 导航到Rancher App Catalog 搜索NFS提供程序 启动NFS提供程序 现在我们已经有了存储提供程序并且定义了默认存储类,我们可以继续部署应用程序组件。我们将使用Helm3来完成这一操作。查看helm官方文档(https://helm.sh/docs/intro/install/ ),在你的电脑上安装helm3客户端。另外,你也可以使用Rancher Catalog来部署helm chart,而无需任何其他工具。需要确保将repo添加到Rancher catalog中。 在我们使用helm之前,我们需要为应用程序创建一个命名空间。在Rancher UI中,进入集群并选择顶端菜单栏的【项目/命名空间】。你可以为JupyterHub创建一个新的命名空间。例如,我们将命名空间称为“jhub“。请注意此名称,因为我们将之后会使用。 创建一个命名空间 接下来,我们可以为将要使用的JupyterHub Chart添加Helm repo。如果使用的是Rancher catalog,你需要在UI上完成此操作而不是Helm CLI: helm repo add jupyterhub https://jupyterhub.github.io/helm-chart/ helm repo update 然后,让我们创建一个config文件,其中包含了我们要与此chart一起使用的设置。我们将该文件命名为config.yaml: proxy: secretToken: "<secret token>" ingress: enabled: true hosts: - <host name> 让我们替换几个项目,使它们是唯一的。用以下输出替换secretToken: openssl rand -hex 32 并替换为你打算用来访问JyupiterHub UI的可解析DNS名称。 有了配置文件之后,就可以安装chart了。我们将引用该配置文件,因此请确保该文件存在你当前的工作目录中: RELEASE=jhub NAMESPACE=jhub helm upgrade --install $RELEASE jupyterhub/jupyterhub --namespace $NAMESPACE --version=0.8.2 --values config.yaml Helm现在应该部署所需的组件。这将需要一些时间,但是最终你应该能够通过之前设置的主机名访问UI。你也可以通过转到Rancher UI中的“工作负载“选项卡来检查状态。当我们尝试在浏览器中设置的主机名时,它将显示以下登录界面: 主机名登录界面 在撰写本文时,有一个issue是Kubernetes 1.16中的更改导致Jyupiter Hub的代码在尝试与Kuberentes API交互时中断。如果要立即修复,我们可以运行以下patch命令: kubectl patch deploy -n $NAMESPACE hub --type json --patch '[{"op": "replace", "path": "/spec/template/spec/containers/0/command", "value": ["bash", "-c", "\nmkdir -p ~/hotfix\ncp -r /usr/local/lib/python3.6/dist-packages/kubespawner ~/hotfix\nls -R ~/hotfix\npatch ~/hotfix/kubespawner/spawner.py << EOT\n72c72\n< key=lambda x: x.last_timestamp,\n---\n> key=lambda x: x.last_timestamp and x.last_timestamp.timestamp() or 0.,\nEOT\n\nPYTHONPATH=$HOME/hotfix jupyterhub --config /srv/jupyterhub_config.py --upgrade-db\n"]}]' 你现在已经在Rancher上部署了可以正常工作的JupyterHub环境。默认情况下,JupyterHub使用PAM身份验证。因此,可以使用系统上的任何有效Linux用户登录。登录后,我们应该能够创建新的notebook: Jupyter登录界面 创建新的notebook 另外,你可以查看其他你可能想配置的身份验证选项。例如,你可以使用Github身份验证来允许用户登录并且创建基于他们Github ID的notebook。你选择好一个身份验证的工具之后,需要按照说明更新我们之前创建的config.yml文件,然后重新运行helm upgrade命令。 总 结 在本文中,我们展示了如何使用Rancher安装JupyterHub来为数据科学和机器学习开发创建可扩展的工作区。如果你想要安装功能齐全的JupyterHub安装,你可能还需要考虑其他因素。本文只是向你展示了如何快速搭建一个基础功能的JupyterHub,希望能帮助你快速开启AI旅程!

优秀的个人博客,低调大师

3 种发布策略,解决 K8s 中快速交付应用的难题

作者 | 郝树伟(流生)阿里云高级研发工程师 前言 软件技术更新换代很快,但我们追求的目标是一直不变的,那就是在安全稳定的前提下,增加应用的部署频率,缩短产品功能的迭代周期,这样的好处就是企业可以在更短的时间内获得产品的价值、更快地获得客户反馈和响应客户需求,从而进一步提升产品的竞争力;除此之外,企业还可以释放更多的资源投入到创新业务的研发上,创造更多的价值,这是一个良性循环的过程。 应用产品的快速迭代诚然能给我们带来各种各样的好处,但挑战也与其并存。更高频率的应用发布,意味着线上业务有不可预期故障的风险更大,除了产品上线之前在预发测试环境中充分测试验证迭代功能之外,制定最合适的应用发布策略就是另外一个非常重要的话题,因为它可以最大限度的降低业务故障的风险以及带来的损失。 云原生应用交付的关键点 我们说频繁地进行产品迭代意味着更大的故障风险,传统应用如此,云原生应用更是如此。因为云原生应用通常都是基于云的分布式部署模式,且每个应用可能是由多个功能组件互相调用来一起提供完整的服务的,每个组件都有自己独立的迭代流程和计划。在这种情况下,功能组件越多,意味着出错的概率越大。那么如何在应用交付层面对上述这些痛点做出改进,我们总结出以下几个云原生应用交付的关键点。 如何充分利用云原生架构基础设施的优势。这个优势我们可以简单总结为两点:弹性和高可用; 如何具有跨平台移植和交付的能力。基础设施底层的计算、存储、网络资源有很大的差异化,在以前,基础架构的不同是由上层应用决定的,而云原生应用的交付需要具有跨平台移植和交付的能力; 如何实现应用运维自治化。自治化不等于自动化,自动化是指触发一个流程,流程结束后能自动达到想要的一个预期结果,而自治化是指应用再高可用的运行态时,如果其中某个功能组件的某个副本出现故障,应用能自动移除故障副本并补充新的应用副本; 如何让应用变得更具有可预测性。应用的交付终态,在我们编写应用编排模板的时候就是可预测到的,如果应用的交付变得更有可预测性,那么风险也会最大程度地降低; 如何提高应用更快的平均恢复时间。如果应用有超出了应用自治的能力范畴之外的故障发生需要人工介入,那更快的平均恢复时间就意味着更低的业务损失。 Kubernetes 是一个可移植的,可扩展的开源平台,用于管理容器化的工作负载和服务,可促进声明式配置和自动化。它自身的平台能力已经满足了我们前面提到的大部分需求。Kubernetes 使用容器技术部署应用,这样的好处包括但不限于: 应用程序创建和部署更敏捷 可移植性 环境一致性 松耦合和分布式 资源隔离 高效率和高密度的资源利用 Kubernetes 还提供了应用管理、调度、监控和运维的强大能力: 服务发现和负载均衡能力 应用的自动部署和回滚能力 应用的自治修复能力 存储编排能力 密钥和配置管理能力 但 Kubernetes 它也有很多功能是不提供但允许扩展的部分,比如日志采集、监控报警等能力。下面这张图就是阿里云容器服务是在支持标准 Kubernetes 的基础上,对与用户息息相关的能力做了增强和提升后的架构大图,包括提供最大的弹性化与低廉成本的全球化接入能力,强大的安全架构支撑能力,深度整合阿里云基础资源服务的能力,并经过 双11 验证和沉淀了海量用户经验,同时支持专有、托管、无服务化、边缘和神龙裸金属等多种产品形态,我们今天后面的所有演示就是在此平台上做的。 应用交付的边界 在 Kubernetes 中应用交付的边界是什么? 从简单处入手,我们可以认为应用的交付就是它的网络服务模式,服务的的后端资源以及业务数据的持久化存储,这些资源被分别抽象成 service、deployment/pod,volume 资源等。 以一个 wordpress 应用为例,它包括两个功能组件:前端组件处理用户请求,后端组件存储数据。前端组件包括一个 frontend service 和 3 个 pod,后端组件包括一个 backend service 和一个 pod 组件,所以这个 wordpress 应用交付的资源就是 2 个 service 和总共 4 个后端 pod。这个后端的 pod 资源我们在 Kubernetes 中通过 deployment 来统一管理,service 资源相当于一个负载均衡器,把请求路由到后端 pod 上,它涉及集群内各个组件之间调用以及外部用户访问集群内服务,所以有不同的种类划分。 根据服务暴露的方式不同,可以分为以下几种: ClusterIP 通过为 Kubernetes 的 Service 分配一个集群内部可访问的固定虚拟 IP(Cluster IP),实现集群内的访问。为最常见的方式。 apiVersion: v1 kind: Service metadata: name: wordpress spec: type: ClusterIP # 默认的service类型,服务仅暴露为集群内部可访问 ports: - port: 80 # 暴露给集群内部的服务端口 targetPort: 80 # 容器监听的服务端口 protocol: TCP selector: app: wordpress # 转发请求到有相同标签的后端pod NodePort NodePort 是把 service 的 port 映射到集群节点的一个端口上,如果你不指定这个端口,系统将选择一个随机端口。大多数时候我们应该让 Kubernetes 来选择端口,用户自己来选择可用端口代价太大。 apiVersion: v1 kind: Service metadata: name: wordpress spec: type: NodePort # NodePort service类型,服务暴露一个固定的静态端口用于集群外部访问 ports: - port: 80 # 暴露给集群内部的服务端口 targetPort: 80 # 容器监听的服务端口 protocol: TCP nodePort: 31570 # 集群外部可以通过此端口访问服务 selector: app: wordpress # 转发请求到有相同标签的后端pod NodePort 的方式虽然可以把服务暴露给集群外访问,但是也有很多缺点: 每个端口只能是一种服务 端口范围有限制,一般是 30000-32767 如果节点的 IP 地址变化了的话,你需要做一些变更操作去适配 所以在生产中一般不推荐这种方式,但如果你的应用对成本比较敏感又能容忍服务有不可用窗口期的话,是可以使用这种方式的。 LoadBalancer LoadBalancer 是服务暴露到集群外或者公网上的标准方式,但它依赖 cloud provider 提供的一个负载均衡器的能力,负载均衡器会单独分配一个 ip 地址并监听后端服务的指定端口,请求的流量会通过指定的端口转发到后端对应的服务。 apiVersion: v1 kind: Service metadata: name: wordpress spec: type: LoadBalancer # LoadBalancer service类型,一般依赖于公共云厂商供的负载均衡能力 ports: - port: 80 # 暴露给集群内部的服务端口 targetPort: 80 # 容器监听的服务端口 protocol: TCP selector: app: wordpress # 转发请求到有相同标签的后端pod Ingress ClusterIP 服务类型仅限集群内通信,NodePort可以实现暴露服务访问入口,但每个节点都会占用一个端口,会增加端口管理的复杂性,LoadBalancer 通常需要第三方云提供商支持,有一定的约束性。而 Ingress 这个服务类型跟我们前面的三种服务类型不一样,它实际上不是一种服务类型,而是类似一种集群服务入口的存在,它可以基于你配置的不同路径或者子域名把流量路由到对应的后端服务,更像是一个“智能路由”服务。 前面介绍了一些应用发布涉及到的资源类型,以及 service 资源类型的几种模式,那 service 如何找到对应的后端 pod 呢,这个就是标签的作用,我们可以把每个应用的 pod 和 service 都打上同样的标签,这个标签的机制就是我们后面要讲的几种应用发布策略的关键点了。 应用的发布策略 在 Kubernetes 集群中,除了根据业务需求选定服务暴露方式外,为了让应用在升级期间依然平稳提供服务,选择一个正确的发布策略就非常重要了。 滚动发布 第一种应用发布策略就是滚动发布,这也是比较常见的策略。它是通过逐个替换实例来逐步部署新版本的应用,直到所有实例都被替换完成为止。 如下图所示,当前我的应用提供的服务版本是 v1, 这个服务的后端有 3 个副本, 但我更新版本 v2 的时候,它是一个副本一个副本地开始替换,直到最终服务的后端全部替换成 v2 版本。 一个应用示例的编排文件如下所示: go-demo-v1.yaml apiVersion: apps/v1 kind: Deployment metadata: name: go-demo spec: replicas: 3 selector: matchLabels: app: go-demo template: metadata: labels: app: go-demo spec: containers: - name: go-demo image: registry.cn-hangzhou.aliyuncs.com/haoshuwei24/go-demo:v1 imagePullPolicy: Always ports: - containerPort: 8080 --- apiVersion: v1 kind: Service metadata: name: go-demo spec: ports: - port: 80 targetPort: 8080 name: go-demo selector: app: go-demo type: ClusterIP 部署版本 v1 $ kubectl apply -f go-demo-v1.yaml 查看 pod 运行状态 $ kubectl get po NAME READY STATUS RESTARTS AGE go-demo-78bc65c564-2rhxp 1/1 Running 0 19s go-demo-78bc65c564-574z6 1/1 Running 0 19s go-demo-78bc65c564-sgl2s 1/1 Running 0 19s 访问应用服务 $ while sleep 0.1; do curl http://172.19.15.25; done Version: v1 Version: v1 Version: v1 Version: v1 Version: v1 Version: v1 更新go-demo-v1.yaml为go-demo-v2.yaml并更新镜像 tag ... registry.cn-hangzhou.aliyuncs.com/haoshuwei24/go-demo:v2 ... 部署版本 v2 $ kubectl apply -f go-demo-v2.yaml 可以查看 pod 会被新版本 pod 逐个替换 $kubectl get po -w NAME READY STATUS RESTARTS AGE application-demo-8594ff4967-85jsg 1/1 Running 0 3m24s application-demo-8594ff4967-d4sv8 1/1 Terminating 0 3m22s application-demo-8594ff4967-w6lpz 0/1 Terminating 0 3m20s application-demo-b98d94554-4mwqd 1/1 Running 0 3s application-demo-b98d94554-ng9wx 0/1 ContainerCreating 0 1s application-demo-b98d94554-pmc5g 1/1 Running 0 4s 访问服务会发现在应用滚动升级过程中,版本 v1 和 v2 都会被访问到,这个时间的长短取决于应用的启动速度 $ while sleep 0.1; do curl http://172.19.15.25; done Version: v1 Version: v2 Version: v1 Version: v1 Version: v2 Version: v1 Version: v1 Version: v2 滚动发布优点就是它比较简单,而且不会占用太多的计算资源。缺点是: 版本在实例之间缓慢替换 这个滚动发布可能需要一定时间 无法控制流量 从应用在集群中的终态上来说,集群中要么只有版本 1 的应用后端,要么只有版本 2 的后端;如果版本 2 有缺陷,那么线上服务应用到的就是整体用户, 虽然我们有机制可以快速回滚,但涉及到整体用户使用故障的代价还是太大。 蓝绿发布 第二种就是蓝绿发布,蓝/绿发布是应用版本 1 与版本 2 的后端 pod 都部署在环境中,通过控制流量切换来决定发布哪个版本。与滚动发布相比,蓝绿发布策略下的应用终态,是可以同时存在版本 1 和版本 2 两种 pod 的,我们可以通过 service 流量的切换来决定当前服务使用哪个版本的后端。 一个应用示例的编排文件如下所示。 go-demo-v1.yaml apiVersion: apps/v1 kind: Deployment metadata: name: go-demo-v1 spec: replicas: 4 selector: matchLabels: app: go-demo version: v1 template: metadata: labels: app: go-demo version: v1 spec: containers: - name: go-demo image: registry.cn-hangzhou.aliyuncs.com/haoshuwei24/go-demo:v1 imagePullPolicy: Always ports: - containerPort: 8080 go-demo-v2.yaml apiVersion: apps/v1 kind: Deployment metadata: name: go-demo-v2 spec: replicas: 4 selector: matchLabels: app: go-demo version: v2 template: metadata: labels: app: go-demo version: v2 spec: containers: - name: go-demo image: registry.cn-hangzhou.aliyuncs.com/haoshuwei24/go-demo:v2 imagePullPolicy: Always ports: - containerPort: 8080 service.yaml apiVersion: v1 kind: Service metadata: name: go-demo spec: ports: - port: 80 targetPort: 8080 name: go-demo selector: app: go-demo version: v1 type: ClusterIP 部署以上 3 个资源 $ kubectl apply -f go-demo-v1.yaml -f go-demo-v2.yaml -f service.yaml 访问服务可以看到目前只访问到版本 1 的服务 $ while sleep 0.1; do curl http://172.19.8.137; done Version: v1 Version: v1 Version: v1 Version: v1 Version: v1 修改service.yaml的 spec.selector 下 version=v2 apiVersion: v1 kind: Service metadata: name: go-demo spec: ports: - port: 80 targetPort: 8080 name: go-demo selector: app: go-demo version: v2 type: ClusterIP 重新部署 $ kubectl apply -f service.yaml 重新访问服务可以看到很快切换到了版本 2 上 $ [root@iZbp13u3z7d2tqx0cs6ovqZ blue-green]# while sleep 0.1; do curl http://172.19.8.137; done Version: v2 Version: v2 Version: v2 我们刚才说到滚动升级有一个过程需要时间,即使回滚,它也需要一定的时间才能回滚完毕,在新版本应用有缺陷的情况下,蓝绿发布的策略可以快速在 v1 和 v2 两个版本之前切流量,所以这个切换流量的时间跟滚动升级相比就缩短了很多了,但蓝绿发布的缺点跟滚动发布相同的就是这个缺陷会影响到整体用户,服务要么百分百切换到版本 2 上,要么百分百切换到版本 1 上,这是个非 0 即 100 的操作,即使蓝绿发布策略可以大大缩短故障恢复时间,但在某些场景下也是不可接受的。 而且集群环境中同时存在两个版本的 pod 副本,资源占用的话相比滚动发布是 2 倍的。 金丝雀发布(灰度发布) 第三种要介绍的发布策略是金丝雀发布,金丝雀部署是应用版本 1 和版本 2 同时部署在环境中,并且用户请求有可能会路由到版本 1 的后端,也可能会路由到版本 2 的后端,从而达到让一部分新用户访问到版本 2 的应用。 这种发布策略下,我们可以通过调整流量百分比来逐步控制应用向新的版本切换,它与蓝绿部署相比,不仅继承了蓝绿部署的优点,而且占用资源优于蓝绿部署所需要的 2 倍资源,在新版本有缺陷的情况下只影响少部分用户,把损失降到最低。 对于灰度发布的概念来说,有人认为它跟金丝雀发布讲的是一个东西,有人认为它们不同。它跟金丝雀发布的过程是相同的,但目的有所不同: 金丝雀发布更倾向于能快速获取用户的一些反馈,比如我可能不确定我的这个新版本功能的用户体验是否能被大众很好的接受,我期望能得到线上用户的一些及时反馈,在产品侧做功能体验调整之后再迭代 v3 版本; 而灰度发布则是我的产品功能已经设计并开发的很完善了,现在就是要逐步替换线上的旧版本,但是要控制发布可能带来的风险,所以要灰度发布。 示例应用 1 如下, 这个示例中我们通过 pod 的数量来控制流量比例。 go-demo-v1.yaml 设定副本数为 9 apiVersion: apps/v1 kind: Deployment metadata: name: go-demo-v1 spec: replicas: 9 selector: matchLabels: app: go-demo version: v1 template: metadata: labels: app: go-demo version: v1 spec: containers: - name: go-demo image: registry.cn-hangzhou.aliyuncs.com/haoshuwei24/go-demo:v1 imagePullPolicy: Always ports: - containerPort: 8080 go-demo-v2.yaml 设定副本数为 1 apiVersion: apps/v1 kind: Deployment metadata: name: go-demo-v2 spec: replicas: 1 selector: matchLabels: app: go-demo version: v2 template: metadata: labels: app: go-demo version: v2 spec: containers: - name: go-demo image: registry.cn-hangzhou.aliyuncs.com/haoshuwei24/go-demo:v2 imagePullPolicy: Always ports: - containerPort: 8080 service.yaml apiVersion: v1 kind: Service metadata: name: go-demo spec: ports: - port: 80 targetPort: 8080 name: go-demo selector: app: go-demo type: ClusterIP 部署以上 3 个资源 $ kubectl apply -f go-demo-v1.yaml -f go-demo-v2.yaml -f service.yaml 访问服务可以看到基本上是 10% 的流量切换到版本 2 上 $ while sleep 0.1; do curl http://172.19.8.248; done Version: v1 Version: v2 Version: v1 Version: v1 Version: v1 Version: v1 Version: v1 Version: v1 Version: v1 Version: v1 Version: v1 另外我们可以使用 nginx ingress controller 来控制流量切换,这个方式要更精准。 go-demo-v1.yaml apiVersion: apps/v1 kind: Deployment metadata: name: go-demo-v1 spec: replicas: 3 selector: matchLabels: app: go-demo version: v1 template: metadata: labels: app: go-demo version: v1 spec: containers: - name: go-demo image: registry.cn-hangzhou.aliyuncs.com/haoshuwei24/go-demo:v1 imagePullPolicy: Always ports: - containerPort: 8080 go-demo-v2.yaml apiVersion: apps/v1 kind: Deployment metadata: name: go-demo-v2 spec: replicas: 1 selector: matchLabels: app: go-demo version: v2 template: metadata: labels: app: go-demo version: v2 spec: containers: - name: go-demo image: registry.cn-hangzhou.aliyuncs.com/haoshuwei24/go-demo:v2 imagePullPolicy: Always ports: - containerPort: 8080 service-v1.yaml apiVersion: v1 kind: Service metadata: name: go-demo-v1 spec: ports: - port: 80 targetPort: 8080 name: go-demo selector: app: go-demo version: v1 type: ClusterIP service-v2.yaml apiVersion: v1 kind: Service metadata: name: go-demo-v2 spec: ports: - port: 80 targetPort: 8080 name: go-demo selector: app: go-demo version: v2 type: ClusterIP ingress.yaml, 设置nginx.ingress.kubernetes.io/service-weight: | go-demo-v1: 100, go-demo-v2: 0, 版本1 - 100% 流量, 版本2 - 0% 流量 apiVersion: extensions/v1beta1 kind: Ingress metadata: annotations: nginx.ingress.kubernetes.io/service-weight: | go-demo-v1: 100, go-demo-v2: 0 name: go-demo labels: app: go-demo spec: rules: - host: go-demo.example.com http: paths: - path: / backend: serviceName: go-demo-v1 servicePort: 80 - path: / backend: serviceName: go-demo-v2 servicePort: 80 部署以上 4 个资源 $ kubectl apply -f go-demo-v1.yaml -f go-demo-v2.yaml -f service-v1.yaml -f service-v2.yaml -f nginx.yaml 访问服务可以看到流量 100% 到版本 1 上 $ while sleep 0.1; do curl http://go-demo.example.com; done Version: v1 Version: v1 Version: v1 Version: v1 Version: v1 Version: v1 更新ingress.yaml, 设置流量比为 50:50 apiVersion: extensions/v1beta1 kind: Ingress metadata: annotations: nginx.ingress.kubernetes.io/service-weight: | go-demo-v1: 50, go-demo-v2: 50 name: go-demo labels: app: go-demo spec: rules: - host: go-demo.example.com http: paths: - path: / backend: serviceName: go-demo-v1 servicePort: 80 - path: / backend: serviceName: go-demo-v2 servicePort: 80 访问服务可以看到流量 50% 到版本 1 上, 50% 到版本 2 上 $ while sleep 0.1; do curl http://go-demo.example.com; done Version: v2 Version: v1 Version: v1 Version: v1 Version: v2 Version: v2 Version: v1 Version: v1 Version: v2 Version: v2 更新ingress.yaml, 设置流量比为 0:100 apiVersion: extensions/v1beta1 kind: Ingress metadata: annotations: nginx.ingress.kubernetes.io/service-weight: | go-demo-v1: 0, go-demo-v2: 100 name: go-demo labels: app: go-demo spec: rules: - host: go-demo.example.com http: paths: - path: / backend: serviceName: go-demo-v1 servicePort: 80 - path: / backend: serviceName: go-demo-v2 servicePort: 80 访问服务可以看到流量 100% 到版本 2 上 $ while sleep 0.1; do curl http://go-demo.example.com; done Version: v2 Version: v2 Version: v2 Version: v2 Version: v2 Version: v2 Version: v2 Version: v2 Version: v2 Version: v2 不管是金丝雀发布还是灰度发布,缺点就是发布周期相对来说要慢很多。 在这些发布策略当中, 当你在开发测试环境中对应用做更新发布的话,用滚动发布; 在生产环境,滚动更新或者蓝绿发布在新版本已经提前测试充分的情况下可以用; 如果对新版本的应用的更新需要最大限度地控制风险,降低故障对用户的影响的话,那就使用金丝雀发布或灰度发布。 以上就是我们在 Kubernetes 当中常用的几种发布策略的介绍。 “阿里巴巴云原生关注微服务、Serverless、容器、Service Mesh 等技术领域、聚焦云原生流行技术趋势、云原生大规模的落地实践,做最懂云原生开发者的技术圈。”

优秀的个人博客,低调大师

实操教程丨如何在K8S集群中部署Traefik Ingress Controller

注:本文使用的Traefik为1.x的版本 在生产环境中,我们常常需要控制来自互联网的外部进入集群中,而这恰巧是Ingress的职责。 Ingress的主要目的是将HTTP和HTTPS从集群外部暴露给该集群中运行的服务。这与Ingress控制如何将外部流量路由到集群有异曲同工之妙。接下来,我们举一个实际的例子来更清楚的说明Ingress的概念。 首先,想象一下在你的Kubernetes集群中有若干个微服务(小型应用程序之间彼此通信)。这些服务能够在集群内部被访问,但我们想让我们的用户从集群外部也能够访问它们。因此,我们需要做的是使用反向代理将每个HTTP(S)(例如,service.yourdomain.com)路由与相应的后端关联,并在该服务的不同实例之间(如,pod)进行负载均衡。与此同时,由于Kubernetes的性质会不断发生变化,因此我们希望跟踪服务后端的更改,以便能够在添加或删除新Pod时将这些HTTP路由重新关联到新Pod实例。 使用Ingress资源和关联的Ingress Controller,你可以实现以下目标: 将你的域app.domain.com指向你的私有网络中的微服务应用程序 将路径domain.com/web指向你的私有网络中的微服务web 将你的域backend.domain.com指向你的私有网络中的微服务后端,并在该微服务的多个实例之间(Pod)进行负载均衡 现在,你理解了Ingress的重要性。它能够帮助将HTTP路由指向在Kubernetes集群中特定的微服务。 但是,流量路由并不是Ingress在Kubernetes中的唯一功能。例如,还可以将Ingress配置为负载均衡流量到你的应用程序、终止SSL、执行基于名称的虚拟主机、在不同服务之间分配流量、设置服务访问规则等。 Kubernetes有一个特别的Ingress API资源,它能够支持上述所有功能。但是,简单地创建一个Ingress API资源是没有作用的。你还需要一个Ingress Controller。目前,Kubernetes支持许多Ingress controller,如Contour、HAProxy、NGINX以及Traefik。 在本文中,我将使用Traefik Ingress Controller创建Ingress。它能够实现现代HTTP反向代理和负载均衡器的功能,从而简化了微服务的部署。此外,Traefik对Docker、Marathon、Consul、Kubernetes、Amazon ECS等系统和环境都提供了强大的支持。 Traefik对于诸如Kubernetes之类的灵活性较强的系统十分有用。在Kubernetes中,每天需要多次添加、删除或升级服务,而Traefik可以监听服务镜像仓库/编排器 API并立即生成或更新路由,因此你的微服务无需手动配置即可与外界连接。 除此之外,Traefik支持多个负载均衡算法、Let’s Encrypt的HTTPS(支持通配证书)、断路器、WebSoket、GRPC和多个监控程序(Rest、Prometheus、Statsd、Datadog、InfluxDB等)。有关Traefik中可用功能的更多信息,请参考其官方文档: https://docs.traefik.cn/ Ingress 资源 在教程开始之前,我们先来简单地讨论一下Ingress资源是如何工作的。以下是隐式使用Nginx Ingress Controller的Ingress示例。 apiVersion: extensions/v1beta1 kind: Ingress metadata: name: ingress-example annotations: nginx.ingress.kubernetes.io/rewrite-target: / spec: rules: - http: paths: - path: /microservice1 backend: serviceName: test servicePort: 80 以上Ingress manifest 包含了一系列HTTP规则,它们用于规定controller如何路由流量。 可选主机。如果未指定主机(如上所示),则该规则适用于通过指定IP地址的所有入站HTTP流量。如果提供了主机(如yourhost.com),则该规则仅适用于该主机。 一个路径列表(如,/microservice1),它指向由serviceName和servicePort定义的关联后端。 一个后端。向Ingress发出的HTTP(和HTTPS)请求将与给定规则的主机和路径匹配,然后将其路由到该规则中指定的后端服务。 在以上例子中,我们配置了一个名为”test“的后端,它将接收所有来自/microservice路径的流量。然而,我们也可以配置一个默认后端,它将将为任何不符合规范中路径的用户请求提供服务。同时,如果不定义任何规则,Ingress将路由所有流量到默认后端。例如: apiVersion: extensions/v1beta1 kind: Ingress metadata: name: test-ingress spec: backend: serviceName: defaultbackend servicePort: 80 在本例中,所有流量都被转发到默认后端中defaultbackend。现在,我们理解了Ingress 资源的基本概念,接下来我们来看看一些具体的例子。 Step 0:前期准备 如上文我们所说的,定义一个Ingress资源没有任何作用,除非你使用了Ingress Controller。在本教程中,我们在Kubernetes集群中将Traefik设置为Ingress Controller。 要完成教程,你需要进行以下准备: 一个正在运行的Kubernetes集群。 一个安装好的命令行工具,kubectl。并配置为与集群通信。 请注意:以下示例均假设你在本地计算上使用Minikube运行Kubernetes集群。 Step 1:启用RBAC 首先,我们需要向Traefik授予一些权限,以访问集群中运行的Pod、endpoint和服务。为此,我们将使用ClusterRole和ClusterRoleBinding资源。但是,你也可以对命名空间范围内的RoleBindings使用最小特权方法。通常,如果集群的命名空间不会动态更改,并且Traefik无法监视所有集群的命名空间,那么这是首选的方法。 让我们创建一个新的ServiceAccount,为Traefik提供集群中的身份。 apiVersion: v1 kind: ServiceAccount metadata: name: traefik-ingress namespace: kube-system 要创建一个ServiceAccount,需要在traefik-service-acc.yaml中保存以上manifest并运行: kubectl create -f traefik-service-acc.yaml serviceaccount "traefik-ingress" created 接下来,让我们创建一个具有一组权限的ClusterRole,该权限将应用于Traefik ServiceAccount。通过ClusterRole,Traefik可以管理和监视集群中所有命名空间中的资源,例如服务、endpoint、secret以及Ingress。 kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1beta1 metadata: name: traefik-ingress rules: - apiGroups: - "" resources: - services - endpoints - secrets verbs: - get - list - watch - apiGroups: - extensions resources: - ingresses verbs: - get - list - watch 将这一规范保存到文件traefik-cr.yaml中,并运行: kubectl create -f traefik-cr.yaml clusterrole.rbac.authorization.k8s.io “traefik-ingress” created 最后,启用这些权限,我们应该将ClusterRole绑定到Traefik ServiceAccount中。使用ClusterRoleBinding manifest可以完成这一操作: kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1beta1 metadata: name: traefik-ingress roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: traefik-ingress subjects: - kind: ServiceAccount name: traefik-ingress namespace: kube-system 保存这一规范到traefik-crb.yaml中,并运行以下命令: kubectl create -f traefik-crb.yaml clusterrolebinding.rbac.authorization.k8s.io “traefik-ingress” created Step 2:部署Traefik到集群 接下来,我们将部署Traefik到Kubernetes集群。官方Traefik文档支持三种类型的部署:使用Deployment对象、使用DaemonSet对象或使用Helm Chart。 在本教程中,我们将使用Deployment manifest。相比其他选项,Deployment有诸多优势。例如,它们能确保更好的可伸缩性,并为滚动更新提供良好支持。 让我们看一下 Deployment manifest: kind: Deployment apiVersion: extensions/v1beta1 metadata: name: traefik-ingress namespace: kube-system labels: k8s-app: traefik-ingress-lb spec: replicas: 1 selector: matchLabels: k8s-app: traefik-ingress-lb template: metadata: labels: k8s-app: traefik-ingress-lb name: traefik-ingress-lb spec: serviceAccountName: traefik-ingress terminationGracePeriodSeconds: 60 containers: - image: traefik name: traefik-ingress-lb ports: - name: http containerPort: 80 - name: admin containerPort: 8080 args: - --api - --kubernetes - --logLevel=INFO 这个Deployment将在kube-system 命名空间中创建一个Traefik副本。Traefik容器将使用此manifest中指定的端口80和8080。 将这个manifest保存到traefik-deployment.yaml文件中,并运行以下命令创建Deployment: kubectl create -f traefik-deployment.yaml deployment.extensions “traefik-ingress” created 现在,让我们检查一下Traefik Pod是否都成功创建了: kubectl --namespace=kube-system get pods NAME READY STATUS RESTARTS AGE .... storage-provisioner 1/1 Running 3 23d traefik-ingress-54d6d8d9cc-ls6cs 1/1 Running 0 1m 如你所见,Deployment Controller启动了一个Traefik副本,并在正在运行,敲棒的! Step 3:为外部访问创建NodePorts 让我们创建一个服务来从集群外部访问Traefik。为此,我们需要一个暴露两个NodePorts的服务。 kind: Service apiVersion: v1 metadata: name: traefik-ingress-service namespace: kube-system spec: selector: k8s-app: traefik-ingress-lb ports: - protocol: TCP port: 80 name: web - protocol: TCP port: 8080 name: admin type: NodePort 将这个manifest保存到traefik-svc.yaml,并创建服务: kubectl create -f traefik-svc.yaml service “traefik-ingress-service” created 现在,让我们验证该服务是否创建: kubectl describe svc traefik-ingress-service --namespace=kube-system Name: traefik-ingress-service Namespace: kube-system Labels: <none> Annotations: <none> Selector: k8s-app=traefik-ingress-lb Type: NodePort IP: 10.102.215.64 Port: web 80/TCP TargetPort: 80/TCP NodePort: web 30565/TCP Endpoints: 172.17.0.6:80 Port: admin 8080/TCP TargetPort: 8080/TCP NodePort: admin 30729/TCP Endpoints: 172.17.0.6:8080 Session Affinity: None External Traffic Policy: Cluster Events: <none> 如你所见,我们现在有两个NodePorts(web和admin),它们分别路由到Traefik Ingress Controller的80和8080容器端口。“admin” NodePort将用于访问Traefik Web UI,“web” NodePort将用于访问通过Ingress暴露的服务。 Step 4:访问Traefik 为了能在浏览器中访问Traefik Web UI,你可以使用“admin”NodePort 30729(请注意,你的NodePort值可能会有所不同)。因为我们还没有添加任何前端,所以UI此时应该是空的。 由于我们尚未给Traefik进行任何配置,因此我们会收到404的响应。 curl $(minikube ip):30565 404 page not found Step 5 :添加Ingress 到集群 现在我们在Kubernetes集群中已经将Traefik作为Ingress Controller了。然而,我们依旧需要定义Ingress资源和暴露Traefik Web UI的服务。 首先,我们创建一个服务: apiVersion: v1 kind: Service metadata: name: traefik-web-ui namespace: kube-system spec: selector: k8s-app: traefik-ingress-lb ports: - name: web port: 80 targetPort: 8080 保存manifest到traefik-webui-svc.yaml中,并运行: kubectl create -f traefik-webui-svc.yaml service “traefik-web-ui” created 让我们验证服务是否已经创建: kubectl describe svc traefik-web-ui --namespace=kube-system Name: traefik-web-ui Namespace: kube-system Labels: <none> Annotations: <none> Selector: k8s-app=traefik-ingress-lb Type: ClusterIP IP: 10.98.230.58 Port: web 80/TCP TargetPort: 8080/TCP Endpoints: 172.17.0.6:8080 Session Affinity: None Events: <none> 如你所见,服务的ClusterIP是10.98.230.58,并在manifest中分配指定端口。 接下来,我们需要创建一个Ingress资源,指向Traefik Web UI后端: apiVersion: extensions/v1beta1 kind: Ingress metadata: name: traefik-web-ui namespace: kube-system spec: rules: - host: traefik-ui.minikube http: paths: - path: / backend: serviceName: traefik-web-ui servicePort: web 本质上,Ingress将所有请求路由到traefik-ui.minikube,在上述步骤中创建的服务暴露Traefik Web UI。 将规范保存到traefik-ingress.yaml,并运行: kubectl create -f traefik-ingress.yaml ingress.extensions “traefik-web-ui” created 为了能够通过traefik-ui.minikube在浏览器中可以访问Traefik Web UI,我们需要添加新的条目到我们/etc/hosts文件中。该条目将包含Minikube IP和主机名。你可以通过运行minikube ip来获取minkube实例的IP地址,然后将新主机的名称保存到/etc/hosts文件中,如下所示: echo "$(minikube ip) traefik-ui.minikube" | sudo tee -a /etc/hosts 192.168.99.100 traefik-ui.minikube 现在,你应该能够在浏览器中访问http://traefik-ui.minikube:<AdminNodePort>并查看Traefik Web UI。别忘了附加”admin”NodePort到主机地址。 在dashboard中,你可以点击Health 链接来查看应用程序的健康状况: Step 6:实现基于名称的路由 现在,我们来演示如何使用Traefik Ingress Controller为前端列表设置基于名称的路由。我们将使用简单的单页网站创建3个Deployment,并显示动物图像:熊、野兔和驼鹿。 --- kind: Deployment apiVersion: extensions/v1beta1 metadata: name: bear labels: app: animals animal: bear spec: replicas: 2 selector: matchLabels: app: animals task: bear template: metadata: labels: app: animals task: bear version: v0.0.1 spec: containers: - name: bear image: supergiantkir/animals:bear ports: - containerPort: 80 --- kind: Deployment apiVersion: extensions/v1beta1 metadata: name: moose labels: app: animals animal: moose spec: replicas: 2 selector: matchLabels: app: animals task: moose template: metadata: labels: app: animals task: moose version: v0.0.1 spec: containers: - name: moose image: supergiantkir/animals:moose ports: - containerPort: 80 --- kind: Deployment apiVersion: extensions/v1beta1 metadata: name: hare labels: app: animals animal: hare spec: replicas: 2 selector: matchLabels: app: animals task: hare template: metadata: labels: app: animals task: hare version: v0.0.1 spec: containers: - name: hare image: supergiantkir/animals:hare ports: - containerPort: 80 每个Deployment都将有两个Pod副本,而每个Pod将在containerPort 80上服务“动物“网站。 让我们保存这些Deployment manifest到animals-deployment.yaml中,并运行: kubectl create -f animals-deployment.yaml deployment.extensions “bear” created deployment.extensions “moose” created deployment.extensions “hare” created 现在,让我们为每个Deployment创建一个服务,使得Pod可以访问: --- apiVersion: v1 kind: Service metadata: name: bear spec: ports: - name: http targetPort: 80 port: 80 selector: app: animals task: bear --- apiVersion: v1 kind: Service metadata: name: moose spec: ports: - name: http targetPort: 80 port: 80 selector: app: animals task: moose --- apiVersion: v1 kind: Service metadata: name: hare annotations: traefik.backend.circuitbreaker: "NetworkErrorRatio() > 0.5" spec: ports: - name: http targetPort: 80 port: 80 selector: app: animals task: hare 请注意:第三项服务使用断路器annotation。断路器是Traefik的一项功能,可防止发生故障的服务器承受高负载。在本例中,我们防止服务器上的高负载超过50%。当此条件匹配时,CB进入“跳闸“状态,在该状态中它会使用预定义的HTTP状态代码进行响应或重定向到另一个前端。 保存这些服务manifest到animals-svc.yaml并运行: kubectl create -f animals-svc.yaml service “bear” created service “moose” created service “hare” created 最后,为每个Deployment创建一个有3个前后端对的Ingress。bear.minikube、moose.minikube和hare.minikube将是我们指向相应后端服务的前端。 Ingress manifest如下所示: apiVersion: extensions/v1beta1 kind: Ingress metadata: name: animals annotations: kubernetes.io/ingress.class: traefik spec: rules: - host: hare.minikube http: paths: - path: / backend: serviceName: hare servicePort: http - host: bear.minikube http: paths: - path: / backend: serviceName: bear servicePort: http - host: moose.minikube http: paths: - path: / backend: serviceName: moose servicePort: http 保存规范到animals-ingress.yaml并运行: kubectl create -f animals-ingress.yaml ingress.extensions “animals” created 现在,在Traefik dashboard内,你可以看到每个主机的前端以及相应的后端列表: 如果你再次编辑etc/hosts,你应该能够在你的浏览器中访问动物网页: echo “$(minikube ip) bear.minikube hare.minikube moose.minikube” | sudo tee -a /etc/hosts 你应该使用“web“NodePort来访问特定网页。例如,http://bear.minikube:<WebNodePort> 我们也可以将三个前端重新配置为在一个域下提供服务,如下所示: apiVersion: extensions/v1beta1 kind: Ingress metadata: name: all-animals annotations: kubernetes.io/ingress.class: traefik traefik.frontend.rule.type: PathPrefixStrip spec: rules: - host: animals.minikube http: paths: - path: /bear backend: serviceName: bear servicePort: http - path: /moose backend: serviceName: moose servicePort: http - path: /hare backend: serviceName: hare servicePort: http 如果你激活这个Ingress,使用相应的路径,三个动物在一个域下都能够访问——animals.minikube。别忘了将这个域添加到/etc/hosts。 echo “$(minikube ip) animals.minikube” | sudo tee -a /etc/hosts 请注意:我们正在配置Traefik,以使用traefik.frontend.rule.type注释,从URL路径中删除前缀。这样我们可以直接使用上一个示例中的容器。由于traefik.frontend.rule.type: PathPrefixStrip规则,你必须使用http://animals.minikube:32484/moose/ 而不是http://animals.minikube:32484/moose Step 7:实现流量分配 借助Traefik,用户可以使用服务权重以受控方式在多个deployment之间分配Ingress流量。这一功能可用于金丝雀发布,它最初应该获得少量但持续增长的流量。 让我们使用以下manifest在两个微服务之间分配Traefik: apiVersion: extensions/v1beta1 kind: Ingress metadata: annotations: traefik.ingress.kubernetes.io/service-weights: | animals-app: 99% animals-app-canary: 1% name: animals-app spec: rules: - http: paths: - backend: serviceName: animals-app servicePort: 80 path: / - backend: serviceName: animals-app-canary servicePort: 80 path: / 请注意traefik.ingress.kubernetes.io/service-weights的注释。它指定了流量如何在指定后端服务(animals-app和animals-app-canary)之间分配。Traefik将把99%的用户请求路由到animals-app deployment支持的Pod,并将1%的用户请求路由到animals-app-canary deployment支持的Pod。 要使此设置正常工作,需要满足一些条件: 所有服务后端必须共享相同的路径和主机。 跨服务后端共享的请求总数应总计为100%。 百分比值应该在支持的精度范围内,目前Traefik支持3个小数位的权重。 总结 如你所见,Ingress是将外部流量路由到Kubernetes集群中相应后端服务的强大工具。用户可以使用Kubernetes支持的许多Ingress controller来实现Ingress。在本教程中,我们重点介绍了Traefik Ingress controller,该控制器支持基于名称的路由,负载均衡以及Ingress controller的其他常见任务。

优秀的个人博客,低调大师

K8S避坑指南 - Deployment更新POD内容器无法收到SIGTERM信号

简述 容器化后,在应用发布时,某个服务重启,导致该服务调用方大量报错,直到服务重启完成。报错的内容是RPC调用失败,我们的RPC这块是有优雅关闭的,也就是说,在进程收到SIGTERM信号后,我们通过JVM的ShutdownHook机制,注册了RPC服务的反注册钩子,在进程收到SIGTERM时应用会主动从注册中心摘除自身防止调用方大量报错。但是为什么容器化后会导致这个问题呢? 问题排查 应用正常启动查看容器内进程 # yum install psmisc # pstree -p bash(1)───java(22)─┬─{java}(23) ├─{java}(24) ├─{java}(25) ├─{java}(26) ├─{java}(27) ├─{java}(28) ├─{java}(29) ├─{java}(30) ... # ps -ef UID PID PPID C STIME TTY TIME CMD root 1 0 0 09:50 ? 00:00:00 /bin/bash run.sh start root 22 1 15 09:50 ? 00:01:20 /app/3rd/jdk/default/bin/java -Xmx512m -Xms512m ... root 49 0 0 09:51 pts/0 00:00:00 bash root 263 49 0 09:59 pts/0 00:00:00 ps -ef 在容器内正常kill 22子进程,可见我们应用的shutdown钩子可以正确处理善后工作但是,在实际生产中,我们的deploy滚动更新时,通过查看被删除pod的日志,发现pod被terminate的时候,应用进程并未正确处理SIGTERM信号,问题产生。 问题分析 根据对Kubernetes机制的调研,如图:https://kubernetes.io/docs/concepts/workloads/pods/pod/#termination-of-pods因为我们的容器是通过run.sh脚本启动,这个在前面截图可以看到,java进程是1号run.sh进程的子进程,对应Kubernetes原理,可知22号java进程在POD删除时不一定会收到SIGTERM,所以导致了我们的shutdown hook不生效。 问题解决 既然已经定位问题,那么解决问题的方法就有了思路,run.sh执行java进程后,将进程上下文让给java进程,java进程接管,java进程变为容器内的1号进程。我们参考了这篇文章受到启发https://yeasy.gitbooks.io/docker_practice/content/image/dockerfile/entrypoint.html在run.sh执行java前面增加exec命令即可然后,重新build镜像,发布,查看进程,发现我们的java进程已经是1号进程然后重启,再查看重启前POD留下的日志问题解决!

优秀的个人博客,低调大师

基于阿里云K8S服务快速构建DevOps流水线 资料下载

本次直播分享kubernetes中devops相关的理论知识及最佳实践,涉及开源jenkins、jenkinsx、gitops、kaniko、helm、skaffold等工具或理论介绍及demo。直播视频全程链接:https://yq.aliyun.com/live/840PPT精彩内容一览:PPT下载地址:https://yq.aliyun.com/download/3308 Kubernetes社区大群欢迎你 进群方式:1.点击链接即可入群:https://dwz.cn/G2EELckH2.扫描下方二维码进群

优秀的个人博客,低调大师

云栖社区钉群系列直播精彩回顾:Java、PG、HBase和K8S

为满足开发者交流的需求,云栖社区所运营的多个钉钉大群均已突破2000人,有同学希望可以看到汇总资料,特别整理,欢迎大家分享并邀请朋友进群。 云栖社区2019年1月技术活动:PG, Java,Spark等30+场预告【持续更新】,欢迎进群。 主讲人:徐雷(点击关注专家,掌握一手干货) 阿里云大学讲师,与阿里P9叶翔主讲《阿里巴巴MongoDB高级实战课程》Java Spring Boot《阿里巴巴MongoDB认证》讲师阿里巴巴MongoDB大会讲师2017翻译《MongoDB实战》第2版吉林大学计算机学士,上海交通大学硕士 Java Spring Boot开发实战系列课程第1讲:Spring Boot 2.0 新特性和入门实战 Java Spring Boot开发实战系列课程第2讲:开发Java MVC网站并显示美女图片 Java Spring Boot开发实战系列课程第4讲:自定义查询和实战User用户注册、登录及Java面试题 Java Spring Boot开发实战系列课程第5讲:三层MVC架构实战与架构分层误区(Java面试题) Java Spring Boot开发实战系列课程第6讲:Spring Boot2.0实战MyBatis与优化(Java面试题) Java Spring Boot开发实战系列课程第7讲:Spring Boot 2.0安全机制与MVC身份验证实战 第8课:Spring Boot2.0自动化配置机制解析(Java高级面试题) Java Spring Boot开发实战系列课程第9讲:Spring Boot 2.0实战MongoDB数据库 主讲人:孤尽《阿里Java开发手册》《码出高效》作者 阿里巴巴Java开发手册》《码出高效》作者孤尽——发现代码之美 主题交流会 主讲人:德哥(点击关注专家,掌握一手干货)阿里云数据库专家,PostgreSQL中国社区校长 阿里云POLARDB-O PPAS(Oracle兼容版)培训 德哥PostgreSQL群直播第1讲:相似人群圈选 德哥PostgreSQL群直播第2讲:多维空间计算 德哥PostgreSQL群直播第3讲:PostgreSQL11新特性 德哥PostgreSQL群直播第4讲:delete_insert并发处理单一PK的业务需求背景原理与ADLOCK PostgreSQL多场景阿里云沙箱实验(第1讲):如何快速构建海量逼真测试数据 PostgreSQL多场景阿里云沙箱实验(第2讲):PG秒杀场景实践 PostgreSQL多场景阿里云沙箱实验(第3讲):PostgreSQL 实时搜索实践 PostgreSQL多场景阿里云沙箱实验(第4讲):PostgreSQL 实时多维分析 PostgreSQL多场景阿里云沙箱实验(第5讲):PostgreSQL 估值、概率计算 PostgreSQL多场景阿里云沙箱实验(第6讲):PostgreSQL 用户画像系统实践 PostgreSQL多场景阿里云沙箱实验(第7讲):PostgreSQL 并行计算 ostgreSQL多场景阿里云沙箱实验(第8讲):PostgreSQL 简单空间应用实践 主讲人:王健(canno)(点击关注专家,掌握一手干货)目前在神州飞象做pg相关的运维工作,热爱pg,正在学习pg内核的相关的代码,欢迎大家和我讨论,一起共同成长。 canno PG群直播第1讲:systemtap动态跟踪pg 王健老师patroni系列课程第1讲:安装部署 王健老师patroni系列课程第2讲:patroni原理分享 主讲人:张泽鹏(redraiment)(点击关注专家,掌握一手干货)阿里巴巴-淘宝-新制造-高级技术专家,PostgreSQL、Clojure、FreeBSD等技术爱好者 redraiment PG群直播第1讲:“with recursive”递归查询的用法 主讲人:曹龙(封神)阿里云ApsaraDB HBase技术负责人,中国HBase开源技术社区发起人之一,10多年大数据库、数据库经验参与研发维护阿里万台Hadoop及ODPS集群 HBase多模式 主讲人:玄陵(郭超)阿里云工程师,负责云hbase 备份恢复以及时序数据库相关 HBase 备份恢复 主讲人:熊嘉男(侧田)Ali-HBase数据链路模块的负责人,负责Ali-HBase集群的数据接入、数据备份、数据迁移、集群容灾 HBase高效一键迁移的设计与实践 主讲人:明惠——阿里云HBase业务架构师 HBase rowkey设计规范 主讲人:敌珐陶克路(阿里集团-阿里云智能事业群-云智能产品研发板块-计算平台事业部-EMR-高级开发工程师) 从 Spark Streaming 到 Structured Streaming 主讲人:江宇(燕回)阿里巴巴计算平台EMR技术专家 Apache Spark系列技术直播 第四讲 【 机器学习介绍与Spark MLlib实践 】 主讲人:王道远(健身) 阿里巴巴计算平台EMR技术专家 Apache Spark系列技术直播 第五讲 【 Spark RDD编程入门 】 主讲人:李潇 李潇现就职于Databricks,专注于Apache Spark的开发和建设。他是Apache Spark项目管理委员会成员。本科毕业于南京理工大学,后在佛罗里达大学(University of Florida)获计算机博士学位, 曾就职于IBM,获发明大师称号(Master Inventor),在数据处理领域发表专利十余篇。(Github: gatorsmile) Apache Spark系列技术直播 第六讲【 What's New in Apache Spark 2.4? 】 主讲人:诚历(孙大鹏)阿里巴巴计算平台事业部EMR技术专家 Apache Spark系列技术直播# 第七讲 【 大数据列式存储之 Parquet/ORC 】 主讲人:溪恒 阿里云高级开发工程师,《自己动手写Docker》作者之一。自毕业起就‘坠入’容器技术圈,沉迷已近四年,具有丰富的Linux和容器领域开发经验。目前从事阿里云容器服务网络方案的设计与实现,专注于容器技术的基础环境研究。 Topic:《Kubernetes的网络实践》Topic简介:网络是Kubernetes的一个重要基础能力,当下社区中也有很多可以选择的网络方案。本次分享主要介绍Kubernetes网络的实现方式,总结阿里云所遇到的问题和各类场景,并介绍开源Terway网络插件中如何解决的这些问题。 Kubernetes的网络实践 持续更新。欢迎分享给更多开发者。

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册