您好,登錄后才能下訂單哦!
這篇文章主要講解了“如何使用Envoy作為前端代理”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“如何使用Envoy作為前端代理”吧!
在本例中一共部署了3個(gè)容器:
front-envoy 容器作為 API 網(wǎng)關(guān),所有的入向請(qǐng)求都通過(guò) front-envoy 容器進(jìn)行路由。front-envoy 容器暴露了 8080,8443 端口分別來(lái)接受 HTTP,HTTPS 請(qǐng)求,并根據(jù)路徑分別將它們路由到對(duì)應(yīng)的服務(wù)上,以及通過(guò) 8001 端口來(lái)接受 Envoy 自帶的 admin 服務(wù)。
分別部署 service1 和 service2 兩個(gè)Flask 應(yīng)用程序,在該容器中啟動(dòng) Envoy 服務(wù), 通過(guò) loopback 地址將請(qǐng)求路由到 Flask 應(yīng)用程序。
service1 和 service2 都使用相同的代碼啟動(dòng) Flask 服務(wù),通過(guò) SERVICE_NAME 這個(gè)環(huán)境變量在訪問(wèn)的時(shí)候可以區(qū)分服務(wù)是 service1 還是 service2 。
# service.py from flask import Flask from flask import request import os import requests import socket import sys app = Flask(__name__) @app.route('/service/<service_number>') def hello(service_number): return ('Hello from behind Envoy (service {})! hostname: {} resolved' 'hostname: {}\n'.format(os.environ['SERVICE_NAME'], socket.gethostname(), socket.gethostbyname(socket.gethostname()))) if __name__ == "__main__": app.run(host='127.0.0.1', port=8080, debug=True)
在 service1 和 service2 容器中還啟動(dòng)了 envoy 服務(wù),外部客戶(hù)端(本例中是 front-envoy 容器)訪問(wèn) service1 和 service2 時(shí)是去訪問(wèn) envoy , 然后由 envoy 通過(guò) loopback 地址 將請(qǐng)求路由到 Flask 應(yīng)用程序。
# service-envoy.yaml static_resources: #定義靜態(tài)資源 listeners: #監(jiān)聽(tīng)器 - address: socket_address: address: 0.0.0.0 #envoy監(jiān)聽(tīng)地址 port_value: 8000 #envoy監(jiān)聽(tīng)端口號(hào) filter_chains: - filters: - name: cr7_filters #自定義filters的名字 typed_config: #https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager codec_type: auto #默認(rèn)配置,connection manager 使用的編解碼器,自動(dòng)適配HTTP/1.1和HTTP/2 stat_prefix: ingress_http #connection manager 發(fā)出統(tǒng)計(jì)信息時(shí)使用的前綴 route_config: #靜態(tài)配置路由管理,可選參數(shù)有3個(gè):rds(通過(guò)RDS API動(dòng)態(tài)加載),route_config(靜態(tài)),scoped_routes(根據(jù)請(qǐng)求參數(shù)匹配路) name: cr7_route #自定義路由配置名稱(chēng) virtual_hosts: #定義一組虛擬主機(jī) - name: cr7_service #自定義虛擬主機(jī)名稱(chēng) domains: #匹配所有域名 - "*" routes: - match: prefix: "/service" #匹配的URI路徑 route: cluster: cr7_cluster #上游集群名稱(chēng) http_filters: - name: envoy.filters.http.router #實(shí)現(xiàn)HTTP轉(zhuǎn)發(fā) # - name: cr7-router # typed_config: # "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router clusters: - name: cr7_cluster #自定義上游集群名稱(chēng) connect_timeout: 0.25s #新連接到上游集群主機(jī)的超時(shí)時(shí)間 #https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/cluster/v3/cluster.proto#envoy-v3-api-enum-config-cluster-v3-cluster-discoverytype type: strict_dns #服務(wù)發(fā)現(xiàn)機(jī)制:通過(guò)域名解析 lb_policy: round_robin #負(fù)載均衡策略 load_assignment: #設(shè)置負(fù)載均衡的成員, 取代了V2 API中的hosts字段 cluster_name: cr7_upstream endpoints: - lb_endpoints: - endpoint: address: socket_address: address: 127.0.0.1 #通過(guò)loopback轉(zhuǎn)發(fā)給本地flask服務(wù) port_value: 8080 #https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/bootstrap/v3/bootstrap.proto.html?highlight=access_log_path#envoy-v3-api-msg-config-bootstrap-v3-admin admin: #envoy管理接口 access_log_path: "/tmp/access.log" address: socket_address: address: 0.0.0.0 port_value: 8001
service1 和 service2 容器啟動(dòng)腳本:首先啟動(dòng)Flask 服務(wù),然后啟動(dòng) envoy 服務(wù)。
# start_service.sh #!/bin/sh python3 /code/service.py & envoy -c /etc/service-envoy.yaml --service-cluster "service${SERVICE_NAME}"
#Dockerfile-service FROM envoyproxy/envoy-alpine-dev:latest RUN apk update && apk add py3-pip bash curl RUN pip3 install -q Flask==0.11.1 requests==2.18.4 RUN mkdir /code ADD ./service.py /code ADD ./start_service.sh /usr/local/bin/start_service.sh RUN chmod u+x /usr/local/bin/start_service.sh ENTRYPOINT ["/bin/sh", "/usr/local/bin/start_service.sh"]
front-envoy 容器中只有 envoy 服務(wù), 負(fù)責(zé)接收所有入訪的流量,并且根據(jù)URI請(qǐng)求路徑分發(fā)給service1 或者 service2 。另外還配置了 HTTPS 加密,生成了證書(shū)和私鑰。
# front-envoy.yaml static_resources: listeners: - address: socket_address: address: 0.0.0.0 port_value: 8080 filter_chains: - filters: - name: envoy.filters.network.http_connection_manager typed_config: "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager codec_type: auto stat_prefix: ingress_http route_config: name: local_route virtual_hosts: - name: backend domains: - "*" routes: - match: prefix: "/service/1" route: cluster: service1 - match: prefix: "/service/2" route: cluster: service2 http_filters: - name: envoy.filters.http.router typed_config: {} - address: socket_address: address: 0.0.0.0 port_value: 8443 filter_chains: - filters: - name: envoy.filters.network.http_connection_manager typed_config: "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager codec_type: auto stat_prefix: ingress_http route_config: name: local_route virtual_hosts: - name: backend domains: - "*" routes: - match: prefix: "/service/1" route: cluster: service1 - match: prefix: "/service/2" route: cluster: service2 http_filters: - name: envoy.filters.http.router typed_config: {} transport_socket: name: envoy.transport_sockets.tls typed_config: "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext common_tls_context: tls_certificates: # The following self-signed certificate pair is generated using: # $ openssl req -x509 -newkey rsa:2048 -keyout a/front-proxy-key.pem -out a/front-proxy-crt.pem -days 3650 -nodes -subj '/CN=front-envoy' # # Instead of feeding it as an inline_string, certificate pair can also be fed to Envoy # via filename. Reference: https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/base.proto#config-core-v3-datasource. # # Or in a dynamic configuration scenario, certificate pair can be fetched remotely via # Secret Discovery Service (SDS). Reference: https://www.envoyproxy.io/docs/envoy/latest/configuration/security/secret. certificate_chain: inline_string: | -----BEGIN CERTIFICATE----- MIICqDCCAZACCQCquzpHNpqBcDANBgkqhkiG9w0BAQsFADAWMRQwEgYDVQQDDAtm cm9udC1lbnZveTAeFw0yMDA3MDgwMTMxNDZaFw0zMDA3MDYwMTMxNDZaMBYxFDAS BgNVBAMMC2Zyb250LWVudm95MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC AQEAthnYkqVQBX+Wg7aQWyCCb87hBce1hAFhbRM8Y9dQTqxoMXZiA2n8G089hUou oQpEdJgitXVS6YMFPFUUWfwcqxYAynLK4X5im26Yfa1eO8La8sZUS+4Bjao1gF5/ VJxSEo2yZ7fFBo8M4E44ZehIIocipCRS+YZehFs6dmHoq/MGvh3eAHIa+O9xssPt ofFcQMR8rwBHVbKy484O10tNCouX4yUkyQXqCRy6HRu7kSjOjNKSGtjfG+h6M8bh 10W7ZrsJ1hWhzBulSaMZaUY3vh6ngpws1JATQVSK1Jm/dmMRciwlTK7KfzgxHlSX 58ENpS7yPTISkEICcLbXkkKGEQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQCmj6Hg vwOxWz0xu+6fSfRL6PGJUGq6wghCfUvjfwZ7zppDUqU47fk+yqPIOzuGZMdAqi7N v1DXkeO4A3hnMD22Rlqt25vfogAaZVToBeQxCPd/ALBLFrvLUFYuSlS3zXSBpQqQ Ny2IKFYsMllz5RSROONHBjaJOn5OwqenJ91MPmTAG7ujXKN6INSBM0PjX9Jy4Xb9 zT+I85jRDQHnTFce1WICBDCYidTIvJtdSSokGSuy4/xyxAAc/BpZAfOjBQ4G1QRe 9XwOi790LyNUYFJVyeOvNJwveloWuPLHb9idmY5YABwikUY6QNcXwyHTbRCkPB2I m+/R4XnmL4cKQ+5Z -----END CERTIFICATE----- private_key: inline_string: | -----BEGIN PRIVATE KEY----- MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC2GdiSpVAFf5aD tpBbIIJvzuEFx7WEAWFtEzxj11BOrGgxdmIDafwbTz2FSi6hCkR0mCK1dVLpgwU8 VRRZ/ByrFgDKcsrhfmKbbph9rV47wtryxlRL7gGNqjWAXn9UnFISjbJnt8UGjwzg Tjhl6EgihyKkJFL5hl6EWzp2Yeir8wa+HZ4Achr473Gyw+2h8VxAxHyvAEdVsrLj zg7XS00Ki5fjJSTJBeoJHLodG7uRKM6M0pIa2N8b6HkzxuHXRbtmuwnWFaHMG6VJ oxlpRje+HmeCnCzUkBNBVIrUmb92YxFyLCVMrsp/ODEeVJfnwQ2lLvI9MhKQQgJw tteSQoYRAgMBAAECggEAeDGdEkYNCGQLe8pvg8Z0ccoSGpeTxpqGrNEKhjfi6NrB NwyVav10iq4FxEmPd3nobzDPkAftfvWc6hKaCT7vyTkPspCMOsQJ39/ixOk+jqFx lNa1YxyoZ9IV2DIHR1iaj2Z5gB367PZUoGTgstrbafbaNY9IOSyojCIO935ubbcx DWwL24XAf51ez6sXnI8V5tXmrFlNXhbhJdH8iIxNyM45HrnlUlOk0lCK4gmLJjy9 10IS2H2Wh4M5zsTpihH1JvM56oAH1ahrhMXs/rVFXXkg50yD1KV+HQiEbglYKUxO eMYtfaY9i2CuLwhDnWp3oxP3HfgQQhD09OEN3e0IlQKBgQDZ/3poG9TiMZSjfKqL xnCABMXGVQsfFWNC8THoW6RRx5Rqi8q08yJrmhCu32YKvccsOljDQJQQJdQO1g09 e/adJmCnTrqxNtjPkX9txV23Lp6Ak7emjiQ5ICu7iWxrcO3zf7hmKtj7z+av8sjO mDI7NkX5vnlE74nztBEjp3eC0wKBgQDV2GeJV028RW3b/QyP3Gwmax2+cKLR9PKR nJnmO5bxAT0nQ3xuJEAqMIss/Rfb/macWc2N/6CWJCRT6a2vgy6xBW+bqG6RdQMB xEZXFZl+sSKhXPkc5Wjb4lQ14YWyRPrTjMlwez3k4UolIJhJmwl+D7OkMRrOUERO EtUvc7odCwKBgBi+nhdZKWXveM7B5N3uzXBKmmRz3MpPdC/yDtcwJ8u8msUpTv4R JxQNrd0bsIqBli0YBmFLYEMg+BwjAee7vXeDFq+HCTv6XMva2RsNryCO4yD3I359 XfE6DJzB8ZOUgv4Dvluie3TB2Y6ZQV/p+LGt7G13yG4hvofyJYvlg3RPAoGAcjDg +OH5zLN2eqah8qBN0CYa9/rFt0AJ19+7/smLTJ7QvQq4g0gwS1couplcCEnNGWiK 72y1n/ckvvplmPeAE19HveMvR9UoCeV5ej86fACy8V/oVpnaaLBvL2aCMjPLjPP9 DWeCIZp8MV86cvOrGfngf6kJG2qZTueXl4NAuwkCgYEArKkhlZVXjwBoVvtHYmN2 o+F6cGMlRJTLhNc391WApsgDZfTZSdeJsBsvvzS/Nc0burrufJg0wYioTlpReSy4 ohhtprnQQAddfjHP7rh3LGt+irFzhdXXQ1ybGaGM9D764KUNCXLuwdly0vzXU4HU q5sGxGrC1RECGB5Zwx2S2ZY= -----END PRIVATE KEY----- clusters: - name: service1 connect_timeout: 0.25s type: strict_dns #服務(wù)發(fā)現(xiàn)機(jī)制:通過(guò)域名解析 lb_policy: round_robin http2_protocol_options: {} load_assignment: cluster_name: service1 endpoints: - lb_endpoints: - endpoint: address: socket_address: address: service1 # 通過(guò) DNS 解析 service1 可以得到 service1 容器的 IP 地址 port_value: 8000 - name: service2 connect_timeout: 0.25s type: strict_dns lb_policy: round_robin http2_protocol_options: {} load_assignment: cluster_name: service2 endpoints: - lb_endpoints: - endpoint: address: socket_address: address: service2 port_value: 8000 admin: access_log_path: "/dev/null" address: socket_address: address: 0.0.0.0 port_value: 8001 layered_runtime: layers: - name: static_layer_0 static_layer: envoy: resource_limits: listener: example_listener_name: connection_limit: 10000
# Dockerfile-frontenvoy FROM envoyproxy/envoy-dev:latest RUN apt-get update && apt-get -q install -y \ curl COPY ./front-envoy.yaml /etc/front-envoy.yaml RUN chmod go+r /etc/front-envoy.yaml CMD ["/usr/local/bin/envoy", "-c", "/etc/front-envoy.yaml", "--service-cluster", "front-proxy"]
# docker-compose.yaml version: "3.7" services: front-envoy: build: context: . dockerfile: Dockerfile-frontenvoy networks: - envoymesh expose: - "8080" - "8443" - "8001" ports: - "8080:8080" - "8443:8443" - "8001:8001" service1: build: context: . dockerfile: Dockerfile-service volumes: - ./service-envoy.yaml:/etc/service-envoy.yaml networks: envoymesh: aliases: - service1 environment: - SERVICE_NAME=1 #通過(guò)環(huán)境變量來(lái)區(qū)分服務(wù) expose: - "8000" service2: build: context: . dockerfile: Dockerfile-service volumes: - ./service-envoy.yaml:/etc/service-envoy.yaml networks: envoymesh: aliases: - service2 environment: - SERVICE_NAME=2 expose: - "8000" networks: envoymesh: {}
確保你已安裝較新版本的 docker 和 docker-compose 。
git clone https://github.com/cr7258/envoy-lab.git
up:?jiǎn)?dòng)容器
-d: 在后臺(tái)運(yùn)行
--build:重新構(gòu)建鏡像
cd envoy-lab/front-proxy docker-compose up -d --build
查看容器:
[root@envoy ~]# docker-compose ps Name Command State Ports ----------------------------------------------------------------------------------------------------------------------------------------------- root_front-envoy_1 /docker-entrypoint.sh /usr ... Up 10000/tcp, 0.0.0.0:8001->8001/tcp, 0.0.0.0:8080->8080/tcp, 0.0.0.0:8443->8443/tcp root_service1_1 /bin/sh /usr/local/bin/sta ... Up 10000/tcp, 8000/tcp root_service2_1 /bin/sh /usr/local/bin/sta ... Up 10000/tcp, 8000/tcp
你現(xiàn)在可以通過(guò) front-envoy 向兩個(gè)服務(wù)發(fā)送請(qǐng)求。
向 service1 發(fā)請(qǐng)求:
[root@envoy ~]# curl -v localhost:8080/service/1 * About to connect() to localhost port 8080 (#0) * Trying ::1... * Connected to localhost (::1) port 8080 (#0) > GET /service/1 HTTP/1.1 > User-Agent: curl/7.29.0 > Host: localhost:8080 > Accept: */* > < HTTP/1.1 200 OK < content-type: text/html; charset=utf-8 < content-length: 89 < server: envoy < date: Mon, 15 Mar 2021 15:29:28 GMT < x-envoy-upstream-service-time: 2 < Hello from behind Envoy (service 1)! hostname: e60ba6d0671c resolvedhostname: 172.18.0.2
向 service2 發(fā)請(qǐng)求:
[root@envoy ~]# curl -v localhost:8080/service/2 * About to connect() to localhost port 8080 (#0) * Trying ::1... * Connected to localhost (::1) port 8080 (#0) > GET /service/2 HTTP/1.1 > User-Agent: curl/7.29.0 > Host: localhost:8080 > Accept: */* > < HTTP/1.1 200 OK < content-type: text/html; charset=utf-8 < content-length: 89 < server: envoy < date: Mon, 15 Mar 2021 15:29:32 GMT < x-envoy-upstream-service-time: 2 < Hello from behind Envoy (service 2)! hostname: 9727cf7b9303 resolvedhostname: 172.18.0.4 * Connection #0 to host localhost left intact
能看到,每個(gè)請(qǐng)求在發(fā)送給前端 Envoy 后被正確路由到相應(yīng)的應(yīng)用程序。
我們也可以通過(guò) HTTPS 請(qǐng)求前端 Envoy 后的服務(wù)。例如,向 service1:
[root@envoy ~]# curl https://localhost:8443/service/1 -k -v * About to connect() to localhost port 8443 (#0) * Trying ::1... * Connected to localhost (::1) port 8443 (#0) * Initializing NSS with certpath: sql:/etc/pki/nssdb * skipping SSL peer certificate verification * SSL connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 * Server certificate: * subject: CN=front-envoy * start date: 7月 08 01:31:46 2020 GMT * expire date: 7月 06 01:31:46 2030 GMT * common name: front-envoy * issuer: CN=front-envoy > GET /service/1 HTTP/1.1 > User-Agent: curl/7.29.0 > Host: localhost:8443 > Accept: */* > < HTTP/1.1 200 OK < content-type: text/html; charset=utf-8 < content-length: 89 < server: envoy < date: Mon, 15 Mar 2021 15:30:10 GMT < x-envoy-upstream-service-time: 2 < Hello from behind Envoy (service 1)! hostname: e60ba6d0671c resolvedhostname: 172.18.0.2 * Connection #0 to host localhost left intact
現(xiàn)在增加 service1 的節(jié)點(diǎn)數(shù)量來(lái)演示 Envoy 的負(fù)載均衡能力:
[root@envoy ~]# docker-compose scale service1=3 WARNING: The scale command is deprecated. Use the up command with the --scale flag instead. Starting root_service1_1 ... done Creating root_service1_2 ... done Creating root_service1_3 ... done
現(xiàn)在,如果我們多次向 service1 發(fā)送請(qǐng)求,前端 Envoy 將通過(guò) round-robin 輪詢(xún)?nèi)_(tái) service1 機(jī)器來(lái)實(shí)現(xiàn)負(fù)載均衡:
docker-compose exec -T front-envoy bash -c "\ curl -s http://localhost:8080/service/1 \ && curl -s http://localhost:8080/service/1 \ && curl -s http://localhost:8080/service/1" \ | grep Hello | grep "service 1" # 返回結(jié)果 Hello from behind Envoy (service 1)! hostname: 707d6f830af2 resolvedhostname: 172.18.0.5 Hello from behind Envoy (service 1)! hostname: 64eebf06b9db resolvedhostname: 172.18.0.6 Hello from behind Envoy (service 1)! hostname: e60ba6d0671c resolvedhostname: 172.18.0.2
當(dāng) Envoy 啟動(dòng)時(shí),也會(huì)同時(shí)啟動(dòng)一個(gè) admin 服務(wù)并綁定指定的端口。 在示例配置中 admin 綁定到了 8001 端口。
我們可以通過(guò) curl 它獲得有用的信息:
[root@envoy ~]# curl localhost:8001/stats cluster.service1.external.upstream_rq_200: 7 ... cluster.service1.membership_change: 2 cluster.service1.membership_total: 3 ... cluster.service1.upstream_cx_http2_total: 3 ... cluster.service1.upstream_rq_total: 7 ... cluster.service2.external.upstream_rq_200: 2 ... cluster.service2.membership_change: 1 cluster.service2.membership_total: 1 ... cluster.service2.upstream_cx_http2_total: 1 ... cluster.service2.upstream_rq_total: 2 ...
能看到,我們可以獲取上游集群的成員數(shù)量,它們完成的請(qǐng)求數(shù)量,有關(guān) http 入口的信息以及大量其他有用的統(tǒng)計(jì)數(shù)據(jù)。
感謝各位的閱讀,以上就是“如何使用Envoy作為前端代理”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)如何使用Envoy作為前端代理這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。