操作
バグ #758
未完了【開発計画】インフラヘルパー Phase 5 - 最適化・品質向上
ステータス:
新規
優先度:
高め
担当者:
-
開始日:
2025-06-26
期日:
進捗率:
0%
予定工数:
説明
🎯 Phase 5: 最適化・品質向上¶
概要¶
インフラヘルパーサービスの性能最適化、品質向上、ドキュメント整備を行い、プロダクションレディな状態にする。
対応期限¶
2025年10月15日(4週間)
実装タスク¶
⚡ 5-1. パフォーマンス最適化¶
バックエンド最適化¶
// 1. データベースクエリ最適化
// - インデックス追加
CREATE INDEX idx_alerts_triggered_at ON alerts(triggered_at);
CREATE INDEX idx_logs_container_timestamp ON logs(container_name, timestamp);
CREATE INDEX idx_metrics_container_metric_time ON metrics(container_name, metric_name, timestamp);
// 2. キャッシング実装
const redis = require('redis');
const client = redis.createClient({ host: 'redis' });
class CacheService {
async get(key) {
return new Promise((resolve, reject) => {
client.get(key, (err, data) => {
if (err) reject(err);
resolve(data ? JSON.parse(data) : null);
});
});
}
async set(key, value, ttl = 300) {
return new Promise((resolve, reject) => {
client.setex(key, ttl, JSON.stringify(value), (err) => {
if (err) reject(err);
resolve();
});
});
}
async invalidate(pattern) {
const keys = await this.scan(pattern);
if (keys.length > 0) {
await client.del(...keys);
}
}
}
// 3. 非同期処理の最適化
class QueueService {
constructor() {
this.queue = new Bull('infra-helper', {
redis: { host: 'redis', port: 6379 }
});
this.queue.process('backup', async (job) => {
return await backupService.createBackup(job.data);
});
this.queue.process('scan', async (job) => {
return await securityScanner.scan(job.data);
});
}
async addJob(type, data, options = {}) {
return await this.queue.add(type, data, {
attempts: 3,
backoff: { type: 'exponential', delay: 2000 },
...options
});
}
}
// 4. メモリ使用量最適化
// - ストリーミング処理
async function streamLargeLogs(containerName, res) {
const container = docker.getContainer(containerName);
const stream = await container.logs({
stdout: true,
stderr: true,
follow: false,
tail: 10000
});
stream.pipe(res);
}
// 5. 接続プーリング
const dockerPool = new GenericPool.Pool({
create: () => new Docker(),
destroy: (docker) => docker.close(),
max: 10,
min: 2
});
フロントエンド最適化¶
// 1. React最適化
import { memo, useMemo, useCallback, lazy, Suspense } from 'react';
// コンポーネントの遅延読み込み
const HeavyComponent = lazy(() => import('./components/HeavyComponent'));
// メモ化されたコンポーネント
const ContainerCard = memo(({ container }) => {
const status = useMemo(() =>
calculateStatus(container), [container.id, container.state]
);
const handleClick = useCallback(() => {
openContainerDetails(container.id);
}, [container.id]);
return (
<div onClick={handleClick}>
{/* コンポーネント内容 */}
</div>
);
});
// 2. バンドルサイズ最適化
// webpack.config.js
module.exports = {
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
priority: 10
},
common: {
minChunks: 2,
priority: 5,
reuseExistingChunk: true
}
}
},
usedExports: true,
sideEffects: false
}
};
// 3. 仮想スクロール実装
import { FixedSizeList } from 'react-window';
function LogViewer({ logs }) {
const Row = ({ index, style }) => (
<div style={style}>
{logs[index].timestamp} - {logs[index].message}
</div>
);
return (
<FixedSizeList
height={600}
itemCount={logs.length}
itemSize={35}
width="100%"
>
{Row}
</FixedSizeList>
);
}
🧪 5-2. テスト強化¶
単体テスト¶
// backend/__tests__/authService.test.js
describe('AuthService', () => {
let authService;
beforeEach(() => {
authService = new AuthService();
});
describe('validateRedmineApiKey', () => {
it('should validate correct API key', async () => {
const mockResponse = { user: { id: 1, login: 'admin' } };
fetch.mockResolvedValue({
ok: true,
json: async () => mockResponse
});
const result = await authService.validateRedmineApiKey('valid-key');
expect(result).toEqual(mockResponse.user);
});
it('should reject invalid API key', async () => {
fetch.mockResolvedValue({ ok: false, status: 401 });
await expect(authService.validateRedmineApiKey('invalid-key'))
.rejects.toThrow('Invalid API key');
});
});
});
// 統合テスト
describe('API Integration Tests', () => {
let app;
let token;
beforeAll(async () => {
app = await createApp();
// テスト用トークン取得
const res = await request(app)
.post('/api/v1/auth/login')
.send({ apiKey: process.env.TEST_API_KEY });
token = res.body.token;
});
describe('Container Management', () => {
it('should list all containers', async () => {
const res = await request(app)
.get('/api/v1/docker/containers')
.set('Authorization', `Bearer ${token}`)
.expect(200);
expect(res.body.success).toBe(true);
expect(Array.isArray(res.body.data)).toBe(true);
});
});
});
E2Eテスト¶
// e2e/dashboard.spec.js
import { test, expect } from '@playwright/test';
test.describe('Dashboard', () => {
test.beforeEach(async ({ page }) => {
await page.goto('https://infra.call2arm.com');
await page.fill('#apiKey', process.env.TEST_API_KEY);
await page.click('button[type="submit"]');
await page.waitForNavigation();
});
test('should display container list', async ({ page }) => {
await expect(page.locator('h1')).toContainText('Infrastructure Helper');
const containers = page.locator('[data-testid="container-card"]');
await expect(containers).toHaveCount.greaterThan(0);
});
test('should update metrics in real-time', async ({ page }) => {
const cpuValue = page.locator('[data-testid="cpu-metric"]');
const initialValue = await cpuValue.textContent();
await page.waitForTimeout(5000);
const updatedValue = await cpuValue.textContent();
expect(initialValue).not.toBe(updatedValue);
});
});
📚 5-3. ドキュメント整備¶
APIドキュメント(OpenAPI)¶
openapi: 3.0.0
info:
title: Infrastructure Helper API
version: 1.2.0
description: VPS-ROOT Infrastructure management service
servers:
- url: https://infra.call2arm.com/api/v1
security:
- bearerAuth: []
paths:
/auth/login:
post:
summary: Authenticate with Redmine API key
security: []
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- apiKey
properties:
apiKey:
type: string
description: Redmine API key
responses:
200:
description: Successful authentication
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
token:
type: string
user:
$ref: '#/components/schemas/User'
components:
schemas:
User:
type: object
properties:
id:
type: integer
login:
type: string
admin:
type: boolean
email:
type: string
ユーザーマニュアル¶
# Infrastructure Helper ユーザーマニュアル
## 目次
1. はじめに
2. 初期設定
3. 基本機能
4. 高度な機能
5. トラブルシューティング
6. FAQ
## 1. はじめに
Infrastructure Helperは、VPS-ROOT環境を効率的に管理するためのWebベースのツールです。
### 主な機能
- Dockerコンテナ管理
- リアルタイム監視
- ログ管理
- バックアップ・復旧
- 自動スケーリング
- セキュリティ監査
## 2. 初期設定
### 2.1 アクセス方法
1. https://infra.call2arm.com にアクセス
2. Redmine APIキーでログイン
### 2.2 APIキーの取得
1. Redmineにログイン
2. 「個人設定」→「APIアクセスキー」
3. 「表示」をクリックしてキーをコピー
## 3. 基本機能
### 3.1 ダッシュボード
メインダッシュボードでは以下の情報が確認できます:
- 稼働中のコンテナ数
- システムリソース使用状況
- 最近のアラート
- クイックアクション
### 3.2 コンテナ管理
#### コンテナ一覧表示
左メニューから「Containers」を選択...
🔒 5-4. セキュリティ強化¶
セキュリティ実装¶
// 1. セキュリティヘッダー
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'unsafe-inline'", "cdn.tailwindcss.com"],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", "data:", "https:"],
connectSrc: ["'self'", "wss://infra.call2arm.com"]
}
},
hsts: {
maxAge: 31536000,
includeSubDomains: true,
preload: true
}
}));
// 2. 入力検証
const { body, validationResult } = require('express-validator');
app.post('/api/v1/scripts/execute',
authenticateToken,
[
body('scriptType').isIn(['vps_status', 'nginx_reload', 'docker_health']),
body('args').optional().isObject()
],
(req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
// 処理続行
}
);
// 3. SQLインジェクション対策
const db = new Database();
const stmt = db.prepare('SELECT * FROM users WHERE id = ?');
const user = stmt.get(userId);
// 4. レート制限
const rateLimiter = new RateLimiter({
windowMs: 15 * 60 * 1000,
max: 100,
skipSuccessfulRequests: false,
keyGenerator: (req) => req.user?.id || req.ip
});
// 5. 監査ログ
class AuditLogger {
async log(action, user, details) {
await db.insert('audit_logs', {
action,
user_id: user.id,
user_login: user.login,
ip_address: user.ipAddress,
user_agent: user.userAgent,
details: JSON.stringify(details),
timestamp: new Date()
});
}
}
📈 5-5. 監視・運用¶
監視設定¶
# prometheus.yml
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'infra-helper'
static_configs:
- targets: ['infra-helper-api:3000']
metrics_path: '/api/v1/metrics/prometheus'
# alerts.yml
groups:
- name: infra-helper
rules:
- alert: HighMemoryUsage
expr: process_resident_memory_bytes > 1e9
for: 5m
labels:
severity: warning
annotations:
summary: "High memory usage detected"
- alert: APIHighLatency
expr: http_request_duration_seconds{quantile="0.99"} > 1
for: 5m
labels:
severity: critical
成果物¶
- パフォーマンス最適化済みコード
- 90%以上のテストカバレッジ
- 完全なAPIドキュメント
- 日本語/英語ユーザーマニュアル
- 運用手順書
- 監視ダッシュボード設定
- セキュリティ監査レポート
- パフォーマンスベンチマーク結果
表示するデータがありません
操作