我在本地机器上设置了 Docker 桌面 Kubernetes 集群,并且运行良好。 现在我正在尝试将 .Net Core gRPC 服务器和 .Net Core Console 负载生成器部署到我的集群。
我正在为 gRPC 应用程序使用 VisualStudio(2019) 的默认模板
服务器:
原型文件
syntax = "proto3";
option csharp_namespace = "KubernetesLoadSample";
package greet;
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply);
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings.
message HelloReply {
string message = 1;
}
.net 核心 gRPC 应用
public class GreeterService : Greeter.GreeterBase
{
private readonly ILogger<GreeterService> _logger;
public GreeterService(ILogger<GreeterService> logger)
{
_logger = logger;
}
public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
{
_logger.LogInformation("Compute started");
double result = 0;
for (int i = 0; i < 10000; i++)
{
for (int j = 0; j < i; j++)
{
result += Math.Sqrt(i) + Math.Sqrt(j);
}
}
return Task.FromResult(new HelloReply
{
Message = "Completed"
}); ;
}
}
和此项目的 DockerFile 如下,
FROM mcr.microsoft.com/dotnet/aspnet:3.1 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:3.1 AS build
WORKDIR /src
COPY ["KubernetesLoadSample.csproj", "KubernetesLoadSample/"]
RUN dotnet restore "KubernetesLoadSample/KubernetesLoadSample.csproj"
WORKDIR "/src/KubernetesLoadSample"
COPY . .
RUN dotnet build "KubernetesLoadSample.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "KubernetesLoadSample.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "KubernetesLoadSample.dll"]
我能够使用
在本地检查此图像PS C:\Users\user> docker run -it -p 8000:80 kubernetesloadsample:latest
info: Microsoft.Hosting.Lifetime[0]
Now listening on: http://[::]:80
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Production
info: Microsoft.Hosting.Lifetime[0]
Content root path: /app
info: KubernetesLoadSample.GreeterService[0]
Compute started // called from BloomRPC Client
客户
Client 是一个 .net 控制台应用程序,循环调用服务器
static async Task Main(string[] args)
{
var grpcServer = Environment.GetEnvironmentVariable("GRPC_SERVER");
Channel channel = new Channel($"{grpcServer}", ChannelCredentials.Insecure);
Console.WriteLine($"Sending load to port {grpcServer}");
while(true)
{
try
{
var client = new Greeter.GreeterClient(channel);
var reply = await client.SayHelloAsync(
new HelloRequest { Name = "GreeterClient" });
Console.WriteLine("result: " + reply.Message);
await Task.Delay(1000);
}
catch (Exception ex)
{
Console.WriteLine($"{DateTime.UtcNow} : tried to connect : {grpcServer} Crashed : {ex.Message}");
}
}
}
客户端的 Docker 文件:
FROM mcr.microsoft.com/dotnet/aspnet:3.1 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:3.1 AS build
WORKDIR /src
COPY ["GrpcClientConsole.csproj", "GrpcClientConsole/"]
RUN dotnet restore "GrpcClientConsole/GrpcClientConsole.csproj"
WORKDIR "/src/GrpcClientConsole"
COPY . .
RUN dotnet build "GrpcClientConsole.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "GrpcClientConsole.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "GrpcClientConsole.dll"]
和部署文件如下,
---
apiVersion: v1
kind: Namespace
metadata:
name: core-load
---
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
name: compute-server
namespace: core-load
spec:
replicas: 4
selector:
matchLabels:
app: compute-server-svc
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: compute-server-svc
spec:
containers:
- env:
image: kubernetesloadsample:latest
imagePullPolicy: Never
name: compute-server-svc
ports:
- containerPort: 80
name: grpc
resources: {}
status: {}
---
apiVersion: v1
kind: Service
metadata:
name: compute-server-svc
namespace: core-load
spec:
clusterIP: None
ports:
- name: grpc
port: 5000
targetPort: 80
protocol: TCP
selector:
app: compute-server-svc
---
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
name: compute-client
namespace: core-load
spec:
replicas: 1
selector:
matchLabels:
app: compute-client
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: compute-client
spec:
containers:
- env:
- name: GRPC_SERVER
value: compute-server-svc.core-load.svc.cluster.local:5000
image: grpc-client-console:latest
imagePullPolicy: Never
name: compute-client
resources: {}
status: {}
---
问题
客户端无法使用此计算服务器-svc.core-load.svc.cluster.local:5000 名称连接 gRPC 服务器。我也尝试过计算服务器-svc.core-load,但面临以下问题
PS E:\study\core\k8sgrpc\KubernetesLoadSample> k get pods -n core-load
NAME READY STATUS RESTARTS AGE
compute-client-bff5f666-cjwf5 1/1 Running 0 15s
compute-server-545567f589-5blkv 1/1 Running 0 15s
compute-server-545567f589-bv4r2 1/1 Running 0 15s
compute-server-545567f589-mdp2x 1/1 Running 0 15s
compute-server-545567f589-wdff5 1/1 Running 0 15s
PS E:\study\core\k8sgrpc\KubernetesLoadSample> k logs compute-client-bff5f666-cjwf5 -n core-load --tail 5
07/09/2021 17:18:35 : tried to connect : compute-server-svc.core-load.svc.cluster.local:5000 Crashed : Status(StatusCode=Unavailable, Detail="failed to connect to all addresses")
07/09/2021 17:18:35 : tried to connect : compute-server-svc.core-load.svc.cluster.local:5000 Crashed : Status(StatusCode=Unavailable, Detail="failed to connect to all addresses")
07/09/2021 17:18:35 : tried to connect : compute-server-svc.core-load.svc.cluster.local:5000 Crashed : Status(StatusCode=Unavailable, Detail="failed to connect to all addresses")
07/09/2021 17:18:35 : tried to connect : compute-server-svc.core-load.svc.cluster.local:5000 Crashed : Status(StatusCode=Unavailable, Detail="failed to connect to all addresses")
07/09/2021 17:18:35 : tried to connect : compute-server-svc.core-load.svc.cluster.local:5000 Crashed : Status(StatusCode=Unavailable, Detail="failed to connect to all addresses")
我没有从与此类似的 stackoverflow 问题中得到任何解决方案,所以我创建了这个。
谁能告诉我我错过了什么或做错了什么?
TIA
答案 0 :(得分:3)
您定义了您的服务:
clusterIP: None
用于创建无头服务。这可能是问题的原因,因此删除它可以解决您的错误。
当您创建 ClusterIP
类型的服务(这是默认类型)时,Kubernetes 会自动为该服务分配一个虚拟 IP(也称为集群 IP,正如类型所建议的),然后用于代理与 Pod 的通信由相关服务选择。
这意味着有一个“新”的 IP 地址(仅从集群内部可见),不同于分配给服务背后的 Pod(或单个 Pod)的各种 IP,然后使用某种方式路由流量对站在后面的 Pod 进行负载平衡。
如果你指定
clusterIP: None
您创建了一个无头服务。您基本上是在告诉 Kubernetes,您不希望将虚拟 IP 分配给服务。代理没有负载平衡,因为没有 IP 进行负载平衡。
相反,DNS 配置将为服务后面(选择)的每个 Pod 返回 A 记录(IP 地址)。
如果您的应用程序需要发现服务背后的每个 Pod,然后使用自己的 IP 地址做任何他们想做的事情,这会很有用。
也许是为了通过内部实现进行负载平衡,也许是因为不同的 Pod(隐藏在同一个服务之下)用于不同的事情......或者也许是因为这些 Pod 中的每一个都想发现其他 Pod(考虑多实例主Kafka 或 Zookeeper 等应用程序,例如)
我不确定您的问题到底是什么,这可能取决于该特定应用程序如何解析主机名..但是您不应该使用无头服务,除非您有必要决定哪个您要联系的 svc 选择的 Pod。
与虚拟 IP 相比,使用 DNS 循环进行负载平衡也(几乎总是)不是一个好主意。例如,每当它们重新启动时的 IP 地址),在访问它们时可能会出现网络问题......等等。
文档中有大量信息: https://kubernetes.io/docs/concepts/services-networking/service/