我的docker随笔44:构建nginx镜像

2024-08-30 04:52

本文主要是介绍我的docker随笔44:构建nginx镜像,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本文介绍 nginx的编译、镜像构建、容器部署。

前言

2022年下半年,某项目需要容器化安装部署,由于我负责的2个服务较边缘,因此我被安排负责镜像的设计、微服务框架的设计、微服务的部署等事情。当我把整套微服务所有的服务分好类,做好Dockerfile,搞好docker-compose,整理初版的mysql,搞了redis和mqtt,最后把相关文件提交至代码仓库后,就对原型做测试,测试正常后被安排做其它的事了。当时是其他人继续搞,如今差不多2年时间,仓库更新了很多,也有很多没更新。接过来后,事情又回到我头上,于是继续整了docker离线安装脚本,最后测试。在测试中发现有些服务请求超时,经查发现是nginx转发时,后端的个别服务退出,虽然有故障转移,但超时了,依然认为有错误。

概述

微服务框架中用来做负载均衡的nginx是官方的镜像,故障转移的方法比较简单,关键配置片段如下所示:

upstream mybackend {server 172.18.18.18:9001 weight=1 max_fails=1 fail_timeout=60s;server 172.18.18.18:9002 weight=1 max_fails=1 fail_timeout=60s;
}

上面配置的作用是,当某个后端如果请求失败,则在60秒内不再转发到该后端。这里的问题是,nginx没有主动检测后端服务的状态,因此要先将业务请求转发后端,才能知晓后端是否正常,不正常(如超时)再转移到下一个后端。如果这个过程的耗时超过了业务请求的时间上限,则请求最终超时,对于当次的处理而言,是失败的。
nginx无法主动检测后端,所以要寻求第三方模块达到目的,而第三方模块要重新编译nginx源码。而nginx镜像的Dockerfile比较复杂,所以还要找一个比较简单的构建。

简言之,本文围绕的问题点是:

如何找到一种方法,让nginx支持主动检测后端服务健康状态,在业务请求到来前,能主动发现并将请求转换到健康的后端服务。

编译nginx

经查,nginx第三方模块有比较多,如gihub上有Weibin Yao(姚伟斌)主导负责的nginx_upstream_check_module,该仓库来自cep21。还有alexzzh的ngx_health_detect_module(不过笔者打补丁后编译不通过,暂不再继续研究)。另外,之前在调研信创时,也知道淘宝出了个自家的tengine。

方案1:官方nginx+补丁编译

由于笔者使用的nginx为1.23.2版本,因此下载该版本,官方地址为https://nginx.org/download,下载文件名为nginx-1.23.2.tar.gz。下载的nginx_upstream_check_module,下载文件名为nginx_upstream_check_module-0.4.0.tar.gz。

解压打补丁,步骤如下:

tar xf nginx-1.23.2.tar.gz 
tar xf nginx_upstream_check_module-0.4.0.tar.gz
cd nginx-1.23.2
patch -p1 < ../nginx_upstream_check_module-0.4.0/check_1.20.1+.patch 

配置编译如下:

./configure \--with-http_ssl_module \--with-http_v2_module \--with-http_realip_module \--with-http_stub_status_module \--with-http_gzip_static_module \--with-pcre \--with-stream \--with-stream_ssl_module \--with-stream_realip_module \--add-module=../nginx_upstream_check_module-0.4.0make# 注:由于nginx是放到容器中运行的,因此就不用make insall了

上述配置项没有指定路径,为默认的/usr/local/nginxconfigure输出的配置文件路径如下:

...
Configuration summary+ using system PCRE library+ using system OpenSSL library+ using system zlib library+ jemalloc library is disablednginx path prefix: "/usr/local/nginx"nginx binary file: "/usr/local/nginx/sbin/nginx"nginx modules path: "/usr/local/nginx/modules"nginx configuration prefix: "/usr/local/nginx/conf"nginx configuration file: "/usr/local/nginx/conf/nginx.conf"nginx pid file: "/usr/local/nginx/logs/nginx.pid"nginx error log file: "/usr/local/nginx/logs/error.log"nginx http access log file: "/usr/local/nginx/logs/access.log"nginx http client request body temporary files: "client_body_temp"nginx http proxy temporary files: "proxy_temp"nginx http fastcgi temporary files: "fastcgi_temp"nginx http uwsgi temporary files: "uwsgi_temp"nginx http scgi temporary files: "scgi_temp"

编译得到的二进制文件为objs/nginx经测试,该方案不符合实际要求,因此不对此方案做测试。

方案2:淘宝tengine编译

淘宝的Tengine目前最新版本为3.1.0,是去年10月份发布的,可以在这里下载,文件名为tengine-3.1.0.tar.gz。从github简介上知道,Tengine基于nginx的1.24.0版本,100%兼容nginx。同时加了许多特性,如能解决本文问题的ngx_http_upstream_check_module,因此不需要打补丁。更多模块,可参考源码工程目录tengine-3.1.0/modules。

配置编译如下:

./configure \--prefix=/etc/nginx  \--sbin-path=/usr/sbin/nginx  \--modules-path=/usr/lib/nginx/modules  \--conf-path=/etc/nginx/nginx.conf  \--error-log-path=/var/log/nginx/error.log  \--http-log-path=/var/log/nginx/access.log  \--pid-path=/var/run/nginx.pid  \--lock-path=/var/run/nginx.lock  \--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_ssl_module \--with-http_v2_module \--with-http_realip_module \--with-http_stub_status_module \--with-http_gzip_static_module \--with-pcre \--with-stream \--with-stream_ssl_module \--with-stream_realip_module \--add-module=modules/ngx_http_upstream_check_modulemake# 注:由于nginx是放到容器中运行的,因此就不用make insall了

本小节的编译项比较多,因此需要作说明。笔者使用的nginx的配置,均是外部挂载,而且也不想调整docker-compose.yaml文件里指定的容器挂载目录,因此参考官方nginx容器的编译项进行编译(编译项的路径相关信息,参见附录)。另外使用--add-module=modules/ngx_http_upstream_check_module指定了工程自带的检查后端服务状态模块。总言之,笔者想达到的目的是,只替换nginx,尽量少调整其它配置文件。

编译得到的二进制文件为objs/nginx。测试说明见下章节。

打包nginx

编译后得到的二进制文件名称为nginx,笔者使用的原始nginx官方镜像为nginx:1.23,由于只是替换nginx这个文件,因此沿用原镜像制作。构建镜像的Dockerfile文件内容如下:

FROM nginx:1.23MAINTAINER Late Lee(li@latelee.cn)Add nginx_lib.tar.gz /usr/lib/# nginx文件位于/usr/sbin/目录下
Add nginx_sbin.tar.gz /usr/sbin/#COPY nginx_sbin/nginx /usr/sbin/RUN chmod +x /usr/sbin/nginx

其中nginx_sbin.tar.gz为nginx可执行程序的压缩文件,需解压到/usr/sbin目录,以替换原来的nginx。nginx_lib.tar.gz是新版本nginx额外用到的依赖库,包括libpcre.so libssl.so libcrypto.so三个库。这些库是测试时发现原镜像缺少的,因此加上。

笔者构建的镜像名为nginx:1.23.tb,标签为1.23是其原本镜像的版本,tb表明该镜像的身份,毫无意外地,该镜像按理应该推送到阿里去的镜像平台,镜像已公开,可用下列命令拉取:

docker pull registry.cn-shenzhen.aliyuncs.com/hxr/nginx:1.23.tb

测试

测试场景:

运行nginx部署,指定8080端口,用于转发到2个后端服务(也是用容器部署)。使用curl命令测试后端服务的info响应。测试命令:

curl localhost:8080/info

响应结果包含有后端服务的节点名称。通过节点名称可以确认是哪个容器做响应。

nginx部署docker-compose.yaml文件如下:

version: '3.8'services:my-nginx:#image: nginx:1.23image: registry.cn-shenzhen.aliyuncs.com/hxr/nginx:1.23.tbcontainer_name: my-nginxhostname: my-nginxrestart: alwaysvolumes:- ./log/nginx:/var/log/nginx- ./config/nginx/html:/usr/share/nginx/html- ./config/nginx/nginx.conf:/etc/nginx/nginx.conf- ./config/nginx/conf.d:/etc/nginx/conf.denvironment:- TZ=Asia/Shanghaiports:- 8080:8080

配置文件config/nginx/conf.d/http_app.conf 核心内容如下:

# 在整个配置中,upstream 后的名称须唯一
upstream bar-upstream {server 172.18.18.18:9001 weight=1 max_fails=1 fail_timeout=60s;  # 外部IP及端口server 172.18.18.18:9002 weight=1 max_fails=1 fail_timeout=60s;  # 外部IP及端口#check interval=2 rise=1 fall=1 timeout=2 type=tcp;#check_http_send "GET /health/liveness HTTP/1.0\r\n\r\n";#check_http_expect_alive http_2xx http_3xx;
}

check interval=1000 rise=1 fall=1 timeout=2000 type=tcp;是开启主动健康检测功能的关键语句。

启动nginx服务容器:

docker-compose up -d
不开启主动检测

check interval=1000 rise=1 fall=1 timeout=2000 type=tcp;注释掉,重启nginx服务:

docke exec -it my-nginx nginx -s reload

同时启动2个后端服务。连续请求版本信息,一切正常。从返回信息中能看到节点切换,说明负载均衡发生作用。

停止其中一个后端服务,再连续请求,查看nginx错误日志(文件为log/nginx/error.log),有部分请求无法正常连接后端。如下:

2024/08/29 17:53:25 [error] 46#0: *2450 connect() failed (111: Connection refused) while connecting to upstream, client: 172.22.0.1, server: localhost, request: "GET /info HTTP/1.1", upstream: "http://192.168.28.11:9002/info", host: "localhost:8080"
2024/08/29 17:53:25 [warn] 46#0: *2450 upstream server temporarily disabled while connecting to upstream, client: 172.22.0.1, server: localhost, request: "GET /info HTTP/1.1", upstream: "http://192.168.28.11:9002/info", host: "localhost:8080"
2024/08/29 17:53:32 [error] 47#0: *2455 connect() failed (111: Connection refused) while connecting to upstream, client: 172.22.0.1, server: localhost, request: "GET /info HTTP/1.1", upstream: "http://192.168.28.11:9002/info", host: "localhost:8080"
2024/08/29 17:53:32 [warn] 47#0: *2455 upstream server temporarily disabled while connecting to upstream, client: 172.22.0.1, server: localhost, request: "GET /info HTTP/1.1", upstream: "http://192.168.28.11:9002/info", host: "localhost:8080"

但curl命令有返回结果,能看到节点切换,可以验证负载均衡发生作用,nginx切换到正常的后端服务。

开启主动检测

打开check interval=1000 rise=1 fall=1 timeout=2000 type=tcp;语句,重启nginx服务。

同时启动2个后端服务。连续请求版本信息,一切正常。

停止其中一个后端服务,再连续请求,查看nginx错误日志,有如下信息输出:

2024/08/29 18:02:43 [error] 25#0: check time out with peer: 192.168.28.11:9002 
2024/08/29 18:02:45 [error] 25#0: check time out with peer: 192.168.28.11:9002 
2024/08/29 18:02:49 [error] 25#0: check time out with peer: 192.168.28.11:9002 
2024/08/29 18:02:51 [error] 25#0: check time out with peer: 192.168.28.11:9002 
2024/08/29 18:02:53 [error] 25#0: check time out with peer: 192.168.28.11:9002 

可以看到,nginx已经可以检测到超时。当收到请求时,则不会转发到检测超时的服务,减少转发耗时。

小结

使用淘宝tengine方案,得到的nginx,可以解决文中的问题。

查询官方nginx编译项

通过nginx -V命令可以查看nginx的版本号及编译项,示例如下:

$ docker run -it --rm nginx:1.23 nginx -V
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
nginx version: nginx/1.23.2
built by gcc 10.2.1 20210110 (Debian 10.2.1-6) 
built with OpenSSL 1.1.1n  15 Mar 2022
TLS SNI support enabled
configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --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 --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-g -O2 -ffile-prefix-map=/data/builder/debuild/nginx-1.23.2/debian/debuild-base/nginx-1.23.2=. -fstack-protector-strong -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fPIC' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -Wl,--as-needed -pie'
nginx配置的额外说明

可以通过http协议或tcp协议来做健康检测。但无论哪种,需要后端服务的支持。如用check_http_send "GET /health/liveness HTTP/1.0\r\n\r\n";做检测,则后端需要响应URL/health/liveness

这篇关于我的docker随笔44:构建nginx镜像的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1119851

相关文章

Nginx 配置跨域的实现及常见问题解决

《Nginx配置跨域的实现及常见问题解决》本文主要介绍了Nginx配置跨域的实现及常见问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来... 目录1. 跨域1.1 同源策略1.2 跨域资源共享(CORS)2. Nginx 配置跨域的场景2.1

nginx启动命令和默认配置文件的使用

《nginx启动命令和默认配置文件的使用》:本文主要介绍nginx启动命令和默认配置文件的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录常见命令nginx.conf配置文件location匹配规则图片服务器总结常见命令# 默认配置文件启动./nginx

Windows的CMD窗口如何查看并杀死nginx进程

《Windows的CMD窗口如何查看并杀死nginx进程》:本文主要介绍Windows的CMD窗口如何查看并杀死nginx进程问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录Windows的CMD窗口查看并杀死nginx进程开启nginx查看nginx进程停止nginx服务

基于Python构建一个高效词汇表

《基于Python构建一个高效词汇表》在自然语言处理(NLP)领域,构建高效的词汇表是文本预处理的关键步骤,本文将解析一个使用Python实现的n-gram词频统计工具,感兴趣的可以了解下... 目录一、项目背景与目标1.1 技术需求1.2 核心技术栈二、核心代码解析2.1 数据处理函数2.2 数据处理流程

Python FastMCP构建MCP服务端与客户端的详细步骤

《PythonFastMCP构建MCP服务端与客户端的详细步骤》MCP(Multi-ClientProtocol)是一种用于构建可扩展服务的通信协议框架,本文将使用FastMCP搭建一个支持St... 目录简介环境准备服务端实现(server.py)客户端实现(client.py)运行效果扩展方向常见问题结

详解如何使用Python构建从数据到文档的自动化工作流

《详解如何使用Python构建从数据到文档的自动化工作流》这篇文章将通过真实工作场景拆解,为大家展示如何用Python构建自动化工作流,让工具代替人力完成这些数字苦力活,感兴趣的小伙伴可以跟随小编一起... 目录一、Excel处理:从数据搬运工到智能分析师二、PDF处理:文档工厂的智能生产线三、邮件自动化:

Nginx Location映射规则总结归纳与最佳实践

《NginxLocation映射规则总结归纳与最佳实践》Nginx的location指令是配置请求路由的核心机制,其匹配规则直接影响请求的处理流程,下面给大家介绍NginxLocation映射规则... 目录一、Location匹配规则与优先级1. 匹配模式2. 优先级顺序3. 匹配示例二、Proxy_pa

Windows 系统下 Nginx 的配置步骤详解

《Windows系统下Nginx的配置步骤详解》Nginx是一款功能强大的软件,在互联网领域有广泛应用,简单来说,它就像一个聪明的交通指挥员,能让网站运行得更高效、更稳定,:本文主要介绍W... 目录一、为什么要用 Nginx二、Windows 系统下 Nginx 的配置步骤1. 下载 Nginx2. 解压

详解如何使用Python从零开始构建文本统计模型

《详解如何使用Python从零开始构建文本统计模型》在自然语言处理领域,词汇表构建是文本预处理的关键环节,本文通过Python代码实践,演示如何从原始文本中提取多尺度特征,并通过动态调整机制构建更精确... 目录一、项目背景与核心思想二、核心代码解析1. 数据加载与预处理2. 多尺度字符统计3. 统计结果可

Nginx 413修改上传文件大小限制的方法详解

《Nginx413修改上传文件大小限制的方法详解》在使用Nginx作为Web服务器时,有时会遇到客户端尝试上传大文件时返回​​413RequestEntityTooLarge​​... 目录1. 理解 ​​413 Request Entity Too Large​​ 错误2. 修改 Nginx 配置2.1