当前位置: 首页 > news >正文

自定义构建生产级 NGINX Docker 镜像的完整实践

1. 为什么你需要亲手构建一个 NGINX Docker 镜像而不是直接docker run nginx在我们团队接手的第7个客户项目里运维同事凌晨三点发来截图线上静态资源服务突然返回 502 Bad Gateway。排查了整整两小时最后发现是上游镜像仓库的nginx:alpine标签被覆盖更新新版本默认关闭了gzip压缩而前端 JS 文件体积暴涨 300%超出了反向代理的缓冲区上限。这个事故让我彻底放弃了“拿来就用”的思维——Docker 的核心价值从来不是省事而是可控NGINX 的强大也从不在于开箱即用而在于可定制。你可能已经用过docker run -p 8080:80 nginx快速启动一个服务这确实方便。但这种便利背后藏着三个隐形成本第一每次docker pull nginx拉取的都是别人编译好的二进制你不知道它链接了哪个版本的 OpenSSL是否启用了http_v2模块甚至不清楚它的worker_processes是按 CPU 核心数自动计算还是硬编码为 1第二所有配置都依赖挂载卷-v一旦宿主机路径权限出错、SELinux 策略拦截或 macOS 的文件共享延迟容器就卡在starting nginx状态第三当你要把服务部署到离线环境、金融级内网或国产化信创平台时那个从 Docker Hub 拉取的镜像根本连不上网。真正的生产级实践必须把“环境一致性”从运行时前移到构建时。我见过太多团队在开发机上docker-compose up一切正常一到测试环境就报unknown directive stream——因为开发用的是nginx:mainline而测试服务器yum install nginx装的是 CentOS 自带的 1.12 版本压根不支持 stream 模块。构建自定义镜像的本质是把你的全部基础设施决策版本、模块、配置、安全策略固化成一行docker build命令让“在我机器上能跑”变成“在任何机器上必然能跑”。这篇文章要带你走完一条完整链路从最基础的FROM nginx:1.25.4开始到编译安装nginx-module-vts实时监控模块、集成lua-nginx-module实现动态路由、打上 SBOM软件物料清单并扫描 CVE 漏洞。过程中我会拆解每一个RUN指令背后的权衡——比如为什么宁可多花 3 分钟编译openssl也不用系统包管理器安装为什么COPY --frombuilder多阶段构建比单阶段镜像小 47%这些都不是教科书里的标准答案而是我在给银行、车企和政务云交付 23 个 NGINX 容器化项目后踩坑总结出的硬核经验。如果你只是想搭个个人博客后面的内容可能显得过度设计但如果你正在为一个日均千万 PV 的 SaaS 平台设计网关层那么接下来每一行代码都可能是未来三年线上稳定性的重要支点。2. 整体架构设计与方案选型逻辑2.1 为什么放弃官方镜像直接使用而选择“构建”而非“配置挂载”很多人会问既然官方nginx镜像已经很成熟为什么还要费劲去docker build这个问题的答案藏在 Docker 镜像的分层机制里。官方镜像本质是一个预编译的“黑盒”它的layers结构如下base image (debian:bookworm-slim) ├── /usr/sbin/nginx (statically linked binary) ├── /etc/nginx/ (default config) ├── /usr/share/nginx/html/ (default index.html) └── entrypoint.sh (startup script)当你用-v /host/conf:/etc/nginx/conf.d挂载配置时Docker 实际做的是覆盖式挂载——宿主机的整个目录会完全替换掉镜像中/etc/nginx/conf.d这一层。这带来两个致命问题第一如果宿主机目录为空NGINX 启动时找不到任何server{}块直接退出第二官方镜像内置的10-listen-on-ipv6-by-default.sh等初始化脚本会被跳过导致 IPv6 支持失效、环境变量注入失败等隐性故障。而构建自定义镜像的核心优势在于控制权下沉到构建阶段。我们不再依赖运行时挂载而是把所有确定性要素二进制、配置、证书、静态资源在docker build时就固化进镜像层。最终生成的镜像结构变成base image (debian:bookworm-slim) ├── /usr/sbin/nginx (custom compiled with modules) ├── /etc/nginx/ (full config tree, no init scripts needed) │ ├── nginx.conf (main config) │ ├── conf.d/ (site configs) │ └── ssl/ (certificates baked in) ├── /usr/share/nginx/html/ (built static assets) └── healthcheck.sh (custom liveness probe)这种设计让容器启动过程从“加载覆盖执行”简化为纯粹的“执行”启动时间缩短 60%且完全规避了挂载路径权限、网络延迟、宿主机 SELinux 策略等外部干扰。更重要的是它天然支持 Air-Gap气隙部署——你只需要把一个.tar包拷贝到内网服务器docker load后即可运行无需任何外部网络连接。2.2 基础镜像选型debian:bookworm-slimvsalpine:latestvsscratch这是构建 NGINX 镜像的第一个技术十字路口。我见过太多人盲目追求“最小镜像”直接选alpine结果在生产环境栽了跟头。让我们用真实数据说话镜像类型大小启动时间模块兼容性安全漏洞CVE调试难度nginx:alpine23MB120ms低musl libc 不兼容部分 C 模块中alpine 3.19 有 12 个中危 CVE极高无bash、strace、gdbdebian:bookworm-slim47MB180ms高glibc 全兼容低仅 3 个低危 CVE低预装curl、jq、vim-tinyscratch5MB80ms极低需完全静态链接无空镜像极高无法进入容器调试我的选择是debian:bookworm-slim理由非常务实第一我们团队 90% 的客户环境是 Debian/Ubuntu 系用相同基础镜像能复用所有 Ansible Playbook 和安全基线检查脚本第二bookworm的glibc 2.36对nginx-module-vts的内存池分配算法有关键修复避免长连接下内存泄漏第三slim变体已移除man、info等文档保留了apt包管理器——这意味着当需要临时安装tcpdump抓包时只需apt update apt install -y tcpdump而不用像alpine那样折腾apk add tcpdump再处理 musl 兼容性。至于scratch它只适合一种场景你有一个完全静态链接的 NGINX 二进制用gcc -static编译且永远不需要登录容器调试。现实中我只在 IoT 设备固件里用过它因为设备存储空间只有 8MB。对服务器端应用这种“极致精简”带来的运维成本远高于节省的几 MB 磁盘空间。2.3 多阶段构建Multi-stage Build的必要性如果你翻看官方 NGINX 镜像的 Dockerfile会发现它用单阶段构建先apt install build-essential再./configure make make install最后apt remove build-essential。这种写法的问题在于——构建依赖会污染最终镜像。即使你apt remove了编译工具/var/lib/apt/lists/目录残留的包索引、/usr/src/下的源码、/tmp/中的中间文件都会留在镜像层里导致镜像臃肿且存在安全风险。多阶段构建的正确姿势是把构建环境和运行环境彻底分离# 构建阶段只负责编译不关心运行时 FROM debian:bookworm-slim AS builder RUN apt update apt install -y \ build-essential \ libpcre3-dev \ libssl-dev \ zlib1g-dev \ wget \ rm -rf /var/lib/apt/lists/* WORKDIR /tmp/nginx-build RUN wget https://nginx.org/download/nginx-1.25.4.tar.gz \ tar -xzf nginx-1.25.4.tar.gz \ cd nginx-1.25.4 \ ./configure \ --prefix/usr \ --sbin-path/usr/sbin/nginx \ --conf-path/etc/nginx/nginx.conf \ --error-log-path/var/log/nginx/error.log \ --http-log-path/var/log/nginx/access.log \ --with-http_ssl_module \ --with-http_v2_module \ --with-http_realip_module \ --with-http_stub_status_module \ --with-stream \ --with-stream_ssl_module \ --with-compat \ make make install # 运行阶段只包含运行必需的文件 FROM debian:bookworm-slim # 复制构建阶段的产物不复制任何构建工具 COPY --frombuilder /usr/sbin/nginx /usr/sbin/nginx COPY --frombuilder /usr/share/man /usr/share/man COPY --frombuilder /etc/nginx /etc/nginx COPY --frombuilder /var/log/nginx /var/log/nginx # 创建运行用户非 root RUN groupadd -g 1001 -f nginx useradd -r -u 1001 -g nginx nginx USER nginx EXPOSE 80 443 HEALTHCHECK --interval30s --timeout3s --start-period5s --retries3 \ CMD curl -f http://localhost/healthz || exit 1 CMD [nginx, -g, daemon off;]这个设计的关键在于COPY --frombuilder指令——它只把builder阶段中明确指定的文件复制到最终镜像/usr/bin/gcc、/usr/include/等构建依赖完全不会进入运行镜像。实测下来多阶段构建的镜像比单阶段小 47%且trivy扫描显示 CVE 数量减少 82%。更重要的是它强制你思考“哪些文件是运行真正必需的” 这种思维模式会渗透到整个架构设计中。2.4 模块扩展策略静态编译 vs 动态加载NGINX 的模块分为两类核心模块如http_core和第三方模块如nginx-module-vts。官方镜像默认只编译核心模块第三方模块需要手动添加。这里有两个技术路线静态编译在./configure时通过--add-module/path/to/module参数引入模块代码直接编译进nginx二进制。优点是启动快、无运行时依赖缺点是每次增删模块都要重新编译整个 NGINX。动态加载编译时启用--with-compat模块以.so文件形式存在通过load_module指令在nginx.conf中加载。优点是模块热插拔缺点是每个.so文件都要单独维护 ABI 兼容性且动态加载有约 5ms 启动延迟。我的选择是核心功能静态编译监控/调试类模块动态加载。原因很现实nginx-module-vts虚拟主机状态监控和lua-nginx-module嵌入式 Lua 脚本这类模块更新频繁如果每次升级都要重编译 NGINXCI/CD 流水线会变得极其脆弱。而像http_ssl_module、http_v2_module这些底层协议模块一旦编译进二进制就几乎永不变更静态编译能获得最佳性能。具体实现上我们在builder阶段同时编译 NGINX 二进制和动态模块# 在 builder 阶段编译动态模块 RUN cd /tmp \ wget https://github.com/vozlt/nginx-module-vts/archive/refs/tags/v0.1.23.tar.gz \ tar -xzf v0.1.23.tar.gz \ cd /tmp/nginx-1.25.4 \ ./configure \ --add-dynamic-module/tmp/nginx-module-vts-0.1.23 \ # ... 其他参数同上 make make install # 复制动态模块到运行镜像 COPY --frombuilder /usr/lib/nginx/modules/ngx_http_vts_module.so /usr/lib/nginx/modules/然后在nginx.conf中启用load_module /usr/lib/nginx/modules/ngx_http_vts_module.so; http { vhost_traffic_status_zone; # ... 其他配置 }这种混合策略兼顾了稳定性与灵活性是我们在线上环境验证过最可靠的方案。3. 核心细节解析与实操要点3.1 安全加固从默认配置到生产就绪的七层过滤官方 NGINX 镜像的默认配置 (/etc/nginx/nginx.conf) 是为通用场景设计的直接用于生产等于裸奔。我们必须在构建镜像时就植入安全基因。以下是我在金融客户项目中强制实施的七层加固措施每一条都对应一个真实攻防案例第一层HTTP 头部精简默认 NGINX 会暴露Server: nginx/1.25.4这等于告诉攻击者你的精确版本号。在nginx.conf中添加server_tokens off; # 关闭 Server 头部 more_clear_headers X-Powered-By X-AspNet-Version; # 移除其他框架标识需安装 headers-more-nginx-module提示headers-more-nginx-module必须静态编译进 NGINX否则more_clear_headers指令无效。这是很多教程忽略的关键点。第二层TLS 1.3 强制启用与弱密码淘汰在ssl_prefer_server_ciphers on;的基础上明确禁用 TLS 1.0/1.1 和所有 CBC 模式密码套件ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384; ssl_ecdh_curve secp384r1;注意secp384r1曲线比默认的prime256v1更安全但要求客户端 OpenSSL 版本 ≥ 1.1.1。我们通过curl -v https://yourdomain.com验证兼容性确保主流浏览器和 Android/iOS App 均能握手成功。第三层请求体大小与超时精细化控制默认client_max_body_size 1m对上传大文件不友好但设得过大又易受 DoS 攻击。我们的策略是按路径区分# 全局限制 client_max_body_size 10m; client_header_timeout 10; client_body_timeout 10; # 上传接口放宽 location /api/upload { client_max_body_size 100m; client_body_timeout 300; } # 静态资源严格限制 location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { client_max_body_size 1k; # 静态文件不该有请求体 }第四层Referer 与 User-Agent 白名单防止图片盗链和爬虫滥用# 防盗链 location ~* \.(jpg|jpeg|png|gif|webp)$ { valid_referers none blocked server_names *.mycompany.com; if ($invalid_referer) { return 403; } } # 拦截恶意 User-Agent if ($http_user_agent ~* (sqlmap|nikto|wget|curl|python-requests)) { return 403; }第五层速率限制与突发流量保护使用limit_req模块防暴力破解和爬虫# 全局限流每秒最多 10 个请求允许突发 20 个 limit_req_zone $binary_remote_addr zoneglobal:10m rate10r/s burst20 nodelay; # 登录接口单独限流 limit_req_zone $binary_remote_addr zonelogin:10m rate1r/s burst3 nodelay; server { location /login { limit_req zonelogin; } location / { limit_req zoneglobal; } }第六层隐藏敏感信息的健康检查端点官方镜像的/status端点暴露过多内部信息。我们创建/healthz端点只返回 HTTP 200location /healthz { return 200 OK; add_header Content-Type text/plain; }并在 Dockerfile 中配置HEALTHCHECK确保容器健康状态被编排系统准确感知。第七层日志格式最小化与敏感字段脱敏默认log_format combined记录完整$request可能泄露 API Key。我们定义安全日志格式log_format secure $remote_addr - $remote_user [$time_local] $request_method $uri $http_version $status $body_bytes_sent $http_referer $http_user_agent $request_time $upstream_response_time; access_log /var/log/nginx/access.log secure;注意$request被$request_method $uri $http_version替代既保留必要信息又剥离了可能含敏感参数的完整请求行。3.2 配置管理如何让nginx.conf成为可版本控制的“代码”把配置文件当作代码来管理是 DevOps 的基本功。我们团队的实践是所有 NGINX 配置必须通过 Git 仓库管理且禁止在容器内直接修改。具体流程如下配置分层设计将配置拆分为三层每层独立版本控制base/基础配置nginx.conf主文件、mime.types由平台团队维护定义全局行为sites/站点配置default.conf,api.mycompany.com.conf由业务团队维护定义路由规则env/环境配置prod.env,staging.env由运维团队维护定义变量值模板化配置生成使用envsubst将环境变量注入配置# 在 Dockerfile 中 COPY nginx.conf.template /etc/nginx/nginx.conf.template RUN echo include /etc/nginx/sites/*.conf; /etc/nginx/nginx.conf.template # 构建时注入环境变量 RUN envsubst /etc/nginx/nginx.conf.template /etc/nginx/nginx.confnginx.conf.template示例worker_processes ${NGINX_WORKERS:-auto}; events { worker_connections ${NGINX_WORKER_CONNECTIONS:-1024}; } http { # ... 其他配置 include /etc/nginx/sites/*.conf; }配置校验自动化在 CI 流水线中加入nginx -t校验# .gitlab-ci.yml 示例 nginx-config-test: image: nginx:1.25.4 script: - cp nginx.conf.template /etc/nginx/nginx.conf - envsubst /etc/nginx/nginx.conf /tmp/nginx.conf - nginx -t -c /tmp/nginx.conf这种设计让配置变更具备了代码的所有特性可追溯Git Blame、可回滚Git Reset、可测试CI 校验、可审计PR Review。当某次上线后出现 502 错误我们能立刻定位到是哪一行proxy_pass地址写错了而不是在几十个服务器上手动grep配置。3.3 静态资源处理从COPY到构建时优化的完整链路很多人以为COPY ./html /usr/share/nginx/html就是处理静态资源的终点其实这只是起点。真正的生产级实践需要在构建阶段完成三件事资源哈希化、压缩优化、缓存策略固化。第一步资源哈希化Cache Busting前端构建工具Webpack/Vite生成的main.js文件名是固定的导致浏览器长期缓存旧版本。解决方案是在构建镜像时重命名文件并更新 HTML 引用# 在 builder 阶段 RUN cd /tmp \ wget https://github.com/shuLhan/pakket/releases/download/v1.0.0/pakket_1.0.0_linux_arm64.deb \ dpkg -i pakket_1.0.0_linux_arm64.deb \ pakket hash --algo sha256 --suffix .[hash] ./html/*.js ./html/*.css这会把main.js重命名为main.a1b2c3d4.js并生成manifest.json映射表。第二步Brotli 压缩预生成NGINX 的ngx_brotli模块支持运行时压缩但 CPU 开销大。更优方案是在构建时预压缩RUN apt install -y brotli \ find ./html -type f \( -name *.js -o -name *.css -o -name *.html \) -exec brotli {} \;然后在nginx.conf中启用brotli on; brotli_comp_level 6; brotli_types text/plain text/css text/javascript application/javascript application/json;第三步缓存头策略固化在nginx.conf中为不同资源类型设置精准缓存头# HTML 文件不缓存或短缓存 location ~* \.html$ { add_header Cache-Control no-cache, no-store, must-revalidate; add_header Pragma no-cache; add_header Expires 0; } # 静态资源强缓存一年 location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { expires 1y; add_header Cache-Control public, immutable; }这套组合拳让我们的静态资源加载速度提升 40%CDN 回源率下降 75%。关键是所有这些优化都在docker build时一次性完成运行时零开销。3.4 日志与监控让容器“会说话”的工程实践容器日志不能只靠docker logs必须设计成可观测系统的一部分。我们的方案是日志标准化 指标暴露 健康探针三位一体。日志标准化强制所有日志输出为 JSON 格式便于 ELK 或 Loki 解析log_format json {time:$time_iso8601, remote_addr:$remote_addr, request:$request, status:$status, body_bytes_sent:$body_bytes_sent, http_referer:$http_referer, http_user_agent:$http_user_agent, request_time:$request_time, upstream_response_time:$upstream_response_time}; access_log /var/log/nginx/access.log json;指标暴露启用nginx-module-vts模块提供 Prometheus 可抓取的指标端点location /status { vhost_traffic_status_display; vhost_traffic_status_display_format html; } location /status/format/json { vhost_traffic_status_display; vhost_traffic_status_display_format json; }然后在 Prometheus 配置中添加 job- job_name: nginx static_configs: - targets: [nginx-service:80]健康探针除了基础的/healthz我们还实现了深度健康检查# healthcheck.sh #!/bin/bash # 检查 NGINX 进程 if ! pgrep -x nginx /dev/null; then exit 1 fi # 检查配置语法 if ! nginx -t /dev/null 21; then exit 1 fi # 检查上游服务连通性如果配置了 proxy_pass if grep -q proxy_pass /etc/nginx/nginx.conf; then upstream$(grep proxy_pass /etc/nginx/nginx.conf | head -1 | awk {print $2} | sed s/;//) if ! curl -f -s http://$upstream/healthz /dev/null; then exit 1 fi fi并在 Dockerfile 中声明HEALTHCHECK --interval10s --timeout3s --start-period30s --retries3 \ CMD /healthcheck.sh这套设计让运维同学能在一个 Dashboard 上看到容器存活状态、QPS 趋势、错误率、上游服务延迟真正实现“所见即所得”的可观测性。4. 实操过程与核心环节实现4.1 从零开始构建完整的 Dockerfile 详解现在让我们把前面所有设计落地为一份可运行的Dockerfile。这不是一个玩具示例而是我们线上环境实际使用的精简版已移除客户特定模块# syntaxdocker/dockerfile:1 # 构建阶段编译 NGINX 二进制和动态模块 FROM debian:bookworm-slim AS builder # 安装构建依赖 RUN apt update apt install -y \ build-essential \ libpcre3-dev \ libssl-dev \ zlib1g-dev \ wget \ curl \ git \ rm -rf /var/lib/apt/lists/* # 创建工作目录 WORKDIR /tmp # 下载并解压 NGINX 源码 RUN wget https://nginx.org/download/nginx-1.25.4.tar.gz \ tar -xzf nginx-1.25.4.tar.gz # 下载并解压第三方模块 RUN wget https://github.com/vozlt/nginx-module-vts/archive/refs/tags/v0.1.23.tar.gz \ tar -xzf v0.1.23.tar.gz \ wget https://github.com/openresty/headers-more-nginx-module/archive/refs/tags/v0.34.tar.gz \ tar -xzf v0.34.tar.gz # 编译 NGINX静态链接所有依赖 WORKDIR /tmp/nginx-1.25.4 RUN ./configure \ --prefix/usr \ --sbin-path/usr/sbin/nginx \ --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 \ --usernginx \ --groupnginx \ --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 \ --add-dynamic-module/tmp/nginx-module-vts-0.1.23 \ --add-dynamic-module/tmp/headers-more-nginx-module-0.34 \ make make install # 运行阶段极简主义 FROM debian:bookworm-slim # 创建运行用户和组 RUN groupadd -g 1001 -f nginx useradd -r -u 1001 -g nginx nginx # 复制构建产物 COPY --frombuilder /usr/sbin/nginx /usr/sbin/nginx COPY --frombuilder /usr/lib/nginx/modules/ngx_http_vts_module.so /usr/lib/nginx/modules/ COPY --frombuilder /usr/lib/nginx/modules/headers-more-nginx-module.so /usr/lib/nginx/modules/ COPY --frombuilder /usr/share/man /usr/share/man COPY --frombuilder /etc/nginx /etc/nginx COPY --frombuilder /var/log/nginx /var/log/nginx # 创建必要的目录 RUN mkdir -p /var/cache/nginx/client_temp \ /var/cache/nginx/proxy_temp \ /var/cache/nginx/fastcgi_temp \ /var/cache/nginx/uwsgi_temp \ /var/cache/nginx/scgi_temp \ chown -R nginx:nginx /var/cache/nginx \ chown -R nginx:nginx /var/log/nginx # 复制自定义配置和健康检查脚本 COPY nginx.conf /etc/nginx/nginx.conf COPY sites/default.conf /etc/nginx/sites/default.conf COPY healthcheck.sh /healthcheck.sh RUN chmod x /healthcheck.sh # 暴露端口 EXPOSE 80 443 # 健康检查 HEALTHCHECK --interval10s --timeout3s --start-period30s --retries3 \ CMD /healthcheck.sh # 设置运行用户 USER nginx # 启动命令 CMD [nginx, -g, daemon off;]关键细节说明第 3 行# syntaxdocker/dockerfile:1启用最新 Dockerfile 语法支持--mounttypecache等高级特性第 22 行--with-compat是动态模块加载的前提缺了它load_module会报错第 42 行--add-dynamic-module指定模块源码路径注意路径必须是绝对路径第 65 行chown -R nginx:nginx /var/cache/nginx是关键NGINX 工作进程以nginx用户运行必须有缓存目录的写权限否则启动失败第 77 行HEALTHCHECK的--start-period30s给 NGINX 足够时间完成初始化加载 SSL 证书、建立上游连接等4.2 构建与测试全流程从本地到 CI/CD构建不是docker build一条命令就结束而是一个闭环验证流程。以下是我们在 GitLab CI 中执行的标准步骤# .gitlab-ci.yml stages: - build - test - scan - deploy build-nginx-image: stage: build image: docker:24.0.7 services: - docker:dind variables: DOCKER_DRIVER: overlay2 script: - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG -f Dockerfile . - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG test-nginx-config: stage: test image: nginx:1.25.4 script: - cp nginx.conf /etc/nginx/nginx.conf - nginx -t # 语法校验 scan-image-security: stage: scan image: aquasec/trivy:0.45.0 script: - trivy image --severity CRITICAL,HIGH --format table $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG deploy-to-staging: stage: deploy image: alpine:3.19 before_script: - apk add curl script: - curl -X POST https://staging-api.example.com/deploy \ -H Authorization: Bearer $DEPLOY_TOKEN \ -d image$CI_REGISTRY_IMAGE:$CI_COMMIT_TAG only: - tags本地快速验证技巧语法校验在修改nginx.conf后用docker run --rm -v $(pwd)/nginx.conf:/etc/nginx/nginx.conf nginx:1.25.4 nginx -t快速验证无需构建镜像配置渲染测试如果用了envsubst先export NGINX_WORKERS4再envsubst nginx.conf.template /tmp/test.conf nginx -t -c /tmp/test.conf镜像大小分析docker buildx build --progressplain --load -f Dockerfile . 21 | grep writing image查看各层大小定位臃肿来源4.3 反向代理实战构建企业级 API 网关现在
http://www.gsyq.cn/news/1387420.html

相关文章:

  • Godot导向行为框架:用Steering Behaviors实现自然AI移动
  • 告别手动启动!用ROS robot_upstart在Ubuntu 20.04上实现节点开机自启(保姆级教程)
  • AI Agent在智能风控中的实战:多智能体欺诈检测与预警
  • 视频字幕提取终极指南:告别字幕不同步,3步实现完美时间轴校准
  • 树莓派Pico驱动电机实战:L298N模块原理与MicroPython控制详解
  • 推荐几家HC-276板材国内厂商:2026高品质的HC-276合金厂商 - 品牌2025
  • ARM ETE调试寄存器架构与TRCIDR功能详解
  • Flink数据流写入Elasticsearch实战
  • 实测对比:MPU6050在STM32上的Sleep与Cycle模式,哪个更省电?(附电流数据)
  • 构建非侵入式智能帮助系统:三层感知架构与无感集成实践
  • PostgreSQL CASE语句深度解析:性能、类型与NULL安全实战指南
  • 【ChatGPT】美国泛林集团Sabre® 系列水平镀铜设备深度拆解、爆炸图10张、信息图10张、C++代码框架
  • 从一次生产事故复盘:我们如何优雅地处理用户上传的‘异常’Excel文件(附Apache POI配置详解)
  • 避坑指南:树莓派4B编译FFmpeg支持H.264硬编时,我遇到的‘OMX_Core.h not found’等错误全解决
  • Topit:macOS窗口置顶神器,让多任务处理效率翻倍
  • 从零到一:用PySide6和Qt Creator 4.14打造你的第一个Python GUI应用
  • RCNet:基于RNN的Delta-Sigma ADC自动化设计新方法
  • Archon Specs:用约束性规范与实时验证消除AI代码生成中的幻觉问题
  • 全国职业院校技能大赛-心得+环境代码全资源
  • 量子程序调试新方法:Bloch向量断言技术解析
  • 3分钟快速上手:用BetterNCM安装器彻底改造你的网易云音乐
  • AX-MES生产制造管理系统-总览
  • 抖音数字资产管理方法论:构建个人内容沉淀系统的技术实践
  • 3步搞定洛雪音乐播放:六音音源修复版完整配置指南
  • nginx配置 请求静态文件时带上额外的响应头信息(可用作获取客户端IP)
  • 接口测试用例设计实战:从契约验证到状态跃迁
  • 重新定义数据科学范式:SISSO如何颠覆黑盒机器学习的认知框架
  • LLM在HPC代码翻译中的实践与评估
  • SideX安全最佳实践:保护你的代码编辑环境
  • 实战教程:如何使用GLM-4.1V-9B-Thinking-gs-A8W8进行图像理解和视频分析的完整指南