【问题标题】:Kubernetes: Multiple containers that have to communicate + exposed nodePortKubernetes:必须通信的多个容器+暴露的nodePort
【发布时间】:2018-06-15 09:26:51
【问题描述】:

在我的设置中,有一组最初构建为使用docker-compose 运行的容器。迁移到 Kubernetes 后,我面临以下挑战:

  1. docker-compose 设法提供某种类型的内部 DNS,允许容器通过其名称进行寻址。如何在 Kubernetes 中创建这样的网络?到目前为止我发现了什么:

    • 它们都可以是一个 pod 的一部分,因此通过 localhost 进行通信
    • 它们都可以有一个带有匹配键值对和服务的通用标签,但是如何处理端口?
  2. 我需要向某个 NodePort 公开一个内部端口,因为它必须公开可用。这样的服务配置如何?到目前为止我发现了什么:

    • 类似这样的:

      apiVersion: v1
      kind: Service
      metadata:
        labels:
          app: frontend
        name: frontend-nodeport
      spec:
        type: NodePort
        ports:
        - name: "3000-30001"
          port: 3000
          nodePort: 30001
        selector:
          app: frontend
      status:
        loadBalancer: {}`
      

【问题讨论】:

  • 1- pod 的想法是运行多个相互依赖的容器,如果其中一个容器失败,则整个应用程序将失败,如果您的容器是这样的,则包含它们在同一个吊舱中。通信可以是本地主机或共享卷。 2-您可以创建 nodeport 服务,并且您将能够访问其中一个 Pod(带有标签),其中一个存在于您使用 clusterIP 与之通信的节点中,否则请求将被丢弃。将您的问题分开,并更具体地说明您需要什么

标签: kubernetes


【解决方案1】:

Docker-compose 设法提供某种类型的内部 DNS,允许容器通过其名称来寻址。如何在 Kubernetes 中创建这样的网络?

根据您的研究,您确实可以有两种方法:

  • 如果您的容器将被一起缩放,然后将它们放在同一个 pod 中,并通过 localhost 通过不同的端口进行通信。这不太可能是您的情况,因为当容器化应用程序更类似于一个物理盒子上的进程而不是单独的服务/服务器时,这种方法更适合。

  • 如果您的容器要单独缩放,这很可能是您的情况,然后使用服务。使用服务,代替 localhost(在前一点),如果跨命名空间访问服务,您将只使用服务名称(如果 pod 位于同一命名空间中)或 FQDN (servicename.namespace.svc.cluster.local)。与之前您必须为容器使用不同端口(因为您使用本地主机地址)相反,在这种情况下,您可以在多个服务中使用相同的端口,因为 service:port 必须是唯一的。如果您愿意,还可以通过服务重新映射容器中的端口。

既然您将这个问题作为一个介绍性问题提出,请注意两点:

  • 服务解析从 pod/container 的角度工作。要对其进行测试,您实际上需要执行到实际容器(或来自主机的代理)中,这是常见的混淆点。只是为了安全测试服务:实际容器中的端口可访问性,而不是来自主容器。
  • 最后,只是为了模拟容器间网络的 docker-compose 设置,您不需要公开 NodePort 或其他任何东西。 Kubernetes 中的服务层将负责 DNS 处理。 NodePort 有不同的意图。

我需要向某个 NodePort 公开一个内部端口。这样的服务配置如何?

您的工作进展顺利,这里是 nice overview 帮助您入门,与您的问题相关的参考如下:

apiVersion: v1
kind: Service
metadata:  
  name: my-nodeport-service
selector:    
  app: my-app
spec:
  type: NodePort
  ports:  
  - name: http
    port: 80
    targetPort: 80
    nodePort: 30036
    protocol: TCP

编辑:您能否提供一个示例,说明如果容器单独缩放,service.yaml 会是什么样子?

  • 第一个是,比如说,api server,我们称它为svc-my-api,它将使用标记为app: my-api 的 pod,并与 pod 的 80 端口通信,并且其他 pod 可以访问(在同一个命名空间中) ) 作为主机:svc-my-api 和端口:8080

    apiVersion: v1
    kind: Service
    metadata:
      name: svc-my-api
      labels:
        app: my-api
    spec:
      selector:
        app: my-api
      ports:
      - protocol: TCP
        port: 8080
        targetPort: 80
    
  • 第二个是 mysql 服务器,我们称之为svc-my-database。假设来自 api pod 的容器(被之前的服务覆盖)想要访问数据库,它们将使用 host:svc-my-database 和 port:3306

    apiVersion: v1
    kind: Service
    metadata:
      name: svc-my-database
      labels:
        app: my-database
    spec:
      selector:
        app: my-database
      ports:
      - name: http
        protocol: TCP
        port: 3306
        targetPort: 3306
    

【讨论】:

  • 非常感谢。到目前为止,选择器位于 .spec.selector。那和你的 .selector 方法有什么区别?
  • 您能否提供一个示例,说明如果容器单独缩放,service.yaml 会是什么样子?
  • 不错的选择器。坦率地说,我没有注意选择器在规范之外,因为我只是按原样记录提供的链接中的相关定义(不要只留下可能在 SO 答案中过时的链接)。据我在 Kubernetes 中的理解,它旨在在规范中使用选择器(根据 API 和 k8s 文档)。我们所有的服务都在规范中使用选择器。
  • 我还根据要求添加了示例来回答,这次是在规范中使用选择器(这是从我们的清单中修改的)。
【解决方案2】:

1.- 您可以将一些参数添加到您的 pod 资源(或任何其他将要创建 pod)中,如下所示:

...
spec:
  hostname: foo-{1..4}        #keep in mind this line
  subdomain: bar              #and this line
  containers:
  - image: busybox
...

注意:假设您刚刚创建了 4 个 pod,主机名为 foo-1, foo-2, foo-3 and foo-4。这些是单独的 pod。你不能做 foo-{1..4}。所以这只是为了演示目的。

如果您现在创建一个与 子域同名 的服务,您将能够通过hostname.service-name.namespace.svc.cluster.local 从集群中的任何位置访问 pod。

例子:

apiVersion: v1
kind: Service
metadata:
  name: bar     #my subdomain is called "bar", so is this service
spec:
  selector:
    app: my-app
  ports:
  - name: foo
    port: 1234
    targetPort: 1234

现在,假设我的 pod 中有标签 app: my-app,因此服务正确地定位了它们。

此时,看看会发生什么(从集群内的任何 pod):

/ # nslookup foo-1.bar.my-namespace.svc.cluster.local
Server:    10.63.240.10
Address 1: 10.63.240.10 kube-dns.kube-system.svc.cluster.local

Name:      foo-1.bar.my-namespace.svc.cluster.local
Address 1: 10.60.1.24 foo-1.bar.my-namespace.svc.cluster.local

2.- 你问题的第二部分几乎是正确的。这是一个 NodePort 服务:

apiVersion: v1
kind: Service
metadata:
  name: svc-nodeport
spec:
  ports:
  - port: 80
    targetPort: 8080
    protocol: TCP
    name: http
  selector:
    app: my-app
  type: NodePort

此服务在端口 80 上运行,因此可以从集群内通过端口 80 访问它。它将端口映射到节点上超过 30000 的随机端口。现在,同样的服务在来自外部世界的节点的端口 30001(例如)上可用。最后将请求转发到容器的8080端口。

【讨论】:

  • 您不必创建与子域同名的服务,就可以通过 FQDN 从集群中的任何位置访问 pod。服务和 pod 是通过标签/选择器绑定的,对于服务,您可以获得格式为 (my-svc.my-namespace.svc.cluster.local) 的 FQDN。但是,如果您希望 Pod 也具有可选的 FQDN,那么您可以为 pod 定义可选的子域(与服务无关),并使 pod 也可以通过它自己的 FQDN 可见。
猜你喜欢
  • 2018-05-22
  • 2019-02-17
  • 1970-01-01
  • 1970-01-01
  • 2021-06-26
  • 2020-06-18
  • 2021-10-18
  • 2019-06-20
  • 2021-08-03
相关资源
最近更新 更多