Files
woodpecker-rustfs/README.md
2025-10-12 19:10:34 +08:00

14 KiB
Raw Blame History

Woodpecker CI - S3 对象存储上传指南

本指南介绍如何在 Woodpecker CI 中使用 S3 插件将文件和文件夹上传到对象存储(兼容 S3 API 的存储服务,如 AWS S3、MinIO、RustFS 等)。

📋 目录


前置准备

1. 安装 plugin-s3

确保您的 Woodpecker Agent 环境中已安装 plugin-s3

# 使用 Homebrew (macOS)
brew install plugin-s3

# 或使用 Go 安装
go install github.com/woodpecker-ci/plugin-s3@latest

# 验证安装
which plugin-s3

2. 准备 S3 凭证

您需要以下信息:

  • Access Key ID: S3 访问密钥 ID
  • Secret Access Key: S3 密钥
  • Bucket 名称: 目标存储桶
  • Endpoint: S3 服务端点(如使用 AWS S3 可省略)
  • Region: 区域(如 us-east-1

配置密钥

通过 Woodpecker UI 配置

  1. 进入您的仓库页面
  2. 点击 SettingsSecrets
  3. 添加以下密钥:
密钥名称 说明 示例值
AWS_ACCESS_KEY_ID S3 访问密钥 ID AKIAIOSFODNN7EXAMPLE
AWS_SECRET_ACCESS_KEY S3 密钥 wJalrXUtnFEMI/K7MDENG/...
S3_BUCKET 存储桶名称 my-bucket
S3_ENDPOINT S3 端点(自建服务) https://s3.example.com:9000
AWS_DEFAULT_REGION AWS 区域 us-east-1
  1. 确保勾选适当的事件类型(如 pushmanualpull_request

通过 CLI 配置

# 添加 Access Key
woodpecker-cli repo secret add \
  --repository your-org/your-repo \
  --name AWS_ACCESS_KEY_ID \
  --value "your-access-key-id"

# 添加 Secret Key
woodpecker-cli repo secret add \
  --repository your-org/your-repo \
  --name AWS_SECRET_ACCESS_KEY \
  --value "your-secret-access-key"

# 添加 Bucket
woodpecker-cli repo secret add \
  --repository your-org/your-repo \
  --name S3_BUCKET \
  --value "my-bucket"

# 添加 Endpoint (可选,用于自建 S3 服务)
woodpecker-cli repo secret add \
  --repository your-org/your-repo \
  --name S3_ENDPOINT \
  --value "https://s3.example.com:9000"

# 添加 Region
woodpecker-cli repo secret add \
  --repository your-org/your-repo \
  --name AWS_DEFAULT_REGION \
  --value "us-east-1"

基础用法

上传单个文件

上传单个文件到 S3 存储桶:

steps:
  - name: upload-single-file
    image: /bin/zsh
    environment:
      AWS_ACCESS_KEY_ID:
        from_secret: AWS_ACCESS_KEY_ID
      AWS_SECRET_ACCESS_KEY:
        from_secret: AWS_SECRET_ACCESS_KEY
      S3_BUCKET:
        from_secret: S3_BUCKET
      S3_ENDPOINT:
        from_secret: S3_ENDPOINT
    commands:
      - |
        # 创建测试文件
        echo "Hello from Woodpecker CI" > hello.txt
        
        # 上传到 S3
        export PLUGIN_SOURCE="hello.txt"
        export PLUGIN_BUCKET="$S3_BUCKET"
        export PLUGIN_TARGET="uploads/"
        export PLUGIN_ENDPOINT="$S3_ENDPOINT"
        export PLUGIN_PATH_STYLE=true
        plugin-s3

结果: hello.txt 将被上传到 s3://your-bucket/uploads/hello.txt


上传多个文件

使用通配符上传多个文件:

steps:
  - name: upload-multiple-files
    image: /bin/zsh
    environment:
      AWS_ACCESS_KEY_ID:
        from_secret: AWS_ACCESS_KEY_ID
      AWS_SECRET_ACCESS_KEY:
        from_secret: AWS_SECRET_ACCESS_KEY
      S3_BUCKET:
        from_secret: S3_BUCKET
      S3_ENDPOINT:
        from_secret: S3_ENDPOINT
    commands:
      - |
        # 创建多个测试文件
        echo "File 1" > file1.txt
        echo "File 2" > file2.txt
        echo "File 3" > file3.log
        
        # 上传所有 .txt 文件
        export PLUGIN_SOURCE="*.txt"
        export PLUGIN_BUCKET="$S3_BUCKET"
        export PLUGIN_TARGET="logs/"
        export PLUGIN_ENDPOINT="$S3_ENDPOINT"
        export PLUGIN_PATH_STYLE=true
        plugin-s3

结果: 所有 .txt 文件将被上传到 s3://your-bucket/logs/


上传整个文件夹

递归上传整个目录及其子目录:

steps:
  - name: upload-folder
    image: /bin/zsh
    environment:
      AWS_ACCESS_KEY_ID:
        from_secret: AWS_ACCESS_KEY_ID
      AWS_SECRET_ACCESS_KEY:
        from_secret: AWS_SECRET_ACCESS_KEY
      S3_BUCKET:
        from_secret: S3_BUCKET
      S3_ENDPOINT:
        from_secret: S3_ENDPOINT
    commands:
      - |
        # 创建目录结构
        mkdir -p dist/css dist/js dist/images
        echo "body { color: red; }" > dist/css/style.css
        echo "console.log('hello');" > dist/js/app.js
        echo "placeholder" > dist/images/logo.png
        echo "<html>Hello</html>" > dist/index.html
        
        # 上传整个 dist 文件夹
        export PLUGIN_SOURCE="dist/**/*"
        export PLUGIN_BUCKET="$S3_BUCKET"
        export PLUGIN_TARGET="website/"
        export PLUGIN_ENDPOINT="$S3_ENDPOINT"
        export PLUGIN_PATH_STYLE=true
        export PLUGIN_STRIP_PREFIX="dist/"
        plugin-s3

结果:

s3://your-bucket/website/css/style.css
s3://your-bucket/website/js/app.js
s3://your-bucket/website/images/logo.png
s3://your-bucket/website/index.html

高级用法

设置文件访问权限

export PLUGIN_ACL="public-read"  # 公开可读
# 可选值: private, public-read, public-read-write, authenticated-read

设置缓存控制

export PLUGIN_CACHE_CONTROL="max-age=3600"  # 缓存 1 小时

设置内容类型

export PLUGIN_CONTENT_TYPE="text/html"
export PLUGIN_CONTENT_ENCODING="gzip"

删除目标文件夹中的旧文件

export PLUGIN_DELETE=true  # 上传前删除目标路径的现有文件

使用服务器端加密

export PLUGIN_ENCRYPTION="AES256"  # 或 "aws:kms"

完整高级示例

steps:
  - name: deploy-website
    image: /bin/zsh
    environment:
      AWS_ACCESS_KEY_ID:
        from_secret: AWS_ACCESS_KEY_ID
      AWS_SECRET_ACCESS_KEY:
        from_secret: AWS_SECRET_ACCESS_KEY
      S3_BUCKET:
        from_secret: S3_BUCKET
      S3_ENDPOINT:
        from_secret: S3_ENDPOINT
    commands:
      - |
        export PLUGIN_SOURCE="public/**/*"
        export PLUGIN_BUCKET="$S3_BUCKET"
        export PLUGIN_TARGET="production/"
        export PLUGIN_ENDPOINT="$S3_ENDPOINT"
        export PLUGIN_PATH_STYLE=true
        export PLUGIN_STRIP_PREFIX="public/"
        export PLUGIN_ACL="public-read"
        export PLUGIN_CACHE_CONTROL="max-age=31536000"
        export PLUGIN_DELETE=true
        plugin-s3

完整示例

最小化示例 - .woodpecker.yml

这是一个完整的 Woodpecker 配置文件,演示如何上传文件和文件夹:

# .woodpecker.yml
labels:
  platform: linux/amd64

when:
  event: [push, manual]

steps:
  # 第一步:构建项目(示例)
  - name: build
    image: node:18-alpine
    commands:
      - echo "Building project..."
      - mkdir -p dist/assets
      - echo '<!DOCTYPE html><html><body><h1>Hello World</h1></body></html>' > dist/index.html
      - echo 'body { font-family: Arial; }' > dist/assets/style.css
      - echo 'console.log("App loaded");' > dist/assets/app.js
      - echo "Build complete!"
      - ls -R dist/

  # 第二步:上传单个日志文件
  - name: upload-build-log
    image: alpine:latest
    environment:
      AWS_ACCESS_KEY_ID:
        from_secret: AWS_ACCESS_KEY_ID
      AWS_SECRET_ACCESS_KEY:
        from_secret: AWS_SECRET_ACCESS_KEY
      S3_BUCKET:
        from_secret: S3_BUCKET
      S3_ENDPOINT:
        from_secret: S3_ENDPOINT
    commands:
      - |
        # 创建构建日志
        date > build.log
        echo "Build completed successfully" >> build.log
        
        # 上传日志文件
        export PLUGIN_SOURCE="build.log"
        export PLUGIN_BUCKET="$S3_BUCKET"
        export PLUGIN_TARGET="logs/build-${CI_COMMIT_SHA:0:8}.log"
        export PLUGIN_ENDPOINT="$S3_ENDPOINT"
        export PLUGIN_PATH_STYLE=true
        plugin-s3
        
        echo "✅ Build log uploaded to s3://$S3_BUCKET/logs/"

  # 第三步:上传整个 dist 文件夹
  - name: upload-dist-folder
    image: alpine:latest
    environment:
      AWS_ACCESS_KEY_ID:
        from_secret: AWS_ACCESS_KEY_ID
      AWS_SECRET_ACCESS_KEY:
        from_secret: AWS_SECRET_ACCESS_KEY
      S3_BUCKET:
        from_secret: S3_BUCKET
      S3_ENDPOINT:
        from_secret: S3_ENDPOINT
    commands:
      - |
        # 上传整个 dist 目录
        export PLUGIN_SOURCE="dist/**/*"
        export PLUGIN_BUCKET="$S3_BUCKET"
        export PLUGIN_TARGET="website/${CI_COMMIT_BRANCH}/"
        export PLUGIN_ENDPOINT="$S3_ENDPOINT"
        export PLUGIN_PATH_STYLE=true
        export PLUGIN_STRIP_PREFIX="dist/"
        export PLUGIN_ACL="public-read"
        plugin-s3
        
        echo "✅ Website deployed to s3://$S3_BUCKET/website/${CI_COMMIT_BRANCH}/"

  # 第四步:上传构建产物(压缩包)
  - name: upload-artifacts
    image: alpine:latest
    environment:
      AWS_ACCESS_KEY_ID:
        from_secret: AWS_ACCESS_KEY_ID
      AWS_SECRET_ACCESS_KEY:
        from_secret: AWS_SECRET_ACCESS_KEY
      S3_BUCKET:
        from_secret: S3_BUCKET
      S3_ENDPOINT:
        from_secret: S3_ENDPOINT
    commands:
      - |
        # 创建压缩包
        apk add --no-cache zip
        zip -r dist-${CI_COMMIT_SHA:0:8}.zip dist/
        
        # 上传压缩包
        export PLUGIN_SOURCE="dist-*.zip"
        export PLUGIN_BUCKET="$S3_BUCKET"
        export PLUGIN_TARGET="releases/${CI_COMMIT_BRANCH}/"
        export PLUGIN_ENDPOINT="$S3_ENDPOINT"
        export PLUGIN_PATH_STYLE=true
        plugin-s3
        
        echo "✅ Artifacts uploaded to s3://$S3_BUCKET/releases/${CI_COMMIT_BRANCH}/"

macOS 本地 Agent 示例

如果您使用本地 macOS agent如您的 Mac mini配置略有不同

# .woodpecker.yml (macOS Local Agent)
labels:
  host: Mac-mini.local
  platform: darwin/arm64

when:
  event: [push, manual]

steps:
  - name: build-app
    image: /bin/zsh
    commands:
      - echo "Building on macOS..."
      - mkdir -p build/output
      - echo "Binary placeholder" > build/output/app
      - echo "Config file" > build/output/config.json
      - ls -R build/

  - name: upload-single-file
    image: /bin/zsh
    environment:
      AWS_ACCESS_KEY_ID:
        from_secret: AWS_ACCESS_KEY_ID
      AWS_SECRET_ACCESS_KEY:
        from_secret: AWS_SECRET_ACCESS_KEY
      S3_BUCKET:
        from_secret: S3_BUCKET
      S3_ENDPOINT:
        from_secret: S3_ENDPOINT
    commands:
      - |
        echo "📦 Uploading config file..."
        export PLUGIN_SOURCE="build/output/config.json"
        export PLUGIN_BUCKET="$S3_BUCKET"
        export PLUGIN_TARGET="configs/"
        export PLUGIN_ENDPOINT="$S3_ENDPOINT"
        export PLUGIN_PATH_STYLE=true
        plugin-s3
        echo "✅ Config uploaded"

  - name: upload-build-folder
    image: /bin/zsh
    environment:
      AWS_ACCESS_KEY_ID:
        from_secret: AWS_ACCESS_KEY_ID
      AWS_SECRET_ACCESS_KEY:
        from_secret: AWS_SECRET_ACCESS_KEY
      S3_BUCKET:
        from_secret: S3_BUCKET
      S3_ENDPOINT:
        from_secret: S3_ENDPOINT
    commands:
      - |
        echo "📦 Uploading entire build folder..."
        export PLUGIN_SOURCE="build/output/**/*"
        export PLUGIN_BUCKET="$S3_BUCKET"
        export PLUGIN_TARGET="builds/macos-$(date +%Y%m%d-%H%M%S)/"
        export PLUGIN_ENDPOINT="$S3_ENDPOINT"
        export PLUGIN_PATH_STYLE=true
        export PLUGIN_STRIP_PREFIX="build/output/"
        plugin-s3
        echo "✅ Build folder uploaded"

故障排查

问题 1: 密钥未传递

错误信息: No S3 credentials found

解决方案:

  • 确保使用 from_secret: 语法而不是 ${SECRET_NAME}
  • 检查 Woodpecker UI 中密钥名称是否完全匹配
  • 确认密钥事件类型包含当前触发事件(如 manual
# ❌ 错误
environment:
  AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID}

# ✅ 正确
environment:
  AWS_ACCESS_KEY_ID:
    from_secret: AWS_ACCESS_KEY_ID

问题 2: plugin-s3 未找到

错误信息: plugin-s3: command not found

解决方案:

# 安装 plugin-s3
brew install plugin-s3

# 或添加到 PATH
export PATH=$PATH:/usr/local/bin

问题 3: 端点连接失败

错误信息: connection refusedtimeout

解决方案:

  • 检查 S3_ENDPOINT 格式(需包含协议,如 https://
  • 确认防火墙规则允许访问
  • 验证 SSL 证书(自签名证书可能需要额外配置)

问题 4: 权限被拒绝

错误信息: Access Denied403 Forbidden

解决方案:

  • 验证 Access Key 和 Secret Key 是否正确
  • 检查 IAM 策略是否允许 s3:PutObject 权限
  • 确认 bucket 存在且有写入权限

调试技巧

添加调试输出以检查环境变量:

commands:
  - |
    echo "=== 调试信息 ==="
    echo "Bucket: ${S3_BUCKET}"
    echo "Endpoint: ${S3_ENDPOINT}"
    echo "Access Key (前10位): ${AWS_ACCESS_KEY_ID:0:10}..."
    echo "================="
    
    # 继续执行上传...

环境变量参考

变量名 说明 必需 示例
PLUGIN_SOURCE 源文件路径(支持通配符) dist/**/*
PLUGIN_BUCKET 目标 bucket my-bucket
PLUGIN_TARGET 目标路径前缀 uploads/
PLUGIN_ENDPOINT S3 端点 URL https://s3.example.com
PLUGIN_PATH_STYLE 使用路径风格 URL true
PLUGIN_STRIP_PREFIX 移除源路径前缀 dist/
PLUGIN_ACL 访问控制列表 public-read
PLUGIN_CACHE_CONTROL 缓存控制头 max-age=3600
PLUGIN_DELETE 上传前删除目标文件 true
PLUGIN_ENCRYPTION 服务器端加密 AES256

总结

本指南涵盖了在 Woodpecker CI 中使用 S3 上传的所有常见场景:

单文件上传: 适用于日志、配置文件等
多文件上传: 使用通配符批量上传
文件夹上传: 递归上传整个目录结构
高级配置: ACL、缓存、加密等

如有问题,请参考 Woodpecker 官方文档 或提交 Issue。


License: MIT
维护者: Your Team
最后更新: 2025-10-12