强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

Apache HTTP Server 完全指南 / Docker 部署

Docker 部署

Docker 为 Apache 提供了标准化、可移植的部署方式。本章介绍 Apache 的 Docker 化部署和管理。

1. 官方镜像

1.1 基本使用

# 拉取官方镜像
docker pull httpd:2.4

# 运行容器
docker run -d --name apache \
    -p 80:80 \
    httpd:2.4

# 验证
curl http://localhost/

# 查看日志
docker logs apache

1.2 自定义配置

# 挂载配置文件
docker run -d --name apache \
    -p 80:80 \
    -v $(pwd)/httpd.conf:/usr/local/apache2/conf/httpd.conf \
    -v $(pwd)/website:/usr/local/apache2/htdocs \
    httpd:2.4

# 挂载多个配置
docker run -d --name apache \
    -p 80:80 \
    -v $(pwd)/httpd.conf:/usr/local/apache2/conf/httpd.conf \
    -v $(pwd)/extra:/usr/local/apache2/conf/extra \
    -v $(pwd)/website:/usr/local/apache2/htdocs \
    -v $(pwd)/logs:/usr/local/apache2/logs \
    httpd:2.4

1.3 启用模块

# Dockerfile
FROM httpd:2.4

# 启用模块
RUN sed -i \
    -e 's/^#\(LoadModule proxy_module\)/\1/' \
    -e 's/^#\(LoadModule proxy_http_module\)/\1/' \
    -e 's/^#\(LoadModule rewrite_module\)/\1/' \
    -e 's/^#\(LoadModule ssl_module\)/\1/' \
    -e 's/^#\(LoadModule headers_module\)/\1/' \
    -e 's/^#\(LoadModule deflate_module\)/\1/' \
    -e 's/^#\(LoadModule expires_module\)/\1/' \
    -e 's/^#\(LoadModule cache_module\)/\1/' \
    -e 's/^#\(LoadModule cache_disk_module\)/\1/' \
    conf/httpd.conf

# 复制自定义配置
COPY httpd.conf /usr/local/apache2/conf/httpd.conf
COPY extra/ /usr/local/apache2/conf/extra/

# 复制网站文件
COPY website/ /usr/local/apache2/htdocs/

2. 自定义镜像

2.1 基本 Dockerfile

# Dockerfile
FROM httpd:2.4

# 安装依赖
RUN apt-get update && apt-get install -y \
    libapache2-mod-security2 \
    && rm -rf /var/lib/apt/lists/*

# 启用模块
RUN a2enmod rewrite ssl headers deflate expires

# 复制配置
COPY httpd.conf /usr/local/apache2/conf/httpd.conf
COPY extra/ /usr/local/apache2/conf/extra/

# 创建日志目录
RUN mkdir -p /usr/local/apache2/logs

# 复制网站
COPY website/ /usr/local/apache2/htdocs/

# 暴露端口
EXPOSE 80 443

# 健康检查
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
    CMD curl -f http://localhost/ || exit 1

# 启动 Apache
CMD ["httpd-foreground"]

2.2 多阶段构建

# 构建阶段
FROM httpd:2.4 AS builder

# 安装构建工具
RUN apt-get update && apt-get install -y \
    build-essential \
    libpcre3-dev \
    libssl-dev \
    && rm -rf /var/lib/apt/lists/*

# 编译自定义模块
COPY modules/ /tmp/modules/
RUN cd /tmp/modules && \
    /usr/local/apache2/bin/apxs -cia mod_custom.c

# 运行阶段
FROM httpd:2.4

# 从构建阶段复制模块
COPY --from=builder /usr/local/apache2/modules/mod_custom.so \
    /usr/local/apache2/modules/

# 配置
COPY httpd.conf /usr/local/apache2/conf/httpd.conf

EXPOSE 80
CMD ["httpd-foreground"]

2.3 PHP-FPM 集成

# Dockerfile.apache
FROM httpd:2.4

# 启用代理模块
RUN sed -i \
    -e 's/^#\(LoadModule proxy_module\)/\1/' \
    -e 's/^#\(LoadModule proxy_fcgi_module\)/\1/' \
    -e 's/^#\(LoadModule rewrite_module\)/\1/' \
    -e 's/^#\(LoadModule deflate_module\)/\1/' \
    conf/httpd.conf

# 添加 PHP-FPM 配置
RUN echo 'ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://php:9000/var/www/html/$1' >> \
    conf/httpd.conf

COPY website/ /usr/local/apache2/htdocs/
EXPOSE 80
CMD ["httpd-foreground"]

3. Docker Compose

3.1 基本 Compose 配置

# docker-compose.yml
version: '3.8'

services:
  apache:
    image: httpd:2.4
    container_name: apache
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./httpd.conf:/usr/local/apache2/conf/httpd.conf
      - ./extra:/usr/local/apache2/conf/extra
      - ./website:/usr/local/apache2/htdocs
      - ./logs:/usr/local/apache2/logs
      - ./ssl:/usr/local/apache2/conf/ssl
    restart: unless-stopped
    networks:
      - web

networks:
  web:
    driver: bridge

3.2 Apache + PHP-FPM

version: '3.8'

services:
  apache:
    build:
      context: ./apache
      dockerfile: Dockerfile
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./website:/var/www/html
      - ./apache/httpd.conf:/usr/local/apache2/conf/httpd.conf
      - ./logs/apache:/var/log/apache2
    depends_on:
      - php
    restart: unless-stopped
    networks:
      - web

  php:
    image: php:8.2-fpm
    container_name: php-fpm
    volumes:
      - ./website:/var/www/html
      - ./php/www.conf:/usr/local/etc/php-fpm.d/www.conf
      - ./php/php.ini:/usr/local/etc/php/php.ini
    restart: unless-stopped
    networks:
      - web

networks:
  web:
    driver: bridge

3.3 Apache + MySQL + PHP

version: '3.8'

services:
  apache:
    build: ./apache
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./website:/var/www/html
    depends_on:
      - php
      - mysql
    restart: unless-stopped
    networks:
      - web

  php:
    image: php:8.2-fpm
    volumes:
      - ./website:/var/www/html
      - ./php/www.conf:/usr/local/etc/php-fpm.d/www.conf
    depends_on:
      - mysql
    restart: unless-stopped
    networks:
      - web

  mysql:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: ${MYSQL_DATABASE}
      MYSQL_USER: ${MYSQL_USER}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
    volumes:
      - mysql_data:/var/lib/mysql
    restart: unless-stopped
    networks:
      - web

  phpmyadmin:
    image: phpmyadmin/phpmyadmin
    environment:
      PMA_HOST: mysql
      PMA_PORT: 3306
    ports:
      - "8080:80"
    depends_on:
      - mysql
    restart: unless-stopped
    networks:
      - web

volumes:
  mysql_data:

networks:
  web:
    driver: bridge

3.4 WordPress 部署

version: '3.8'

services:
  apache:
    build: ./apache
    ports:
      - "80:80"
    volumes:
      - wordpress_data:/var/www/html
    depends_on:
      - php
      - mysql
    restart: unless-stopped

  php:
    image: php:8.2-fpm
    volumes:
      - wordpress_data:/var/www/html
    restart: unless-stopped

  mysql:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: root_password
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: wordpress_password
    volumes:
      - mysql_data:/var/lib/mysql
    restart: unless-stopped

volumes:
  wordpress_data:
  mysql_data:

4. 配置管理

4.1 环境变量

# Dockerfile
FROM httpd:2.4

# 环境变量
ENV APACHE_SERVER_NAME=www.example.com
ENV APACHE_SERVER_ADMIN=[email protected]
ENV APACHE_DOCUMENT_ROOT=/usr/local/apache2/htdocs

# 使用 envsubst 生成配置
RUN apt-get update && apt-get install -y gettext-base

COPY httpd.conf.template /usr/local/apache2/conf/httpd.conf.template
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

ENTRYPOINT ["/entrypoint.sh"]
CMD ["httpd-foreground"]
#!/bin/bash
# entrypoint.sh

# 生成配置文件
envsubst '${APACHE_SERVER_NAME} ${APACHE_SERVER_ADMIN} ${APACHE_DOCUMENT_ROOT}' \
    < /usr/local/apache2/conf/httpd.conf.template \
    > /usr/local/apache2/conf/httpd.conf

# 执行原始入口点
exec "$@"
# httpd.conf.template
ServerName ${APACHE_SERVER_NAME}
ServerAdmin ${APACHE_SERVER_ADMIN}
DocumentRoot ${APACHE_DOCUMENT_ROOT}

4.2 配置文件挂载

version: '3.8'

services:
  apache:
    image: httpd:2.4
    volumes:
      # 主配置
      - ./config/httpd.conf:/usr/local/apache2/conf/httpd.conf
      
      # 虚拟主机配置
      - ./config/vhosts:/usr/local/apache2/conf/vhosts
      
      # SSL 证书
      - ./ssl/certs:/usr/local/apache2/conf/ssl/certs:ro
      - ./ssl/private:/usr/local/apache2/conf/ssl/private:ro
      
      # 网站文件
      - ./website:/usr/local/apache2/htdocs
      
      # 日志
      - ./logs:/usr/local/apache2/logs

4.3 秘密管理

version: '3.8'

services:
  apache:
    image: httpd:2.4
    secrets:
      - ssl_cert
      - ssl_key
      - htpasswd
    volumes:
      - ./website:/usr/local/apache2/htdocs

secrets:
  ssl_cert:
    file: ./ssl/certs/server.crt
  ssl_key:
    file: ./ssl/private/server.key
  htpasswd:
    file: ./config/.htpasswd

5. 生产环境部署

5.1 优化 Dockerfile

FROM httpd:2.4-alpine

# 安装必要工具
RUN apk add --no-cache \
    curl \
    openssl

# 创建非 root 用户
RUN addgroup -g 1000 apache && \
    adduser -u 1000 -G apache -s /bin/sh -D apache

# 启用模块
RUN sed -i \
    -e 's/^#\(LoadModule rewrite_module\)/\1/' \
    -e 's/^#\(LoadModule ssl_module\)/\1/' \
    -e 's/^#\(LoadModule headers_module\)/\1/' \
    -e 's/^#\(LoadModule deflate_module\)/\1/' \
    -e 's/^#\(LoadModule expires_module\)/\1/' \
    conf/httpd.conf

# 复制配置
COPY httpd.conf /usr/local/apache2/conf/httpd.conf
COPY ssl/ /usr/local/apache2/conf/ssl/

# 创建必要目录
RUN mkdir -p /usr/local/apache2/logs && \
    chown -R apache:apache /usr/local/apache2

# 设置权限
COPY --chown=apache:apache website/ /usr/local/apache2/htdocs/

# 健康检查
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
    CMD curl -f http://localhost/ || exit 1

# 暴露端口
EXPOSE 80 443

# 使用非 root 用户
USER apache

# 启动命令
CMD ["httpd-foreground"]

5.2 安全配置

version: '3.8'

services:
  apache:
    build: .
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./website:/usr/local/apache2/htdocs:ro
      - ./logs:/usr/local/apache2/logs
    # 安全选项
    read_only: true
    tmpfs:
      - /tmp
    security_opt:
      - no-new-privileges:true
    cap_drop:
      - ALL
    cap_add:
      - NET_BIND_SERVICE
    # 资源限制
    deploy:
      resources:
        limits:
          cpus: '2.0'
          memory: 512M
        reservations:
          cpus: '0.5'
          memory: 128M
    restart: unless-stopped
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

6. CI/CD 集成

6.1 自动构建

# .github/workflows/docker.yml
name: Build and Push

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Build Docker image
        run: docker build -t my-apache:${{ github.sha }} .
      
      - name: Test Docker image
        run: |
          docker run -d --name test -p 80:80 my-apache:${{ github.sha }}
          sleep 5
          curl -f http://localhost/ || exit 1
          docker stop test
      
      - name: Push to Registry
        if: github.ref == 'refs/heads/main'
        run: |
          docker tag my-apache:${{ github.sha }} registry.example.com/my-apache:latest
          docker push registry.example.com/my-apache:latest

6.2 多环境部署

# docker-compose.prod.yml
version: '3.8'

services:
  apache:
    image: registry.example.com/my-apache:${IMAGE_TAG:-latest}
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /data/website:/usr/local/apache2/htdocs
      - /data/logs/apache:/usr/local/apache2/logs
      - /etc/ssl/certs:/usr/local/apache2/conf/ssl/certs:ro
      - /etc/ssl/private:/usr/local/apache2/conf/ssl/private:ro
    environment:
      - APACHE_SERVER_NAME=www.example.com
      - APACHE_ENV=production
    deploy:
      replicas: 3
      update_config:
        parallelism: 1
        delay: 30s
      restart_policy:
        condition: on-failure
    networks:
      - web

7. 监控与日志

7.1 Docker 日志

version: '3.8'

services:
  apache:
    image: httpd:2.4
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "5"
        tag: "apache"
    volumes:
      - ./logs:/usr/local/apache2/logs

7.2 Prometheus 监控

version: '3.8'

services:
  apache:
    image: httpd:2.4
    # ...
    
  apache-exporter:
    image: lusotycoon/apache-exporter
    command: --scrape_uri=http://apache/server-status?auto
    depends_on:
      - apache
    networks:
      - monitoring
      
  prometheus:
    image: prom/prometheus
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
    networks:
      - monitoring
      
  grafana:
    image: grafana/grafana
    ports:
      - "3000:3000"
    networks:
      - monitoring

8. 备份与恢复

8.1 备份脚本

#!/bin/bash
# backup-apache.sh

BACKUP_DIR="/backup/apache/$(date +%Y%m%d)"
mkdir -p $BACKUP_DIR

# 备份配置
docker cp apache:/usr/local/apache2/conf $BACKUP_DIR/conf

# 备份网站文件
docker cp apache:/usr/local/apache2/htdocs $BACKUP_DIR/htdocs

# 备份日志
docker cp apache:/usr/local/apache2/logs $BACKUP_DIR/logs

# 备份 Docker 配置
cp docker-compose.yml $BACKUP_DIR/
cp Dockerfile $BACKUP_DIR/

# 压缩
tar -czf $BACKUP_DIR.tar.gz -C /backup/apache $(date +%Y%m%d)
rm -rf $BACKUP_DIR

echo "备份完成: $BACKUP_DIR.tar.gz"

8.2 恢复脚本

#!/bin/bash
# restore-apache.sh

BACKUP_FILE=$1

if [ -z "$BACKUP_FILE" ]; then
    echo "用法: $0 <backup-file.tar.gz>"
    exit 1
fi

# 解压
tar -xzf $BACKUP_FILE -C /tmp/

# 停止容器
docker stop apache

# 恢复配置
docker cp /tmp/*/conf apache:/usr/local/apache2/

# 恢复网站
docker cp /tmp/*/htdocs apache:/usr/local/apache2/

# 启动容器
docker start apache

# 清理
rm -rf /tmp/*

echo "恢复完成"

9. 业务场景

9.1 微服务架构

version: '3.8'

services:
  # API 网关
  gateway:
    build: ./gateway
    ports:
      - "80:80"
      - "443:443"
    
  # 用户服务
  user-service:
    build: ./user-service
    
  # 订单服务
  order-service:
    build: ./order-service
    
  # 产品服务
  product-service:
    build: ./product-service

9.2 开发环境

version: '3.8'

services:
  apache:
    build: ./apache
    ports:
      - "80:80"
    volumes:
      - ./website:/usr/local/apache2/htdocs
      - ./apache/httpd.conf:/usr/local/apache2/conf/httpd.conf
    environment:
      - APACHE_ENV=development

10. 注意事项

  1. 镜像选择:生产环境使用 Alpine 镜像减小体积
  2. 安全扫描:定期扫描镜像漏洞
  3. 资源限制:设置 CPU 和内存限制
  4. 日志管理:配置日志轮转,避免磁盘占满
  5. 健康检查:配置健康检查确保服务可用

11. 扩展阅读

12. 总结

Docker 为 Apache 部署带来了巨大优势:

  • 标准化:统一的构建和部署流程
  • 可移植:环境一致,避免"在我机器上能运行"
  • 可扩展:轻松水平扩展
  • 版本控制:配置和镜像版本化管理

结合 Docker Compose 和 CI/CD,可以实现高效的 Apache 部署和管理。