使用google的存储服务来做图床

之前写了《自建图床系统》,用了一段时间
主要的弊端就是利用率不高,太占资源。
lychee的docker中自带mysql,及php环境。
占了cpu资源,但自己使用得还是比较少的,总得来说不划算。

于是尝试用了google存储服务。
效果让人惊喜

  • 操作方便快捷,体验和操作本地文件系统差不多。
  • 共享的域名目前还没有被墙。
  • 存储服务的文件系统可以直接挂载在虚机上(挂载操作非常简单)。
  • 价格在接受范围内,0.026刀每G每月,提供两个数据中心的冗余。

操作storage

主要参考 https://cloud.google.com/storage/docs/quickstart-gsutil

创建一个区域

相当于创建一块硬盘

1
gsutil mb gs://xxx

上传对象

1
gsutil cp Desktop\t2.png gs://xxx

下载对象

1
gsutil cp  gs://xxx/t2.png Desktop

区域间的复制

1
gsutil cp gs://xxx/t2.png gs://yyy

列出区域的文件夹

1
gsutil ls gs://xxx/

使资源可以公共访问

给所有人读权限

1
gsutil acl ch -u AllUsers:R gs://xxx/t2.png

去掉权限

1
gsutil acl ch -d AllUsers gs://xxx/t2.png

做为文件系统挂载在虚机上

主要参考

安装gcsfuse

1
2
3
4
5
export GCSFUSE_REPO=gcsfuse-`lsb_release -c -s`
echo "deb http://packages.cloud.google.com/apt $GCSFUSE_REPO main" | sudo tee /etc/apt/sources.list.d/gcsfuse.list
curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
sudo apt-get update
sudo apt-get install gcsfuse

使用

  • 给Cloud Storage FUSE 权限
  • 创建目录mkdir /path/to/mount
  • 创建你想挂载的区域
  • 进行操作gcsfuse example-bucket /path/to/mount(这里的example-bucket是前面gs://example-bucket的strong)
  • 开始浏览ls /path/to/mount

其它操作

  • 挂载子文件夹gcsfuse --only-dir foldername/ my-bucket /mount/point
  • 取消挂载fusermount -u /home/shared/local_folder/
  • --file-mode--dir-mode可以指定权限
  • -o allow_other可以让别的用户访问,同时要修改/etc/fuse.conf

https://github.com/googlecloudplatform/gcsfuse/blob/master/docs/semantics.md#inodes

走过的坑

某天服务器重启后,挂载的磁盘没有了。于是找到这篇文章,继续来操作。
执行挂载gcsfuse xx dir,显示成功了。

1
2
3
4
Opening GCS connection...
Opening bucket...
Mounting file system...
File system has been successfully mounted.

但进入目录后,看不到文件。
执行ls,报错

1
ls: reading directory '.': Input/output error

猜想是目录的问题,新建了一个别的目录,也是一样的失败。
再猜想是存储的问题,新开了一台机器,同样的操作,也是可以挂上去的。
再猜想是存储的目录文件有问题,把源来的文件复制到一个新目录,再操作,还是不行。
再猜想是权限问题,运行gcloud init把账号重新认证了,也没有解决。
后来猜想是gcfuse的版本或者是gcloud版本问题,更新之后,也没有解决。

没办法,找网上的办法,
https://github.com/GoogleCloudPlatform/gcsfuse/issues/174
这个和我的情况有一点一样。但按上面的做法,我也已经重新做这个,没有问题。
但这里面提供了一个思路,可以用--foreground --debug_fuse看来debug信息。
于是看到了解决问题的新希望。
按上面加调试命令进行挂载。
输出的部分含有

1
2
3
4
5
WARNING, bucket doesn't appear to work:  Get https://www.googleapis.com/storage/v1/b/xxxx/o?maxResults=1&projection=full: oauth2: cannot fetch token: 400 Bad Request
Response: {
"error": "invalid_grant",
"error_description": "Bad Request"
}

无效的授权。看来和权限很相关了。

继续找,发现一个和我情况差不多的人,见https://thornelabs.blog/posts/resolve-google-cloud-api-oauth2-cannot-fetch-token-invalid-grant-error.html

这个人也是试了很多方法,没有解决,然后他用把~/.cofig/gcloud目录删除了,再重新gcloud init
然后解决了。

再进行挂摘。发现挂载成功。ls 下可以出文件。
但还没有完。上了nginx目录后,发现还是访问不了。
但发现和之后访问不了有区别,之后是404错误,现在是403错误。
就是说之后是找不文件,现在是没有权限访问。又是权限问题。
突然想到当时挂载时没有加允许别的用户访问的参数。
nginx不是以当前用户来运行的,访问不了文件。
于是再次加上参数试了下。果然可以了
gcsfuse --only-dir t/ -o allow_other fengcl blog_img

调错找错,是个需要耐心与细心的活。
但还是不能理解,为什么重启之后就出这个问题。

关于图床上传工具

在现成的api与库
https://cloud.google.com/storage/docs/reference/libraries#client-libraries-install-java
把上次的上传工具稍微改改。
增加生成文件名逻辑(目前取的是图片md5的中间16位)。

注意事项
gsutil是gcloud中的工具,之前要把gcloud配置好,进行鉴权等。
gsutil的路径要根据实际情况写,目前是写死到代码中了
上传之前还是要 set https_proxy