结合Afilmory+s3存储部署私人“画廊”服务

13 9.3~11.9 分钟 4178

引言

作为一名业余摄影爱好者,我一直希望能有一个纯粹的展示个人“作品”的地方。前段时间冲浪时,无意间发现了Afilmory这个开源Gallery项目。它完全满足对一个私人在线画廊的需求:

  • 高效

  • 美观

  • 兼容性强

因此在此记录以下本次折腾的过程

准备工作

  • 服务器需求:推荐使用2C4G及以上配置的海外服务器,使用海外服务器是因为部署期间需要使用一些国外网站服务,使用国内的服务器可能会遇到网络问题

  • 部署环境:单机k3s(简化版k8s)

部署Afilmory

Afilmory简介

Afilmory是一款现代化的静态Gallery服务。其具有以下特性(更多功能请参阅官方网站

  • 高性能的图像渲染、响应式布局和现代 UI 设计

  • 智能缩略图生成、EXIF 信息显示、多存储后端支持等

Afilmory镜像构建

Afilmory本质是一个类似Hexo的静态网页项目,因此如果使用容器化技术部署需要每次变更时都重新构建镜像,这也是官方推荐的使用方法

相关文件

构建Afilmory前需要准备好四个文件

  • config.json: 配置网站基础信息,包含网站名称,作者信息等

  • builder.config.json: 镜像构建配置,包含后端存储,Github缓存等

  • .env: 构建时需要使用到的环境变量信息

  • Dockerfile: 用于docker构建镜像

下述四个文件内容模板均来自于Afilmory官方文档,实际部署时需要按需修改

`config.json`

{
  "name": "Your Photo Gallery",
  "title": "Your Photo Gallery", 
  "description": "Capturing beautiful moments in life",
  "url": "https://your-domain.com",
  "accentColor": "#fb7185",
  "author": {
    "name": "Your Name",
    "url": "https://your-website.com",
    "avatar": "https://your-avatar-url.com/avatar.png"
  },
  "social": {
    "twitter": "@yourusername"
  },
  "extra": {
    "accessRepo": true
  }
}

`builder.config.json`

{
  "repo": {
    "enable": false,                                              # 是否使用github缓存加速
    "url": "https://github.com/username/gallery-public"           # 用于缓存加速的github仓库地址
  },
  "storage": {
    "provider": "s3",                                             # 后端图片存储方式, 官方当前支持local,s3,github,本配置为使用s3的配置,其他可以参考官方文档
    "bucket": "your-photos-bucket",
    "region": "us-east-1",
    "prefix": "photos/",
    "customDomain": "cdn.yourdomain.com"
  },
  "performance": {                                                # 提升性能的配置:按需配置
    "worker": {
      "enabled": true,
      "maxWorkers": 4
    }
  }
}

上述配置使用的s3作为后端图片存储服务,理论上可使用任何兼容aws s3接口的服务包括但不限于:腾讯云,阿里云等

`.env`

# Database Configuration
PG_CONNECTION_STRING=postgresql://user:password@postgres:5432/afilmory

# S3 Storage Configuration
S3_ACCESS_KEY_ID=your_access_key_id
S3_SECRET_ACCESS_KEY=your_secret_access_key

# Git Repository (optional)
GIT_TOKEN=your_github_token

# Application Settings
NODE_ENV=production
PORT=3000

`Dockerfile`

# Dockerfile for Next.js app in a pnpm monorepo
# This Dockerfile should be built from the root of the monorepo:
# > docker build -t iris-ssr .
# > docker run -p 3000:3000 iris-ssr

# -----------------
# Base stage
# -----------------
FROM node:20-alpine AS base
WORKDIR /app
RUN corepack enable

# -----------------
# Builder stage
# -----------------
FROM base AS builder

RUN apk update && apk add --no-cache git perl

RUN git clone https://github.com/Afilmory/Afilmory --depth 1 .
COPY config.json ./
COPY builder.config.json ./
COPY .env ./

ARG S3_ACCESS_KEY_ID
ARG S3_SECRET_ACCESS_KEY
ARG GIT_TOKEN
ARG PG_CONNECTION_STRING

RUN sh ./scripts/preinstall.sh
# Install all dependencies
RUN pnpm install --frozen-lockfile

# Build the app.
# The build script in the ssr package.json handles building the web app first.
RUN pnpm --filter=@afilmory/ssr build

# -----------------
# Runner stage
# -----------------
FROM base AS runner

WORKDIR /app

ENV NODE_ENV=production
# ENV PORT and other configurations are now in the config files
# and passed through environment variables during runtime.
RUN apk add --no-cache curl wget
# Create a non-root user
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

USER nextjs

COPY --from=builder --chown=nextjs:nodejs /app/apps/ssr/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/apps/ssr/.next/static /app/apps/ssr/.next/static
COPY --from=builder --chown=nextjs:nodejs /app/apps/ssr/public /app/apps/ssr/public

# The standalone output includes the server.js file.
# The PORT environment variable is automatically used by Next.js.
EXPOSE 3000

CMD ["node", "apps/ssr/server.js"]

镜像构建

上述文件按需修改后,使用docker build命令构建镜像,然后导入到k3s环境中

# 构建本地镜像
docker build --no-cache -t afilmory .
# 从docker中导出镜像
docker save -o afilmory.tar afilmory:latest
# 将导出的镜像导入k3s中
k3s ctr images import afilmory.tar
# 重新部署pod, pod_name需要根据部署的情况替换
kubectl delete pod {pod_name}

部署Pod

`afilmory.yaml`

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: gallery
  labels:
    app: gallery
spec:
  replicas: 1
  selector:
    matchLabels:
      app: gallery
  template:
    metadata:
      labels:
        app: gallery
    spec:
      containers:
      - name: gallery
        image: afilmory:latest
        imagePullPolicy: IfNotPresent
        env:
        - name: TZ
          value: Asia/Shanghai
---
apiVersion: v1
kind: Service
metadata:
  name: gallery
  labels:
    run: gallery
spec:
  ports:
  - port: 80
    name: http
    targetPort: 3000
    protocol: TCP
  selector:
    app: gallery
# 部署afilmory
kubectl apply -f afilmory.yaml

配置traefik代理svc

treafix + cert manger 实现证书自动签发+proxy请求见:文章

总结

附录