OSS CI/CD比較:Gitea Actions vs Drone CI vs Woodpecker CI でGitHub Actionsを自前運用する
オープンソースラボ編集部 ・ 2026年6月14日
OSS CI/CD比較:Gitea Actions vs Drone CI vs Woodpecker CI でGitHub Actionsを自前運用する
GitHub Actions(月$0.008/分〜)・CircleCI(月$15〜)・Jenkins(OSS・設定複雑)に対して、Gitea Actions(GitHub Actions互換・Giteaと統合)・Drone CI(Docker-native・YAML宣言的パイプライン)・Woodpecker CI(Drone forkの軽量版)はCI/CDをセルフホストできます。
OSS CI/CDをセルフホストする理由
- コスト: GitHub Actions(月500分無料・超過$0.008/分 → 月10万分=$800/月)→ VPS+Droneで$30/月
- プライベートリポジトリ無制限: GitHub.com の制限なしに内部リポジトリでCI/CD
- カスタムランナー: GPUランナー・特殊ハードウェア・社内ネットワーク専用のカスタム環境
- コンプライアンス: ビルドログ・アーティファクトを社内ネットワーク内に保持
主要ツールの概要
Gitea + Gitea Actions
2016年公開(Gitea Actions: 2023年)、Go製のOSSです。GitHubスター44k+。GitHub Actionsと互換性のあるワークフロー構文を使ってセルフホストGitサーバーでCI/CDを実行できます。既存のGitHub Actionsワークフローをほぼそのままで移行できます。
# docker-compose.yml - Gitea + Gitea Actions Runner
version: '3.8'
services:
gitea:
image: gitea/gitea:1.22-rootless
restart: unless-stopped
ports:
- "3000:3000"
- "2222:2222"
environment:
USER_UID: "1000"
USER_GID: "1000"
GITEA__database__DB_TYPE: postgres
GITEA__database__HOST: gitea-db:5432
GITEA__database__NAME: gitea
GITEA__database__USER: gitea
GITEA__database__PASSWD: ${DB_PASSWORD}
GITEA__server__DOMAIN: git.yourcompany.com
GITEA__server__ROOT_URL: https://git.yourcompany.com
GITEA__server__HTTP_PORT: "3000"
GITEA__server__SSH_PORT: "2222"
GITEA__mailer__ENABLED: "true"
GITEA__mailer__FROM: git@yourcompany.com
GITEA__mailer__SMTP_ADDR: smtp.sendgrid.net
GITEA__mailer__SMTP_PORT: "587"
GITEA__mailer__USER: apikey
GITEA__mailer__PASSWD: ${SENDGRID_KEY}
# Actions有効化
GITEA__actions__ENABLED: "true"
volumes:
- gitea_data:/var/lib/gitea
depends_on:
- gitea-db
gitea-db:
image: postgres:16-alpine
environment:
POSTGRES_DB: gitea
POSTGRES_USER: gitea
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- gitea_pgdata:/var/lib/postgresql/data
gitea-runner:
image: gitea/act_runner:latest
restart: unless-stopped
environment:
GITEA_INSTANCE_URL: https://git.yourcompany.com
GITEA_RUNNER_REGISTRATION_TOKEN: ${GITEA_RUNNER_TOKEN}
GITEA_RUNNER_NAME: my-runner
GITEA_RUNNER_LABELS: "ubuntu-latest,ubuntu-22.04,linux"
CONFIG_FILE: /etc/act_runner/config.yaml
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./act_runner_config.yaml:/etc/act_runner/config.yaml
- runner_data:/data
depends_on:
- gitea
volumes:
gitea_data:
gitea_pgdata:
runner_data:
# .gitea/workflows/deploy.yml - GitHub Actions互換のワークフロー
name: Build and Deploy
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run lint
- run: npm run type-check
- run: npm test
build:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Registry
uses: docker/login-action@v3
with:
registry: ${{ secrets.REGISTRY_URL }}
username: ${{ secrets.REGISTRY_USER }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Build and Push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ secrets.REGISTRY_URL }}/myapp:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max
deploy:
needs: build
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- name: Deploy to Production
uses: appleboy/ssh-action@v1.0.0
with:
host: ${{ secrets.PROD_HOST }}
username: deploy
key: ${{ secrets.PROD_SSH_KEY }}
script: |
docker pull ${{ secrets.REGISTRY_URL }}/myapp:${{ github.sha }}
docker service update --image ${{ secrets.REGISTRY_URL }}/myapp:${{ github.sha }} myapp_web
Drone CI
2014年公開、Go製のOSSです。GitHubスター31k+。すべてのパイプラインステップをDockerコンテナとして実行する設計で、環境の再現性が高くステップ間の依存関係が明確です。.drone.ymlの宣言的なYAML構文がシンプルで学習コストが低いです。
# docker-compose.yml - Drone CI + Gitea統合
version: '3.8'
services:
drone-server:
image: drone/drone:2
restart: unless-stopped
ports:
- "8080:80"
- "8443:443"
environment:
DRONE_GITEA_SERVER: https://git.yourcompany.com
DRONE_GITEA_CLIENT_ID: ${GITEA_OAUTH_CLIENT_ID}
DRONE_GITEA_CLIENT_SECRET: ${GITEA_OAUTH_CLIENT_SECRET}
DRONE_RPC_SECRET: ${DRONE_RPC_SECRET}
DRONE_SERVER_HOST: drone.yourcompany.com
DRONE_SERVER_PROTO: https
DRONE_DATABASE_DRIVER: postgres
DRONE_DATABASE_DATASOURCE: postgres://drone:${DB_PASSWORD}@drone-db/drone?sslmode=disable
DRONE_REDIS_CONNECTION: redis://drone-redis:6379
volumes:
- drone_data:/data
depends_on:
- drone-db
- drone-redis
drone-runner:
image: drone/drone-runner-docker:1
restart: unless-stopped
environment:
DRONE_RPC_PROTO: https
DRONE_RPC_HOST: drone.yourcompany.com
DRONE_RPC_SECRET: ${DRONE_RPC_SECRET}
DRONE_RUNNER_CAPACITY: 4
DRONE_RUNNER_NAME: docker-runner
volumes:
- /var/run/docker.sock:/var/run/docker.sock
drone-db:
image: postgres:16-alpine
environment:
POSTGRES_DB: drone
POSTGRES_USER: drone
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- drone_pgdata:/var/lib/postgresql/data
drone-redis:
image: redis:7-alpine
volumes:
drone_data:
drone_pgdata:
# .drone.yml - Node.js アプリのCI/CDパイプライン
kind: pipeline
type: docker
name: default
steps:
- name: install
image: node:20-alpine
commands:
- npm ci --frozen-lockfile
- name: lint-and-test
image: node:20-alpine
environment:
DATABASE_URL:
from_secret: TEST_DATABASE_URL
commands:
- npm run lint
- npm run type-check
- npm run test:ci
depends_on:
- install
- name: build
image: node:20-alpine
environment:
NEXT_PUBLIC_API_URL:
from_secret: STAGING_API_URL
commands:
- npm run build
depends_on:
- lint-and-test
- name: docker-build-push
image: plugins/docker
settings:
registry:
from_secret: REGISTRY_URL
repo:
from_secret: REGISTRY_REPO
tags:
- latest
- ${DRONE_COMMIT_SHA:0:8}
username:
from_secret: REGISTRY_USER
password:
from_secret: REGISTRY_PASSWORD
depends_on:
- build
when:
branch:
- main
- name: deploy-staging
image: appleboy/drone-ssh
settings:
host:
from_secret: STAGING_HOST
username: deploy
key:
from_secret: STAGING_SSH_KEY
script:
- docker pull $${REGISTRY_REPO}:$${DRONE_COMMIT_SHA:0:8}
- docker compose -f /opt/app/docker-compose.yml up -d
when:
branch:
- main
depends_on:
- docker-build-push
# Drone API でビルド状況を監視・Slack通知(Python)
import requests
import os
DRONE_URL = 'https://drone.yourcompany.com'
DRONE_TOKEN = os.environ['DRONE_API_TOKEN']
headers = {'Authorization': f'Bearer {DRONE_TOKEN}'}
def get_recent_builds(owner: str, repo: str, limit: int = 10) -> list:
resp = requests.get(
f'{DRONE_URL}/api/repos/{owner}/{repo}/builds',
headers=headers,
params={'limit': limit},
)
resp.raise_for_status()
return resp.json()
def get_build_status_summary(owner: str, repo: str) -> dict:
builds = get_recent_builds(owner, repo, 50)
statuses = [b['status'] for b in builds]
return {
'total': len(statuses),
'success': statuses.count('success'),
'failure': statuses.count('failure'),
'running': statuses.count('running'),
'success_rate': round(statuses.count('success') / len(statuses) * 100, 1),
}
# 使用例
summary = get_build_status_summary('myorg', 'myapp')
print(f"ビルド成功率: {summary['success_rate']}% ({summary['success']}/{summary['total']})")
機能比較表
| 比較項目 | Gitea Actions | Drone CI | Woodpecker CI |
|---|---|---|---|
| GitHub Actions互換 | ✅(95%) | ❌(独自YAML) | ❌(Drone互換) |
| Docker-native | ✅ | ✅ | ✅ |
| UI管理画面 | ✅(Gitea統合) | ✅ | ✅ |
| 設定の学習コスト | 低(GitHub準拠) | 低 | 低 |
| Gitサーバー一体型 | ✅ | ❌ | ❌ |
| GitHub Stars | 44k+ | 31k+ | 4k+ |
OSS CI/CDはDevOpsカテゴリ/categories/devopsのコンテナレジストリ(Harbor)・観測可能性スタック(OpenTelemetry+Grafana)と統合してビルド→テスト→デプロイ→監視のフルサイクルをオンプレ完結で実現します。セキュリティカテゴリ/categories/securityのHashiCorp VaultのDynamic SecretsをDrone CIと統合してビルド時のDB認証情報を都度発行・失効させることでシークレット漏洩リスクを排除できます。
FAQ
Q. GitHub ActionsからGitea Actionsへの移行コストはどれくらいですか?
A. GitHub ActionsとGitea Actionsは同じワークフロー構文(YAMLのon・jobs・steps・uses)を使うため、多くのワークフローは.github/workflows/を.gitea/workflows/に移動するだけで動作します。注意点: ①uses: actions/checkout@v4などの公式アクションはGitea ActionsでGitHub.comのアクションリポジトリから取得できる(ネットワーク接続必要)②GITHUB_*環境変数(GITHUB_SHA・GITHUB_REF等)はGITEA_*に変更③GitHub PackagesはGitea Container Registryに移行④GitHub Environments(production/staging)はGitea 1.22以降でサポート。移行成功率: 一般的なNode.js/Python/GoのCI/CDワークフローは80〜90%が無改修または軽微な修正で動作します。
Q. Drone CIのシークレット管理はどうすればいいですか?
A. ①プロジェクト単位のシークレット: Drone UIまたはAPI(POST /api/repos/{owner}/{repo}/secrets)でシークレットを登録し、.drone.ymlでfrom_secret:参照②Organization シークレット: 複数リポジトリで共有するシークレットをOrg levelで登録③HashiCorp Vault統合: drone-vaultプラグインでVaultからシークレットを動的に取得(from_secret: vault:secret/data/myapp#API_KEY形式)④環境変数へのエクスポート: .drone.ymlのenvironment.MY_KEY.from_secret: MY_KEYでシークレットを環境変数としてステップに渡す。注意: シークレットはPRビルドではデフォルトで渡されない(fork PR経由のシークレット漏洩を防ぐため)。信頼済みリポジトリのPRのみシークレットを渡す設定(allow_pull_requests: true)も可能。
Q. Woodpecker CIとDrone CIはどう違いますか?
A. Woodpecker CIはDrone CI 0.8系からフォークされたOSSプロジェクトです。主な違い: ①ライセンス: DroneはEnterprise版が有料・CE版の機能制限あり(Organizationは有料)。WoodpeckerはApache 2.0で完全無料②設定ファイル: WoodpeckerはDroneとほぼ互換性があり(.woodpecker.yml)、移行コストが低い③マルチパイプライン: WoodpeckerはCI構成を複数ファイルに分割できる(.woodpecker/*.yml)④プラグインエコシステム: DroneのプラグインはWoodpeckerでも動作するものが多い。選択基準: ①Organization・複数チームで使うならWoodpecker(無制限無料)②既存のDroneパイプラインを流用するならWoodpecker(移行コスト最小)③Drone Enterprise機能(RBAC・Audit Logs)が必要ならDrone Enterprise検討。
Q. セルフホストCI/CDのランナーのスペックはどう決めますか?
A. ビルドの種類によって必要スペックが異なります。①Node.js/Python Webアプリ: 2コア4GB RAM(同時4並列ビルドなら8コア16GB)②Docker imageビルド: 4コア8GB RAM(Buildx multi-platformは×2〜3)③Flutter/React Nativeビルド: 4コア16GB RAM(iOS/Android同時なら8コア32GB)④機械学習モデル学習: GPU(NVIDIA T4〜A100)+ 32GB+ RAM。コスト最適化: ①スポットインスタンス(AWS Spot/GCP Preemptible)をランナーとして使い、ビルド時のみ起動②autoscaling: Drone + Amazon EC2 Plugin・Woodpecker + Kubernetes Runnerで需要に応じたランナー自動起動③キャッシュ戦略: node_modules・Docker layer cacheをボリュームマウントまたはRegistry Cacheで共有してビルド時間50〜70%短縮。
まとめ
| ユースケース | 推奨ツール |
|---|---|
| GitHub Actions移行・Gitサーバー一体型 | Gitea + Gitea Actions |
| Docker-native・シンプルYAML・拡張性 | Drone CI |
| Drone互換・完全無料・Organization無制限 | Woodpecker CI |