【问题标题】:How to make a request from a Flask API in a Kubernetes Namespace to another Flask API in another namespace internally (Using the DNS) using minikube如何使用 minikube 在内部(使用 DNS)从 Kubernetes 命名空间中的 Flask API 向另一个命名空间中的另一个 Flask API 发出请求
【发布时间】:2020-05-04 19:04:00
【问题描述】:

我读到我需要在命名空间 B 中运行另一个服务,该服务映射到命名空间 A 负载平衡器服务。 (你可以在我的 yaml b 上看到这个服务)。

我不想使用负载均衡器提供的外部 IP(如果我的场景是使用 GCP/Azure/AWS/IBM 云/OpenShift 在云上复制的)。

我使用 minikube v1.6.2Kubernetes v1.17 部署了下一个场景:

命名空间a:

deployment/python-hello-world  READY: 1/1

service/python-hello-world  
TYPE: Loadbalancer CLUSTER-IP: 10.96.167.227 EXT-IP: <pending> PORTS: 80:31603/TCP

命名空间 b:

deployment/python-hello-world  READY: 1/1

service/python-hello-world  
TYPE: Loadbalancer CLUSTER-IP: 10.96.67.10 EXT-IP: <pending> PORTS: 80:31595/TCP

service/connection 
TYPE: ExternalName CLUSTER-IP: <none> EXTERNAL-IP: python-hello-world-external.a.svc.cluster.local PORT: 31603/TCP

Kubernetes yaml a

apiVersion: apps/v1
kind: Deployment
metadata:
  name: python-hello-world
  namespace: a
spec:
  replicas: 1
  selector:
    matchLabels:
      app: python-hello-world
  template:
    metadata:
      labels:
        app: python-hello-world
    spec:
      containers:
      - name: server
        image: python-hello-world
        ports:
        - containerPort: 9090
        env:
        - name: PORT
          value: "9090"

---

apiVersion: v1
kind: Service
metadata:
  name: python-hello-world-external
  namespace: a
spec:
  type: LoadBalancer
  selector:
    app: python-hello-world
  ports:
  - name: http
    port: 80
    targetPort: 9090

Kubernetes yaml b

apiVersion: apps/v1
kind: Deployment
metadata:
  name: python-hello-world
  namespace: b
spec:
  replicas: 1
  selector:
    matchLabels:
      app: python-hello-world
  template:
    metadata:
      labels:
        app: python-hello-world
    spec:
      containers:
      - name: server
        image: python-hello-world
        ports:
        - containerPort: 9091
        env:
        - name: PORT
          value: "9091"

---

apiVersion: v1
kind: Service
metadata:
  name: python-hello-world-external
  namespace: b
spec:
  type: LoadBalancer
  selector:
    app: python-hello-world
  ports:
  - name: http
    port: 80
    targetPort: 9091

---

apiVersion: v1
kind: Service
metadata:
  name: connection
  namespace: b
spec:
  type: ExternalName
  externalName: python-hello-world-external.a.svc.cluster.local
  ports:
  - port: 31603

为了在我的浏览器中访问 API A,我在终端中运行:

$ minikube service python-hello-world-external -n a
|-----------|-----------------------------|-------------|-----------------------------|
| NAMESPACE |            NAME             | TARGET PORT |             URL             |
|-----------|-----------------------------|-------------|-----------------------------|
| a         | python-hello-world-external | http        | http://192.168.39.196:31603 |
|-----------|-----------------------------|-------------|-----------------------------|

用于访问 API B:

$ minikube service python-hello-world-external -n b
|-----------|-----------------------------|-------------|-----------------------------|
| NAMESPACE |            NAME             | TARGET PORT |             URL             |
|-----------|-----------------------------|-------------|-----------------------------|
| b         | python-hello-world-external | http        | http://192.168.39.196:31595 |
|-----------|-----------------------------|-------------|-----------------------------|

Flask API A

from flask import Flask

app = Flask(__name__)

@app.route('/')
def index():
    return "Hello World A"

if __name__ == '__main__':
    app.run(debug=False, port=9090, host='0.0.0.0')

Flask API B

import requests
from flask import Flask

app = Flask(__name__)

@app.route('/a')
def call_a():
    response = requests.get("I DONT KNOW WHAT TO PUT HERE")
    return response

if __name__ == '__main__':
    app.run(debug=False, port=9091, host='0.0.0.0') 
  1. 是否可以使用 minikube 在内部发送请求?
  2. 如果是这样,我的配置中是否缺少某些内容?
  3. 如果是这样,我应该在 requests.get("") 中写什么 URL?

【问题讨论】:

  • 如果您不希望从 API A 到 API B 的请求不通过负载均衡器,那么您需要一个不是 type: LoadBalancer 的服务(例如 clusterIP)。您可以使用&lt;service_name&gt;.&lt;namespace&gt; 格式访问您的服务
  • 您是否阅读过 Kubernetes 文档中的Connecting Applications with Services 和相关页面?您可以使用 Kubernetes 提供的 DNS 名称从一个 Pod 连接到一个服务(并从那里连接到另一个 Pod),它不会通过外部负载均衡器。

标签: python docker flask kubernetes minikube


【解决方案1】:

正如人们在 cmets 中已经建议的那样,LoadBalancer 并不是这里的最佳选择。实际上它有完全不同的目的,即它用于将您的应用程序暴露在外部,顺便说一下,这在 Minikube 中不起作用(而是创建了简单的NodePort 服务)。要使用功能齐全的LoadBalancer,您需要使用一些云提供商的服务。 GCP、AWS 或 Azure 等所有主要参与者都支持此功能。可能您决定使用LoadBalancer 来实现负载均衡器功能,但不用担心,简单的ClusterIP 也可以做到这一点。如果你有 3 个前端 Pods(通常由 Deployment 管理)并且他们需要与其他 3 个提供后端服务的 Pods 通信,简单的 ClusterIPService(你可以省略类型,因为这是默认类型)将完成这项工作,包括对所有底层后端Pods 的请求进行适当的负载平衡。正如@David Maze 建议的那样,熟悉Kubernetes 官方文档 中的this 文章,您应该可以轻松掌握整个概念。

Here 你可以在一个非常相似的主题上找到我的旧答案之一。我想您可能会发现它很有用,因为它详细解释了如何在 Kubernetes 集群 内完成不同 Pods 集(代表应用程序架构中的不同 microservices)之间的通信。

对于位于不同命名空间中的资源之间的通信,也可以在 Kubernetes 中使用@jordanm 建议的简写形式轻松完成:&lt;service_name&gt;.&lt;namespace&gt; 或完全限定域名&lt;service-name&gt;.&lt;namespace-name&gt;.svc.cluster.local(甚至更多推荐的)。更多详情您可以找到here

当您创建 服务 时,它会创建相应的 DNS 条目。这 条目的形式 &lt;service-name&gt;.&lt;namespace-name&gt;.svc.cluster.local,表示如果 一个容器只使用&lt;service-name&gt;,它将解析到服务 这是命名空间的本地。这对于使用相同的 跨多个命名空间的配置,例如 Development、Staging 和生产。如果你想跨命名空间,你需要 使用完全限定域名 (FQDN)。

【讨论】:

    【解决方案2】:

    这是从第二个 API 服务访问 1 个 API 服务但在同一命名空间内的 1 个示例。也许它可以提供帮助。

    按照以下方式在 Python 中创建您的 2 个 API 服务器,并在我的 Minikube 上进行了尝试和测试。在 Kubernetes 中托管第一个作为 ClusterIp 服务。使用 NodePort 托管第二个以访问 Minikube 集群外部。

    第一个服务是使用它在第二个服务中的 ClusterIp 访问的,如下面的 Python 代码所示,我尝试使用服务名称访问但没有成功。


    这是第一个烧瓶 api 服务器(.py 文件),它将在第二个烧瓶 api 服务器中调用:

    import flask
    from flask import Flask
    import json
    from flask import request
    
    
    application = Flask(__name__)
    
    
    @application.route('/api/v1/square', methods=['GET'])
    def square():
        # sample api call: http://0.0.0.0:8003/api/v1/square?nb1=11
        nb1 = request.args.get('nb1')
        sq_nb1 = int(nb1)*int(nb1)
        return flask.jsonify(sq_nb1)
    
    
    if __name__ == '__main__':
        application.run(debug=True, host="0.0.0.0", port=8003)
    

    第二个 API 服务器(.py 文件)调用 Kubernetes 中托管为 ClusterIP 的第一个 API 服务器

    import flask
    from flask import Flask
    import json
    from flask import request
    import requests
    
    
    application = Flask(__name__)
    
    
    @application.route('/api/v1/sumsq', methods=['GET'])
    def sumSq():
        # sample api call: http://0.0.0.0:8002/api/v1/sumsq?nb1=111&nb2=222
        nb1 = request.args.get('nb1')
        nb2 = request.args.get('nb2')
        sum_val = int(nb1) + int(nb2)
    
        #  call square micro-service (Svc: 3-Internal-API-Server)
        api_url = "http://10.96.55.98/api/v1/square?nb1={v}".format(v=sum_val)
        # get IP using 'kubectl get svc -n <ns_name>' command
    
        res = requests.get(url=api_url)
        sum_sq_val = res.json()
        return flask.jsonify(sum_sq_val)
    
    
    if __name__ == '__main__':
        application.run(debug=True, host="0.0.0.0", port=8002)
    

    【讨论】:

      猜你喜欢
      • 2014-09-06
      • 1970-01-01
      • 2022-11-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-03
      • 1970-01-01
      相关资源
      最近更新 更多