チーム開発でのコンテナ環境標準化戦略:組織レベルでの効率的運用ガイド

約110分で読めます by ぽんたぬき
チーム開発でのコンテナ環境標準化戦略:組織レベルでの効率的運用ガイド

チーム開発でのコンテナ環境標準化戦略:組織レベルでの効率的運用ガイド

個人でのコンテナ開発環境構築をマスターしたら、次の重要な課題はチーム全体での標準化と効率的な運用です。「新人が環境構築に1週間かかる」「メンバーごとに異なる環境で『私の環境では動く』問題が頻発」「設定ファイルの管理が属人化」といった課題を解決する必要があります。

この記事では、5人から500人規模まで対応できる組織レベルでのコンテナ環境標準化戦略を詳しく解説します。効果的なワークフロー設計、新人オンボーディングの自動化、設定管理のベストプラクティスを習得できます。

組織レベル標準化の戦略フレームワーク

標準化の段階的アプローチ

Phase 1: 基盤標準化(1-2週間)

  • 基本的なDockerfile・Compose テンプレート統一
  • VS Code DevContainer 設定標準化
  • 最小限の開発ルール策定

Phase 2: ワークフロー統合(2-4週間)

  • Git フック・CI/CD との連携
  • 自動化されたテスト・品質チェック
  • ドキュメント・知識共有システム

Phase 3: 組織最適化(1-3ヶ月)

  • メトリクス収集・分析システム
  • 継続的改善プロセス
  • 新技術導入評価・適用

チーム規模別の標準化戦略

小規模チーム(2-10人)の場合:

# team-standards/small-team-config.yml
standardization_level: "basic"
governance: "informal"
automation_level: "minimal"

required_tools:
  - docker: ">=20.0"
  - vscode: "latest"
  - git: ">=2.30"

standard_files:
  - .devcontainer/devcontainer.json
  - docker-compose.yml
  - .env.example
  - README.md

workflow:
  setup_time_target: "30 minutes"
  review_process: "peer review"
  documentation: "inline comments + README"

中規模チーム(11-50人)の場合:

# team-standards/medium-team-config.yml
standardization_level: "comprehensive"
governance: "formal_guidelines"
automation_level: "high"

required_tools:
  - docker: "20.10.x"  # 固定バージョン
  - vscode: ">=1.70.0"
  - pre-commit: "latest"

standard_files:
  - .devcontainer/devcontainer.json
  - docker-compose.yml
  - docker-compose.override.yml
  - .env.example
  - .env.local.example
  - scripts/setup.sh
  - docs/DEVELOPMENT.md

workflow:
  setup_time_target: "15 minutes"
  review_process: "mandatory code review + automated checks"
  documentation: "dedicated wiki + API docs"
  monitoring: "development metrics collection"

大規模組織(50人以上)の場合:

# team-standards/enterprise-config.yml
standardization_level: "enterprise"
governance: "strict_policies"
automation_level: "full"

required_tools:
  - docker: "20.10.21"  # セキュリティ検証済み固定版
  - vscode: "1.74.3"
  - pre-commit: "2.20.0"
  - security_scanner: "required"

standard_files:
  - .devcontainer/
    - devcontainer.json
    - Dockerfile
    - docker-compose.yml
  - scripts/
    - setup.sh
    - validate.sh
    - security-check.sh
  - docs/
    - DEVELOPMENT.md
    - SECURITY.md
    - CONTRIBUTING.md
  - .github/
    - workflows/dev-environment-check.yml

workflow:
  setup_time_target: "10 minutes"
  review_process: "multi-stage approval + security review"
  documentation: "comprehensive documentation site"
  monitoring: "full observability + compliance tracking"
  compliance: "SOC2 + security audits"

統一開発環境テンプレートの設計

プロジェクトテンプレート構造

チーム全体で再利用可能な標準テンプレートを設計します:

team-dev-templates/
├── 📁 base/                           # 共通基盤
│   ├── 📄 .devcontainer/
│   │   ├── 📄 devcontainer.json      # 基本DevContainer設定
│   │   ├── 📄 Dockerfile.base        # 共通ベースイメージ
│   │   └── 📄 docker-compose.base.yml
│   ├── 📄 scripts/
│   │   ├── 📄 setup.sh               # 環境セットアップ
│   │   ├── 📄 validate.sh            # 環境検証
│   │   ├── 📄 update.sh              # 環境更新
│   │   └── 📄 troubleshoot.sh        # トラブルシューティング
│   └── 📄 docs/
│       ├── 📄 DEVELOPMENT.md         # 開発ガイド
│       ├── 📄 TROUBLESHOOTING.md     # 問題解決
│       └── 📄 TEAM_STANDARDS.md      # チーム標準
├── 📁 python-web/                    # Python Webアプリ用
│   ├── 📄 .devcontainer/
│   │   ├── 📄 devcontainer.json
│   │   └── 📄 Dockerfile
│   ├── 📄 pyproject.toml
│   ├── 📄 requirements/
│   │   ├── 📄 base.txt
│   │   ├── 📄 dev.txt
│   │   └── 📄 test.txt
│   └── 📄 tests/
├── 📁 data-science/                  # データサイエンス用
│   ├── 📄 .devcontainer/
│   ├── 📄 notebooks/
│   ├── 📄 data/
│   └── 📄 models/
├── 📁 frontend/                      # フロントエンド用
│   ├── 📄 .devcontainer/
│   ├── 📄 package.json
│   └── 📄 src/
└── 📁 fullstack/                     # フルスタック用
    ├── 📄 .devcontainer/
    ├── 📄 backend/
    ├── 📄 frontend/
    └── 📄 database/

統一DevContainer設定

チーム標準DevContainer基盤:

// base/.devcontainer/devcontainer.json - チーム共通基盤
{
  "name": "${PROJECT_NAME} Development Environment",
  "dockerComposeFile": ["docker-compose.base.yml", "../docker-compose.yml"],
  "service": "app",
  "workspaceFolder": "/workspace",
  "shutdownAction": "stopCompose",

  // チーム統一設定
  "customizations": {
    "vscode": {
      "settings": {
        // エディタ統一設定
        "editor.formatOnSave": true,
        "editor.codeActionsOnSave": {
          "source.organizeImports": true
        },
        "files.trimTrailingWhitespace": true,
        "files.insertFinalNewline": true,
        
        // チーム統一インデント設定
        "editor.tabSize": 2,
        "editor.insertSpaces": true,
        
        // Git統一設定
        "git.autofetch": true,
        "git.enableSmartCommit": true,
        
        // ターミナル統一設定
        "terminal.integrated.defaultProfile.linux": "bash",
        "terminal.integrated.profiles.linux": {
          "team-shell": {
            "path": "/bin/bash",
            "args": ["-c", "source /workspace/scripts/team-aliases.sh && bash"]
          }
        }
      },

      // チーム必須拡張機能
      "extensions": [
        // 基本開発ツール
        "ms-vscode.vscode-typescript-next",
        "esbenp.prettier-vscode",
        "ms-python.python",
        "ms-python.vscode-pylance",
        
        // Git・バージョン管理
        "eamodio.gitlens",
        "github.vscode-pull-request-github",
        
        // コード品質
        "ms-python.flake8",
        "ms-python.mypy-type-checker",
        "bradlc.vscode-tailwindcss",
        
        // チーム協働
        "ms-vsliveshare.vsliveshare",
        "gruntfuggly.todo-tree",
        "streetsidesoftware.code-spell-checker",
        
        // コンテナ・DevOps
        "ms-azuretools.vscode-docker",
        "ms-vscode-remote.remote-containers"
      ]
    }
  },

  // ライフサイクルコマンド(チーム統一)
  "onCreateCommand": {
    "install-team-tools": "bash scripts/setup.sh",
    "validate-environment": "bash scripts/validate.sh"
  },
  "postCreateCommand": "bash scripts/post-create.sh",
  "postStartCommand": "bash scripts/health-check.sh",

  // ポート転送統一設定
  "forwardPorts": [3000, 8000, 8080, 5432, 6379],
  "portsAttributes": {
    "3000": {
      "label": "Frontend Dev Server",
      "onAutoForward": "openBrowser"
    },
    "8000": {
      "label": "Backend API",
      "onAutoForward": "openBrowser"
    },
    "5432": {
      "label": "PostgreSQL",
      "onAutoForward": "silent"
    }
  },

  // チーム環境変数
  "containerEnv": {
    "TEAM_STANDARDS_VERSION": "2.1.0",
    "DEVELOPMENT_MODE": "true",
    "LOG_LEVEL": "debug"
  },

  // チーム統一機能
  "features": {
    "ghcr.io/devcontainers/features/git:1": {
      "version": "latest"
    },
    "ghcr.io/devcontainers/features/github-cli:1": {
      "version": "latest"
    },
    "ghcr.io/devcontainers/features/node:1": {
      "version": "18"
    }
  },

  // 権限・セキュリティ設定
  "containerUser": "vscode",
  "updateRemoteUserUID": true,
  "remoteUser": "vscode"
}

プロジェクト種別特化設定(例:Python Web):

// python-web/.devcontainer/devcontainer.json
{
  "name": "Python Web Development",
  
  // ベース設定を継承
  "dockerComposeFile": [
    "../base/.devcontainer/docker-compose.base.yml",
    "docker-compose.yml"
  ],
  "service": "python-web",
  "workspaceFolder": "/workspace",

  // Python特化カスタマイズ
  "customizations": {
    "vscode": {
      "settings": {
        // Python特化設定
        "python.defaultInterpreterPath": "/usr/local/bin/python",
        "python.linting.enabled": true,
        "python.linting.pylintEnabled": true,
        "python.linting.flake8Enabled": true,
        "python.formatting.provider": "black",
        "python.testing.pytestEnabled": true,
        "python.testing.pytestArgs": ["tests/"],
        
        // Django/Flask設定
        "python.envFile": "${workspaceFolder}/.env",
        "python.terminal.activateEnvironment": false
      },

      // Python特化拡張機能
      "extensions": [
        "ms-python.python",
        "ms-python.vscode-pylance", 
        "ms-python.black-formatter",
        "ms-python.isort",
        "ms-python.mypy-type-checker",
        "ms-python.flake8",
        "ms-toolsai.jupyter",
        "batisteo.vscode-django",
        "ckolkman.vscode-postgres"
      ]
    }
  },

  // Python特化ライフサイクル
  "onCreateCommand": {
    "install-python-deps": "pip install -r requirements/dev.txt",
    "setup-pre-commit": "pre-commit install"
  },
  "postCreateCommand": "python manage.py migrate",

  // Python特化ポート設定
  "forwardPorts": [8000, 8080, 5432],
  "portsAttributes": {
    "8000": {
      "label": "Django/Flask Dev Server",
      "onAutoForward": "openBrowser"
    }
  }
}

自動化セットアップスクリプト

包括的環境セットアップスクリプト:

#!/bin/bash
# scripts/setup.sh - チーム統一環境セットアップ

set -euo pipefail

# 設定
TEAM_STANDARDS_VERSION="2.1.0"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"

# ログ関数
log() {
    echo "🔧 [$(date +'%Y-%m-%d %H:%M:%S')] $*"
}

error() {
    echo "❌ [$(date +'%Y-%m-%d %H:%M:%S')] ERROR: $*" >&2
}

success() {
    echo "✅ [$(date +'%Y-%m-%d %H:%M:%S')] $*"
}

# 環境検証
validate_environment() {
    log "環境を検証中..."
    
    # 必須ツールチェック
    local required_tools=("docker" "git" "curl")
    for tool in "${required_tools[@]}"; do
        if ! command -v "$tool" &> /dev/null; then
            error "$tool が見つかりません"
            exit 1
        fi
        success "$tool が利用可能"
    done
    
    # Dockerバージョンチェック
    local docker_version=$(docker --version | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)
    log "Docker version: $docker_version"
    
    # Git設定チェック
    if ! git config user.name &> /dev/null; then
        error "Git user.name が設定されていません"
        echo "設定してください: git config --global user.name 'Your Name'"
        exit 1
    fi
    
    if ! git config user.email &> /dev/null; then
        error "Git user.email が設定されていません"
        echo "設定してください: git config --global user.email 'your.email@company.com'"
        exit 1
    fi
    
    success "環境検証完了"
}

# チーム標準ツールインストール
install_team_tools() {
    log "チーム標準ツールをインストール中..."
    
    # Pre-commit hooks
    if command -v pip &> /dev/null; then
        pip install --user pre-commit
        if [ -f ".pre-commit-config.yaml" ]; then
            pre-commit install
            success "pre-commit hooks インストール完了"
        fi
    fi
    
    # GitHub CLI
    if ! command -v gh &> /dev/null; then
        if command -v apt-get &> /dev/null; then
            curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg
            echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null
            sudo apt update
            sudo apt install gh
        fi
    fi
    
    success "チーム標準ツール インストール完了"
}

# プロジェクト固有セットアップ
setup_project() {
    log "プロジェクト固有セットアップを実行中..."
    
    # 環境変数ファイルセットアップ
    if [ -f ".env.example" ] && [ ! -f ".env" ]; then
        cp .env.example .env
        log ".env ファイルを作成しました(.env.example からコピー)"
        echo "⚠️  .env ファイルを確認して、必要な値を設定してください"
    fi
    
    # ローカル設定ファイル
    if [ -f ".env.local.example" ] && [ ! -f ".env.local" ]; then
        cp .env.local.example .env.local
        log ".env.local ファイルを作成しました"
    fi
    
    # Git hooks セットアップ
    if [ -d ".githooks" ]; then
        git config core.hooksPath .githooks
        chmod +x .githooks/*
        success "Git hooks セットアップ完了"
    fi
    
    # 依存関係インストール
    if [ -f "requirements.txt" ]; then
        pip install -r requirements.txt
    elif [ -f "package.json" ]; then
        npm install
    elif [ -f "Gemfile" ]; then
        bundle install
    fi
    
    success "プロジェクト固有セットアップ完了"
}

# チーム標準検証
validate_team_standards() {
    log "チーム標準への適合性を検証中..."
    
    local compliance_errors=()
    
    # 必須ファイル存在チェック
    local required_files=(
        ".devcontainer/devcontainer.json"
        "README.md"
        ".gitignore"
    )
    
    for file in "${required_files[@]}"; do
        if [ ! -f "$file" ]; then
            compliance_errors+=("必須ファイルが不足: $file")
        fi
    done
    
    # DevContainer設定検証
    if [ -f ".devcontainer/devcontainer.json" ]; then
        if ! jq . .devcontainer/devcontainer.json > /dev/null 2>&1; then
            compliance_errors+=("DevContainer設定が無効なJSON形式")
        fi
    fi
    
    # README.md 内容チェック
    if [ -f "README.md" ]; then
        local readme_required_sections=("## 開発環境セットアップ" "## 使用方法")
        for section in "${readme_required_sections[@]}"; do
            if ! grep -q "$section" README.md; then
                compliance_errors+=("README.md に必須セクションが不足: $section")
            fi
        done
    fi
    
    # エラーレポート
    if [ ${#compliance_errors[@]} -gt 0 ]; then
        error "チーム標準への適合性問題が発見されました:"
        for err in "${compliance_errors[@]}"; do
            echo "  - $err"
        done
        echo ""
        echo "問題を修正してから再実行してください。"
        exit 1
    fi
    
    success "チーム標準への適合性検証完了"
}

# ヘルスチェック
health_check() {
    log "環境ヘルスチェックを実行中..."
    
    # Docker接続テスト
    if ! docker ps > /dev/null 2>&1; then
        error "Docker daemon に接続できません"
        exit 1
    fi
    
    # ポート使用状況チェック
    local common_ports=(3000 8000 8080 5432 6379)
    local used_ports=()
    
    for port in "${common_ports[@]}"; do
        if netstat -tuln 2>/dev/null | grep -q ":$port "; then
            used_ports+=("$port")
        fi
    done
    
    if [ ${#used_ports[@]} -gt 0 ]; then
        log "使用中のポート: ${used_ports[*]}"
        echo "開発サーバー起動時に競合する可能性があります"
    fi
    
    # ディスク容量チェック
    local disk_usage=$(df . | tail -1 | awk '{print $5}' | sed 's/%//')
    if [ "$disk_usage" -gt 85 ]; then
        log "⚠️  ディスク使用率が高いです ($disk_usage%)"
        echo "docker system prune でクリーンアップを検討してください"
    fi
    
    success "ヘルスチェック完了"
}

# 完了レポート
completion_report() {
    echo ""
    echo "🎉 チーム開発環境セットアップが完了しました!"
    echo ""
    echo "📋 次のステップ:"
    echo "1. .env ファイルの設定値を確認・更新"
    echo "2. VS Code でプロジェクトを開く"
    echo "3. 'Dev Containers: Reopen in Container' を実行"
    echo "4. 開発を開始!"
    echo ""
    echo "🔗 参考資料:"
    echo "- 開発ガイド: docs/DEVELOPMENT.md"
    echo "- チーム標準: docs/TEAM_STANDARDS.md"
    echo "- トラブルシューティング: docs/TROUBLESHOOTING.md"
    echo ""
    echo "❓ 問題が発生した場合:"
    echo "- ./scripts/troubleshoot.sh を実行"
    echo "- チームSlackの #dev-support チャンネルで質問"
    echo ""
}

# メイン実行
main() {
    log "チーム開発環境セットアップを開始します..."
    log "Team Standards Version: $TEAM_STANDARDS_VERSION"
    echo ""
    
    validate_environment
    install_team_tools
    setup_project
    validate_team_standards
    health_check
    completion_report
    
    success "セットアップが正常に完了しました ✨"
}

# オプション処理
while [[ $# -gt 0 ]]; do
    case $1 in
        --skip-validation)
            SKIP_VALIDATION=true
            shift
            ;;
        --verbose)
            set -x
            shift
            ;;
        --help)
            echo "チーム開発環境セットアップスクリプト"
            echo ""
            echo "使用方法: $0 [オプション]"
            echo ""
            echo "オプション:"
            echo "  --skip-validation  検証をスキップ"
            echo "  --verbose         詳細ログを表示"
            echo "  --help           このヘルプを表示"
            exit 0
            ;;
        *)
            error "不明なオプション: $1"
            exit 1
            ;;
    esac
done

# メイン実行
main

新人オンボーディング自動化

ワンクリックセットアップシステム

新人向け自動化オンボーディング:

#!/bin/bash
# scripts/onboarding.sh - 新人向け完全自動セットアップ

set -euo pipefail

# 新人オンボーディング用設定
ONBOARDING_VERSION="1.0.0"
COMPANY_NAME="Your Company"
TEAM_NAME="Development Team"

# インタラクティブセットアップ
interactive_setup() {
    echo "🎉 $COMPANY_NAME $TEAM_NAME へようこそ!"
    echo "========================================="
    echo ""
    echo "この自動セットアップでは、開発環境を完全に準備します。"
    echo "所要時間: 約10-15分"
    echo ""
    
    read -p "続行しますか? (y/N): " -n 1 -r
    echo
    if [[ ! $REPLY =~ ^[Yy]$ ]]; then
        echo "セットアップをキャンセルしました。"
        exit 0
    fi
    
    # 基本情報収集
    echo ""
    echo "📝 基本情報を設定します"
    echo "========================"
    
    # Git設定
    if ! git config user.name &> /dev/null; then
        read -p "Git ユーザー名を入力してください: " git_name
        git config --global user.name "$git_name"
    fi
    
    if ! git config user.email &> /dev/null; then
        read -p "Git メールアドレスを入力してください: " git_email
        git config --global user.email "$git_email"
    fi
    
    # SSH キー設定
    setup_ssh_key
    
    # 開発設定
    echo ""
    echo "⚙️  開発設定をカスタマイズします"
    echo "=========================="
    
    read -p "普段使用するエディタは? (1: VS Code, 2: IntelliJ, 3: その他): " editor_choice
    case $editor_choice in
        1)
            PREFERRED_EDITOR="vscode"
            ;;
        2)
            PREFERRED_EDITOR="intellij"
            ;;
        *)
            PREFERRED_EDITOR="other"
            ;;
    esac
    
    read -p "主な開発言語は? (1: Python, 2: JavaScript, 3: Java, 4: その他): " language_choice
    case $language_choice in
        1)
            PRIMARY_LANGUAGE="python"
            ;;
        2)
            PRIMARY_LANGUAGE="javascript"
            ;;
        3)
            PRIMARY_LANGUAGE="java"
            ;;
        *)
            PRIMARY_LANGUAGE="other"
            ;;
    esac
}

# SSH キーセットアップ
setup_ssh_key() {
    echo ""
    echo "🔑 SSH キーを設定します"
    echo "===================="
    
    if [ ! -f ~/.ssh/id_ed25519 ]; then
        read -p "SSH キーを生成しますか? (Y/n): " -n 1 -r
        echo
        if [[ $REPLY =~ ^[Yy]$ ]] || [[ -z $REPLY ]]; then
            local email=$(git config user.email)
            ssh-keygen -t ed25519 -C "$email" -f ~/.ssh/id_ed25519 -N ""
            
            # SSH エージェントに追加
            eval "$(ssh-agent -s)"
            ssh-add ~/.ssh/id_ed25519
            
            echo ""
            echo "✅ SSH キーが生成されました"
            echo ""
            echo "📋 以下の公開キーをGitHubに登録してください:"
            echo "=============================================="
            cat ~/.ssh/id_ed25519.pub
            echo "=============================================="
            echo ""
            echo "GitHub Settings → SSH and GPG keys → New SSH key"
            echo ""
            read -p "GitHubへの登録が完了したらEnterを押してください..."
            
            # GitHub接続テスト
            if ssh -T git@github.com 2>&1 | grep -q "successfully authenticated"; then
                echo "✅ GitHub SSH接続が確認できました"
            else
                echo "⚠️  GitHub SSH接続に問題があります。後で確認してください。"
            fi
        fi
    else
        echo "✅ SSH キーは既に存在します"
    fi
}

# 必要ツールインストール
install_required_tools() {
    echo ""
    echo "🛠️  必要なツールをインストールします"
    echo "============================"
    
    # OS判定
    if [[ "$OSTYPE" == "darwin"* ]]; then
        install_tools_macos
    elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
        install_tools_linux
    elif [[ "$OSTYPE" == "msys" ]] || [[ "$OSTYPE" == "cygwin" ]]; then
        install_tools_windows
    else
        echo "⚠️  お使いのOSは自動インストールに対応していません"
        echo "手動でツールをインストールしてください:"
        echo "- Docker"
        echo "- Git"
        echo "- VS Code"
        echo "- Node.js"
        return
    fi
}

install_tools_macos() {
    echo "macOS用ツールをインストール中..."
    
    # Homebrewインストール
    if ! command -v brew &> /dev/null; then
        echo "Homebrewをインストール中..."
        /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
    fi
    
    # 必須ツール
    local tools=("git" "docker" "docker-compose" "node" "yarn")
    for tool in "${tools[@]}"; do
        if ! command -v "$tool" &> /dev/null; then
            echo "$tool をインストール中..."
            brew install "$tool"
        fi
    done
    
    # VS Code
    if ! command -v code &> /dev/null; then
        echo "VS Code をインストール中..."
        brew install --cask visual-studio-code
    fi
    
    # OrbStack (Docker Desktop代替)
    if ! command -v orbstack &> /dev/null; then
        echo "OrbStack をインストール中..."
        brew install --cask orbstack
    fi
}

install_tools_linux() {
    echo "Linux用ツールをインストール中..."
    
    # パッケージマネージャー判定
    if command -v apt-get &> /dev/null; then
        # Ubuntu/Debian
        sudo apt-get update
        sudo apt-get install -y curl wget git
        
        # Docker
        if ! command -v docker &> /dev/null; then
            curl -fsSL https://get.docker.com -o get-docker.sh
            sudo sh get-docker.sh
            sudo usermod -aG docker $USER
        fi
        
        # Node.js
        if ! command -v node &> /dev/null; then
            curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
            sudo apt-get install -y nodejs
        fi
        
        # VS Code
        if ! command -v code &> /dev/null; then
            wget -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > packages.microsoft.gpg
            sudo install -o root -g root -m 644 packages.microsoft.gpg /etc/apt/trusted.gpg.d/
            echo "deb [arch=amd64,arm64,armhf signed-by=/etc/apt/trusted.gpg.d/packages.microsoft.gpg] https://packages.microsoft.com/repos/code stable main" | sudo tee /etc/apt/sources.list.d/vscode.list
            sudo apt-get update
            sudo apt-get install -y code
        fi
        
    elif command -v dnf &> /dev/null; then
        # Fedora/RHEL
        sudo dnf install -y curl wget git docker nodejs npm
        sudo systemctl enable --now docker
        sudo usermod -aG docker $USER
    fi
}

# チーム設定配布
distribute_team_settings() {
    echo ""
    echo "👥 チーム設定を配布します"
    echo "======================"
    
    # VS Code設定
    local vscode_settings_dir=""
    if [[ "$OSTYPE" == "darwin"* ]]; then
        vscode_settings_dir="$HOME/Library/Application Support/Code/User"
    elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
        vscode_settings_dir="$HOME/.config/Code/User"
    elif [[ "$OSTYPE" == "msys" ]] || [[ "$OSTYPE" == "cygwin" ]]; then
        vscode_settings_dir="$APPDATA/Code/User"
    fi
    
    if [ -n "$vscode_settings_dir" ] && [ -d "$vscode_settings_dir" ]; then
        # チーム統一VS Code設定を配布
        if [ -f "team-configs/vscode-settings.json" ]; then
            cp team-configs/vscode-settings.json "$vscode_settings_dir/settings.json"
            echo "✅ VS Code設定を更新しました"
        fi
        
        # チーム統一拡張機能インストール
        if [ -f "team-configs/vscode-extensions.txt" ]; then
            echo "📦 チーム標準拡張機能をインストール中..."
            while IFS= read -r extension; do
                if [ -n "$extension" ] && [[ ! "$extension" =~ ^# ]]; then
                    code --install-extension "$extension" || true
                fi
            done < team-configs/vscode-extensions.txt
            echo "✅ 拡張機能インストール完了"
        fi
    fi
    
    # Git設定配布
    if [ -f "team-configs/gitconfig" ]; then
        cat team-configs/gitconfig >> ~/.gitconfig
        echo "✅ Git設定を更新しました"
    fi
    
    # Shell設定配布
    if [ -f "team-configs/team-aliases.sh" ]; then
        local shell_config=""
        if [ -n "$BASH_VERSION" ]; then
            shell_config="$HOME/.bashrc"
        elif [ -n "$ZSH_VERSION" ]; then
            shell_config="$HOME/.zshrc"
        fi
        
        if [ -n "$shell_config" ]; then
            echo "source $(pwd)/team-configs/team-aliases.sh" >> "$shell_config"
            echo "✅ シェル設定を更新しました"
        fi
    fi
}

# 学習リソース案内
provide_learning_resources() {
    echo ""
    echo "📚 学習リソースと次のステップ"
    echo "============================"
    echo ""
    echo "🎯 今すぐできること:"
    echo "1. プロジェクトをクローンして開発開始"
    echo "   git clone https://github.com/company/project-name.git"
    echo ""
    echo "2. 最初のプルリクエストを作成"
    echo "   - 自己紹介をREADME.mdに追加"
    echo "   - 簡単なバグ修正から始める"
    echo ""
    echo "📖 必読ドキュメント:"
    echo "- チーム開発ガイド: docs/TEAM_GUIDE.md"
    echo "- コーディング規約: docs/CODING_STANDARDS.md"
    echo "- Git ワークフロー: docs/GIT_WORKFLOW.md"
    echo ""
    echo "🎥 推奨学習コンテンツ:"
    echo "- 社内Docker研修動画: https://company.com/docker-training"
    echo "- Git実践ワークショップ: 毎週金曜日 15:00-16:00"
    echo "- ペアプログラミングセッション: #pair-programming で募集"
    echo ""
    echo "❓ サポート窓口:"
    echo "- 技術的質問: #dev-support"
    echo "- 環境構築問題: #dev-environment"  
    echo "- その他質問: #general"
    echo ""
    echo "👥 メンター制度:"
    echo "新入社員には経験豊富なメンターが付きます。"
    echo "メンター: [自動アサイン予定] さん"
    echo "初回1on1: 来週中に設定されます"
    echo ""
}

# 完了サマリー
completion_summary() {
    echo ""
    echo "🎉 オンボーディング完了!"
    echo "======================="
    echo ""
    echo "✅ 完了した設定:"
    echo "- Git設定 (ユーザー名・メール)"
    echo "- SSH キー生成・GitHub登録"
    echo "- 必要ツールインストール"
    echo "- チーム標準設定配布"
    echo "- VS Code拡張機能インストール"
    echo ""
    echo "📝 あなたの環境情報:"
    echo "- Git User: $(git config user.name) <$(git config user.email)>"
    echo "- Docker: $(docker --version 2>/dev/null || echo '未インストール')"
    echo "- Node.js: $(node --version 2>/dev/null || echo '未インストール')"
    echo "- エディタ設定: $PREFERRED_EDITOR"
    echo "- 主要言語: $PRIMARY_LANGUAGE"
    echo ""
    echo "🚀 次のアクション:"
    echo "1. ターミナルを再起動 (設定を反映)"
    echo "2. 'scripts/validate.sh' を実行 (環境確認)"
    echo "3. VS Code でプロジェクトを開く"
    echo "4. 初回プルリクエストを作成"
    echo ""
    echo "Welcome to the team! 🎊"
}

# メイン実行
main() {
    interactive_setup
    install_required_tools
    distribute_team_settings
    
    # チーム標準セットアップ実行
    if [ -f "scripts/setup.sh" ]; then
        bash scripts/setup.sh --skip-validation
    fi
    
    provide_learning_resources
    completion_summary
}

# エラーハンドリング
trap 'echo "❌ オンボーディング中にエラーが発生しました"; exit 1' ERR

echo "新人オンボーディング開始..."
main "$@"

ワークフロー統合とCI/CD連携

Git Hooks による品質保証

チーム統一pre-commit設定:

# .pre-commit-config.yaml - チーム標準品質チェック
repos:
  # 基本的なコード品質
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.4.0
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer
      - id: check-yaml
      - id: check-json
      - id: check-merge-conflict
      - id: check-executables-have-shebangs
      - id: check-case-conflict

  # Docker設定検証
  - repo: https://github.com/hadolint/hadolint
    rev: v2.12.0
    hooks:
      - id: hadolint-docker
        args: [--config, .hadolint.yaml]

  # Python品質チェック
  - repo: https://github.com/psf/black
    rev: 23.7.0
    hooks:
      - id: black
        language_version: python3

  - repo: https://github.com/pycqa/isort
    rev: 5.12.0
    hooks:
      - id: isort
        args: [--profile, black]

  - repo: https://github.com/pycqa/flake8
    rev: 6.0.0
    hooks:
      - id: flake8
        additional_dependencies: [flake8-docstrings]

  # セキュリティチェック
  - repo: https://github.com/PyCQA/bandit
    rev: 1.7.5
    hooks:
      - id: bandit
        args: [-r, src/, -f, json, -o, bandit-report.json]

  # シークレット検出
  - repo: https://github.com/Yelp/detect-secrets
    rev: v1.4.0
    hooks:
      - id: detect-secrets
        args: ['--baseline', '.secrets.baseline']

  # コミットメッセージ形式チェック
  - repo: https://github.com/commitizen-tools/commitizen
    rev: v3.6.0
    hooks:
      - id: commitizen
      - id: commitizen-branch
        stages: [push]

チーム統一commitizen設定:

# pyproject.toml - コミットメッセージ標準化
[tool.commitizen]
name = "cz_conventional_commits"
version = "1.0.0"
tag_format = "v$version"
update_changelog_on_bump = true

[tool.commitizen.settings]
# チーム統一コミットタイプ
allowed_prefixes = [
    "feat",      # 新機能
    "fix",       # バグ修正
    "docs",      # ドキュメント
    "style",     # コードスタイル
    "refactor",  # リファクタリング
    "test",      # テスト関連
    "chore",     # その他のタスク
    "ci",        # CI/CD関連
    "perf",      # パフォーマンス改善
    "build",     # ビルド関連
]

# スコープ(プロジェクト固有)
scopes = [
    "api",
    "frontend", 
    "backend",
    "database",
    "docker",
    "docs",
    "tests",
]

自動化テスト・デプロイパイプライン

GitHub Actions チーム標準ワークフロー:

# .github/workflows/team-standards-check.yml
name: Team Standards Check

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

env:
  TEAM_STANDARDS_VERSION: "2.1.0"

jobs:
  #============================================================================
  # 環境設定検証
  #============================================================================
  validate-environment:
    name: Validate Development Environment
    runs-on: ubuntu-latest
    
    steps:
    - name: Checkout code
      uses: actions/checkout@v4

    - name: Validate DevContainer configuration
      run: |
        if [ ! -f ".devcontainer/devcontainer.json" ]; then
          echo "❌ DevContainer設定が見つかりません"
          exit 1
        fi
        
        # JSON形式検証
        if ! jq . .devcontainer/devcontainer.json > /dev/null; then
          echo "❌ DevContainer設定が無効なJSON形式です"
          exit 1
        fi
        
        echo "✅ DevContainer設定は有効です"

    - name: Validate Docker configuration
      run: |
        if [ -f "Dockerfile" ]; then
          # Hadolint でDockerfile検証
          docker run --rm -i hadolint/hadolint < Dockerfile
        fi
        
        if [ -f "docker-compose.yml" ]; then
          # docker-compose設定検証
          docker-compose config > /dev/null
        fi

    - name: Check required documentation
      run: |
        required_docs=(
          "README.md"
          "docs/DEVELOPMENT.md"
        )
        
        for doc in "${required_docs[@]}"; do
          if [ ! -f "$doc" ]; then
            echo "❌ 必須ドキュメントが不足: $doc"
            exit 1
          fi
        done
        
        echo "✅ 必須ドキュメントが存在します"

  #============================================================================
  # コード品質チェック  
  #============================================================================
  code-quality:
    name: Code Quality Check
    runs-on: ubuntu-latest
    
    steps:
    - name: Checkout code
      uses: actions/checkout@v4

    - name: Setup Python
      uses: actions/setup-python@v4
      with:
        python-version: '3.11'

    - name: Install dependencies
      run: |
        pip install pre-commit
        pre-commit install

    - name: Run pre-commit hooks
      run: pre-commit run --all-files

    - name: Upload code quality reports
      uses: actions/upload-artifact@v3
      if: always()
      with:
        name: code-quality-reports
        path: |
          bandit-report.json
          *.log

  #============================================================================
  # 開発環境テスト
  #============================================================================
  test-dev-environment:
    name: Test Development Environment
    runs-on: ubuntu-latest
    
    steps:
    - name: Checkout code
      uses: actions/checkout@v4

    - name: Build development environment
      run: |
        if [ -f "docker-compose.yml" ]; then
          docker-compose build
        elif [ -f "Dockerfile" ]; then
          docker build -t test-env .
        fi

    - name: Test environment startup
      run: |
        if [ -f "docker-compose.yml" ]; then
          docker-compose up -d
          sleep 30
          
          # ヘルスチェック
          if [ -f "scripts/health-check.sh" ]; then
            docker-compose exec -T app bash scripts/health-check.sh
          fi
          
          docker-compose down
        fi

    - name: Run setup script test
      run: |
        if [ -f "scripts/setup.sh" ]; then
          # セットアップスクリプトのドライラン
          bash scripts/setup.sh --skip-validation || true
        fi

  #============================================================================
  # チーム標準適合性チェック
  #============================================================================
  team-compliance:
    name: Team Standards Compliance
    runs-on: ubuntu-latest
    
    steps:
    - name: Checkout code
      uses: actions/checkout@v4

    - name: Check team standards version
      run: |
        if [ -f "team-config.yml" ]; then
          version=$(grep "standards_version:" team-config.yml | cut -d'"' -f2)
          if [ "$version" != "$TEAM_STANDARDS_VERSION" ]; then
            echo "⚠️  チーム標準バージョンが古い可能性があります"
            echo "Current: $version, Expected: $TEAM_STANDARDS_VERSION"
          fi
        fi

    - name: Validate naming conventions
      run: |
        # ファイル命名規則チェック
        find . -name "*.py" -exec basename {} \; | while read file; do
          if [[ ! "$file" =~ ^[a-z_][a-z0-9_]*\.py$ ]]; then
            echo "❌ Python ファイル命名規則違反: $file"
            exit 1
          fi
        done
        
        # ディレクトリ命名規則チェック  
        find . -type d -name "*" | while read dir; do
          basename_dir=$(basename "$dir")
          if [[ "$basename_dir" =~ [A-Z] ]] && [[ "$basename_dir" != ".git" ]] && [[ "$basename_dir" != ".github" ]]; then
            echo "⚠️  ディレクトリ名に大文字が含まれています: $dir"
          fi
        done

    - name: Check git configuration
      run: |
        # .gitignore の存在確認
        if [ ! -f ".gitignore" ]; then
          echo "❌ .gitignore ファイルが存在しません"
          exit 1
        fi
        
        # 必須除外パターンチェック
        required_patterns=(
          "*.pyc"
          "__pycache__/"
          ".env"
          "*.log"
          ".DS_Store"
        )
        
        for pattern in "${required_patterns[@]}"; do
          if ! grep -q "$pattern" .gitignore; then
            echo "⚠️  .gitignore に推奨パターンが不足: $pattern"
          fi
        done

  #============================================================================
  # セキュリティチェック
  #============================================================================
  security-check:
    name: Security Check
    runs-on: ubuntu-latest
    
    steps:
    - name: Checkout code
      uses: actions/checkout@v4

    - name: Run Trivy vulnerability scanner
      uses: aquasecurity/trivy-action@master
      with:
        scan-type: 'fs'
        scan-ref: '.'
        format: 'sarif'
        output: 'trivy-results.sarif'

    - name: Upload Trivy scan results
      uses: github/codeql-action/upload-sarif@v2
      if: always()
      with:
        sarif_file: 'trivy-results.sarif'

    - name: Check for secrets
      run: |
        # detect-secrets を使用
        pip install detect-secrets
        detect-secrets scan --all-files --baseline .secrets.baseline

  #============================================================================
  # 通知とレポート
  #============================================================================
  notify-results:
    name: Notify Results
    needs: [validate-environment, code-quality, test-dev-environment, team-compliance, security-check]
    runs-on: ubuntu-latest
    if: always()
    
    steps:
    - name: Generate summary report
      run: |
        echo "## 🔍 Team Standards Check Results" >> $GITHUB_STEP_SUMMARY
        echo "" >> $GITHUB_STEP_SUMMARY
        
        # 各ジョブの結果をサマリーに追加
        echo "| Check | Status |" >> $GITHUB_STEP_SUMMARY
        echo "|-------|--------|" >> $GITHUB_STEP_SUMMARY
        echo "| Environment Validation | ${{ needs.validate-environment.result }} |" >> $GITHUB_STEP_SUMMARY
        echo "| Code Quality | ${{ needs.code-quality.result }} |" >> $GITHUB_STEP_SUMMARY
        echo "| Dev Environment Test | ${{ needs.test-dev-environment.result }} |" >> $GITHUB_STEP_SUMMARY
        echo "| Team Compliance | ${{ needs.team-compliance.result }} |" >> $GITHUB_STEP_SUMMARY
        echo "| Security Check | ${{ needs.security-check.result }} |" >> $GITHUB_STEP_SUMMARY

    - name: Slack notification
      if: failure()
      uses: 8398a7/action-slack@v3
      with:
        status: failure
        text: "🚨 Team standards check failed for ${{ github.repository }}"
      env:
        SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}

メトリクス収集・分析システム

開発効率測定

チーム生産性メトリクス収集:

#!/usr/bin/env python3
# scripts/team-metrics-collector.py

import json
import subprocess
import time
from datetime import datetime, timedelta
from pathlib import Path
from typing import Dict, List, Any
import requests
import sqlite3

class TeamMetricsCollector:
    def __init__(self, config_file="team-metrics-config.json"):
        self.config = self.load_config(config_file)
        self.db_path = "team_metrics.db"
        self.init_database()
    
    def load_config(self, config_file):
        """設定ファイル読み込み"""
        try:
            with open(config_file, 'r') as f:
                return json.load(f)
        except FileNotFoundError:
            return self.get_default_config()
    
    def get_default_config(self):
        """デフォルト設定"""
        return {
            "github": {
                "enabled": True,
                "token": "",
                "repos": []
            },
            "docker": {
                "enabled": True,
                "collect_build_times": True,
                "collect_image_sizes": True
            },
            "development": {
                "enabled": True,
                "collect_setup_times": True,
                "collect_error_rates": True
            },
            "team": {
                "size": 10,
                "experience_levels": {
                    "junior": 3,
                    "mid": 4, 
                    "senior": 3
                }
            }
        }
    
    def init_database(self):
        """データベース初期化"""
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        # テーブル作成
        cursor.execute('''
            CREATE TABLE IF NOT EXISTS setup_times (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                timestamp TEXT NOT NULL,
                user_id TEXT NOT NULL,
                setup_type TEXT NOT NULL,
                duration_seconds INTEGER NOT NULL,
                success BOOLEAN NOT NULL,
                error_message TEXT
            )
        ''')
        
        cursor.execute('''
            CREATE TABLE IF NOT EXISTS build_metrics (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                timestamp TEXT NOT NULL,
                project_name TEXT NOT NULL,
                build_type TEXT NOT NULL,
                duration_seconds INTEGER NOT NULL,
                image_size_mb REAL,
                cache_hit_ratio REAL,
                success BOOLEAN NOT NULL
            )
        ''')
        
        cursor.execute('''
            CREATE TABLE IF NOT EXISTS development_metrics (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                timestamp TEXT NOT NULL,
                user_id TEXT NOT NULL,
                action TEXT NOT NULL,
                duration_seconds INTEGER,
                error_count INTEGER DEFAULT 0,
                metadata TEXT
            )
        ''')
        
        cursor.execute('''
            CREATE TABLE IF NOT EXISTS team_health (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                timestamp TEXT NOT NULL,
                metric_name TEXT NOT NULL,
                metric_value REAL NOT NULL,
                unit TEXT NOT NULL
            )
        ''')
        
        conn.commit()
        conn.close()
    
    def collect_setup_metrics(self):
        """環境セットアップメトリクス収集"""
        print("📊 Collecting setup metrics...")
        
        # 最近のセットアップログを分析
        setup_log_path = Path("logs/setup.log")
        if setup_log_path.exists():
            with open(setup_log_path) as f:
                logs = f.readlines()
            
            setup_times = self.parse_setup_logs(logs)
            self.store_setup_metrics(setup_times)
    
    def parse_setup_logs(self, logs: List[str]) -> List[Dict]:
        """セットアップログ解析"""
        setup_times = []
        current_setup = None
        
        for line in logs:
            if "Setup starting" in line:
                current_setup = {
                    'start_time': self.extract_timestamp(line),
                    'user_id': self.extract_user_id(line),
                    'setup_type': 'full'
                }
            elif "Setup completed" in line and current_setup:
                end_time = self.extract_timestamp(line)
                duration = (end_time - current_setup['start_time']).total_seconds()
                
                current_setup.update({
                    'duration_seconds': int(duration),
                    'success': True,
                    'error_message': None
                })
                setup_times.append(current_setup)
                current_setup = None
            elif "Setup failed" in line and current_setup:
                end_time = self.extract_timestamp(line)
                duration = (end_time - current_setup['start_time']).total_seconds()
                
                current_setup.update({
                    'duration_seconds': int(duration),
                    'success': False,
                    'error_message': self.extract_error_message(line)
                })
                setup_times.append(current_setup)
                current_setup = None
        
        return setup_times
    
    def collect_build_metrics(self):
        """ビルドメトリクス収集"""
        print("🏗️  Collecting build metrics...")
        
        # Docker ビルド履歴を分析
        try:
            # Docker images 情報収集
            result = subprocess.run(
                ["docker", "images", "--format", "json"],
                capture_output=True, text=True
            )
            
            if result.returncode == 0:
                images = [json.loads(line) for line in result.stdout.strip().split('\n') if line]
                self.analyze_image_metrics(images)
        except Exception as e:
            print(f"Error collecting Docker metrics: {e}")
    
    def analyze_image_metrics(self, images: List[Dict]):
        """イメージメトリクス分析"""
        for image in images:
            size_str = image.get('Size', '0B')
            size_mb = self.parse_size_to_mb(size_str)
            
            build_metric = {
                'timestamp': datetime.now().isoformat(),
                'project_name': image.get('Repository', 'unknown'),
                'build_type': 'docker_image',
                'duration_seconds': 0,  # ビルド時間は別途収集
                'image_size_mb': size_mb,
                'cache_hit_ratio': 0.0,  # キャッシュ情報は別途収集
                'success': True
            }
            
            self.store_build_metric(build_metric)
    
    def collect_development_metrics(self):
        """開発活動メトリクス収集"""
        print("💻 Collecting development metrics...")
        
        # Git activity analysis
        if self.config["github"]["enabled"]:
            self.collect_git_metrics()
        
        # Error rates from logs
        self.collect_error_metrics()
    
    def collect_git_metrics(self):
        """Git活動メトリクス収集"""
        try:
            # 最近1週間のコミット数
            result = subprocess.run([
                "git", "log", "--since=1.week", "--oneline"
            ], capture_output=True, text=True)
            
            commit_count = len(result.stdout.strip().split('\n')) if result.stdout.strip() else 0
            
            # チーム健康度メトリクスとして記録
            self.store_team_health_metric(
                "weekly_commits", commit_count, "count"
            )
            
            # プルリクエスト統計(GitHub API使用)
            if self.config["github"]["token"]:
                self.collect_github_pr_metrics()
                
        except Exception as e:
            print(f"Error collecting Git metrics: {e}")
    
    def collect_github_pr_metrics(self):
        """GitHub PR メトリクス収集"""
        headers = {
            "Authorization": f"token {self.config['github']['token']}",
            "Accept": "application/vnd.github.v3+json"
        }
        
        for repo in self.config["github"]["repos"]:
            try:
                # 最近のPR統計
                url = f"https://api.github.com/repos/{repo}/pulls"
                params = {
                    "state": "all",
                    "since": (datetime.now() - timedelta(days=7)).isoformat()
                }
                
                response = requests.get(url, headers=headers, params=params)
                if response.status_code == 200:
                    prs = response.json()
                    
                    # PR統計を計算
                    merged_prs = len([pr for pr in prs if pr.get('merged_at')])
                    avg_review_time = self.calculate_avg_review_time(prs)
                    
                    # メトリクス保存
                    self.store_team_health_metric("weekly_merged_prs", merged_prs, "count")
                    if avg_review_time:
                        self.store_team_health_metric("avg_review_time_hours", avg_review_time, "hours")
                        
            except Exception as e:
                print(f"Error collecting GitHub metrics for {repo}: {e}")
    
    def calculate_avg_review_time(self, prs: List[Dict]) -> float:
        """平均レビュー時間計算"""
        review_times = []
        
        for pr in prs:
            created_at = datetime.fromisoformat(pr['created_at'].replace('Z', '+00:00'))
            merged_at = pr.get('merged_at')
            
            if merged_at:
                merged_at = datetime.fromisoformat(merged_at.replace('Z', '+00:00'))
                review_time = (merged_at - created_at).total_seconds() / 3600  # 時間単位
                review_times.append(review_time)
        
        return sum(review_times) / len(review_times) if review_times else 0
    
    def collect_error_metrics(self):
        """エラーメトリクス収集"""
        error_log_patterns = [
            "logs/error.log",
            "logs/app.log",
            "/var/log/containers/*.log"
        ]
        
        total_errors = 0
        for pattern in error_log_patterns:
            error_count = self.count_errors_in_logs(pattern)
            total_errors += error_count
        
        self.store_team_health_metric("daily_error_count", total_errors, "count")
    
    def count_errors_in_logs(self, log_pattern: str) -> int:
        """ログファイル内のエラー数カウント"""
        try:
            import glob
            error_count = 0
            
            for log_file in glob.glob(log_pattern):
                with open(log_file, 'r') as f:
                    content = f.read()
                    error_count += content.lower().count('error')
                    error_count += content.lower().count('exception')
                    error_count += content.lower().count('critical')
            
            return error_count
        except Exception:
            return 0
    
    def generate_team_dashboard(self) -> Dict[str, Any]:
        """チームダッシュボード用データ生成"""
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        dashboard_data = {
            "summary": {},
            "trends": {},
            "health_score": 0
        }
        
        # セットアップ時間統計
        cursor.execute('''
            SELECT 
                AVG(duration_seconds) as avg_setup_time,
                COUNT(*) as total_setups,
                SUM(CASE WHEN success = 1 THEN 1 ELSE 0 END) as successful_setups
            FROM setup_times 
            WHERE timestamp > datetime('now', '-7 days')
        ''')
        
        setup_stats = cursor.fetchone()
        if setup_stats[0]:
            dashboard_data["summary"]["avg_setup_time_minutes"] = round(setup_stats[0] / 60, 2)
            dashboard_data["summary"]["setup_success_rate"] = round(setup_stats[2] / setup_stats[1] * 100, 1) if setup_stats[1] > 0 else 0
        
        # ビルド統計
        cursor.execute('''
            SELECT 
                AVG(duration_seconds) as avg_build_time,
                AVG(image_size_mb) as avg_image_size,
                COUNT(*) as total_builds
            FROM build_metrics 
            WHERE timestamp > datetime('now', '-7 days')
        ''')
        
        build_stats = cursor.fetchone()
        if build_stats[0]:
            dashboard_data["summary"]["avg_build_time_minutes"] = round(build_stats[0] / 60, 2)
            dashboard_data["summary"]["avg_image_size_mb"] = round(build_stats[1], 1)
        
        # チーム健康度スコア計算
        health_score = self.calculate_team_health_score(cursor)
        dashboard_data["health_score"] = health_score
        
        conn.close()
        return dashboard_data
    
    def calculate_team_health_score(self, cursor) -> int:
        """チーム健康度スコア計算 (0-100)"""
        score_factors = []
        
        # セットアップ成功率 (30%)
        cursor.execute('''
            SELECT 
                SUM(CASE WHEN success = 1 THEN 1 ELSE 0 END) * 100.0 / COUNT(*) as success_rate
            FROM setup_times 
            WHERE timestamp > datetime('now', '-30 days')
        ''')
        setup_success_rate = cursor.fetchone()[0] or 0
        score_factors.append(min(setup_success_rate, 100) * 0.3)
        
        # セットアップ時間 (20%)
        cursor.execute('''
            SELECT AVG(duration_seconds) FROM setup_times 
            WHERE timestamp > datetime('now', '-30 days') AND success = 1
        ''')
        avg_setup_time = cursor.fetchone()[0] or 0
        setup_time_score = max(0, 100 - (avg_setup_time / 60 - 10) * 5)  # 10分が理想
        score_factors.append(setup_time_score * 0.2)
        
        # エラー率 (30%)
        cursor.execute('''
            SELECT AVG(metric_value) FROM team_health 
            WHERE metric_name = 'daily_error_count' 
            AND timestamp > datetime('now', '-7 days')
        ''')
        avg_daily_errors = cursor.fetchone()[0] or 0
        error_rate_score = max(0, 100 - avg_daily_errors * 2)
        score_factors.append(error_rate_score * 0.3)
        
        # PR処理速度 (20%)
        cursor.execute('''
            SELECT AVG(metric_value) FROM team_health 
            WHERE metric_name = 'avg_review_time_hours' 
            AND timestamp > datetime('now', '-7 days')
        ''')
        avg_review_time = cursor.fetchone()[0] or 0
        review_time_score = max(0, 100 - (avg_review_time - 24) * 2)  # 24時間が理想
        score_factors.append(review_time_score * 0.2)
        
        return round(sum(score_factors))
    
    def store_setup_metrics(self, metrics: List[Dict]):
        """セットアップメトリクス保存"""
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        for metric in metrics:
            cursor.execute('''
                INSERT INTO setup_times 
                (timestamp, user_id, setup_type, duration_seconds, success, error_message)
                VALUES (?, ?, ?, ?, ?, ?)
            ''', (
                metric.get('start_time', datetime.now()).isoformat(),
                metric.get('user_id', 'unknown'),
                metric.get('setup_type', 'unknown'),
                metric.get('duration_seconds', 0),
                metric.get('success', False),
                metric.get('error_message')
            ))
        
        conn.commit()
        conn.close()
    
    def store_build_metric(self, metric: Dict):
        """ビルドメトリクス保存"""
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        cursor.execute('''
            INSERT INTO build_metrics 
            (timestamp, project_name, build_type, duration_seconds, image_size_mb, cache_hit_ratio, success)
            VALUES (?, ?, ?, ?, ?, ?, ?)
        ''', (
            metric['timestamp'],
            metric['project_name'],
            metric['build_type'],
            metric['duration_seconds'],
            metric['image_size_mb'],
            metric['cache_hit_ratio'],
            metric['success']
        ))
        
        conn.commit()
        conn.close()
    
    def store_team_health_metric(self, metric_name: str, value: float, unit: str):
        """チーム健康度メトリクス保存"""
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        cursor.execute('''
            INSERT INTO team_health (timestamp, metric_name, metric_value, unit)
            VALUES (?, ?, ?, ?)
        ''', (datetime.now().isoformat(), metric_name, value, unit))
        
        conn.commit()
        conn.close()
    
    def extract_timestamp(self, log_line: str) -> datetime:
        """ログ行からタイムスタンプ抽出"""
        # 簡略化された実装
        return datetime.now()
    
    def extract_user_id(self, log_line: str) -> str:
        """ログ行からユーザーID抽出"""
        # 簡略化された実装
        return "user123"
    
    def extract_error_message(self, log_line: str) -> str:
        """ログ行からエラーメッセージ抽出"""
        return log_line.strip()
    
    def parse_size_to_mb(self, size_str: str) -> float:
        """サイズ文字列をMBに変換"""
        if 'GB' in size_str:
            return float(size_str.replace('GB', '')) * 1024
        elif 'MB' in size_str:
            return float(size_str.replace('MB', ''))
        elif 'KB' in size_str:
            return float(size_str.replace('KB', '')) / 1024
        else:
            return 0.0

def main():
    collector = TeamMetricsCollector()
    
    print("📊 Starting team metrics collection...")
    
    collector.collect_setup_metrics()
    collector.collect_build_metrics()
    collector.collect_development_metrics()
    
    dashboard_data = collector.generate_team_dashboard()
    
    print("📋 Team Dashboard Summary:")
    print(f"Health Score: {dashboard_data['health_score']}/100")
    print(f"Avg Setup Time: {dashboard_data['summary'].get('avg_setup_time_minutes', 'N/A')} minutes")
    print(f"Setup Success Rate: {dashboard_data['summary'].get('setup_success_rate', 'N/A')}%")
    print(f"Avg Build Time: {dashboard_data['summary'].get('avg_build_time_minutes', 'N/A')} minutes")
    
    # ダッシュボードデータをJSONで出力
    with open('team_dashboard.json', 'w') as f:
        json.dump(dashboard_data, f, indent=2)
    
    print("✅ Metrics collection completed!")

if __name__ == "__main__":
    main()

まとめ

この記事では、チーム開発でのコンテナ環境標準化について、組織レベルでの効率的な運用方法を詳しく解説しました。

重要な標準化ポイント

段階的標準化アプローチ:

  • Phase 1: 基盤標準化(基本テンプレート統一)
  • Phase 2: ワークフロー統合(CI/CD・品質チェック)
  • Phase 3: 組織最適化(メトリクス・継続改善)

チーム規模別戦略:

  • 小規模チーム: 最小限の標準化
  • 中規模チーム: 包括的なガイドライン
  • 大規模組織: 厳格なポリシーとコンプライアンス

自動化による効率化:

  • ワンクリック環境セットアップ
  • 新人オンボーディング自動化
  • 品質保証の自動化
  • メトリクス収集・分析

導入の進め方

  1. 現状分析: チームの規模・スキルレベル・課題の把握
  2. 段階的導入: 小さく始めて徐々に拡張
  3. 継続的改善: メトリクス収集による定量的な改善
  4. 文化醸成: 標準化の価値を共有し、チーム全体で推進

成功の指標

  • 新人の環境構築時間: 1日 → 30分以内
  • 環境起因のトラブル: 月10件 → 月1件以下
  • コードレビューの効率: レビュー時間30%短縮
  • チーム全体の開発速度: 20-40%向上

チーム標準化をマスターしたら、最新のコンテナ技術動向についても学習することをお勧めします:

効果的なチーム標準化により、個人の生産性向上だけでなく、組織全体の開発効率と品質を大幅に向上させることができます。


zation/)

関連記事

Webスクレイピング入門:株価・仮想通貨価格を取得してみよう
データ分析

Webスクレイピング入門:株価・仮想通貨価格を取得してみよう

Webスクレイピング入門:株価・仮想通貨価格を取得してみよう 投資やトレードをしていると、リアルタイムの価格情報が欲しくなりますよね。この記事では、Pythonを使って株価や仮想通貨価格を自動取得する方法を、初心者でもわかりやすく解説します。 Webスクレイピングとは? 基本概念...

VSCode設定ガイド:プロレベルの開発効率を実現するカスタマイズ完全版
データ分析

VSCode設定ガイド:プロレベルの開発効率を実現するカスタマイズ完全版

VSCode設定ガイド:プロレベルの開発効率を実現するカスタマイズ完全版 Visual Studio Code(VSCode)は、軽量でありながら強力な機能を持つ無料のコードエディタです。適切な設定とカスタマイズにより、プロフェッショナルな開発環境を構築できます。この記事では、初心者から上級者まで役...

CCXTを使って仮想通貨のトレードをしてみる(第4回)
データ分析

CCXTを使って仮想通貨のトレードをしてみる(第4回)

はじめに 注意: 仮想通貨取引には大きなリスクが伴います。必ず余剰資金で行い、税務・法務についても最新の情報を確認し、必要に応じて専門家の助言を受けてください。 第3回/useccxtpython3では、CCXTを使った仮想通貨の自動取引ボットのリスク管理とバックテストについて解説しました。今回は仮...

コメント

0/2000