
1. 项目背景与核心价值在当前的互联网服务架构中Nginx作为高性能的反向代理服务器Tomcat作为稳定的Java应用容器二者的组合已经成为企业级Web应用部署的黄金标准。而容器化技术的引入则让这套经典架构焕发出新的生命力。我最早接触这套架构是在2016年当时我们团队正在将一个传统部署的电商系统迁移到容器环境。经过多次迭代现在这套部署方案已经稳定支撑日均千万级PV的业务流量。今天要分享的就是经过实战检验的完整部署方案。与传统部署方式相比容器化方案具有三大核心优势环境一致性开发、测试、生产环境完全一致彻底解决在我机器上能跑的问题快速伸缩通过容器编排工具可实现秒级扩容资源隔离每个服务独立运行避免资源抢占2. 架构设计与组件选型2.1 整体架构解析我们的目标架构如下图所示注实际部署时不包含图示此处仅为说明客户端 → Nginx容器 → Tomcat容器集群 → Redis/MySQL等后端服务Nginx作为流量入口主要承担以下职责静态资源缓存CSS/JS/图片等负载均衡轮询/加权等策略SSL终端卸载请求过滤与限流Tomcat容器则专注于Java应用运行环境Session管理动态内容生成2.2 容器化技术选型在容器运行时选择上我们推荐使用Docker而非Podman等替代方案原因包括企业级生态更完善监控、日志等配套工具链社区支持更广泛问题更容易找到解决方案与Kubernetes的兼容性更好对于生产环境建议使用Docker的固定版本而非latest标签。当前推荐版本为20.10.x系列该版本经过长期验证稳定性较好。3. 环境准备与基础配置3.1 主机环境要求建议的服务器最低配置CPU4核x86_64架构内存8GB磁盘100GB SSD操作系统Ubuntu 20.04 LTS或CentOS 7.9关键系统参数调优# 增加文件描述符限制 echo * soft nofile 65535 /etc/security/limits.conf echo * hard nofile 65535 /etc/security/limits.conf # 调整内核参数 echo net.core.somaxconn 1024 /etc/sysctl.conf echo vm.overcommit_memory 1 /etc/sysctl.conf sysctl -p3.2 Docker安装与配置Ubuntu系统安装示例# 卸载旧版本 sudo apt-get remove docker docker-engine docker.io containerd runc # 安装依赖 sudo apt-get update sudo apt-get install \ apt-transport-https \ ca-certificates \ curl \ gnupg \ lsb-release # 添加Docker官方GPG密钥 curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg # 设置稳定版仓库 echo \ deb [archamd64 signed-by/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) stable | sudo tee /etc/apt/sources.list.d/docker.list /dev/null # 安装Docker引擎 sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io # 验证安装 sudo docker run hello-world生产环境关键配置建议配置Docker日志轮转避免日志占满磁盘设置私有镜像仓库认证信息配置cgroup驱动为systemd4. Nginx容器化实战4.1 镜像构建最佳实践不建议直接使用官方nginx镜像作为生产环境基础镜像我们推荐的分层构建方案# 第一阶段构建环境 FROM alpine:3.14 as builder RUN apk add --no-cache \ gcc \ libc-dev \ make \ openssl-dev \ pcre-dev \ zlib-dev \ linux-headers \ curl \ gnupg \ libxslt-dev \ gd-dev ARG NGINX_VERSION1.21.6 RUN curl -fsSL https://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz | tar xz WORKDIR /nginx-${NGINX_VERSION} RUN ./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 \ --usernginx \ --groupnginx \ --with-http_ssl_module \ --with-http_realip_module \ --with-http_addition_module \ --with-http_sub_module \ --with-http_dav_module \ --with-http_flv_module \ --with-http_mp4_module \ --with-http_gunzip_module \ --with-http_gzip_static_module \ --with-http_random_index_module \ --with-http_secure_link_module \ --with-http_stub_status_module \ --with-http_auth_request_module \ --with-threads \ --with-stream \ --with-stream_ssl_module \ --with-mail \ --with-mail_ssl_module \ --with-file-aio \ --with-http_v2_module \ --with-cc-opt-Os -fomit-frame-pointer -g \ --with-ld-opt-Wl,--as-needed RUN make -j$(getconf _NPROCESSORS_ONLN) RUN make install # 第二阶段生产镜像 FROM alpine:3.14 RUN apk add --no-cache \ pcre \ zlib \ openssl COPY --frombuilder /usr/sbin/nginx /usr/sbin/nginx COPY --frombuilder /etc/nginx /etc/nginx COPY --frombuilder /var/log/nginx /var/log/nginx COPY --frombuilder /var/cache/nginx /var/cache/nginx RUN adduser -S nginx RUN mkdir -p /var/cache/nginx/client_temp EXPOSE 80 443 STOPSIGNAL SIGQUIT CMD [nginx, -g, daemon off;]构建命令docker build -t custom-nginx:1.21.6 .4.2 关键配置详解生产环境nginx.conf核心配置user nginx; worker_processes auto; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; multi_accept on; use epoll; } http { include /etc/nginx/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 /var/log/nginx/access.log main; sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; gzip on; gzip_disable msie6; 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/xmlrss text/javascript; include /etc/nginx/conf.d/*.conf; }虚拟主机配置示例conf.d/default.confupstream tomcat_cluster { least_conn; server tomcat1:8080 weight3; server tomcat2:8080 weight2; server tomcat3:8080 weight1; keepalive 32; } server { listen 80; server_name example.com; location / { proxy_pass http://tomcat_cluster; proxy_http_version 1.1; proxy_set_header Connection ; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_connect_timeout 3s; proxy_read_timeout 10s; proxy_send_timeout 10s; } location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ { expires 30d; access_log off; add_header Cache-Control public; } location /nginx_status { stub_status; access_log off; allow 127.0.0.1; deny all; } }4.3 容器运行与调优启动Nginx容器的推荐命令docker run -d \ --name nginx \ --restart unless-stopped \ -p 80:80 \ -p 443:443 \ -v /path/to/nginx.conf:/etc/nginx/nginx.conf:ro \ -v /path/to/conf.d:/etc/nginx/conf.d:ro \ -v /path/to/logs:/var/log/nginx \ -v /path/to/cache:/var/cache/nginx \ --cpu-shares 512 \ --memory 1g \ --memory-swap 1g \ custom-nginx:1.21.6性能调优参数说明worker_processes通常设置为CPU核心数worker_connections单个worker最大连接数需结合ulimit -n设置keepalive_timeout长连接保持时间建议5-15秒gzip_comp_level压缩级别6是性价比最佳选择5. Tomcat容器化实战5.1 镜像构建策略我们采用分阶段构建方案确保最终镜像最小化# 构建阶段 FROM maven:3.8.6-jdk-11 as builder WORKDIR /app COPY pom.xml . RUN mvn dependency:go-offline COPY src ./src RUN mvn package -DskipTests # 生产镜像 FROM tomcat:9.0.64-jre11-temurin # 移除默认应用 RUN rm -rf /usr/local/tomcat/webapps/* # 配置优化 COPY --frombuilder /app/target/your-app.war /usr/local/tomcat/webapps/ROOT.war COPY server.xml /usr/local/tomcat/conf/server.xml COPY setenv.sh /usr/local/tomcat/bin/setenv.sh RUN chmod x /usr/local/tomcat/bin/setenv.sh EXPOSE 8080 CMD [catalina.sh, run]关键配置文件说明server.xml优化项Connector port8080 protocolHTTP/1.1 connectionTimeout20000 redirectPort8443 maxThreads200 minSpareThreads10 enableLookupsfalse acceptCount100 compressionon compressionMinSize2048 compressableMimeTypetext/html,text/xml,text/plain,text/css,text/javascript,application/javascript URIEncodingUTF-8/setenv.sh内存配置#!/bin/sh export JAVA_OPTS$JAVA_OPTS -server -Xms1024m -Xmx1024m -XX:MetaspaceSize128m -XX:MaxMetaspaceSize512m export JAVA_OPTS$JAVA_OPTS -XX:UseG1GC -XX:DisableExplicitGC -XX:HeapDumpOnOutOfMemoryError -XX:HeapDumpPath/heapdump.hprof5.2 集群部署方案使用Docker Compose部署Tomcat集群version: 3.8 services: tomcat1: image: your-tomcat-image:latest restart: unless-stopped environment: - JAVA_OPTS-Xms512m -Xmx512m -Djava.security.egdfile:/dev/./urandom volumes: - ./logs/tomcat1:/usr/local/tomcat/logs networks: - app-network deploy: resources: limits: cpus: 0.5 memory: 768M tomcat2: image: your-tomcat-image:latest restart: unless-stopped environment: - JAVA_OPTS-Xms512m -Xmx512m -Djava.security.egdfile:/dev/./urandom volumes: - ./logs/tomcat2:/usr/local/tomcat/logs networks: - app-network deploy: resources: limits: cpus: 0.5 memory: 768M tomcat3: image: your-tomcat-image:latest restart: unless-stopped environment: - JAVA_OPTS-Xms512m -Xmx512m -Djava.security.egdfile:/dev/./urandom volumes: - ./logs/tomcat3:/usr/local/tomcat/logs networks: - app-network deploy: resources: limits: cpus: 0.5 memory: 768M networks: app-network: driver: bridge5.3 Session共享方案生产环境推荐使用Redis实现Session共享添加Maven依赖dependency groupIdorg.springframework.session/groupId artifactIdspring-session-data-redis/artifactId version2.7.0/version /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-redis/artifactId /dependency配置Redis连接spring.redis.hostredis-host spring.redis.port6379 spring.redis.passwordyour-password spring.session.store-typeredis spring.session.redis.flush-modeon_save spring.session.redis.namespacespring:session添加Spring配置类Configuration EnableRedisHttpSession public class SessionConfig extends AbstractHttpSessionApplicationInitializer { Bean public RedisConnectionFactory redisConnectionFactory() { return new LettuceConnectionFactory(); } }6. 系统集成与测试6.1 服务编排与网络配置完整的docker-compose.yml示例version: 3.8 services: nginx: image: custom-nginx:1.21.6 ports: - 80:80 - 443:443 volumes: - ./nginx/conf.d:/etc/nginx/conf.d:ro - ./nginx/logs:/var/log/nginx depends_on: - tomcat1 - tomcat2 - tomcat3 networks: - frontend - backend tomcat1: image: your-tomcat-image:latest environment: - SPRING_PROFILES_ACTIVEprod volumes: - ./tomcat/logs1:/usr/local/tomcat/logs networks: - backend deploy: resources: limits: memory: 768M tomcat2: image: your-tomcat-image:latest environment: - SPRING_PROFILES_ACTIVEprod volumes: - ./tomcat/logs2:/usr/local/tomcat/logs networks: - backend deploy: resources: limits: memory: 768M tomcat3: image: your-tomcat-image:latest environment: - SPRING_PROFILES_ACTIVEprod volumes: - ./tomcat/logs3:/usr/local/tomcat/logs networks: - backend deploy: resources: limits: memory: 768M redis: image: redis:6.2-alpine command: redis-server --requirepass yourpassword volumes: - ./redis/data:/data networks: - backend ports: - 6379:6379 networks: frontend: driver: bridge backend: driver: bridge6.2 压力测试与性能调优使用JMeter进行压力测试的推荐配置测试计划结构线程组500并发用户持续10分钟HTTP请求模拟关键业务路径监听器聚合报告、响应时间图关键监控指标Nginx活跃连接数、请求处理速率Tomcat线程池使用情况、响应时间系统CPU、内存、IO使用率常见瓶颈与解决方案瓶颈现象可能原因解决方案Nginx 502错误Tomcat响应超时增加proxy_read_timeout高并发时响应慢Tomcat线程数不足增加maxThreadsCPU使用率高GC频繁调整JVM内存参数内存持续增长内存泄漏分析heap dump6.3 日志收集与监控推荐使用ELK栈进行日志收集Filebeat配置示例filebeat.inputs: - type: log paths: - /var/log/nginx/*.log fields: type: nginx - type: log paths: - /usr/local/tomcat/logs/*.log fields: type: tomcat output.logstash: hosts: [logstash:5044]Prometheus监控指采集Nginx使用nginx-exporterTomcat使用JMX exporter系统使用node-exporter7. 生产环境部署建议7.1 安全加固措施容器安全使用非root用户运行容器设置只读文件系统限制容器能力docker run --user 1000:1000 \ --read-only \ --cap-drop ALL \ your-imageNginx安全隐藏服务器版本信息server_tokens off;限制HTTP方法if ($request_method !~ ^(GET|HEAD|POST)$ ) { return 405; }添加安全头add_header X-Frame-Options SAMEORIGIN; add_header X-Content-Type-Options nosniff; add_header X-XSS-Protection 1; modeblock;Tomcat安全禁用管理界面配置严格的访问控制定期更新JDK补丁7.2 高可用方案Nginx高可用使用Keepalived实现VIP漂移多实例部署负载均衡器Tomcat集群至少3个实例分布在不同物理节点配合服务发现实现动态扩缩容数据持久化使用共享存储或分布式文件系统重要数据定期备份7.3 持续部署流程推荐CI/CD流程代码提交触发构建运行单元测试和集成测试构建Docker镜像并扫描漏洞推送到镜像仓库滚动更新生产环境容器自动化冒烟测试监控验证使用Jenkinsfile示例pipeline { agent any stages { stage(Build) { steps { sh mvn clean package sh docker build -t your-image . } } stage(Test) { steps { sh mvn test sh docker run your-image mvn verify } } stage(Deploy) { steps { sh docker push your-image sh kubectl set image deployment/your-app your-appyour-image } } } }8. 常见问题排查指南8.1 启动问题排查容器启动失败# 查看容器日志 docker logs container_name # 检查退出状态 docker inspect -f {{.State.ExitCode}} container_nameNginx配置测试docker exec nginx nginx -tTomcat启动超时检查JVM内存设置查看catalina.out日志增加启动超时时间8.2 性能问题排查慢请求分析# 统计Nginx慢请求 awk $71 {print $0} /var/log/nginx/access.log | sort -k7 -nr | head -20 # 分析Tomcat线程转储 jstack pid thread_dump.log内存泄漏诊断# 生成heap dump jmap -dump:live,formatb,fileheap.hprof pid # 使用MAT工具分析8.3 网络问题排查容器间通信测试docker exec -it nginx ping tomcat1端口连通性检查telnet tomcat1 8080DNS解析验证docker exec nginx nslookup tomcat19. 进阶优化方向9.1 动态扩缩容方案基于CPU使用率的自动扩缩docker service update --replicas5 your_service使用Kubernetes HPAapiVersion: autoscaling/v2beta2 kind: HorizontalPodAutoscaler metadata: name: tomcat-hpa spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: tomcat minReplicas: 3 maxReplicas: 10 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 709.2 服务网格集成使用Istio实现金丝雀发布流量镜像熔断机制配置示例apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: tomcat-vs spec: hosts: - tomcat.example.com http: - route: - destination: host: tomcat subset: v1 weight: 90 - destination: host: tomcat subset: v2 weight: 109.3 混合云部署策略跨云集群方案使用Kubernetes Federation部署地域感知服务全局负载均衡配置示例apiVersion: scheduling.federation.k8s.io/v1alpha1 kind: ReplicaSchedulingPreference metadata: name: tomcat-preference namespace: default spec: targetKind: FederatedDeployment totalReplicas: 10 clusters: cluster1: minReplicas: 4 maxReplicas: 6 weight: 1 cluster2: minReplicas: 4 maxReplicas: 6 weight: 1在实际生产环境中这套NginxTomcat容器化方案已经稳定运行超过3年期间经历了多次大促活动的考验。最关键的体会是容器化不是简单的环境打包而是需要从架构设计、资源分配、监控告警等多个维度进行整体规划。特别是在流量突增场景下合理的资源限制和自动扩缩容策略往往比单纯增加服务器更有效。