穷人的孩子早当家是有一定道理的。由于用不起某里云的 OSS (对象存储)服务,自己折腾了一番。期间踩坑若干,故自行记录聊以慰籍。

技术选型是采用 MinIO 与 Thumbor 无疑,网上相关的文章也很多。我的故事分为 5 个节点:

0x00、最初的记忆——Docker 安装

是的,我一开始打算以 Docker 方式部署。

MinIO 的 Docker 部署方式可以完全参照官方文档进行:

docker run \
  -d \
  -p 9000:9000 \
  -p 9001:9001 \
  --name minio \
  -e MINIO_ROOT_USER='xxx' \
  -e MINIO_ROOT_PASSWORD='xxx' \
  minio/minio server /data --console-address ':9001'

MINIO_ROOT_USER 与 MINIO_ROOT_PASSWORD 是登录 MinIO Console 的账号密码,记得替换。

而 Thumbor 则是选择了一个叫做 Minimal Compact Thumbor 的镜像,真的是简单:

docker run -p 8888:80 minimalcompact/thumbor

一行搞定。

搞到这里,MinIO 已通过 Docker 方式跑起来了,本地测试 Thumbor 发现无法处理 MinIO 提供的私有地址,比如以下这种情况。

通过调用 MinIO 的 getPresignedObjectUrl 接口获取的私有地址:

http://127.0.0.1:9000/test/test.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=348201GIYPQI49I606RF%2F20210713%2Fxxx%2Fs3%2Faws4_request&X-Amz-Date=20210713T042509Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=xxx

Thumbor 处理的地址:

http://127.0.0.1:8888/unsafe/500x0/http://127.0.0.1:9000/test/test.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=348201GIYPQI49I606RF%2F20210713%2Fxxx%2Fs3%2Faws4_request&X-Amz-Date=20210713T042509Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=xxx

结果报 400 错误。

0x01、曲径通幽——通过 Python-pip 安装 Thumbor

因为折腾失败了,一顿分析后感觉应该编辑下 thumbor.conf,可能有关。又看了几篇文章,大部分都以 Python-pip 方式安装的,所以实验如下:

yum install python-pip -y
pip install thumbor

好了,失败。原因是操作系统 CentOS 7.x 自带 Python 2。而官方文档说了需要 Python 3.7 及以上:

Thumbor v7.0.0 and later only supports python 3.7+. This change was important to improve our codebase and ensure it’s easier to change in future releases. More breaking changes will come, but we do not anticipate any as big as this one. Please refer to release notes for details on how to upgrade.

好的,那就安装 Python 3。首先安装一些依赖:

yum install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gcc make libffi-devel python-pip -y

下载源码包,安装 Python 3.7:

wget -c https://www.python.org/ftp/python/3.7.11/Python-3.7.11.tgz
tar xzf pPython-3.7.11.tgz
cd Python-3.7.11
./configure prefix=/usr/local/python3 && make && make install

一顿刷屏之后,success 了。建两个软链,也可以不做:

ln -s /usr/local/python3/bin/python3.7 /usr/bin/python3.7
ln -s /usr/local/python3/bin/pip3.7 /usr/bin/pip3.7

验证一下:

python3.7 -V
Python 3.7.11

如果没建软链接,要这样:

/usr/local/python3/bin/python3.7 -V

还可以给 pip 升下级:

/usr/local/python3/bin/python3.7 -m pip install --upgrade pip

继续,大活来了:

pip install thumbor3.7

安装完成后生成配置文件:

thumbor-config > ./thumbor.conf

我就死在这儿了,一直报:

-bash: thumbor-config: command not found

一番折腾后无果,欲弃之。

0x02、回头草——Docker 真香定律

考虑到后续需要分布式部署,决定回归 Docker 的怀抱。总结当前的两个问题:

- MinIO 以 Docker 方式部署,网上有人说容器停了会丢数据;
- Thumbor 无法解析 MinIO 的私有地址。

第一个问题好办,想办法持久化存储就行,可以通过 -v 指定映射关系:

docker run \
  -d \
  -p 9000:9000 \
  -p 9001:9001 \
  --name minio \
  -v /data/minio:/data \
  -e MINIO_ROOT_USER='xxx' \
  -e MINIO_ROOT_PASSWORD='xxx' \
  minio/minio server /data --console-address ':9001'

/data/minio 是宿主机的数据目录,MinIO 搞定,剩下就是接口调试。

第二个问题在我一顿翻文档之后发现:

Thumbor only understands properly encoded URIs. In order to use the URI above (or any other for that matter), we first need to encode it.

真相大白。古人云,一定要看文档,真的没错。

0x03、强迫症——难以忍受的“unsafe”

由于本地 80、443 端口不能在公网开放,故通过另一台主机的 Nginx 配置 3 个域名,反向代理到这台主机,分别对应 MinIO 的 9000、9001 端口及 Thumbor 的 8888 端口。

现在 Thumbor 处理的地址是这样的:

https://oss.dev.xxx.com/unsafe/500x0/api.minio.dev.xxx.com%2Fbucket%2Ftest%2Ftest.jpg%3FX-Amz-Algorithm%3DAWS4-HMAC-SHA256%26X-Amz-Credential%3DQ6OYL97O80V8FKTIET78%252F20210713%252Fcnc-dev%252Fs3%252Faws4_request%26X-Amz-Date%3D20210713T074421Z%26X-Amz-Expires%3D604800%26X-Amz-SignedHeaders%3Dhost%26X-Amz-Signature%3Da11b4cdf85c47d6a8e90712ea7e9e5813d4ee8b39a9103b1be690c0ea7f6a949

正在大功告成的时候,前端弟兄说“unsafe”太难受了,能不能改掉。我尝试在 Nginx 上代理到 x.x.x.x:8888/unsafe,但是不行,会出现 400。

继续看文档,最终找到这么一章可以完美解决这个强迫症症状。

最终,Thumbor 容器的启动命令改造为:

docker run \
  -d \
  -p 8888:80 \
  --name thumbor \
  -e SECURITY_KEY='xxx' \
  -e ALLOW_UNSAFE_URL=False \
  -e THUMBOR_NUM_PROCESSES=5 \
  minimalcompact/thumbor

其中:

- SECURITY_KEY 密钥交给前端就能根据文档进行后续处理;
- ALLOW_UNSAFE_URL 是允许 unsafe 链接,此处关闭;
- THUMBOR_NUM_PROCESSES 大概是多线程数量,未测试。

0x04、最终还是用了 Thumbor AWS

本来故事到这儿,已经可以歇了——至少昨天是这样的。后来同志们折腾半天发现不用 unsafe,拼接私有地址,还是 400 错误。

看到 Docker 中的日志是这样的:

2021-07-16 02:32:26 thumbor:WARNING Malformed URL: /ZM83RRQJ8B08K79PCZs1wcC1MLk=/1000x0/api.minio.dev.xxx.com%2Ftest%2F2021%2F07%2F15%2F778aec46abda4e1fc25d9e7dfc6802de.jpg%3FX-Amz-Algorithm%3DAWS4-HMAC-SHA256%26X-Amz-Credential%3DQ6OYL97O80V8FKTIET78%252F20210716%252Fcnc-dev%252Fs3%252Faws4_request%26X-Amz-Date%3D20210716T023226Z%26X-Amz-Expires%3D1800%26X-Amz-SignedHeaders%3Dhost%26X-Amz-Signature%3Da2939aad07f44238db934c3798cdaa40944e426c78892f8e38bd2d3b6b5f7cfc

网上也有类似的讨论,好像也没个结论。

看来私有地址的路是走不通了,网上文章有提到 Thumbor AWS 可以完美匹配 MinIO。可惜几乎都是以 pip install tc_aws 的形式来安装的,不适用。

结合了一些资料后,自己折腾出一个脚本:

docker run \
  -d \
  -p 8888:80 \
  --name thumbor \
  -e SECURITY_KEY='xxx' \
  -e ALLOW_UNSAFE_URL=False \
  -e AWS_ACCESS_KEY_ID='111' \
  -e AWS_SECRET_ACCESS_KEY='222' \
  -e TC_AWS_REGION='cnc-dev' \
  -e TC_AWS_ENDPOINT='http://127.0.0.1:9000' \
  -e LOADER='tc_aws.loaders.s3_loader' \
  minimalcompact/thumbor

其中:AWS_ACCESS_KEY_ID 等于启动 MinIO 容器命令中的 MINIO_ROOT_USER,AWS_SECRET_ACCESS_KEY 等于启动 MinIO 容器命令中的 MINIO_ROOT_PASSWORD。

结果是报 599 错误:

2021-07-16 03:03:48 thumbor:ERROR ERROR retrieving image from S3 1.jpg: {'ResponseMetadata': {'HTTPStatusCode': 599, 'HTTPHeaders': {}}, 'Error': {'Message': '', 'Code': '599'}}

一番搜索,599 是 Python Tornado 报的,这里有关于 Tornado 599 的讨论。说是 599 属于连接超时。

然后我就清醒了,脚本改成:

docker run \
  -d \
  -p 8888:80 \
  --name thumbor \
  -e SECURITY_KEY='xxx' \
  -e ALLOW_UNSAFE_URL=False \
  -e AWS_ACCESS_KEY_ID='111' \
  -e AWS_SECRET_ACCESS_KEY='222' \
  -e TC_AWS_REGION='cnc-dev' \
  -e TC_AWS_ENDPOINT='http://x.x.x.x:9000' \
  -e LOADER='tc_aws.loaders.s3_loader' \
  minimalcompact/thumbor

这里的 x.x.x.x 是宿主机网卡绑定的 IP 地址。

一次性成功,最终的 URI 格式是这样的:

https://oss.xxx.com/kL1goioOIwzaBZZTbxoO2Py20LM=/300x0/BUCKET-NAME/FILE-NAME.png

真的可以休息了。

TODO:分布式待折腾。

标签: oss, minio, thumbor

添加新评论