前言

容器化对现在(0202年)来说,已经不算是什么新东西了,老黄最近也在公司推动这一块的发展,有幸落地了几个项目,有.NET Core的,也有.NET Framework的。

容器化现在主流的就是docker,说到docker,51%的概率是离不开kubernetes的。

当容器数量不多的时候,可以考虑人工+半自动化的方式维护。

当容器数量多了的话,不言而喻是需要引入容器编排的利器。

这也算是一个渐进的过程吧。

下面来看看基于 Serverless Kubernetes 的简单实践(不会介绍kubernetes的相关内容哈)。

为什么选择 Serverless Kubernetes

国内云产商基本都会有提供多个版本的Kubernetes让我们自己选择,有的公司可能能力强,一套打包带走。

老黄这边选择的是 Serverless 版的,Serverless 可以说是比较火的一个概念,也可以说是真正的云原生所应该有的基本形态。

当然老黄做出这个决定还有一个更重要的原因,不用自己维护服务器,可以更加专注自身的业务,只需要交付打包好的镜像即可。

毕竟老黄公司没有运维,已经充当半个运维了,不想让自己累趴。。

相信这个是大部分中小型公司一个比较ok的选择。

准备镜像

这里会写两个简单Web Api项目用来演示,一个.NET Core的,一个.NET Framework的。

其中.NET Core会暴露给集群外部访问,.NET Framework只在集群内部访问,同时.NET Core还会调用.NET Framework的接口。

.NET Framework

代码的话就是一个默认的ValuesController。

  1. public class ValuesController : ApiController
  2. {
  3. // GET api/values
  4. public IEnumerable<string> Get()
  5. {
  6. return new string[] { "value1", "value2", "nfx in k8s" };
  7. }
  8. }

知道.NET Framework可以基于jexus跑在Linux下面的话,应该就知道要怎么打包制作镜像了。

可以直接用 beginor 做好的镜像 beginor/jexus-x64:6.2.1.12。

ps: 老黄这边是因为有不少项目需要用到图片,所以是自己单独弄了一个,加了libgdiplus 等一些必备的东西进去。

先准备一个jexus的配置文件,这里用的是最简单的。

  1. port=80
  2. root=/ /app
  3. hosts=*

然后就是Dockerfile了

  1. # 按需替换
  2. FROM jexus-x64-img:6.1 AS base
  3. # FROM beginor/jexus-x64:6.2.1.12 AS base
  4. FROM mono:6.8 AS build
  5. WORKDIR /src
  6. COPY . .
  7. # 还原nuget包
  8. RUN nuget restore ServerlessNetApp.sln -Source https://api.nuget.org/v3/index.json
  9. # 编译
  10. RUN msbuild NfxApi/NfxApi.csproj /t:ReBuild /p:Configuration=Release /p:OutDir=/src/out /p:DeleteExistingFiles=True /p:DeployOnBuild=True /p:DeployDefaultTarget=WebPublish /p:WebPublishMethod=FileSystem
  11. FROM base AS final
  12. WORKDIR /app
  13. # 把发布文件复制过来
  14. COPY --from=build /src/out/_PublishedWebsites/NfxApi /app
  15. COPY ./nfxweb /usr/jexus/siteconf/default
  16. # 按需放开
  17. # RUN sed -i 's/TLSv1.2/TLSv1.0/g' /etc/ssl/openssl.cnf
  18. CMD [ "jws", "restart"]

build一下,打包出一个镜像

  1. docker build -t nfxapi:v1 -f ./Dockerfile.nfx .

还有重要的一步是,推送到镜像仓库,这样容器服务那边才可以拉取到。

.NET Core

代码也是很简单的,多了一个用HttpClient调用.NET Framework的接口就是了。

  1. [ApiController]
  2. [Route("")]
  3. public class GwController : ControllerBase
  4. {
  5. private readonly IHttpClientFactory _factory;
  6. public GwController(IHttpClientFactory factory)
  7. {
  8. _factory = factory;
  9. }
  10. [HttpGet]
  11. public string Get()
  12. {
  13. return $"gw-svc in k8s";
  14. }
  15. [HttpGet("svc")]
  16. public async Task<string> GetAsync()
  17. {
  18. var client = _factory.CreateClient();
  19. // 请求上面的.NET Framewore 项目
  20. // 用服务名的方式来处理服务发现
  21. var resp = await client.GetAsync("http://api-nfx-svc/api/values");
  22. resp.EnsureSuccessStatusCode();
  23. var res = await resp.Content.ReadAsStringAsync();
  24. return $"ok - {res}";
  25. }
  26. }

下面这个Dockerfile应该好熟悉的了

  1. FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
  2. WORKDIR /app
  3. EXPOSE 80
  4. FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
  5. WORKDIR /src
  6. COPY . .
  7. RUN dotnet restore "ServerlessNetApp.sln"
  8. WORKDIR /src/GwApi
  9. RUN dotnet build "GwApi.csproj" -c Release -o /app/build
  10. FROM build AS publish
  11. RUN dotnet publish "GwApi.csproj" -c Release -o /app/publish
  12. FROM base AS final
  13. WORKDIR /app
  14. COPY --from=publish /app/publish .
  15. # 按需放开
  16. #RUN sed -i 's/TLSv1.2/TLSv1.0/g' /etc/ssl/openssl.cnf
  17. ENTRYPOINT ["dotnet", "GwApi.dll"]

同样的要把它打包成镜像推送到镜像仓库。

  1. docker build -t ncapi:v1 -f ./Dockerfile.nc .

运行起来

运行起来的话就是准备一些yml文件了,这里就贴出部分内容,具体的可以去github看。

先来看看Deployment和Service。

  1. apiVersion: extensions/v1beta1
  2. kind: Deployment
  3. metadata:
  4. name: api-nfx-svc
  5. namespace: test
  6. labels:
  7. app: api-nfx-svc
  8. spec:
  9. replicas: 1
  10. selector:
  11. matchLabels:
  12. app: api-nfx-svc
  13. strategy:
  14. rollingUpdate:
  15. maxSurge: 25%
  16. maxUnavailable: 25%
  17. type: RollingUpdate
  18. template:
  19. metadata:
  20. labels:
  21. app: api-nfx-svc
  22. spec:
  23. containers:
  24. image: >-
  25. 镜像仓库地址/api-nfx:v1
  26. imagePullPolicy: IfNotPresent
  27. name: api-nfx
  28. resources:
  29. requests:
  30. cpu: 250m
  31. memory: 512Mi
  32. # 省略部分 ...
  33. ---
  34. apiVersion: v1
  35. kind: Service
  36. metadata:
  37. name: api-nfx-svc
  38. namespace: test
  39. spec:
  40. ports:
  41. - port: 80
  42. protocol: TCP
  43. targetPort: 80
  44. selector:
  45. app: api-nfx-svc
  46. clusterIP: None
  47. sessionAffinity: None

因为要把.NET Core项目暴露出去,让外部访问,所以我们还要有一个Ingress。

这里的话是基于阿里云的负载均衡,没有用ingress-nginx或ingress-traefik,不那么通用。

  1. apiVersion: extensions/v1beta1
  2. kind: Ingress
  3. metadata:
  4. annotations:
  5. # 指定 SLB 的Id
  6. service.beta.kubernetes.io/alicloud-loadbalancer-id: lb-xxxxxxx
  7. name: gw-ingress
  8. namespace: test
  9. spec:
  10. rules:
  11. - host: ncgw.xxx.com
  12. http:
  13. paths:
  14. - backend:
  15. serviceName: api-nc-svc
  16. servicePort: 80
  17. path: /
  18. status:
  19. loadBalancer:
  20. ingress:
  21. - ip: xxx.xxx.xxx.xxxx

依次把服务,路由跑起来。

  1. kubectl apply -f ../k8s/svc-nfx.yml
  2. kubectl apply -f ../k8s/svc-nc.yml
  3. kubectl apply -f ../k8s/ingress.yml

然后就可以看到在控制台的无状态中出现了我们刚才创建的两个应用。

ps: 老黄手抖,把应用名加了个-svc。。。

服务还有路由

最后就是负载均衡

最后通过DNS解析一下域名到这个负载均衡的IP就可以了。

这个时候应用已经跑起来了,现在是只暴露出了.NET Core的项目可以给外面的访问

访问.NET Core项目的这个地址, http://ncgw.domain.com/svc, 就是通过SLB->集群里的.NET Core->集群里面.NET Framework

一些额外细节

阿里云的serverless kubernetes是基于弹性容器实例(ECI)的,所以最终创建的pod是运行在ECI里面的。

下面是ECI的一个列表。

对比一下两者的监控,

先是.NET Core的

再看看.NET Framwork的

.NET Framework的项目确实是占用的资源多一点。

进去容器里面看看吧。

进来容器里面,其实就是进入了集群环境了。

我们同样可以通过服务名去访问到对应的服务了。

最后一个就是服务发现是基于DNS的。

写在最后

serverless kubernetes用起来确实比较方便,省了很多不必要的麻烦,不过也是踩着坑过来的,坑踩多了,也就可以轻车熟路了。

这里也只是演示了最简单的应用,还有水平伸缩(HPA),日志,监控等一系列的内容,这里是没有提及到的。

可能有人会问:

  1. 为什么还有.NET Framework,不直接.NET Core?

很多老业务不是说动就能动的那么干脆,毕竟还有数据库的限制。。。

  1. .NET Framework容器化有什么坑?

只要你代码没问题,可以在linux下面跑,那就没什么坑不坑的,要是用了一些不支持的特性,那谁也救不了的。

  1. serverless kubernetes的其他问题

可以参靠各大云产商的官方文档和提工单咨询。

最后就是这篇文章的代码可以在我的github查阅:

ServerlessNetApp

用Serverless Kubernetes为.NET (Core)应用保驾护航的更多相关文章

  1. 基于Kubernetes 构建.NET Core技术中台

    今天下午在腾讯云+社区社区分享了<基于Kubernetes 构建.NET Core技术中台>,下面是演讲内容的文字实录. 我们为什么需要中台 我们现在处于企业信息化的新时代.为什么这样说呢 ...

  2. Serverless Kubernetes入门:对kubernetes做减法

    背景 Kubernetes作为通用的容器编排系统,承载了广泛的应用和场景,包括CI/CD,数据计算,在线应用,AI等,然而由于其通用性和复杂性,管理一个kubernetes集群对于很多用户而言还是充满 ...

  3. Serverless Kubernetes全面升级2.0架构:支持多命名空间、RBAC、CRD、PV/PVC等功能

    Serverless Kubernetes概述: 阿里云Serverless Kubernetes容器服务最新开放香港.新加坡.悉尼区域,同时全面开放2.0架构,帮助用户更加便捷.轻松地步入“以应用为 ...

  4. Serverless Kubernetes 入门:对 Kubernetes 做减法

    作者 | 贤维  阿里巴巴高级技术专家 导读:Serverless Kubernetes 是阿里云容器服务团队对未来 Kubernetes 演进方向的一种探索,通过对 Kubernetes 做减法,降 ...

  5. 从零入门 Serverless | 一文讲透 Serverless Kubernetes 容器服务

    作者 | 张维(贤维) 阿里云函数计算开发工程师 导读:Serverless Kubernetes 是以容器和 kubernetes 为基础的 Serverless 服务,它提供了一种简单易用.极致弹 ...

  6. 从零入门 Serverless | Serverless Kubernetes 应用部署及扩缩容

    作者 | 邓青琳(轻零) 阿里云技术专家 导读:本文分为三个部分,首先给大家演示 Serverless Kubernetes 集群的创建和业务应用的部署,其次介绍 Serverless Kuberne ...

  7. Serverless Kubernetes 和 Serverless on Kubernetes 的区别

    什么是 Kubernetes? Kubernetes 是一个可移植的.可扩展的开源平台,用于管理容器化的工作负载和服务,可促进声明式配置和自动化. 什么是 Serverless ? 无服务器是一种云原 ...

  8. 基于Kubernetes 构建.NET Core 的技术体系

    很多公司技术支持岗位的工作,如配置域名,部署环境,修改复位配置,服务重启,扩容缩容,梳理和完善监控,根据开发的需要查找日志等工作,需要和开发进行大量的沟通,如什么是外网域名,什么是内网域名.A nam ...

  9. EDAS Serverless & Kubernetes SLB LVS Nginx

    分布式缓存负载均衡的规则处理:虚拟节点对一致性哈希的改进 - yanghuahui - 博客园https://www.cnblogs.com/yanghuahui/p/3755460.html EDA ...

随机推荐

  1. MySQL死锁及解决方案

    一.MySQL锁类型 1. MySQL常用存储引擎的锁机制 MyISAM和MEMORY采用表级锁(table-level locking) BDB采用页面锁(page-level locking)或表 ...

  2. 使用请求头认证来测试需要授权的 API 接口

    使用请求头认证来测试需要授权的 API 接口 Intro 有一些需要认证授权的接口在写测试用例的时候一般会先获取一个 token,然后再去调用接口,其实这样做的话很不灵活,一方面是存在着一定的安全性问 ...

  3. 纯CSS如何实现状态圆点

    .circle { display: inline-block; width: 12px; height: 12px; } .circle:after { content: ''; margin: 3 ...

  4. 探究:Adobe Premiere Pro CC 2018 导入SRT字幕显示不全问题

    问题:如果使用PR,大概率会遇到导入SRT格式的字幕文件后,PR里面显示的字幕不完整,字幕丢失的问题. 探究:字幕文件的内容正常,导入PR后字幕出现丢失. 查看字幕文件,并测试,发现如下图,如果出现字 ...

  5. bug的描述

    我们知道了自身的症状,那么就从这里开始,一起聊一聊一个优秀的 BUG,应该包含哪些方面的内容呢? 标题 其实每一个 BUG 也都是一个小的文档,既然是文档,我们首先就要做好一个 “标题党”,当然,此 ...

  6. Day10-微信小程序实战-交友小程序-自定义callPhone 和copyText组件

    ---为了方便用户可以拨打电话和复制微信号(下面就要实现这样的两个功能) 注意:在小程序中是没办法直接的添加用户的微信的,所以就只能是复制微信号 (这种东西的话可以直接去做,也可以做成组件,做出组件的 ...

  7. chromedp入门

    chromedp入门 chromedp是什么? chromedp是go写的,支持Chrome DevTools Protocol 的一个驱动浏览器的库.并且它不需要依赖其他的外界服务(比如 Selen ...

  8. xutils工具上传日志文件

    首先下载xutils java包: 添加到项目的工程中: 第二在新建一个类继承application package logback.ecmapplication.cetcs.com.myapplic ...

  9. jquery入门(2)

    3.jQuery常用方法 3.1 dom属性相关方法 addClass() 为每个匹配的元素添加指定的样式名 $('div').addClass('box'); //为页面中所有的div添加一个box ...

  10. DOM-BOM-EVENT(3)

    3.Node常用属性 childNodes 获取所有子节点 <div id="wrap"> <div>1111</div> <div> ...