用Docker+Nginx+Redis搭建个文档服务器

习惯上只是简单把 Nginx 用作 WebServer,最近看了看它的插件,发现其实有很多玩法,特别是很多工作可以不再需要写代码了,通过安装配置插件就可以实现。本文以搭建一个文档服务器为例,演示一下怎样使用 Nginx 插件。

项目概述

本项目尝试用Nginx的多个模块搭建一个文档服务器,实现文件的上传和浏览。纯粹用Nginx实现是想讲文件上传作为一个独立的基础模块,如果其他业务模块需要文件管理功能,可以直接使用。

项目地址:https://github.com/javanan/tms-nginx-finder/

安装插件

名称功能指令
echo-nginx-module快速响应内容echo
nginx-upload-module上传文件upload_xxx
njs用 Javascript 处理业务逻辑js_xxx
set-misc-nginx-module在 nginx.conf 文件中处理变量set_unescape_uri
redis2-nginx-moduleredis 客户端redis2_xxx

配置 Nginx

环境参数

环境变量参数名说明
REDIS_KEY_UPLOAD_START_TIME$redis_key_upload_start_timeRedis 中用于保存服务启动时间的 key
REDIS_KEY_UPLOAD_COUNTER$redis_key_upload_counterRedis 中用于保存上传文件次数的 key
REDIS_CHANNEL_UPLOAD$redis_channel_uploadRedis 中接收上传文件信息的 channel
LOCAL_UPLOAD_LOG本地保存上传文件日志,指定了记,不指定不记

需要在nginx.conf文件中添加如下设置,用env指令说明需要使用的环境变量,用js_set指令创建变量并赋值(没有找到直接在配置文件中使用环境变量的方法)。

env REDIS_KEY_UPLOAD_START_TIME;
env REDIS_KEY_UPLOAD_COUNTER;
env REDIS_CHANNEL_UPLOAD;
js_include /usr/local/nginx/njs/upload.js;
js_set $redis_key_upload_start_time var_redis_key_upload_start_time;
js_set $redis_key_upload_counter var_redis_key_upload_counter;
js_set $redis_channel_upload var_redis_channel_upload;

访问目录

我们希望可以通过 Nginx 直接访问某个目录下的文件,例如:nginx 工作目录下的 files 目录,在nginx.conf中添加如下内容:

location = /files/ {
  root .;
  autoindex on;
}

上传文件

我们用nginx-upload-module插件实现文件上传功能。安装完成后,在nginx.conf中添加如下配置:

location /upload/ {
  # 指定上传文件的存放位置
  upload_store /usr/local/nginx/files;

  # 设置转发的信息
  upload_set_form_field $upload_field_name.name "$upload_file_name";
  upload_set_form_field $upload_field_name.content_type "$upload_content_type";
  upload_set_form_field $upload_field_name.path "$upload_tmp_path";
  upload_aggregate_form_field "$upload_field_name.md5" "$upload_file_md5";
  upload_aggregate_form_field "$upload_field_name.size" "$upload_file_size";

  # 文件上传后转发请求
  upload_pass @upload_response;
  # add_header "Content-Type" "text/html; charset=UTF-8";
  # echo "echo: Upload done";
}

指令upload_pass是文件上传后将文件的基本信息转发到指定地址。接收上传文件信息的地址用的是命名地址(named location),它不是按照正则匹配的,用于内部转发(后面 njs 模块会说明如何实现)。

上传的文件会放在指令upload_store指定的位置,文件是由数字组成的递增的字符,例如:0000000001,0000000002。如果不需要后续处理,可以不用转发上传文件数据,直接通过echo指令返回结果。

处理文件

因为无法指定上传文件的命名(没有扩展名),而且每次重启 Nginx 都会从头开始给文件命名,可能会覆盖已有的文件,这样使用起来不方便,所以希望能够修改上传文件的名字。这里我们使用了njs模块,在nginx.conf中添加如下配置:

js_include /usr/local/nginx/njs/upload.js;
location @upload_response {
  js_content handle;
}

文件的命名由 3 个部分组成:服务启动时间+启动以来上传的文件数加 1+扩展名,例如:20191224_124808_8.mp4。为了实现这个要求,需要记录服务启动时间和上传文件次数。最简单的方法考虑是做成全局变量,但是在 Nginx 中没有找到实现方法。本来想可以把数据写到本地文件中,但是这样应该会有并发读取的问题,所以决定用 Redis 来保存数据。

访问 Redis

Redis 中存放两个数据:1、启动时间;2、计数器。每次上传一个文件就通过启动时间和计数器组合出一个文件名。获取启动时间用get命令,获取计数器用incr命令。利用 redis2-nginx-module 模块可以把 nginx 变成一个 redis 客户端,我们在nginx.conf中添加如下配置:

location = /redis/counter {
  redis2_query get $redis_key_upload_start_time;
  redis2_query incr $redis_key_upload_counter;
  redis2_pass redis:6379;
}

Redis 除了存储共享信息外,我们还用它进行事件通知,每次完成一个文件的处理后,利用 Redis 的发布订阅机制发送一条上传文件的信息,这样如果其他的系统需要进行扩展可以接收这个事件。在nginx.conf中添加如下配置:

location = /redis/publish {
  set_unescape_uri $message $arg_message;
  redis2_query publish $redis_channel_upload $message;
  redis2_pass redis:6379;
}

容器化

为了便于使用,我们将整个项目做成 docker 容器。容器有 3 个:Nginx 容器,Redis 容器和 Redis-cli 容器,其中 Redis-cli 是为了在 Redis 中设置初始值。

设置时区

alpine镜像默认的时区是UTC,和我们差了 8 个小时。前面提到过需要将服务启动时间作为上传文件名的一部分,因此需要把失去调整为Asia/Shanghai。Dockerfile 中添加如下内容:

RUN sed -i 's?http://dl-cdn.alpinelinux.org/?https://mirrors.aliyun.com/?' /etc/apk/repositories && \
    apk add -U tzdata && \
    cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
    apk del tzdata

Redis 初始值

我们需要每次服务启动时在 Redis 中记录启动时间,想到最简单的方法 Redis 服务启动后,用redis-cli执行如下命令。

date +'%Y%m%d_%H%M%S' | xargs redis-cli -h redis set uploadBootAt

环境变量

docker-compose.yml文件中指定环境变量的值,如果需要可以通过docker-compose.override.yml文件覆盖。

environment:
  - REDIS_KEY_UPLOAD_BOOT_AT=upload:start_time
  - REDIS_KEY_UPLOAD_COUNTER=upload:counter
  - REDIS_CHANNEL_UPLOAD=upload:event

其他

volumes:
  - ./nginx/nginx.conf:/usr/local/nginx/conf/nginx.conf:ro
  - ./nginx/html:/usr/local/nginx/html
  - ./nginx/njs:/usr/local/nginx/njs
  - ./upload:/usr/local/nginx/files

这里分享个经验。本来想让文件上传到容器中的tmp目录下,然后再改名到volumes指定的目录下。但是,这样需要在两个device之间移动文件,是不允许的,所以改成了文件直接上传到指定的目录,就地改名。


nginx.conf中设置连接 Redis。

location = /redis/counter {
  redis2_query get $redis_key_upload_start_time;
  redis2_query incr $redis_key_upload_counter;
  redis2_pass redis:6379;
}

这需要两个容器之间进行连接,但事先我们并不知道地址是什么,解决的方法是在docker-compose.yml中进行指定。

Containers for the linked service are reachable at a hostname identical to the alias, or the service name if no alias was specified.

nginx:
  ...
  links:
      - redis

JS 代码说明

nginx.conf文件

env REDIS_KEY_UPLOAD_START_TIME;
js_set $redis_key_upload_start_time var_redis_key_upload_start_time;

njs/upload.js

//
function var_redis_key_upload_start_time(r) {
  return process.env.REDIS_KEY_UPLOAD_START_TIME;
}

通过js_set指令可以解决在nginx.conf文件中无法引用环境变量给变量赋值的问题。


r.subrequest("/redis/counter", { method: "GET" }, function(res) {
  ......
});

subrequest方法可以发起调用,但是不能对命名地址(named location)进行调用。


var fs = require("fs");
fs.renameSync(oFileData.path, newpath);

使用fs模块可以进行简单的文件操作。但是不能用require调用自己编写的模块。

在这里插入图片描述

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要配置 PHP 环境、Nginx、MySQL 和 Redis,你按照以下步骤进行操作: 1. 首,安装 DockerDocker Compose(如果尚未安)。 2. 创建一个新的目录,用于存放你的文件和配置文件。 在该目录下一个 `docker-compose.yml` 文件将以下内容复制到文件中: yaml version: '3' services: nginx: image: nginx:latest : - 80:80 volumes - ./nginx.conf://nginx/nginx.conf ./public:/var/www/html depends_on: - php php: image: php:latest volumes: - ./php.ini:/usr/local/etc/php/php.ini - ./public:/var/www/html mysql: image: mysql:latest ports: - 3306:3306 environment: - MYSQL_ROOT_PASSWORD=your_mysql_root_password - MYSQL_DATABASE=your_mysql_database - MYSQL_USER=your_mysql_user - MYSQL_PASSWORD=your_mysql_password volumes: - ./mysql:/var/lib/mysql redis: image: redis:latest ports: - 6379:6379 volumes: - ./redis:/data ``` 4. 创建一个 `nginx.conf` 文件,并将以下内容复制到文件中。你可以根据需要进行修改。 ```nginx events {} http { server { listen 80; server_name localhost; root /var/www/html; index index.php index.html; location / { try_files $uri $uri/ /index.php?$query_string; } location ~ \.php$ { fastcgi_pass php:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } } } ``` 5. 创建一个 `php.ini` 文件,并根据需要进行修改。 6. 创建一个 `public` 文件夹用于存放你的 PHP 项目文件。 7. 运行以下命令启动 Docker 容器: ```shell docker-compose up -d ``` 这将会启动 Nginx、PHP、MySQL 和 Redis 容器。 现在,你已经成功配置了 PHP 环境、Nginx、MySQL 和 Redis。你可以将你的 PHP 项目文件放在 `public` 文件夹中,然后通过访问 `http://localhost` 来访问你的应用程序。请确保修改 `mysql` 服务中的环境变量,设置你自己的 MySQL 根密码、数据库名称、用户名和密码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值