zoukankan      html  css  js  c++  java
  • 用Serverless Kubernetes为.NET (Core)应用保驾护航

    前言

    容器化对现在(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。

    public class ValuesController : ApiController
    {
        // GET api/values
        public IEnumerable<string> Get()
        {
            return new string[] { "value1", "value2", "nfx in k8s" };
        }
    }
    

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

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

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

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

    port=80
    root=/ /app
    hosts=*
    

    然后就是Dockerfile了

    # 按需替换
    FROM jexus-x64-img:6.1 AS base
    # FROM beginor/jexus-x64:6.2.1.12 AS base
    
    FROM mono:6.8 AS build
    WORKDIR /src
    COPY . .
    # 还原nuget包
    RUN nuget restore ServerlessNetApp.sln -Source https://api.nuget.org/v3/index.json
    # 编译
    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
    
    FROM base AS final
    WORKDIR /app
    # 把发布文件复制过来
    COPY --from=build /src/out/_PublishedWebsites/NfxApi /app
    COPY ./nfxweb /usr/jexus/siteconf/default
    # 按需放开
    # RUN sed -i 's/TLSv1.2/TLSv1.0/g' /etc/ssl/openssl.cnf
    CMD [ "jws", "restart"]
    

    build一下,打包出一个镜像

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

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

    .NET Core

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

    [ApiController]
    [Route("")]
    public class GwController : ControllerBase
    {
        private readonly IHttpClientFactory _factory;
    
        public GwController(IHttpClientFactory factory)
        {
            _factory = factory;
        }
    
        [HttpGet]
        public string Get()
        {
            return $"gw-svc in k8s";
        }
    
        [HttpGet("svc")]
        public async Task<string> GetAsync()
        {
            var client = _factory.CreateClient();
            
            // 请求上面的.NET Framewore 项目
            // 用服务名的方式来处理服务发现
            var resp = await client.GetAsync("http://api-nfx-svc/api/values");
            resp.EnsureSuccessStatusCode();
            var res = await resp.Content.ReadAsStringAsync();
    
            return $"ok - {res}";
        }
    }
    

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

    FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
    WORKDIR /app
    EXPOSE 80
    
    FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
    WORKDIR /src
    COPY . .
    RUN dotnet restore "ServerlessNetApp.sln"
    WORKDIR /src/GwApi
    RUN dotnet build "GwApi.csproj" -c Release -o /app/build
    
    FROM build AS publish
    RUN dotnet publish "GwApi.csproj" -c Release -o /app/publish
    
    FROM base AS final
    WORKDIR /app
    COPY --from=publish /app/publish .
    
    # 按需放开
    #RUN sed -i 's/TLSv1.2/TLSv1.0/g' /etc/ssl/openssl.cnf
    ENTRYPOINT ["dotnet", "GwApi.dll"]
    

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

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

    运行起来

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

    先来看看Deployment和Service。

    apiVersion: extensions/v1beta1
    kind: Deployment
    metadata:
      name: api-nfx-svc
      namespace: test
      labels:
        app: api-nfx-svc
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: api-nfx-svc
      strategy:
        rollingUpdate:
          maxSurge: 25%
          maxUnavailable: 25%
        type: RollingUpdate
      template:
        metadata:
          labels:
            app: api-nfx-svc
        spec:
          containers:
               image: >-
                镜像仓库地址/api-nfx:v1
               imagePullPolicy: IfNotPresent
               name: api-nfx
               resources:
                 requests:
                   cpu: 250m
                   memory: 512Mi
    # 省略部分 ...
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: api-nfx-svc
      namespace: test
    spec:
      ports:
      - port: 80
        protocol: TCP
        targetPort: 80
      selector:
        app: api-nfx-svc
      clusterIP: None
      sessionAffinity: None
    

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

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

    apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
      annotations:
        # 指定 SLB 的Id
        service.beta.kubernetes.io/alicloud-loadbalancer-id: lb-xxxxxxx
      name: gw-ingress
      namespace: test
    spec:
      rules:
        - host: ncgw.xxx.com
          http:
            paths:
              - backend:
                  serviceName: api-nc-svc
                  servicePort: 80
                path: /
    status:
      loadBalancer:
        ingress:
          - ip: xxx.xxx.xxx.xxxx
    

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

    kubectl apply -f ../k8s/svc-nfx.yml
    
    kubectl apply -f ../k8s/svc-nc.yml
    
    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

  • 相关阅读:
    CPP Info Memo part3
    在Google搜索结果显示原始链接(转自 月光博客)
    libc 之 locales
    Git 分支管理与本地 repository 创建
    py2exe issue: ImportError: No module named _fontdata_enc_winansi (http://stackoverflow.com/)
    CPP Info Memo (Part 1)
    CPP Info Memo part2
    HOWTO: Increase write speed by 'aligning' FAT32(通过对齐 FAT32 提高U盘访问速度, 转载)
    (转载)Gentoo中文man乱码
    如何选择开源许可证?(转载)
  • 原文地址:https://www.cnblogs.com/catcher1994/p/13258780.html
Copyright © 2011-2022 走看看