在我們配置 Elasticsearh 安全的時候,我們可以考慮三個方面的東西:
- firewalls
- 反向代理 (reverse proxies)
- Elastic Security
我們可以利用 firewall 已經 IP filtering 來限制或允許特定的 IP 地址來訪問我們的 Elasticsearch。對於 OSS 的用戶來說,他們可以使用 reverse proxy 的方法來實現最基本的安全配置。當然對於 Baisic license 以上的用戶來說,我們建議使用 Elastic Security。
在今天的文章中,我將來講述如何使用 Nginx 來實現 reverse proxy 已經負載均衡。
我的配置
我的配置如下:
我在 MacOS 的機器上安裝了 Elasticsearch 及 Kibana。我在 Ubuntu 的機器上安裝了 Nginx。如果你還沒有安裝自己的 Elasticsearch 及 Kibana,請參閱我之前的文章 “Elastic:菜鳥上手指南” 進行安裝。特別值得指出的是,為了能夠使得我們的 Elasticsearch 能夠被 Niginx 所訪問,那么請修改 config/elasticsearch.yml 中的配置:
-
network.host: 0.0.0.0
-
discovery.type: single-node
一點點背景
Elasticsearch 的定義性功能之一是通過基於 HTTP的(寬松的)RESTful 服務公開。
當然,好處很容易闡明:API 對所有Web開發人員都是熟悉且可預測的。 通過 curl 命令或在瀏覽器中即可輕松使用。 使用各種編程語言編寫 API 包裝器很容易。
盡管如此,Elasticsearch 基於 HTTP 的本質的重要性已根深蒂固:以其適合於軟件開發和體系結構的現有范例的方式。
HTTP作為架構范例
典型的現代軟件或信息系統通常是松散耦合服務的集合,這些服務通過網絡(通常通過 HTTP)進行通信。在設計方面,此方法的重要方面是,你始終可以“撕裂”服務鏈,並將另一個添加或更改功能的組件插入“堆棧”。在過去,傳統上將其稱為“中間件”,但在 RESTful Web 服務的背景下又重新出現,例如 Rack中間件,特別是在 Ruby on Rails 框架中使用。
HTTP 特別適合於此類體系結構,因為它的明顯缺點(缺乏狀態,基於文本的表示形式,以 URI 為中心的語義……)變成了一個優勢:中間件都不必適應“鏈”中的特定內容,並僅傳遞狀態代碼,標題和正文。從這個意義上講,HTTP 在功能上是透明的–沒關系,例如,是否從原始 Web 服務器或其他大陸的緩存中獲取圖像。仍然是相同的“資源”。
緩存是 HTTP 這方面的一個主要示例,Roy Fielding 在 RESTful 體系結構的開創性工作中已經介紹過。 (有關該主題的詳細信息,請參閱Ryan Tomayko的《事物緩存》和Mark Nottingham的《緩存教程》。)
從技術上講,緩存在這里充當代理–它“代表”堆棧中的其他組件。
但是代理可以做的更多。認證和授權就是一個很好的例子:代理可以攔截對服務的請求,執行認證和/或授權例程,並允許或拒絕對客戶端的訪問。
這種代理通常稱為反向代理。當你認為傳統代理將從本地網絡“轉發”流量到遠程網絡(互聯網)時,此名稱有意義,因為在這里反向轉發是因為“反向”代理將來自 Internet 的請求轉發到“本地”后端。可以使用 Java 或 Go 之類的編程語言或諸如 Node.js 之類的框架來實現這種代理。或者,我們可以使用可配置的網絡服務器,例如 Nginx。
Nginx
Nginx 是最初由 Igor Sysoev 編寫的開源 Web 服務器,專注於高性能,並發性和低內存占用。 (有關詳細的技術概述,請參見《開源應用程序體系結構》一書的相關章節。)
Nginx 從一開始就考慮到代理角色,並且支持許多相關的配置指令和選項。 在 Django 應用程序的 Ruby on Rails 前面將 Nginx 作為負載平衡器運行是相當普遍的。 許多大型 PHP 應用程序甚至將 Nginx 放在運行 mod_php 的 Apache 前面,以加速靜態內容的提供和擴展應用程序。 本文的大多數部分都假定安裝了標准的 Nginx,但是高級部分依賴於Lua 模塊來安裝 Nginx。如果你還沒有安裝自己的 Nginx,請參考我之前的文章 “Beats:使用Elastic Stack對Nginx Web服務器監控” 來進行安裝。
要將 Nginx 用作 Elasticsearch 的 “100%透明”代理,我們需要一個非常小的配置。我們直接修改 /etc/nginx/nginx.conf 文件,並修改 http 的部分如下:
/etc/nginx/nginx.conf
-
http {
-
server {
-
listen 8080;
-
location / {
-
proxy_pass http://192.168.0.3:9200;
-
}
-
}
-
}
請注意上面的 192.168.0.3 是我的 MacOS 的 IP 地址。經過這樣的設置,我們重新啟動 Niginx 服務:
sudo service nginx restart
我們可以通過如下的命令來檢查服務是否正常運行:
sudo service nginx status
-
$ sudo service nginx status
-
● nginx.service - A high performance web server and a reverse proxy server
-
Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset:>
-
Active: active (running) since Wed 2020-09-02 17:52:33 CST; 14min ago
-
Docs: man:nginx(8)
-
Process: 25616 ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; master_proc>
-
Process: 25634 ExecStart=/usr/sbin/nginx -g daemon on; master_process on; (>
-
Main PID: 25635 (nginx)
-
Tasks: 9 (limit: 18985)
-
Memory: 8.2M
-
CGroup: /system.slice/nginx.service
-
├─25635 nginx: master process /usr/sbin/nginx -g daemon on; master>
-
├─25636 nginx: worker process
-
├─25637 nginx: worker process
-
├─25638 nginx: worker process
-
├─25639 nginx: worker process
-
├─25640 nginx: worker process
-
├─25641 nginx: worker process
-
├─25642 nginx: worker process
-
└─25643 nginx: worker process
經過上面的改造后,我們可以通過如下的命令來檢查反向代理是否已經起作用了:
curl -XGET http://192.168.0.4:8080
我們在 terminal 中打入上面的命令:
-
curl -XGET http://192.168.0.4:8080
-
{
-
"name" : "liuxg",
-
"cluster_name" : "elasticsearch",
-
"cluster_uuid" : "u8tKdzFjQaOiJ5sF_d15oQ",
-
"version" : {
-
"number" : "7.9.0",
-
"build_flavor" : "default",
-
"build_type" : "tar",
-
"build_hash" : "a479a2a7fce0389512d6a9361301708b92dff667",
-
"build_date" : "2020-08-11T21:36:48.204330Z",
-
"build_snapshot" : false,
-
"lucene_version" : "8.6.0",
-
"minimum_wire_compatibility_version" : "6.8.0",
-
"minimum_index_compatibility_version" : "6.0.0-beta1"
-
},
-
"tagline" : "You Know, for Search"
-
}
顯然當我們向 Ubuntu 的 IP 地址 192.168.0.4 發送請求時,我們可以看到相應的輸出。這個請求的結果來自安裝於 IP 192.168.0.3 的 MacOS 上的 Elasticsearch。
這個代理當然是毫無用處的,它只是在客戶端和 Elasticsearch 之間移交數據。 盡管精明的讀者可能已經猜到它已經在“堆棧”中添加了一些內容,即記錄每個請求。
使用案例
在本文中,我們將介紹 Nginx 作為 Elasticsearch 的反向代理的一些更有趣的用例。
持久 HTTP 連接
讓我們從一個非常簡單的示例開始:使用 Nginx 作為代理,以保持與 Elasticsearch 的持久(“keep-alive”)連接。 為什么我們要這樣做? 主要原因是為了減輕 Elasticsearch 在使用不支持持久連接的客戶端時為每個請求打開和關閉連接的壓力。 Elasticsearch 不僅僅是處理網絡,還有更多的責任,打開/關閉連接會浪費寶貴的時間和資源(例如打開文件的限制)。
像本文中的所有示例一樣,本鏈接提供了完整的配置。我們創建如下的文件:
/etc/nginx/nginx_keep_alive.conf
-
events {
-
worker_connections 1024;
-
}
-
http {
-
upstream elasticsearch {
-
server 127.0.0.1:9200;
-
keepalive 15;
-
}
-
server {
-
listen 8080;
-
location / {
-
proxy_pass http://192.168.0.3:9200;
-
proxy_http_version 1.1;
-
proxy_set_header Connection "Keep-Alive";
-
proxy_set_header Proxy-Connection "Keep-Alive";
-
}
-
}
-
}
讓我們以如下的方法來啟動 Nginx:
-
-
/etc/nginx
-
-
$ sudo service nginx stop
-
當你直接向 Elasticsearch 執行請求時,你會注意到打開的連接數一直在增加:
-
liuxg@liuxgu :/etc/nginx$ curl 'mac:9200/_nodes/stats/http?pretty' | grep total_opened
-
% Total % Received % Xferd Average Speed Time Time Time Current
-
Dload Upload Total Spent Left Speed
-
100 753 100 753 0 0 245k 0 --:--:-- --:--:-- --:--:-- 245k
-
"total_opened" : 94
-
liuxg@liuxgu:/etc/nginx$ curl 'mac:9200/_nodes/stats/http?pretty' | grep total_opened
-
% Total % Received % Xferd Average Speed Time Time Time Current
-
Dload Upload Total Spent Left Speed
-
100 753 100 753 0 0 245k 0 --:--:-- --:--:-- --:--:-- 245k
-
"total_opened" : 95
-
liuxg@liuxgu :/etc/nginx$ curl 'mac:9200/_nodes/stats/http?pretty' | grep total_opened
-
% Total % Received % Xferd Average Speed Time Time Time Current
-
Dload Upload Total Spent Left Speed
-
100 753 100 753 0 0 367k 0 --:--:-- --:--:-- --:--:-- 367k
-
"total_opened" : 96
我們可以看到向 Elasticsearch 直接發送請求的時候,這個 total_opened 的數值是一直在增加的。但是使用 Nginx 時則完全不同,打開的連接數保持不變 (在 Ubuntu 機器發送的請求):
-
liuxg@liuxgu :/etc/nginx$ curl 'localhost:8080/_nodes/stats/http?pretty' | grep total_opened
-
% Total % Received % Xferd Average Speed Time Time Time Current
-
Dload Upload Total Spent Left Speed
-
100 753 100 753 0 0 245k 0 --:--:-- --:--:-- --:--:-- 245k
-
"total_opened" : 97
-
liuxg@liuxgu:/etc/nginx$ curl 'localhost:8080/_nodes/stats/http?pretty' | grep total_opened
-
% Total % Received % Xferd Average Speed Time Time Time Current
-
Dload Upload Total Spent Left Speed
-
100 753 100 753 0 0 367k 0 --:--:-- --:--:-- --:--:-- 367k
-
"total_opened" : 97
-
liuxg@liuxgu :/etc/nginx$ curl 'localhost:8080/_nodes/stats/http?pretty' | grep total_opened
-
% Total % Received % Xferd Average Speed Time Time Time Current
-
Dload Upload Total Spent Left Speed
-
100 753 100 753 0 0 367k 0 --:--:-- --:--:-- --:--:-- 367k
-
"total_opened" : 97
我們可以看到連接數是保持不變的。
簡單的負載均衡器
只需很小的配置更改,我們就可以使用它將請求傳遞到多個 Elasticsearch 節點,並將 Nginx 用作輕量級負載均衡器:
/etc/nginx/nginx_keep_alive.conf
-
events {
-
worker_connections 1024;
-
}
-
http {
-
upstream elasticsearch {
-
server 192.168.0.3:9200;
-
server 192.168.0.5:9200;
-
server 192.168.0.6:9200;
-
server 192.168.0.7:9200;
-
keepalive 15;
-
}
-
server {
-
listen 8080;
-
location / {
-
proxy_pass http://elasticsearch;
-
proxy_http_version 1.1;
-
proxy_set_header Connection "Keep-Alive";
-
proxy_set_header Proxy-Connection "Keep-Alive";
-
}
-
}
-
}
如你所見,我們在upstream directive 指令中添加了其它的附加節點。 Nginx 現在將以循環方式自動在這些服務器之間分配請求,從而將Elasticsearch 集群上的負載平均分配到各個節點上。在實際的使用中,我們可以以如下的方式來查詢當前使用的 Elasticsearch 節點的名稱:
-
curl localhost: 8080 | grep name
-
% Total % Received % Xferd Average Speed Time Time Time Current
-
Dload Upload Total Spent Left Speed
-
100 530 100 530 0 0 172k 0 --:--:-- --:--:-- --:--:-- 172k
-
"name" : "liuxg",
-
"cluster_name" : "elasticsearch",
上面顯示我的節點的名稱為 liuxg。如果我們有多個節點,我們可以重復使用上面的命令,我們將看到有不同的節點返回結果,就像下面的顯示一樣:
這是一種理想的行為,因為它防止命中單個“熱”節點,該節點必須執行常規節點職責,還路由所有流量並執行所有其他關聯的操作。 要更改配置,我們只需要更新 upstream directive 中的服務器列表,並向 Nginx 發送一個重載信號即可。
有關 Nginx 負載平衡功能的更多信息,包括不同的平衡策略,為不同的節點設置“權重”,運行狀況檢查和實時監控,請參閱使用NGINX和NGINX Plus進行負載平衡。
(請注意,正式的 Elasticsearch 客戶端可以自行執行這種負載平衡,並具有自動重新加載集群中節點列表,在另一個節點上重試請求等功能)。
結論
在本文中,我們充分利用了 Elasticsearch 是通過 HTTP 公開的服務這一事實。 我們已經看到 HTTP 在概念上如何很好地適合於將軟件體系結構設計為獨立的,分離的服務的當前范例,以及如何將 Nginx 用作高性能,可定制的代理。