PHP项目Docker容器内日志如何持久化

wen PHP项目 19

本文目录导读:

PHP项目Docker容器内日志如何持久化

  1. 使用Docker Volumes(推荐方案)
  2. 使用Bind Mounts(直接挂载宿主机目录)
  3. PHP代码层面配置
  4. 配置Nginx访问日志持久化
  5. 日志收集方案(ELK Stack)
  6. 日志轮转配置
  7. 最佳实践建议
  8. 监控和告警

在PHP项目的Docker容器中实现日志持久化,主要有以下几种方案:

使用Docker Volumes(推荐方案)

Docker Compose配置

version: '3.8'
services:
  php-app:
    image: your-php-app:latest
    volumes:
      - php-logs:/var/www/html/logs
    environment:
      - LOG_DIR=/var/www/html/logs
volumes:
  php-logs:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: /path/on/host/logs  # 宿主机存储路径

Docker命令方式

# 创建卷
docker volume create php-logs
# 运行容器时挂载
docker run -d \
  --name php-app \
  -v php-logs:/var/www/html/logs \
  your-php-app:latest

使用Bind Mounts(直接挂载宿主机目录)

version: '3.8'
services:
  php-app:
    image: your-php-app:latest
    volumes:
      - /data/logs/php:/var/www/html/logs:rw
    # 或相对路径
    # - ./logs:/var/www/html/logs

PHP代码层面配置

修改PHP日志配置

// config.php
define('LOG_PATH', '/var/www/html/logs/app.log');
// 确保目录存在
if (!is_dir('/var/www/html/logs')) {
    mkdir('/var/www/html/logs', 0777, true);
}
// 日志写入函数
function writeLog($message, $level = 'INFO') {
    $logFile = LOG_PATH . '/' . date('Y-m-d') . '.log';
    $content = sprintf(
        "[%s] [%s] %s%s",
        date('Y-m-d H:i:s'),
        $level,
        $message,
        PHP_EOL
    );
    file_put_contents($logFile, $content, FILE_APPEND | LOCK_EX);
}

使用Monolog(推荐)

use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\RotatingFileHandler;
// 创建日志器
$log = new Logger('app');
// 按天轮转,保留30天
$log->pushHandler(
    new RotatingFileHandler('/var/www/html/logs/app.log', 30, Logger::DEBUG)
);
// 使用
$log->info('User login', ['user_id' => 123]);
$log->error('Database connection failed', ['error' => $e->getMessage()]);

配置Nginx访问日志持久化

version: '3.8'
services:
  nginx:
    image: nginx:alpine
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d
      - nginx-logs:/var/log/nginx
    depends_on:
      - php-app
  php-app:
    image: your-php-app:latest
    volumes:
      - php-logs:/var/www/html/logs
volumes:
  php-logs:
  nginx-logs:

Nginx配置示例

server {
    listen 80;
    server_name example.com;
    access_log /var/log/nginx/access.log main buffer=32k flush=5s;
    error_log /var/log/nginx/error.log warn;
    location ~ \.php$ {
        fastcgi_pass php-app:9000;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

日志收集方案(ELK Stack)

version: '3.8'
services:
  php-app:
    image: your-php-app:latest
    volumes:
      - php-logs:/var/www/html/logs
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
  filebeat:
    image: elastic/filebeat:7.15.0
    volumes:
      - php-logs:/var/www/html/logs:ro
      - ./filebeat.yml:/usr/share/filebeat/filebeat.yml:ro
    depends_on:
      - elasticsearch
  elasticsearch:
    image: elasticsearch:7.15.0
    environment:
      - discovery.type=single-node
    volumes:
      - es-data:/usr/share/elasticsearch/data
  kibana:
    image: kibana:7.15.0
    ports:
      - "5601:5601"
    depends_on:
      - elasticsearch
volumes:
  php-logs:
  es-data:

日志轮转配置

Docker Compose中配置

version: '3.8'
services:
  php-app:
    image: your-php-app:latest
    volumes:
      - php-logs:/var/www/html/logs
    logging:
      driver: "local"
      options:
        max-size: "10m"    # 单个日志文件最大10MB
        max-file: "5"      # 保留5个日志文件
        compress: "true"   # 压缩旧日志

Docker运行命令

docker run -d \
  --log-opt max-size=10m \
  --log-opt max-file=5 \
  --log-opt compress=true \
  --name php-app \
  your-php-app:latest

最佳实践建议

Dockerfile示例

FROM php:8.1-fpm
# 创建日志目录并设置权限
RUN mkdir -p /var/log/php && \
    chown -R www-data:www-data /var/log/php
# 复制PHP配置
COPY php.ini /usr/local/etc/php/
COPY www.conf /usr/local/etc/php-fpm.d/
# 应用代码
COPY . /var/www/html
# 创建挂载点
VOLUME ["/var/www/html/logs", "/var/log/php"]
# 启动脚本
COPY docker-entrypoint.sh /usr/local/bin/
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["php-fpm"]

权限处理

# docker-entrypoint.sh
#!/bin/bash
set -e
# 确保日志目录存在且权限正确
LOG_DIR="/var/www/html/logs"
if [ ! -d "$LOG_DIR" ]; then
    mkdir -p "$LOG_DIR"
fi
chown -R www-data:www-data "$LOG_DIR"
# 执行主命令
exec "$@"

监控和告警

# promtail.yml (Loki日志收集)
scrape_configs:
  - job_name: php-logs
    static_configs:
      - targets: ['localhost']
        labels:
          job: php-app
          __path__: /var/log/php/*.log
    pipeline_stages:
      - regex:
          expression: '^(?P<timestamp>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) \[(?P<level>\w+)\] (?P<message>.*)$'
      - labels:
          level:

选择建议:

  • 开发环境:使用Bind Mounts简单方便
  • 生产环境:使用Docker Volumes + 日志收集系统(ELK/Loki)
  • 小型项目:使用RotatingFileHandler + Docker Volumes
  • 大型项目:考虑集中式日志管理(ELK Stack或Grafana Loki)

抱歉,评论功能暂时关闭!