使用Nginx和IP共享创建冗余负载均衡器(Akamai)

首先

本文介绍了使用HAProxy实现冗余的文章,但是在本文中,我们将介绍使用Nginx作为冗余负载均衡器的情况。

 

本文的结构

nginx-lb-complete.jpg
    • IP Sharing がサポートされている Chicago Region を利用

 

    • Linode インスタンスの Distribution は Ubuntu 22.04 LTS で構成

 

    • Nginx が動くロードバランサー層と Web サーバが動く Web 層を構成

 

    • Nginx をロードバランサーとして構成

 

    • 2 台の Nginx サーバーの Public IP をIP Sharingにて Active/Standby 構成

 

    • Web 層は 2 台構成。Web 層も Nginx で構成。

 

    • ロードバランサー層と Web 層は Private IP で接続

 

    • Nginx サーバーは証明書を取得し、TLS にてクライアントから通信を処理

 

    • 負荷分散方式はラウンドロビン、および Nginx の ip_hash 機能でバランシング (sticky は未使用)

 

    • それぞれの Linode インスタンスに Cloud Firewall を適用

 

    • IP Sharing は lelastic で構成

 

    (オプション)AkamaiのWeb Secuirty/CDNサービス(Akamai Connected Cloud)を適用の際、Cloud Firewall へ Site Shield の IP アドレスリストを適用

/等等/主机

XXX.XXX.XXX.1  ord-nginx1 # Loadbalancer 1
XXX.XXX.XXX.2  ord-nginx2 # Loadbalancer 2
XXX.XXX.XXX.119  ord-nginx # Shared IP for Loadbalancer 1/2
192.XXX.XXX.101	ord-web1  # Web 1 Private IP
192.XXX.XXX.102	ord-web2  # Web 2 Private IP

共享IP+.

IP Sharing 在 Akamai 提供的云服务中是实现 IP 故障切换的重要功能。有关详细信息,请参考下面的文章。

 

简言之,对于Public IP的故障转移有两种方式,截至撰写时点,东京(Tokyo)支持旧的ARP方式,而其他许多站点则支持新的BGP方式。东京将计划进行网络升级,并最终使用BGP方式。请参阅下方页面获取每个数据中心的支持情况。

 

本文将说明如何使用支持BGP的数据中心进行故障切换的方法。

创建Web1

create-web1-2.jpg
可以随时添加私有IP。

参照以下页面,创建基本布局。

 

关于二进制文件,您可以使用 Linux 发行版存储库中提供的预编译二进制文件,这是最简单的选项。

apt install nginx
如果要使用会话粘性(stickey)功能,请从源代码进行编译。
ord-nginx1:~# nginx -v
nginx version: nginx/1.18.0 (Ubuntu)

我将进行动作确认。

ord-nginx1 # curl -I 127.0.0.1
HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)
Date: Fri, 21 Jul 2023 09:18:32 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Fri, 21 Jul 2023 05:22:40 GMT
Connection: keep-alive
ETag: "64ba1620-264"
Accept-Ranges: bytes
web1-nginx-plain.jpg

配置文件是/etc/nginx/nginx.conf,文档根目录是/var/www/html/。

TLS设置

请参考以下页面上关于 TLS 的设置方法。

 

这次我们将按照以下页面上的步骤来使用 certbot 进行创建。

 

在Linux环境中安装UFW。

将来使用云防火墙进行更详细的控制,但也会在Linux实例内进行设置。

sudo apt update
sudo apt install ufw
sudo ufw allow ssh
sudo ufw allow http
sudo ufw allow https
sudo ufw enable

安装snapd

安装包管理器snap。snap是用于打包的certbot将在此之后安装。

apt install snapd
snap install core
snap refresh core

Certbot的安装

sudo apt remove certbot
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot

使用 Certbot 创建 TLS/SSL证书

使用以下命令可以自动设置Nginx配置,非常方便。

certbot --nginx

需要输入一些内容。以下是输入示例。

ord-nginx1# certbot --nginx
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Enter email address (used for urgent renewal and security notices)
 (Enter 'c' to cancel): {my_account}@foo.com

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.3-September-21-2022.pdf. You must
agree in order to register with the ACME server. Do you agree?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: Y

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Would you be willing, once your first certificate is successfully issued, to
share your email address with the Electronic Frontier Foundation, a founding
partner of the Let's Encrypt project and the non-profit organization that
develops Certbot? We'd like to send you email about our work encrypting the web,
EFF news, campaigns, and ways to support digital freedom.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: Y
Account registered.
Please enter the domain name(s) you would like on your certificate (comma and/or
space separated) (Enter 'c' to cancel): nginx-ha.{mydoman_name}
Requesting a certificate for nginx-ha.{mydomain_name}

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/nginx-ha.{mydomain_name}/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/nginx-ha.{mydomain_name}/privkey.pem
This certificate expires on 2023-10-19.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.

Deploying certificate
Successfully deployed certificate for nginx-ha.{mydomain_name} to /etc/nginx/sites-enabled/default
Congratulations! You have successfully enabled HTTPS on https://nginx-ha.{mydoman_name}

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:
 * Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
 * Donating to EFF:                    https://eff.org/donate-le
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

我们来确认一下 Let’s Encrypt 证书是如何创建的。

ord-nginx1# cat /etc/letsencrypt/live/README
This directory contains your keys and certificates.

`[cert name]/privkey.pem`  : the private key for your certificate.
`[cert name]/fullchain.pem`: the certificate file used in most server software.
`[cert name]/chain.pem`    : used for OCSP stapling in Nginx >=1.3.7.
`[cert name]/cert.pem`     : will break many server configurations, and should not be used
                 without reading further documentation (see link below).

WARNING: DO NOT MOVE OR RENAME THESE FILES!
         Certbot expects these files to remain in this location in order
         to function properly!

We recommend not moving these files. For more information, see the Certbot
User Guide at https://certbot.eff.org/docs/using.html#where-are-my-certificates.
nginx-ha-domain.jpg

Web2的制作

create-web2.jpg

使用Linode的克隆功能创建Web1。创建后,更改主机名。不需要进行其他操作。

hostnamectl set-hostname ord-web2

创建Nginx1(负载均衡)

create-nginx1-clone.jpg

假设我们将使用在Web1上创建的证书信息,并通过Linode的克隆功能创建Web1。我们会更改主机名。

当实例的大小不同时,在克隆时进行选择。
hostnamectl set-hostname ord-nginx1
ord-nginx1# cat /etc/nginx/nginx.conf
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
	worker_connections 768;
	# multi_accept on;
}

http {
	upstream sample_app {
        ip_hash;                # Forwarding based on an IP address
		server 192.XXX.XXX.101 max_fails=2 fail_timeout=10s;# ord-web1 Private
		server 192.XXX.XXX.102 max_fails=2 fail_timeout=10s; # ord-web2 Private
	}
	server {
		server_name nginx-ha.{mydomain_name};
		listen 443;
		ssl_certificate	/etc/letsencrypt/live/nginx-ha.{mydomain_name}/fullchain.pem;
		ssl_certificate_key /etc/letsencrypt/live/nginx-ha.{mydomain_name}/privkey.pem;
		location / {
			if_modified_since off;
			expires off;
			proxy_pass http://sample_app;
		}
	}

	##
	# Basic Settings
	##

	sendfile on;
	tcp_nopush on;
	types_hash_max_size 2048;
	# server_tokens off;

	# server_names_hash_bucket_size 64;
	# server_name_in_redirect off;

	include /etc/nginx/mime.types;
	default_type application/octet-stream;

	##
	# SSL Settings
	##

	ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
	ssl_prefer_server_ciphers on;

	##
	# Logging Settings
	##

	access_log /var/log/nginx/access.log;
	error_log /var/log/nginx/error.log;

	##
	# Gzip Settings
	##

	gzip on;

	# gzip_vary on;
	# gzip_proxied any;
	# gzip_comp_level 6;
	# gzip_buffers 16 8k;
	# gzip_http_version 1.1;
	# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

	##
	# Virtual Host Configs
	##

	include /etc/nginx/conf.d/*.conf;
	include /etc/nginx/sites-enabled/*;
}

创建Nginx2(负载均衡器)

create-nginx2-clone.jpg

将Nginx1克隆为Nginx2,并更改主机名。

hostnamectl set-hostname ord-nginx2

Nginx1/Nginx2的配置设置。

create-nginx-lb-conf.jpg

确认nginx.conf是否按上述方式运作。

重要的是正確地將上游和服務器關聯起來。上游的簡單設置如下:將請求平均分配到兩個轉發目標上,並使用私有 IP 而不是公共 IP。

	upstream sample_app {
		server 192.XXX.XXX.101 
		server 192.XXX.XXX.102 
	}

在服务器中,通过 proxy_pass 指定的 sample_app 字符串与 upstream 字符串的设置和链接非常重要。if_modified_since off;和 expires off; 是为了测试目的而添加的,以防止浏览器进行缓存。

server {
		server_name nginx-ha.{mydomain_name};
		listen 443;
		ssl_certificate	/etc/letsencrypt/live/nginx-ha.{mydomain_name}/fullchain.pem;
		ssl_certificate_key /etc/letsencrypt/live/nginx-ha.{mydomain_name}/privkey.pem;
		location / {
			if_modified_since off;
			expires off;
            proxy_connect_timeout 10;
			proxy_pass http://sample_app;
		}
	}

索引文件的更改

为了更容易地确定是被引导到哪个 Web 服务器,我们将更改文档根目录的索引文件。

网1

编辑 /var/www/html/ 目录下的索引文件。

web1-homepage.jpg

Web2

web2-homepage.jpg

共享IP设置

create-ip-sharing.jpg

参考以下文章,进行IP共享配置。

 

Lo 设备的预检确认

IP共享会在LO设备上设置一个共享的IP地址。先确认设置之前的状态。只有回环地址被注册。

Nginx1

ord-nginx1 # ip -4 a show dev lo
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever

Nginx2的意思是…… (The meaning of Nginx2 is…)

ord-nginx2 # ip -4 a show dev lo
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever

在 netplan 的配置中,将共享 IP 分配给 lo。

# This file describes the network interfaces available on your system
# For more information, see netplan(5).
network:
  version: 2
  renderer: networkd
  ethernets:
    eth0:
      dhcp4: yes
    lo:  # ここから追加します。
      match:
        name: lo
      addresses:
        - XXX.XXX.XXX.119/32 # /32 を設定します。
ord-nginx1 # netplan apply
ord-nginx2 # netplan apply

请再次确认lo设备的设置。

Nginx1(Nginx1)

ord-nginx1 # ip -4 a show dev lo
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet XXX.XXX.XXX.119/32 scope global lo
       valid_lft forever preferred_lft forever

Nginx2

ord-nginx2 # ip -4 a show dev lo
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet XXX.XXX.XXX.119/32 scope global lo
       valid_lft forever preferred_lft forever

引入Lelastic

弹性安装

version=v0.0.6
curl -LO https://github.com/linode/lelastic/releases/download/$version/lelastic.gz
gunzip lelastic.gz
chmod 755 lelastic
sudo mv lelastic /usr/local/bin/

/etc/systemd/system/lelastic.service 可以用以下方式表达:

請提供以下資訊:什麼是您所需的解決方案? 有任何特定要求嗎? 意圖和行動的背景是什麼? 在參與解決方案的過程中,您的角色和目標是什麼?

Nginx1(以主要角色运行)

[Unit]
Description= Lelastic
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=/usr/local/bin/lelastic -dcid 18 -primary &
ExecReload=/bin/kill -s HUP $MAINPID

[Install]
WantedBy=multi-user.target

由于我们使用芝加哥的数据中心,所以我们将其设置为18。

Nginx2(作为次要服务器运行)。

[Unit]
Description= Lelastic
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=/usr/local/bin/lelastic -dcid 18 -secondary &
ExecReload=/bin/kill -s HUP $MAINPID

[Install]
WantedBy=multi-user.target

共同的设定

sudo chmod 644 /etc/systemd/system/lelastic.service
sudo systemctl start lelastic
sudo systemctl enable lelastic

Nginx1/2 的网络

请确认已经注册了私有 IP,以及公共 IP。

/etc/systemd/network/05-eth0.network可以被中文翻译为「/etc/systemd/network/05-eth0网络」。

[Match]
Name=eth0

[Network]
DHCP=no
DNS=172.232.0.15 172.232.0.16 172.232.0.19

Domains=members.linode.com
IPv6PrivacyExtensions=false

Gateway=XXX.XXX.XXX.1
Address=XXX.XXX.XXX.11/24 # Public IP address
Address=192.YYY.YYY.11/17 # Private IP address

在 DNS 服务器中更改 CNAME 目标。

因为在Web层服务器上获取了证书,最终将会被引导至在负载均衡层设置的共享IP。

之前

nginx-ha.{mydomain_name}.	300	IN	CNAME	XXX-XXX-XXX-1.ip.linodeusercontent.com.
XXX-XXX-XXX-1.ip.linodeusercontent.com. 85996 IN A XXX.XXX.XXX.1

完成

nginx-ha.{mydomain_name}.	300	IN	CNAME	XXX-XXX-XXX-10.ip.linodeusercontent.com.
XXX-XXX-XXX-10.ip.linodeusercontent.com.	21600 IN A XXX.XXX.XXX.10

可以直接在A记录中指定IP地址。

云防火墙的配置

负载均衡器的设置

create-firewall-1.jpg
firewall-front-mark.jpg
firewall-back-linode.jpg

网页设置

create-firewall-2.jpg

本例中,我们将设置只允许通过两个负载均衡器的私有IP。负载均衡器的公共IP将被明确丢弃。

firewall-lb.jpg
firewall-web-linode.jpg

网站防护的设置(选项)

这是负载均衡器的设置。

nginx-lb-complete.jpg

如果您已经安装了Akamai安全产品,您可以将本文介绍的配置视为Akamai CDN的源站。在这种情况下,源站的IP将设置为之前设置的共享IP。通过使用Site Shiled和Cloud Firewall,您可以阻止Akamai网络以外的通信,并防止直接攻击源站。获取Site Shield的IP后,您需要在负载均衡器的Cloud Firewall设置中进行控制。

考试

停止 Web1 上的 Nginx。

stop-web1.jpg
ord-web1# systemctl stop nginx
navigate-web2.jpg
stop-nginx-web1.jpg

重新启动 Web1 上的 Nginx。

ord-web1# systemctl start nginx

谷歌浏览器将连接Web1。只要Web1仍然运行,就会保持与Web1的连接。这是通过nginx.conf文件中的ip_hash设置来实现的,该设置根据客户端的IP进行负载均衡。如果禁用此设置,则每次会以轮询方式交替显示Web1/Web2索引。

接下来,将关闭Web1服务器。当proxy_connect_timeout设置为10秒超时后,将重定向到Web2。proxy_connect_timeout的默认值为60秒,所以如果没有设置,将等待1分钟。

我将启动Web1的服务器。

在Chinese,我将对以下句子进行翻译:在Web1/Web2上显示访问日志。

tail -f /var/log/nginx/access.log

在日志中发现了来自Nginx1的私有IP访问。

192.XXX.XXX.101 - - [24/Jul/2023:12:34:41 +0000] "GET / HTTP/1.0" 200 629 "-" "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1"

停止 Nginx1

stop-lb-nginx1.jpg

在这种状态下,将负载均衡器 Nginx1 关闭电源。

确认下线后,再次通过Chrome浏览器访问。日志显示有来自Nginx2的私有IP的访问。

192.XXX.XXX.102 - - [24/Jul/2023:12:35:36 +0000] "GET / HTTP/1.0" 200 629 "-" "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1"

如果成功启动并且正常运行,那么测试就结束了。

总结

我已解釋在 Linode 實例之前配置 Nginx 作為負載平衡器,並使用 IP 共享實現冗餘。同時,我還介紹了 Cloud Firewall 的設置示例,以便在使用 Akamai 安全產品的情況下採用。

bannerAds