Adding the Fair Module to Nginx in Docker
Background
My blog used to be single-server, but now I want to deploy on multiple servers - one overseas and one domestic. Can domestic requests go to the domestic server while overseas requests go to the overseas server? This would reduce latency and load.
The answer is yes. Since the server uses nginx for load balancing, I plan to use nginx's fair module (third-party) for load balancing. Fair doesn't use the built-in round-robin algorithm - instead, it intelligently load balances based on page size and response time.
Since I also deploy nginx via Docker, I need to remove the previously deployed nginx and rebuild a custom nginx image with the fair module.
Steps
Before stopping the previous nginx, we can build the custom nginx image first. Then we just need to stop the old one and start the new one - very simple.
Build Custom Nginx Image
Create a dedicated nginx folder in the user directory
mkdir nginx_ws
Download the fair module package and nginx installation package in advance
wget http://nginx.org/download/nginx-1.18.0.tar.gz
Place both in the folder you just created.
Add Dockerfile
touch Dockerfile
Add content to Dockerfile
FROM centos:7.8.2003
MAINTAINER runnable.run
# Add local files
ADD nginx-1.18.0.tar.gz /usr/local/src
ADD nginx-upstream-fair-master.zip /usr/local/src
# Enter specified directory
WORKDIR /usr/local/src
# Install unzip tool and extract fair module
RUN yum install -y unzip && unzip nginx-upstream-fair-master.zip
# Enter specified directory
WORKDIR /usr/local/src/nginx-1.18.0
RUN yum install -y gcc gcc-c++ glibc make autoconf openssl openssl-devel \
&& yum install -y libxslt-devel -y gd gd-devel GeoIP GeoIP-devel pcre pcre-devel \
&& useradd -M -s /sbin/nologin nginx && BUILD_CONFIG="--prefix=/usr/local/nginx \
--http-client-body-temp-path=/var/cache/nginx/client_temp \
--http-proxy-temp-path=/var/cache/nginx/proxy_temp \
--http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp \
--http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp \
--http-scgi-temp-path=/var/cache/nginx/scgi_temp \
--with-http_stub_status_module \
--with-http_ssl_module \
--with-stream \
--with-http_v2_module \
--with-threads \
--add-module=/usr/local/src/nginx-upstream-fair-master" && ./configure $BUILD_CONFIG \
&& mkdir -p /var/cache/nginx && make && make install
ENV PATH /usr/local/nginx/sbin:$PATH
EXPOSE 80
EXPOSE 443
ENTRYPOINT ["nginx"]
CMD ["-g","daemon off;"]
Command explanations:
FROM: Specifies base image, must be the first command
MAINTAINER: Maintainer information
ADD: Adds local files to container, tar files are auto-extracted (network compressed resources are not), can access network resources like wget
WORKDIR: Working directory, similar to cd command
RUN: Commands executed when building the image
ENV: Sets environment variables
EXPOSE: Specifies ports for external interaction
ENTRYPOINT: Configures container to be executable. Combined with CMD, can omit "application" and use only parameters.
CMD: Called after container is built, i.e., when container starts.
Build
docker build -t centos7.8_nginx1.18:v1 .
Success Message
When you see this, it's successful:
Successfully built f91ed12a53e7
Start a Simple Nginx First to Copy Config Files
docker run --name nginx -p 8081:80 -d --rm nginx
Copy config files from container to specified directory:
docker cp nginx:/usr/local/nginx/conf/nginx.conf /root/nginx_ws/dockerData/nginx/conf/nginx.conf
Delete the container you just created. Since we added --rm when creating it, stopping it will auto-delete:
docker stop nginx
Modify Config File
Reference configuration:
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
upstream blogServer {
fair;
#server ip1:8080;
server ip2:8080;
}
server {
listen 443;
server_name runnable.run;
ssl on;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
ssl_certificate /ssl/6349085_www.runnable.run.pem;
ssl_certificate_key /ssl/6349085_www.runnable.run.key;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
location / {
proxy_pass http://blogServer;
error_page 404 https://www.runnable.run;
}
error_page 404 https://www.runnable.run;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
server{
listen 80;
server_name runnable.run;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
rewrite ^(.*) https://$host$1 permanent;
}
server {
listen 443;
server_name www.runnable.run;
ssl on;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
ssl_certificate /ssl/6349085_www.runnable.run.pem;
ssl_certificate_key /ssl/6349085_www.runnable.run.key;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
location / {
proxy_pass http://blogServer;
error_page 404 https://www.runnable.run;
}
error_page 404 https://www.runnable.run;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
server{
listen 80;
server_name www.runnable.run;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
rewrite ^(.*) https://$host$1 permanent;
}
}
Start Using Custom Image
docker run -d -p 80:80 -p 443:443 --name nginx \
-v /root/nginx_ws/dockerData/nginx/conf/nginx.conf:/usr/local/nginx/conf/nginx.conf \
-v /root/nginx_ws/dockerData/nginx/ssl:/ssl/ \
-v /root/nginx_ws/dockerData/nginx/www:/usr/share/nginx/html \
centos7.8_nginx1.18:v1
References
This article referenced:
Installing solo blog from scratch