使用 imgproxy 处理 ActiveStorage 图片变换
最近将 Geeknote 的图片处理换到了 imgproxy,记录一下过程。
为什么使用 imgproxy
imgproxy 是一个开源的图片处理引擎,可以用于替代 ActiveStorage 的原生图片处理或云服务的图片处理。
相比其他方案,自部署 imgproxy 的优势为:
- 将图片处理负载移出 Rails 进程。
- 更方便设置 CDN。
- 更容易控制成本。(相比云服务)
工作原理
默认情况下,ActiveStorage 在提供图片变换的时候会返回一个重定向地址:
<%= image_tag user.avatar %>
// <img src="/rails/active_storage/representations/redirect/xxx...">
Rails 进程将会接收这个请求,如果这时图片还没处理,Rails 会即时生成图片变换,然后上传到云储存,然后重定向到云储存地址。
当使用 imgproxy 的时候,返回的是 imgproxy 的代理地址:
<%= image_tag user.avatar %>
// <img src="https://imgproxy.yourdomain.com/signed/rs:fill:300:400/g:sm/aHR0cH...">
这时候处理图片的是 imgproxy 进程,Rails 就不用管图片变换了。
操作
以下展示如何在生产环境配置 imgproxy。
imgproxy 需要访问后端储存的文件,用开发环境本地储存有些麻烦,建议用 S3 兼容的服务测试。以下省略 ActiveStorage 的 S3 配置。
安装和设置 imgproxy-rails
在 Gemfile 中添加并安装:
gem "imgproxy-rails"
在 config/application.rb
中添加配置:
if ENV["IMGPROXY_ENDPOINT"].present?
config.active_storage.resolve_model_to_route = :imgproxy_active_storage
end
这行配置允许通过环境变量开启 imgproxy 功能。
需要开启时,在 Rails 环境变量中设置:
# 必须
# imgproxy 的终端地址
IMGPROXY_ENDPOINT=https://imgproxy.yourdomain.com
# 推荐
# 与 imgproxy 加签的密钥
IMGPROXY_KEY=yourimgproxykey
IMGPROXY_SALT=yourimgproxysalt
# 可选
# 使用 S3 短地址,避免地址太长
IMGPROXY_USE_S3_URLS=true
更多配置可以参考 https://github.com/imgproxy/imgproxy.rb?tab=readme-ov-file#configuration-options
设置 IMGPROXY_ENDPOINT
后,Rails 会自动把 variant 地址改为 imgproxy 的地址,接下来需要部署 imgproxy 服务。
部署 imgproxy
这里用 fly.io 部署为例,你也可以用其他方式部署。其他部署方式参考 https://docs.imgproxy.net/installation 。
用 fly 命令行创建应用:
$ fly launch --image darthsim/imgproxy:v3
在弹出网页中选择部署地点和主机配置,确认后配置如下:
app = 'your-imgproxy-app'
primary_region = 'hkg'
[build]
image = 'darthsim/imgproxy:v3'
[http_service]
internal_port = 8080
force_https = true
auto_stop_machines = true
auto_start_machines = true
min_machines_running = 0
processes = ['app']
执行部署:
$ fly deploy
部署成功后,访问 https://your-imgproxy-app.fly.dev 应可看到 imgproxy 信息。
现在继续添加环境变量:
# 推荐
# 和 Rails 配置配对的加签密钥
IMGPROXY_KEY=yourimgproxykey
IMGPROXY_SALT=yourimgproxysalt
# 使用 S3 后端
IMGPROXY_USE_S3=true
IMGPROXY_S3_ENDPOINT=xxx
IMGPROXY_S3_REGION=auto
AWS_ACCESS_KEY_ID=xxx
AWS_SECRET_ACCESS_KEY=xxx
重启应用后,现在应该可以看到 Rails 应用输出 imgproxy 地址,而 imgproxy 服务正常返回图片。
配置 CDN
imgproxy 本身只处理图片,不处理缓存,要避免每个请求都重新生成图片,需要在 imgproxy 前面加 CDN。
以 Cloudflare 为例,为域名 imgproxy.yourdomain.com 打开代理模式,在缓存规则中设置该域名开启缓存,即可用 CDN 缓存生成的图片。
总结
以上就是在生产环境用 imgproxy 替代 ActiveStorage 图片变换的全过程。