分布式文件系统
1.简介
通过先前的例子我们发现普通的方式安装及其麻烦,假如我们需要搭建集群,那更加麻烦。所以在安装软件时并不推荐使用常规的方式去安装,而是推荐使用基于Docker方式去安装
2.镜像选择
要想基于Dokcer的方式去安装,那么我们就需要选择合适的镜像。为了更好的安装,我更换了一台计算机,其IP地址为172.16.0.4
并安装了docker,搭建了私服。如果不知道安装,可以参考《Docker 使用系列》
-
搜索镜像
docker search fastdfs
发现虽然镜像有很多,但是并没有官方所提供的。同时其他的镜像我们也不清楚别人构建的过程。因此我们可以自己制作一个镜像。
3. 制作镜像
3.1 镜像文件解释
我们可以从github来拉取一个制作镜像的Dockerfile
.
-
地址
https://github.com/gzlj/fastdfs
-
目录结构
-
关于文件解释
所需的软件
-
Dockerfile解释
#基础镜像 FROM centos:7 #作者信息 MAINTAINER liujun "[email protected]" #安装所需的依赖 RUN yum install -y zlib zlib-devel pcre pcre-devel gcc gcc-c++ openssl openssl-devel libevent libevent-devel perl unzip #安装 libfastcommon #将libfastcommon-1.0.35.zip 复制到 /usr/local/src/ ADD libfastcommon-1.0.35.zip /usr/local/src/ # 进入到 /usr/local/src 并解压,同时还编译和运行 RUN cd /usr/local/src \ && unzip /usr/local/src/libfastcommon-1.0.35.zip \ && cd libfastcommon-1.0.35 \ && ./make.sh \ && ./make.sh install #安装 fastdfs # 将fastdfs-5.11.zip 复制到 /usr/local/src/下 ADD fastdfs-5.11.zip /usr/local/src/ # 解压 RUN cd /usr/local/src/ && unzip fastdfs-5.11.zip # 编译安装,同时将配置复制到 /etc/fdfs下 RUN cd /usr/local/src/fastdfs-5.11 \ && ./make.sh \ && ./make.sh install \ && cp conf/*.conf /etc/fdfs \ && cd /etc/fdfs/ \ && rm -rf *.sample #安装nginx #将fastdfs-nginx-module_v1.16.tar.gz 复制 /usr/local/src/ ADD fastdfs-nginx-module_v1.16.tar.gz /usr/local/src/ #ADD fastdfs-nginx-module-1.20.zip /usr/local/src/ #run cd /usr/local/src/ && unzip fastdfs-nginx-module-1.20.zip && ln -s fastdfs-nginx-module-1.20 fastdfs-nginx-module #将nginx-1.7.8.tar.gz 复制 /usr/local/src/ ADD nginx-1.7.8.tar.gz /usr/local/src/ # 添加模块,编译安装nginx RUN cd /usr/local/src/ \ && cd nginx-1.7.8 \ && ./configure --prefix=/usr/local/nginx --add-module=/usr/local/src/fastdfs-nginx-module/src \ && make \ && make install \ && cp /usr/local/src/fastdfs-nginx-module/src/mod_fastdfs.conf /etc/fdfs/ # 复制 nginx.conf 到 /usr/local/nginx/conf/ ADD nginx.conf /usr/local/nginx/conf/ #创建 storage和tracker 存储日志和数据目录 RUN mkdir -p /export/fastdfs/{storage,tracker} # 将脚本复制到 /usr/local/src/ ADD tracker.sh /usr/local/src/ ADD storage.sh /usr/local/src/
-
nginx.conf解释
#user nobody; worker_processes 1; #error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info; #pid logs/nginx.pid; events { worker_connections 1024; } http { include 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 logs/access.log main; sendfile on; #tcp_nopush on; #keepalive_timeout 0; keepalive_timeout 65; #gzip on; server { # 默认监听 8080,这个在创建容器时可以更换 listen 8080; # 监听域名为本机 server_name localhost; #charset koi8-r; #access_log logs/host.access.log main; # 如果发送的请求中,包含group 交给ngx_fastdfs_module 处理 location ~/group[1-9]/M00 { root /export/fastdfs/storage/data; ngx_fastdfs_module; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # # 错误页面 error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } # proxy the PHP scripts to Apache listening on 127.0.0.1:80 # #location ~ \.php$ { # proxy_pass http://127.0.0.1; #} # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # #location ~ \.php$ { # root html; # fastcgi_pass 127.0.0.1:9000; # fastcgi_index index.php; # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; # include fastcgi_params; #} # deny access to .htaccess files, if Apache's document root # concurs with nginx's one # #location ~ /\.ht { # deny all; #} } # another virtual host using mix of IP-, name-, and port-based configuration # #server { # listen 8000; # listen somename:8080; # server_name somename alias another.alias; # location / { # root html; # index index.html index.htm; # } #} # HTTPS server # #server { # listen 443 ssl; # server_name localhost; # ssl_certificate cert.pem; # ssl_certificate_key cert.key; # ssl_session_cache shared:SSL:1m; # ssl_session_timeout 5m; # ssl_ciphers HIGH:!aNULL:!MD5; # ssl_prefer_server_ciphers on; # location / { # root html; # index index.html index.htm; # } #} }
-
tracker.sh解释
#!/bin/sh if [ ! -f /initialized ]; then { touch /initialized #TRACKER_PORT 创建容器时需要手动指,如果采用默认的话,可以把这行删掉 sed -i "s#\(port\).*#\1=$TRACKER_PORT#" /etc/fdfs/tracker.conf #TRACKER_BASE_PATH 创建容器时需要手动指定 sed -i "s#\(base_path\).*#\1=$TRACKER_BASE_PATH#" /etc/fdfs/tracker.conf } fi # 重启 tracker /usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf restart # 展示日志 tail -f /export/fastdfs/tracker/logs/trackerd.log
-
storage.sh 解释
#!/bin/sh if [ ! -f /initialized ]; then { touch /initialized # STORAGE_PORT 创建容器时需要手动指定,如果采用默认的话,可以把这行删掉 sed -i "s#\(port\).*#\1=$STORAGE_PORT#" /etc/fdfs/storage.conf # GROUP_NAME 创建容器时需要手动指定组名,如果采用默认的话,可以把这行删掉 sed -i "s#\(group_name\).*#\1=$GROUP_NAME#" /etc/fdfs/storage.conf # STORAGE_BASE_PATH 创建容器时需要手动指定存储日志和数据的目录 sed -i "s#\(base_path\).*#\1=$STORAGE_BASE_PATH#" /etc/fdfs/storage.conf # STORAGE_BASE_PATH 创建容器时需要手动指定文件上传的存储目录 sed -i "s#\(store_path0\).*#\1=$STORAGE_PATH0#" /etc/fdfs/storage.conf # 创建容器时手动指定tracker_server sed -i "s#\(tracker_server\).*##" /etc/fdfs/storage.conf #HTTP_SERVER_PORT 创建容器时手动指定 sed -i "s#\(http.server_port\).*#\1=$HTTP_SERVER_PORT#" /etc/fdfs/storage.conf # STORAGE_BASE_PATH 创建容器时 指定 STORAGE_BASE_PATH 的值是mod_fastdfs.conf存储日志和数据的目录 sed -i "s#\(base_path\).*#\1=$STORAGE_BASE_PATH#" /etc/fdfs/mod_fastdfs.conf # STORAGE_PATH0 创建容器时 指定 STORAGE_PATH0文件上传的存储路径 sed -i "s#\(store_path0\).*#\1=$STORAGE_PATH0#" /etc/fdfs/mod_fastdfs.conf # STORAGE_PORT 手动指定端口,想要默认可以直接删掉 sed -i "s#\(storage_server_port\).*#\1=$STORAGE_PORT#" /etc/fdfs/mod_fastdfs.conf # 设置 mod_fastdfs 的 tracker_server sed -i "s#\(tracker_server\).*##" /etc/fdfs/mod_fastdfs.conf # GROUP_NAME 设置组名 sed -i "s#\(group_name\).*#\1=$GROUP_NAME#" /etc/fdfs/mod_fastdfs.conf # GROUP_COUNT 设置组的数量 sed -i "s#\(group_count\).*#\1=$GROUP_COUNT#" /etc/fdfs/mod_fastdfs.conf # 设置 HTTP_SERVER_PORT 端口 sed -i "s#\(http.server_port\).*#\1=$HTTP_SERVER_PORT#" /etc/fdfs/mod_fastdfs.conf #设置组名 sed -i "s#\(url_have_group_name\).*#\1=true#" /etc/fdfs/mod_fastdfs.conf # 这个非常重要,将HTTP_SERVER_PORT 的值设置为Nginx的监听端口 sed -i "s#listen 8080#listen $HTTP_SERVER_PORT#g" /usr/local/nginx/conf/nginx.conf for i in $( echo $TRACKER_SERVER | awk -v FS="," '{for(i=1;i<=NF;i++)print $i}' );do echo "tracker_server=$i" >> /etc/fdfs/storage.conf;done for i in $( echo $TRACKER_SERVER | awk -v FS="," '{for(i=1;i<=NF;i++)print $i}' );do echo "tracker_server=$i" >> /etc/fdfs/mod_fastdfs.conf;done #add groups 添加组 i=1 while(( $i<=$GROUP_COUNT )) do # 设置组信息 echo "[group$i]" >> /etc/fdfs/mod_fastdfs.conf # 设置组名 echo "group_name=group$i" >> /etc/fdfs/mod_fastdfs.conf # 设置组的端口 echo "storage_server_port=$STORAGE_PORT" >> /etc/fdfs/mod_fastdfs.conf # 设置组的存储路径数量 echo "store_path_count=1" >> /etc/fdfs/mod_fastdfs.conf # 设置组的文件存储路径 echo "store_path0=$STORAGE_PATH0" >> /etc/fdfs/mod_fastdfs.conf let "i++" done } fi cd /etc/fdfs touch mime.types /usr/local/nginx/sbin/nginx -t /usr/local/nginx/sbin/nginx # 启动storage /usr/bin/fdfs_storaged /etc/fdfs/storage.conf restart #展示日志 tail -f /export/fastdfs/storage/logs/storaged.log
3.2 镜像制作
-
根据上述中的 liujun 给我们提供的制作镜像的文件下载下来,并上传到 计算机上
-
下载 unzip 并解压
-
进入解压好的目录下,进行构建
docker build -t 宿主机Ip:私服端口/fastdfs:5.11 . 这个格式的镜像可以直接推送到私服,不用起别名
镜像构建成功
-
上传到私服
docker push 172.16.0.47:5000/fastdfs:5.11
成功后访问私服:
上传成功。
3.3 创建容器
这里我们创建一个tracker容器和一个storage容器,当然可以创建集群,无非是多创建几个容器。
但是我们在一台宿主机搭建集群意义也不大,如果多台机器的话,都是重复工作。如果有实际需求可以自己动手搭建。可以参考上述文件中的
READ ME.md
3.3.1 创建并运行容器
-
创建并运行容器(tracker)
docker run -di --name=fdfs_tracker -v /var/fdfs/tracker:/export/fastdfs/tracker --net=host -e TRACKER_BASE_PATH=/export/fastdfs/tracker -e TRACKER_PORT=22123 172.16.0.47:5000/fastdfs:5.11 sh /usr/local/src/tracker.sh
-v /var/fdfs/tracker
将track容器存储数据的目录映射到宿主机上--net=host
网络模式,映射容器上所有端口-e TRACKER_BASE_PATH=/export/fastdfs/tracker
设置tracker容器内存储日志和数据的目录,不要改-e TRACKER_PORT=22123
设置track的端口sh /usr/local/src/tracker.sh
执行容器里面的脚本 -
创建并运行容器(storage)
docker run -di --name=fdfs_storage -v /var/fastdfs/storage:/export/fastdfs/storage --net=host -e STORAGE_PORT=23001 -e STORAGE_BASE_PATH=/export/fastdfs/storage -e STORAGE_PATH0=/export/fastdfs/storage -e TRACKER_SERVER=172.16.0.47:22123 -e GROUP_COUNT=1 -e HTTP_SERVER_PORT=8081 -e GROUP_NAME=group1 172.16.0.47:5000/fastdfs:5.11 sh /usr/local/src/storage.sh
-v /var/fdfs/tracker
将track容器存储数据的目录映射到宿主机上--net=host
网络模式,映射容器上所有端口-e STORAGE_PORT=23001
设置storage的端口-e STORAGE_BASE_PATH=/export/fastdfs/storage
设置 storage容器内存储日志和数据的位置,不要改-e STORAGE_PATH0 =/export/fastdfs/storage
设置文件上传的存储路径-e TRACKER_SERVER=172.16.0.47:22123
设置tracker_server设置地址-e GROUP_COUNT=1
设置组的数量为1-e HTTP_SERVER_POR=8081
设置storage的http端口和nginx的监听端口-e GROUP_NAME=group1
设置组名sh /usr/local/src/storage.sh
执行storage脚本
3.3.2 测试
进入storage容器中,测试是否与tracker进行了连接
docker exec -it fdfs_storage /bin/bash
测试命令
/usr/bin/fdfs_monitor /etc/fdfs/storage.conf
连接成功。
通过浏览器访问,也可以看到nginx
4.Java客户端连接
4.1 简介
FastDFS的作者余庆先生也给我们提供一个java客户端用来连接 FastDFS,但是已经很久不维护了。但是在GitHub上有一款开源的FastDFS客户端。 这个客户端得到了在原来余庆先生提供的客户端基础上进行大量的重构
配置及其简单,支持连接池,支持自动生成缩略图,同时还支持SpringBoot 2.x
地址:https://github.com/tobato/FastDFS_Client
4.2 编码
4.2.1 上传普通文件
-
创建SpringBoot项目并导入依赖(springboot 版本:2.1.13.RELEASE)
com.github.tobato
fastdfs-client
1.27.2
-
修改
application.yml
文件,增加配置fdfs: connect-timeout: 600 so-timeout: 1501 tracker-list: # tracker地址 - 172.16.0.47:22123
-
增加配置类
package com.wangzh.fastdfs.config; import com.github.tobato.fastdfs.FdfsClientConfig; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableMBeanExport; import org.springframework.context.annotation.Import; import org.springframework.jmx.support.RegistrationPolicy; @Configuration @Import(FdfsClientConfig.class) // 解决jmx重复注册问题 @EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING) public class FastDFSClientConfig { }
-
测试上传普通文件
package com.wangzh.fastdfs; import com.github.tobato.fastdfs.domain.fdfs.StorePath; import com.github.tobato.fastdfs.service.FastFileStorageClient; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @RunWith(SpringRunner.class) @SpringBootTest public class FastdfsApplicationTests { /** * * 注入上传的客户端对象 */ @Autowired private FastFileStorageClient storageClient; @Test public void upload() throws FileNotFoundException { File file = new File("C:\\Users\\wangzh\\Desktop\\html.pdf"); /* * 第一个参数 为组名,不写 默认group1 * 第二个参数为文件流 * 第三个参数为上传文件的大小 * 第四个参数为 文件后缀名 * */ StorePath storePath = storageClient.uploadFile("group1", new FileInputStream(file), file.length(), "pdf"); /* * 打印文件名Id 包含组名 * 执行后的结果为: group1/M00/00/00/rBAAL16qgcOAbO_rAAi5YaAFEK0182.pdf * group1 组名 * M00 代表设置的 storage_path0 00/00 存储的具体磁盘目录 * rBAAL16qgcOAbO_rAAi5YaAFEK0182.pdf */ System.out.println(storePath.getFullPath()); /* * 打印文件名,不包含组名 * 执行后的结果为: M00/00/00/rBAAL16qgcOAbO_rAAi5YaAFEK0182.pdf * */ System.out.println(storePath.getPath()); } }
访问:
http://172.16.0.47:8081/group1/M00/00/00/rBAAL16qgcOAbO_rAAi5YaAFEK0182.pdf
文件上传成功。
4.2.2 上传图片
上传图片并自动创建缩略图
-
增加缩略图配置
fdfs: connect-timeout: 600 so-timeout: 1501 tracker-list: # tracker地址 - 172.16.0.47:22123 thumb-image: width: 70 height: 70
-
编码
package com.wangzh.fastdfs; import com.github.tobato.fastdfs.domain.fdfs.StorePath; import com.github.tobato.fastdfs.domain.fdfs.ThumbImageConfig; import com.github.tobato.fastdfs.service.FastFileStorageClient; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @RunWith(SpringRunner.class) @SpringBootTest public class FastdfsApplicationTests { /** * * 注入上传的客户端对象 */ @Autowired private FastFileStorageClient storageClient; /** * 注入缩略图配置对象 */ @Autowired private ThumbImageConfig thumbImageConfig; @Test public void testUpload() throws FileNotFoundException { File file = new File("D:\\1_soft\\1.jpg"); StorePath storePath = storageClient.uploadImageAndCrtThumbImage(new FileInputStream(file), file.length(), "jpg", null); System.out.println("带分组路径:" + storePath.getFullPath()); System.out.println("不带分组路径:" + storePath.getPath()); System.out.println("获取缩略图路径:" + thumbImageConfig.getThumbImagePath(storePath.getPath())); } }
结果:
带分组路径:group1/M00/00/00/rBAAL16qhXaAbzbAACXrwCHvecY269.jpg 不带分组路径:M00/00/00/rBAAL16qhXaAbzbAACXrwCHvecY269.jpg 获取缩略图路径:M00/00/00/rBAAL16qhXaAbzbAACXrwCHvecY269_70x70.jpg
我们通过浏览器访问一下:
http://172.16.0.47:8081/group1/M00/00/00/rBAAL16qhXaAbzbAACXrwCHvecY269_70x70.jpg
http://172.16.0.47:8081/group1/M00/00/00/rBAAL16qhXaAbzbAACXrwCHvecY269.jpg