Kubernetes初探[1]:部署你的第一个ASP.NET Core应用到k8s集群

Kubernetes简介

Kubernetes是Google基于Borg开源的容器编排调度引擎,作为CNCF(Cloud Native Computing Foundation)最重要的组件之一,它的目标不仅仅是一个编排系统,而是提供一个规范,可以让你来描述集群的架构,定义服务的最终状态,Kubernetes可以帮你将系统自动得达到和维持在这个状态。

更直白的说,Kubernetes可以让用户通过编写一个yaml或者json格式的配置文件,也可以是通过工具/代码生成或者是直接请求Kubernetes API来创建应用,该配置文件中包含了用户想要应用程序保持的状态,不管整个Kubernetes集群中的个别主机发生什么问题,都不会影响应用程序的状态,你还可以通过改变该配置文件或请求Kubernetes API来改变应用程序的状态。

这意味着开发人员不需要在意节点的数目,也不需要在意从哪里运行容器以及如何与它们交流。开发人员也不需要管理硬件优化,或担心节点关闭(它们将遵循墨菲法则),因为新的节点会添加到Kubernetes集群,同时Kubernetes会在其他运行的节点中添加容器,Kubernetes会发挥最大的作用。

总结:Kubernetes是容器控制平台,可以抽象所有的底层基础设施(容器运行用到的基础设施)。

Kubernetes——让容器应用进入大规模工业生产。

Kubernetes另一个深入人心的特点是:它标准化了云服务提供商。比如,有一个Azure、Google云平台或其他云服务提供商的专家,他担任了一个搭建在全新的云服务提供商的项目。这可能引起很多后果,比如说:他可能无法在截止期限内完成;公司可能需要招聘更多相关的人员,等等。相对的,Kubernetes就没有这个问题。因为不论是哪家云服务提供商,你都可以在上面运行相同的命令,以既定的方式向Kubernetes API服务器发送请求,Kubernetes会负责抽象,并在不同的云服务商中实现。

对于公司来说,这意味着他们不需要绑定到任何一家云服务商。他们可以计算其他云服务商的开销,然后转移到别家,并依旧保留着原来的专家,原来的人员,他们还可以花更少的钱。

Pod

Kubernetes有很多技术概念,同时对应很多API对象,最重要的也是最基础的对象就是Pod。Pod是Kubernetes集群中运行部署应用的最小单元,并且是支持多个容器的。

Pod的设计理念是支持多个容器在一个Pod中共享网络地址和文件系统,可以通过进程间通信和文件共享这种简单高效的方式组合完成服务。Pod对多容器的支持是Kubernetes最基础的设计理念。比如你运行一个操作系统发行版的软件仓库,一个Nginx容器用来发布软件,另一个容器专门用来从源仓库做同步,这两个容器的镜像不太可能是一个团队开发的,但是他们一块儿工作才能提供一个微服务;这种情况下,不同的团队各自开发构建自己的容器镜像,在部署的时候组合成一个微服务对外提供服务。不过,在大多数情况下,我们只会在Pod中运行一个容器,本文中的例子也是这样的。

Pod 的另一个特征是:如果我们希望使用其他 RKE 等技术的话,我们可以做到不依赖Docker容器。

Docker是kubernetes中最常用的容器运行时,但是Pod也支持其他容器运行时。

总的来说,Pod的主要特征包括:

  • 每个Pod可以在Kubernetes集群内拥有唯一的IP地址;

  • Pod可以拥有多个容器。这些容器共享同一个端口空间,所以他们可以通过localhost交流(可想而知它们无法使用相同的端口),与其他Pod内容器的交流可以通过结合Pod的IP来完成;

  • 一个Pod内的容器共享同一个卷、同一个 IP、端口空间、IPC 命名空间。

定义一个Pod

如下,我们定义一个最简单的Pod:

apiVersion: v1kind: Pod # 定义Kubernetes资源的类型为Podmetadata:  name: demo-web # 定义资源的名称  labels: # 为Pod贴上标签,后面会介绍其用处    app: demo-webspec: # 定义资源的状态,对于Pod来说,最重要属性就是containers  containers: # containers一个数组类型,如果你希望部署多个容器,可以添加多项    - name: web # 定义本Pod中该容器的名称      image: rainingnight/aspnetcore-web # 定义Pod启动的容器镜像地址      ports:        - containerPort: 80 # 定义容器监听的端口(与Dockerfile中的EXPOSE类似,只是为了提供文档信息)

然后保存,我这里命名为demo-web-pod.yaml

现在我们可以在终端中输入以下命令来创建该Pod:

kubectl create -f demo-web-pod.yaml# 输出# pod/demo-web created

可以使用如下命令,来查看kubernetes中的Pod列表:

kubectl get pods# 输出# NAME                           READY   STATUS    RESTARTS   AGE# demo-web                       1/1     Running   0          65s

如果该Pod还处于ContainerCreating状态的话,你可以在运行命令的时候加入--watch参数,这样当Pod变成运行状态的时候,会自动显示在终端中。

访问应用程序

在上面,我们成功部署了一个ASP.NET Core Mvc程序的Pod,那么如何访问它呢?如果只是为了调试,我们可以使用转发端口的方式来快速访问:

kubectl port-forward demo-web 8080:80# 输出# Forwarding from 127.0.0.1:8080 -> 80

然后我们再浏览器中访问:127.0.0.1:8080,显示如下:

640?wx_fmt=png

如上,还展示了Pod的主机名和IP,这是因为我在应用中添加了如下代码:

public void OnGet(){HostName = Dns.GetHostName();HostIP = Dns.GetHostEntry(HostName).AddressList.FirstOrDefault(x => x.AddressFamily == AddressFamily.InterNetwork).ToString();
}

不过,端口转发的方式只能在本机访问,为了从外部访问应用程序,我们需要创建Kubernetes中的另外一种资源:Service

Service

Kubernetes中的Service资源可以作为一组提供相同服务的Pod的入口,这个资源肩负发现服务和平衡Pod之间负荷的重任。

在Kubernetes集群中,我们拥有提供不同服务的Pod,那么Service如何知道该处理哪个Pod呢?

这个问题就用标签来解决的,具体分两个步骤:

  • 给所有需要Service处理的对象Pod贴上标签。

  • 在Service中使用一个选择器(Label Selector),该选择器定义了所有贴有对应的标签的对象Pod。

标签

标签提供了一种简单的方法用于管理Kubernetes中的资源。它们用一对键值表示,且可以用于所有资源。

其实在上面的Pod定义中,我们已经定义了标签:

metadata:  name: demo-web  labels:    app: demo-web

如上,我们为Pod附加了标签app:demo-web,在查看Pod的时候,可以使用--show-labels参数来显示Pod对应的标签:

kubectl get pods --show-labels# 输出# NAME                           READY   STATUS    RESTARTS   AGE     LABELS# demo-web                       1/1     Running   0          1m52s   app=demo-web

可以看到,我们的Pod都拥有一个app=demo-web标签。

定义Service

现在,让我们为刚才创建的Pod定义一个Service:

apiVersion: v1kind: Service # 定义Kubernetes资源的类型为Servicemetadata:  name: demo-web-service # 定义资源的名称spec:  selector: # 指定对应的Pod    app: demo-web # 指定Pod的标签为demo-web  ports:  - protocol: TCP # 协议类型    port: 80 # 指定Service访问的端口    targetPort: 80 # 指定Service转发请求的端口    nodePort: 30000  type: NodePort # 指定Service的类型,在这里使用NodePort来对外访问

如上,我们使用selector属性来选择相应的标签,并把服务类型(type)设置为NodePorttype的取值有以下4种:

  • ClusterIP:默认值,通过集群的内部IP暴露服务,该模式下,服务只能够在集群内部可以访问。

  • NodePort:通过每个Node上的IP和静态端口(NodePort)暴露服务,NodePort服务会路由到ClusterIP服务,这个ClusterIP服务会自动创建。

  • LoadBalancer:使用云提供商的负载均衡器,可以向外部暴露服务,外部的负载均衡器可以路由到NodePort服务和ClusterIP服务。

  • ExternalName:通过返回CNAME和它的值,可以将服务映射到externalName字段的内容(如:foo.bar.example.com)。没有任何类型代理被创建,这只有 Kubernetes 1.7 或更高版本的kube-dns才支持。

对于服务类型我们先了解这么多就可以了,后续会再来详细介绍。

然后使用如下命令创建Service:

kubectl create -f demo-web-service.yaml# 输出# service/demo-web-service created

使用如下命令来检查服务的状态:

kubectl get services# 输出# NAME               TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE# demo-web-service   NodePort    10.105.132.214   <none>        80:30000/TCP   10s

如上,它有一个CLUSTER-IP为10.105.132.214,因此我们可以在集群内使用10.105.132.214:80来访问该服务,如果是在集群外部,可以使用NodeIP:30000来访问。

服务发现与负载均衡

在上面我们说到,Service肩负着发现服务和平衡Pod之间负荷的重任,那它是怎么做的呢?让我们先再添加一个Pod:

apiVersion: v1kind: Podmetadata:  name: demo-web-copy  labels:    app: demo-webspec:  containers:    - name: web      image: rainingnight/aspnetcore-web            ports:        - containerPort: 80

如上,其定义与之前的Pod一样,只是把name改成了demo-web-copy,然后创建Pod:

kubectl create -f demo-web-copy.pod.yaml# 查看Podkubectl get pods# 输出# NAME                           READY   STATUS    RESTARTS   AGE# demo-web                       1/1     Running   0          10m# demo-web-copy                  1/1     Running   0          29s

现在我们使用NodeIP:30000来访问,打开两个浏览器窗口,多刷新几次,以便让它们分别路由到不同的Pod,最终显示如下:

640?wx_fmt=png

可以看到,我们新创建的Pod已经通过Servie来接受请求了,不需要修改成任何程序代码,Kubernetes就已经帮我们实现了服务发现和负载均衡,是不是非常爽。

Deployment

在上面我们手动部署了两个Pod,但是这只是单机的玩法,它与直接使用Docker容器相比并无太大优势,如果我们需要部署一千个实例,那就是一个痛苦的过程,或者我们又想快速更新和迅速回滚,这根本就是不可能的!

其实在k8s中,我们很少直接使用Pod,更多的是使用Kubernetes的另外一种资源:Deployment

Deployment表示用户对Kubernetes集群的一次更新操作。可以是创建一个新的服务或是更新一个新的服务,也可以是滚动升级一个服务。Deployment可以帮助每一个应用程序的生命都保持相同的一点:那就是变化。此外,只有挂掉的应用程序才会一尘不变,否则,新的需求会源源不断地涌现,更多代码会被开发出来、打包以及部署,这个过程中的每一步都有可能出错。Deployment可以自动化应用程序从一版本升迁到另一版本的过程,并保证服务不间断,如果有意外发生,它可以让我们迅速回滚到前一个版本。

Deployment定义

现在,我们使用Deployment来部署我们的Pod,并实现在部署期间服务不间断服务,可以如下定义:

apiVersion: apps/v1kind: Deployment # 定义Kubernetes资源的类型为Deploymentmetadata:  name: demo-web-deployment # 定义资源的名称  labels:    app: demo-web-deploymentspec:  # 定义资源的状态。  replicas: 2 # 定义我们想运行多少个Pod,在这里我们希望运行2个  selector:    matchLabels: # 定义该部署匹配哪些Pod      app: demo-web  minReadySeconds: 5 # 可选,指定Pod可以变成可用状态的最小秒数,默认是0  strategy: # 指定更新版本时,部署使用的策略    type: RollingUpdate # 策略类型,使用RollingUpdate可以保证部署期间服务不间断    rollingUpdate:      maxUnavailable: 1 # 部署时最大允许停止的Pod数量(与replicas相比)      maxSurge: 1 # 部署时最大允许创建的Pod数量(与replicas相比)  template: # 用来指定Pod的模板,与Pod的定义类似    metadata:      labels: # 根据模板创建的Pod会被贴上该标签,与上面的matchLabels对应        app: demo-web    spec:      containers:        - name: web          image: rainingnight/aspnetcore-web          imagePullPolicy: Always # 默认是IfNotPresent,如果设置成Always,则每一次部署都会重新拉取容器映像(否则,如果本地存在指定的镜像版本,就不会再去拉取)          ports:            - containerPort: 80

保存为demo-web-deployment.yaml,然后输入以下命令来创建Deployment:

kubectl create -f demo-web-deployment.yaml# 输出# deployment.apps/demo-web-deployent created

现在我们再来查看以下Pod:

kubectl get pods# 输出# NAME                                   READY   STATUS    RESTARTS   AGE# demo-web                               1/1     Running   0          4h28m# demo-web-copy                          1/1     Running   0          18m# demo-web-deployment-745f7997c4-d24bb   1/1     Running   0          16s# demo-web-deployment-745f7997c4-jk9jn   1/1     Running   0          16s

如上,我们有4个运行中的Pod,其中前二个是我们手动创建的,其他两个是使用Deployment创建的。

我们可以使用kubectl delete pod <pod-name>删除一个Deployment创建的Pod,看看结果会怎样:

kubectl delete pod demo-web-deployment-745f7997c4-d24bb# 输出# pod "demo-web-deployment-745f7997c4-d24bb" deleted

再次查看Pod列表:

kubectl get pods# 输出# NAME                                   READY   STATUS    RESTARTS   AGE# demo-web                               1/1     Running   0          31m# demo-web-copy                          1/1     Running   0          22m# demo-web-deployment-745f7997c4-jk9jn   1/1     Running   0          3m39s# demo-web-deployment-745f7997c4-mrrw6   1/1     Running   0          11s

可以看到,又重新创建了一个Pod:demo-web-deployment-745f7997c4-mrrw6,Deployment会监控我们的Pod数量,保持为我们预期的个数。

零停机时间部署(Zero-downtime)

现在我们尝试以下零停机部署,首先修改Deployment中的image为:rainingnight/aspnetcore-web:1.0.0,然后运行如下命令:

kubectl apply -f demo-web-deployment.yaml --record# 输出# deployment.apps/demo-web-deployment configured

将kubectl的--record设置为true可以在annotation中记录当前命令创建或者升级了该资源。这在未来会很有用,例如,查看在每个 Deployment revision 中执行了哪些命令。

除了修改yaml外,还可以直接运行kubectl set image deployment demo-web-deployment web=rainingnight/aspnetcore-web:1.0.0 --record来达到同样的效果。

然后使用如下命令检查服务更新状态:

kubectl rollout status deployment demo-web-deployment# 输出# Waiting for deployment "demo-web-deployment" rollout to finish: 1 old replicas are pending termination...# Waiting for deployment "demo-web-deployment" rollout to finish: 1 old replicas are pending termination...# Waiting for deployment "demo-web-deployment" rollout to finish: 1 old replicas are pending termination...# Waiting for deployment "demo-web-deployment" rollout to finish: 1 old replicas are pending termination...# Waiting for deployment "demo-web-deployment" rollout to finish: 1 of 2 updated replicas are available...# Waiting for deployment "demo-web-deployment" rollout to finish: 1 of 2 updated replicas are available...# deployment "demo-web-deployment" successfully rolled out

如上可以看到,新版本已经成功上线,并在这个过程中副本被逐个替换,也就意味着应用程序始终在线。

现在我们刷新一下浏览器,可以看到标题已经变成了Home page - Web-v1:

回滚到前一个状态

如果突然发现新上线的版本有Bug,需要紧急回滚到上一个版本,那对Kubernetes来说也是非常简单的。

我们首先运行如下命令来查看历史版本:

kubectl rollout history deployment demo-web-deployment# 输出# deployment.extensions/demo-web-deployment # REVISION  CHANGE-CAUSE# 1         <none># 2         kubectl apply --filename=demo-web-deployment.yaml --record=true

如上,可以看到有2条历史,那么为什么第1条的CHANGE-CAUSE<none>呢,这就是因为我们第二次部署的时候使用了--record=true参数。现在,我们想回滚到第一个版本,只需运行如下命令:

kubectl rollout undo deployment demo-web-deployment --to-revision=1# 输出# deployment.extensions/demo-web-deployment rolled back

再次刷新浏览器,标题又变回了Home page - Web

部署多个应用

现在我们再部署一个ASP.NET Core WebApi程序,并在刚才的Web应用中调用它,形成一个最简单的微服务模式。

部署WebApi

与前面的Web应用的部署类似,就不用过多介绍,定义如下YAML:

apiVersion: apps/v1kind: Deploymentmetadata:  name: demo-api-deployment  labels:    app: demo-api-deploymentspec:  replicas: 2  selector:    matchLabels:      app: demo-api  minReadySeconds: 5  strategy:    type: RollingUpdate    rollingUpdate:      maxUnavailable: 1      maxSurge: 1  template:    metadata:      labels:        app: demo-api    spec:      containers:        - name: api          image: rainingnight/aspnetcore-api          imagePullPolicy: Always          ports:            - containerPort: 80

然后创建Deployment:

kubectl create -f demo-api-deployment.yaml 

查看部署情况:

kubectl get pods# 输出# NAME                                   READY   STATUS    RESTARTS   AGE# demo-api-deployment-66575d644-9wk7g    1/1     Running   0          75s# demo-api-deployment-66575d644-fknpx    1/1     Running   0          75s# demo-web-deployment-745f7997c4-h7fr8   1/1     Running   0          9m23s# demo-web-deployment-745f7997c4-kvptm   1/1     Running   0          9m23s

前面手动创建的2个Pod已经被我删除了,因为用Deployment创建的Pod就好了。

现在我们为Api应用也创建一个Service,以便在Web应用中访问它:

apiVersion: v1kind: Servicemetadata:  name: demo-api-servicespec:  selector:    app: demo-api  ports:  - protocol: TCP    port: 80    targetPort: 80

因为我们的Api应用是不需要在集群外部访问的,因此服务类型(type)不需要设置,使用默认的ClusterIP就可以了。

部署Servcie:

kubectl create -f demo-api-service.yaml

然后查看Servie:

kubectl get services# 输出# NAME               TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE# demo-api-service   ClusterIP   10.111.25.49     <none>        80/TCP         26s# demo-web-service   NodePort    10.105.132.214   <none>        80:30000/TCP   58m

可以使用浏览器来访问:10.111.25.49/api/values 来验证一下是否部署成功。

调用服务

那么,还剩下最后一个问题,我们的Web应用中如何获取到Api应用的访问地址呢?

我们先看一下,在Web应用的代码中是怎么调用Api的:

// Startup.cspublic void ConfigureServices(IServiceCollection services){services.AddHttpClient("api", _ => _.BaseAddress = new Uri(Configuration["ApiBaseUrl"]));
}// FetchData.cshtmlpublic class FetchDataModel : PageModel{    private static HttpClient _client;    public FetchDataModel(IHttpClientFactory httpClientFactory)    {_client = httpClientFactory.CreateClient("api");}    public IList<WeatherForecast> Forecasts { get; set; }    public async Task OnGetAsync()    {        var res = await _client.GetStringAsync("/api/SampleData/WeatherForecasts");Forecasts = JsonConvert.DeserializeObject<IList<WeatherForecast>>(res);}
}

如上,我们首先注册了一个HttpClient,并从配置文件中读取ApiBaseUrl做为BaseAddress,然后在FetchData页面中使用HttpClient调用Api服务。

因为在Asp.Net Core中,默认情况下,环境变量中的配置是会覆盖appsettings.json中的配置的,因此我们可以使用添加环境变量的方式来配置ApiBaseUrl

修改demo-web-deployment.yaml,添加env属性,如下:

containers:  - name: web    image: rainingnight/aspnetcore-web    imagePullPolicy: Always    ports:      - containerPort: 80    env:      - name: ApiBaseUrl        value: "http://10.111.25.49"

然后在Kubernetes中应用该配置:

kubectl apply -f demo-web-deployment.yaml 

等待滚动更新完成,刷新浏览器,点击FetchData菜单上,可以看到数据成功返回,但是直接使用集群IP10.111.25.49,这也有点太低级了,其实我们可以直接使用域名:http://demo-api-service,修改后如下:

  env:    - name: ApiBaseUrl      value: "http://demo-api-service"

提交到Kubernetes,然后刷新浏览器,可以看到完美运行,这是因为CoreDNS(Kube-DNS)帮我们完成了域名解析。

在Kubernetes 1.11中,CoreDNS已经实现了基于DNS的服务发现的GA,可作为kube-dns插件的替代品。这意味着CoreDNS将作为各种安装工具未来发布版本中的一个选项来提供。事实上,kubeadm团队选择将其作为Kubernetes 1.11的默认选项。

CoreDNS是一个通用的、权威的DNS服务器,提供与Kubernetes后向兼容但可扩展的集成。它解决了kube-dns所遇到的问题,并提供了许多独特的功能,可以解决各种各样的用例。

DNS服务器监控kubernetes创建服务的API, 并为每个服务创建一组dns记录。如果在整个群集中启用了dns, 所有Pod都会使用它作为DNS服务器。比如我们的demo-api-service服务,DNS服务器会创建一条"my-service.my-ns"也就是10.111.25.49:demo-api-service.default的dns记录,因为我们的Web应用和Api应用在同一个命名空间(default)中,所以可以直接使用demo-api-service来访问。

总结

本文带领大家一步一步部署了一个最简单的ASP.NET Core MVC + WebApi的微服务程序,介绍了Kubernetes中最基本的三个概念:PodDeploymentService,相信大家对Kubernetes也有了一个全面的认识。

虽然Kubernetes整个体系是非常复杂的,但是不用担心,一开始我们不用去求甚解,最重要的是先跑起来,后续我会和大家一起逐步深入,由简到繁,愉快的掌握Kubernetes。

附本文所用示例代码:https://github.com/RainingNight/AspNetCoreDocker。

相关资料:

  • Kubernetes Concepts

  • 使用Kubeadm(1.13+)快速搭建Kubernetes集群

  • kubernetes-dashboard(1.8.3)部署与踩坑

原文地址:https://www.cnblogs.com/RainingNight/p/first-aspnetcore-app-in-k8s.html


.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com

640?wx_fmt=jpeg

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

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

相关文章

01分数规划

参考文章 01分数规划 什么是01分数规划&#xff1a; 给定n个a[i]和b[i]&#xff0c;a[i]和b[i]绑定在一起要选同时选&#xff0c;求sum(a[i]) 除以 sum(b[i]) 的最大值&#xff0c;sum为求和函数 对于这种问题我们可以多定义一个数组x[1…n]&#xff0c;x为bool型只取0或者1,…

CF1156D 0-1-Tree(换根DP)

牛犇犇titlesolutioncodetitle 戳一戳 solution 直接设dp[i][k]dp[i][k]dp[i][k]表示以iii为根时&#xff0c;子树内&#xff0c;边权为kkk时的答案 &#xff08;定义写得好复杂&#xff0c;可略过&#xff09; 考虑对于点uuu&#xff0c;vvv是他的一个儿子&#xff0c;两点…

Entity Framework 6.3 和 EF Core 3.0 路线图

尽管脱离了 .NET Core 发布循环&#xff0c;但是 EF Core 正在开发其 3.0 路线图。除此之外&#xff0c;还对原来的 Entity Framework 进行了一些重要的变更。更多服务器端的查询将 LINQ 查询转换为对应的 SQL 查询通常是比较困难的&#xff0c;甚至是不可能的。许多 QRM 只能在…

EFCore+Mysql仓储层建设(分页、多字段排序、部分字段更新)

前沿园子里已有挺多博文介绍了EFCoreMysql/MSSql如何进行使用&#xff0c;但实际开发不会把EF层放在Web层混合起来&#xff0c;需要多个项目配合结构清晰的进行分层工作&#xff0c;本文根据个人实践经验总结将各个项目进行分层&#xff0c;仅供想自己搭建,包含数据仓储以及分页…

[FWT] 时隔一年再回首FWT(快速沃尔什变换),我终于不再是个门外汉

时隔一年再回首FWT&#xff0c;我似乎有了新理解&#xff1f;&#xff1f; 添加了原理的推导&#xff0c;以前就只有模板… 文章目录引入or&#xff08;或&#xff09;卷积原理FWT_or正变换FWT_or逆变换模板and&#xff08;与&#xff09;卷积原理FWT_and正变换FWT_and逆变换模…

Loj #149. 01 分数规划(01分数规划模板题)

链接 题意&#xff1a; 题解&#xff1a; 详细解法看这里 这里说个点&#xff0c;eps一定要开足够小&#xff0c;我一开始开的1e-5&#xff0c;结果就过了90%的数据&#xff0c;开到1e-7就足够了 代码&#xff1a; #include<bits/stdc.h> typedef long long ll; usin…

如何测试 ASP.NET Core Web API

在本文中&#xff0c;我们将研究如何测试你的 ASP .NET Core 2.0 Web API 解决方案。我们将了解使用单元测试进行内部测试&#xff0c;使用全新的 ASP .NET Core 的集成测试框架来进行外部测试。本文要点正确理解并使用单元测试和你的 ASP .NET Core Web API 解决方案一样重要。…

[帝皇杯day 1] [NOIP2018模拟赛]小P的loI(暴力+素筛),【NOIP模拟赛】创世纪(贪心),无聊的数对(线段树)

文章目录T1&#xff1a;小P的loltitlesolutioncodeT2&#xff1a;创世纪titlesolutioncodeT3&#xff1a;无聊的数对titlesolutioncodeT1&#xff1a;小P的lol title solution 此题非常水… 先用素数筛&#xff0c;筛出[1,n][1,n][1,n]中的质数 质数越小&#xff0c;倍数的分…

[2-sat专练]poj 3683,hdu 1814,hdu 1824,hdu 3622,hdu 4115,hdu 4421

文章目录Priest Johns Busiest DaycodePeaceful CommissioncodeLets go homecodeBomb GamecodeEliminate the ConflictcodeBit MagiccodePriest John’s Busiest Day 题目 司仪必须在婚礼开始或结束时出现&#xff0c;考虑把第iii场婚礼拆成两个点 iii&#xff1a;表示司仪在婚…

.NET Core中的一个接口多种实现的依赖注入与动态选择

最近有个需求就是一个抽象仓储层接口方法需要SqlServer以及Oracle两种实现方式&#xff0c;为了灵活我在依赖注入的时候把这两种实现都给注入进了依赖注入容器中&#xff0c;但是在服务调用的时候总是获取到最后注入的那个方法的实现&#xff0c;这时候就在想能不能实现动态的选…

Sightseeing Cows POJ - 3621

题意&#xff1a; L个点&#xff0c;P边的点边带权的有向图&#xff0c;求一个环点权和与边权和比值的最大值。 题解&#xff1a; 01分数规划判负环 详细看这里 还是套用01分数规划模型&#xff0c;点权为value[i],边权为cost[u],一个环为C&#xff0c;问题要求最大化 最…

C# Memory Cache 踩坑记录

背景前些天公司服务器数据库访问量偏高,运维人员收到告警推送,安排我团队小伙伴排查原因.我们发现原来系统定期会跑一个回归测试,该测运行的任务较多,每处理一条任务都会到数据库中取相关数据,高速地回归测试也带来了高频率的数据库读取.解决方案1我们认为每个任务要取的数据大…

[贪心专题]CF549G,CF351E,CF226D,CF1276C,CF1148E,CF798D

文章目录T1&#xff1a;CF1276C Beautiful RectangletitlesolutioncodeT2&#xff1a;CF226D The tabletitlesolutioncodeT3&#xff1a;CF549G Happy LinetitlesolutioncodeT4&#xff1a;CF798D Mike and distributiontitlesolutioncodeT5&#xff1a;CF351E Jeff and Permut…

【数位DP】CF 54C,509C,431D,628D,855E,1245F,95D

这一次有题解了&#xff01;&#xff01;T1&#xff1a;CF54C First Digit LawtitlesolutioncodeT2&#xff1a;CF509C Sums of DigitstitlesolutioncodeT3&#xff1a;CF431D Random TasktitlesolutioncodeT4&#xff1a;CF628D Magic NumberstitlesolutioncodeT5&#xff1a;…

C#如何安全、高效地玩转任何种类的内存之Memory(三)

前言我们都知道&#xff0c;.Net Core是微软推出的一个通用开发平台&#xff0c;它是跨平台和开源的&#xff0c;由一个.NET运行时、一组可重用的框架库、一组SDK工具和语言编译器组成&#xff0c;旨在让.Net developers可以更容易地编写高性能的服务应用程序和基于云的可伸缩服…

.netcore下的微服务、容器、运维、自动化发布

微服务1.1 基本概念1.1.1 什么是微服务&#xff1f;微服务架构是SOA思想某一种具体实现。是一种将单应用程序作为一套小型服务开发的方法&#xff0c;每种应用程序都在其自己的进程中运行&#xff0c;并采用轻量级的通讯机制&#xff08;TCP&#xff09;进行通信。这…

[选拔赛1]花园(矩阵快速幂),JM的月亮神树(最短路),保护出题人(斜率优化)

多年不考试&#xff0c;一夜回到解放前T1&#xff1a;花园titlesolutioncodeT2&#xff1a;月亮神树titlesolutioncodeT3&#xff1a;保护出题人titlesolutioncodeT1&#xff1a;花园 title 小 L 有一座环形花园&#xff0c;沿花园的顺时针方向&#xff0c;他把各个花圃编号为…

.NET的关于人脸识别引擎分享(C#)

最近在Github上找合适的人脸识别引擎&#xff0c;想要本地化用&#xff0c;不用开放的一些API&#xff08;比如腾讯AI、百度AI&#xff09;,有些场景联不了网&#xff0c;一开始搜索的是时候&#xff08;关键字&#xff1a;face recognition&#xff09;就找到了最出名的face_r…

UOJ#84-[UR #7]水题走四方【dp】

正题 题目链接:https://uoj.ac/problem/84 题目大意 有nnn个点的一棵树&#xff0c;111为根&#xff0c;两个人从根节点往下走&#xff08;只能从深度小的点走到深度大的点&#xff09;。 两个人每一秒都可以一条边&#xff08;也可以不移动&#xff09;&#xff0c;或者不消…

Docker最全教程——数据库容器化(十一)

终于按时完成第二篇。本来准备着手讲一些实践&#xff0c;但是数据库部分没有讲到&#xff0c;部分实践会存在一些问题&#xff0c;于是就有了此篇以及后续——数据库容器化。本篇将从SQL Server容器化实践开始&#xff0c;并逐步讲解其他数据库的容器化实践&#xff0c;中间再…