可以使用 Python 的请求访问 Elasticsearch 但不能使用官方客户端

Able to access Elasticsearch with Python's Requests but not with official client

我在 Kubernetes 上有一个 Elasticsearch DB 运行 作为 Istio 虚拟服务暴露给 my_domain.com/elastic,我可以通过浏览器访问它没有问题(因为我成功登录到端点).我还可以使用 Python 的请求查询数据库。但是如果我使用 my_domain.com/elastic,我就无法使用官方 python 客户端访问数据库。 LoadBalancer IP 即使在客户端也能完美运行。我错过了什么?我通过 Cert-Manager 和 CloudFlare 为 my_domain.com 设置了 SSL 证书。

这个有效:

import requests
import os
data = ' { "query": { "match_all": {} } }'
headers = {'Content-Type': 'application/json'}
auth= ('elastic', os.environ['ELASTIC_PASSWORD']) 
response = requests.post('https://mydomain.cloud/elastic/_search', auth=auth,  data=data, headers=headers)
print(response.text)

这行不通(我尝试了很多不同的参数):

from datetime import datetime
import os
from elasticsearch import Elasticsearch, RequestsHttpConnection


es = Elasticsearch(,
   [{'host': 'mydomain.cloud', 'port': 443, 'url_prefix': 'elastic', 'use_ssl': True}],
    http_auth=('elastic', os.environ['ELASTIC_PASSWORD']), # 1Password or kubectl get secret elastic-cluster-es-elastic-user -o go-template='{{.data.elastic | base64decode}}' -n elastic-system
    schema='https'#, verify_certs=False,
    # use_ssl=True,
    # connection_class = RequestsHttpConnection,
    # port=443,
)

# if not es.ping():
#     raise ValueError("Connection failed")

doc = {
    'author': 'kimchy',
    'text': 'Elasticsearch: cool. bonsai cool.',
    'timestamp': datetime.now(),
}
res = es.index(index="test-index", id=1, document=doc)
print(res['result'])

res = es.get(index="test-index", id=1)
print(res['_source'])

es.indices.refresh(index="test-index")

res = es.search(index="test-index", query={"match_all": {}})
print("Got %d Hits:" % res['hits']['total']['value'])
for hit in res['hits']['hits']:
    print("%(timestamp)s %(author)s: %(text)s" % hit["_source"])

产生的错误:

elasticsearch.exceptions.RequestError: RequestError(400, 'no handler found for uri [//test-index/_doc/1] and method [PUT]', 'no handler found for uri [//test-index/_doc/1] and method [PUT]') 

cluster.yaml

apiVersion: elasticsearch.k8s.elastic.co/v1
kind: Elasticsearch
metadata:
  name: elastic-cluster
  namespace: elastic-system
spec:
  version: 7.15.2
  http:
    # tls:
    #   selfSignedCertificate:
    #      disabled: true
    service:
      spec:
        type: LoadBalancer
  nodeSets:
  - name: master-nodes
    count: 2
    config:
      node.roles: ["master"]
    volumeClaimTemplates:
    - metadata:
        name: elasticsearch-data # Do not change this name unless you set up a volume mount for the data path.
      spec:
        accessModes:
        - ReadWriteOnce
        resources:
          requests:
            storage: 5Gi
        storageClassName: local-storage
  - name: data-nodes
    count: 2
    config:
      node.roles: ["data"]
    volumeClaimTemplates:
    - metadata:
        name: elasticsearch-data # Do not change this name unless you set up a volume mount for the data path.
      spec:
        accessModes:
        - ReadWriteOnce
        resources:
          requests:
            storage: 10Gi
        storageClassName: local-storage
    podTemplate:
      # metadata:
      #   annotations:
      #     traffic.sidecar.istio.io/includeInboundPorts: "*"
      #     traffic.sidecar.istio.io/excludeOutboundPorts: "9300" 
      #     traffic.sidecar.istio.io/excludeInboundPorts: "9300"
      spec:
        # automountServiceAccountToken: true
        containers:
        - name: elasticsearch
          resources:
            requests:
              memory: 4Gi
              cpu: 3
            limits:
              memory: 4Gi
              cpu: 3

虚拟-service.yaml

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: elastic-vts
  namespace: elastic-system
spec:
  hosts:
  - "mydomain.cloud"
  gateways:
  - istio-system/gateway
  http:
  - match:
    - port: 443
    - uri:
        prefix: /elastic
    rewrite:
      uri: /
    route:
    - destination:
        host: elastic-cluster-es-http.elastic-system.svc.cluster.local
        port:
          number: 9200

目的地-rule.yaml

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: elastic-destination-rule
  namespace: elastic-system
spec:
  host: elastic-cluster-es-http.elastic-system.svc.cluster.local
  trafficPolicy:
    tls:
      mode: SIMPLE

gateway.yaml

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: gateway
  namespace: istio-system
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - 'mydomain.cloud'
    tls:
      httpsRedirect: true
  - port:
      number: 443
      name: https
      protocol: HTTPS
    hosts:
      - 'mydomain.cloud'
    tls:
      mode: SIMPLE
      credentialName: letsencrypt-staging-tls
     

我已经复现了你的问题,解决方法如下。首先,注意你的yaml文件:

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: elastic-vts
  namespace: elastic-system
spec:
  hosts:
  - "mydomain.cloud"
  gateways:
  - istio-system/gateway
  http:
  - match:
    - port: 443
    - uri:
        prefix: /elastic   <---- here is the problem
    rewrite:
      uri: /
      ...

出现的错误如下所示:

elasticsearch.exceptions.RequestError: RequestError(400, 'no handler found for uri [//test-index/_doc/1] and method [PUT]', 'no handler found for uri [//test-index/_doc/1] and method [PUT]')

问题就在那里:[//test-index/_doc/1](关于重复/字符)。我认为这与提到的问题 here 类似。要解决此问题,我建议将 / 添加到 prefix: /elastic 行,您的 yaml 将类似于此示例:

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: elastic-vts
  namespace: elastic-system
spec:
  hosts:
  - "mydomain.cloud"
  gateways:
  - istio-system/gateway
  http:
  - match:
    - port: 443
    - uri:
        prefix: /elastic/ <---- here
    rewrite:
      uri: /
      ...

此时 Elastic 的答案如下:

Got 1 Hits:
2021-12-30T09:20:12.038004 kimchy: Elasticsearch: cool. bonsai cool.