Tutorial

Neue Updates und Verbesserungen zu Macfleet.

Wichtiger Hinweis

Die in diesen Tutorials bereitgestellten Codebeispiele und Skripte dienen nur zu Bildungszwecken. Macfleet ist nicht verantwortlich für Probleme, Schäden oder Sicherheitslücken, die durch die Verwendung, Änderung oder Implementierung dieser Beispiele entstehen können. Überprüfen und testen Sie Code immer in einer sicheren Umgebung, bevor Sie ihn in Produktionssystemen verwenden.

Menu Bar Customization and Icon Management on macOS

Customize menu bar appearance and manage system icons across your MacFleet devices. This tutorial covers icon visibility control, user interface optimization, and enterprise-grade menu bar management for improved user experience and organizational consistency.

Understanding Menu Bar Management

The macOS menu bar contains various system indicators and quick access icons:

  • Network indicators - VPN, Wi-Fi, Bluetooth status
  • System monitors - Battery, volume, date/time
  • Application icons - Third-party app status indicators
  • User controls - Spotlight, Control Center, Siri
  • Corporate tools - MDM agents, security software

Basic VPN Icon Management

Hide VPN Icon from Menu Bar

#!/bin/bash

# Hide VPN icon from menu bar
hide_vpn_icon() {
    echo "=== Hiding VPN Icon from Menu Bar ==="
    
    # Get current user
    local currentUser
    currentUser=$(echo "show State:/Users/ConsoleUser" | scutil | awk '/Name :/ { print $3 }')
    
    if [[ "$currentUser" == "loginwindow" || -z "$currentUser" ]]; then
        echo "❌ No active user session found"
        return 1
    fi
    
    echo "👤 Current user: $currentUser"
    
    # Function to run commands as current user
    runAsUser() {
        local currentUserID
        currentUserID=$(id -u "$currentUser")
        if [[ "$currentUser" != "loginwindow" ]]; then
            /bin/launchctl asuser "$currentUserID" sudo -u "$currentUser" "$@"
        fi
    }
    
    # Remove VPN menu extra
    if runAsUser /usr/libexec/PlistBuddy -c 'delete menuExtras: "/System/Library/CoreServices/Menu Extras/VPN.menu"' "/Users/$currentUser/Library/Preferences/com.apple.systemuiserver.plist" 2>/dev/null; then
        echo "✅ VPN menu entry removed"
    else
        echo "⚠️  VPN menu entry not found or already removed"
    fi
    
    # Restart system services to apply changes
    runAsUser /usr/bin/killall cfprefsd 2>/dev/null
    runAsUser /usr/bin/killall SystemUIServer 2>/dev/null
    
    echo "🔄 System UI refreshed"
    echo "✅ VPN icon hidden from menu bar"
}

# Execute function
hide_vpn_icon

Show VPN Icon in Menu Bar

#!/bin/bash

# Show VPN icon in menu bar
show_vpn_icon() {
    echo "=== Adding VPN Icon to Menu Bar ==="
    
    local currentUser
    currentUser=$(echo "show State:/Users/ConsoleUser" | scutil | awk '/Name :/ { print $3 }')
    
    if [[ "$currentUser" == "loginwindow" || -z "$currentUser" ]]; then
        echo "❌ No active user session found"
        return 1
    fi
    
    echo "👤 Current user: $currentUser"
    
    runAsUser() {
        local currentUserID
        currentUserID=$(id -u "$currentUser")
        if [[ "$currentUser" != "loginwindow" ]]; then
            /bin/launchctl asuser "$currentUserID" sudo -u "$currentUser" "$@"
        fi
    }
    
    # Add VPN menu extra
    local vpn_path="/System/Library/CoreServices/Menu Extras/VPN.menu"
    if runAsUser /usr/libexec/PlistBuddy -c "add menuExtras: string '$vpn_path'" "/Users/$currentUser/Library/Preferences/com.apple.systemuiserver.plist" 2>/dev/null; then
        echo "✅ VPN menu entry added"
    else
        echo "⚠️  VPN menu entry already exists"
    fi
    
    # Restart system services
    runAsUser /usr/bin/killall cfprefsd 2>/dev/null
    runAsUser /usr/bin/killall SystemUIServer 2>/dev/null
    
    echo "✅ VPN icon shown in menu bar"
}

# Execute function
show_vpn_icon

Enterprise Menu Bar Management System

#!/bin/bash

# MacFleet Enterprise Menu Bar Management System
# Comprehensive interface customization, user experience optimization, and fleet deployment

# Configuration
LOG_FILE="/var/log/macfleet_menubar.log"
CONFIG_DIR="/etc/macfleet/interface"
PROFILES_DIR="$CONFIG_DIR/profiles"
BACKUP_DIR="/var/backups/menubar_configs"
REPORTS_DIR="$CONFIG_DIR/reports"

# Available menu extras
declare -A MENU_EXTRAS=(
    ["vpn"]="/System/Library/CoreServices/Menu Extras/VPN.menu"
    ["wifi"]="/System/Library/CoreServices/Menu Extras/AirPort.menu"
    ["bluetooth"]="/System/Library/CoreServices/Menu Extras/Bluetooth.menu"
    ["volume"]="/System/Library/CoreServices/Menu Extras/Volume.menu"
    ["battery"]="/System/Library/CoreServices/Menu Extras/Battery.menu"
    ["clock"]="/System/Library/CoreServices/Menu Extras/Clock.menu"
    ["displays"]="/System/Library/CoreServices/Menu Extras/Displays.menu"
    ["timemachine"]="/System/Library/CoreServices/Menu Extras/TimeMachine.menu"
    ["textinput"]="/System/Library/CoreServices/Menu Extras/TextInput.menu"
    ["script"]="/System/Library/CoreServices/Menu Extras/Script Menu.menu"
)

# Profile configurations
declare -A MENU_PROFILES=(
    ["minimal"]="clock,battery,wifi"
    ["standard"]="clock,battery,wifi,volume,bluetooth"
    ["full"]="clock,battery,wifi,volume,bluetooth,displays,vpn"
    ["corporate"]="clock,battery,wifi,vpn,timemachine"
    ["education"]="clock,battery,wifi,volume,textinput"
    ["kiosk"]="clock,battery"
    ["developer"]="clock,battery,wifi,volume,bluetooth,displays,script"
    ["secure"]="clock,battery,wifi"
)

# Logging function
log_action() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}

# Setup directories
setup_directories() {
    for dir in "$CONFIG_DIR" "$PROFILES_DIR" "$BACKUP_DIR" "$REPORTS_DIR"; do
        if [[ ! -d "$dir" ]]; then
            mkdir -p "$dir"
            log_action "Created directory: $dir"
        fi
    done
}

# Get current user
get_current_user() {
    local user
    user=$(echo "show State:/Users/ConsoleUser" | scutil | awk '/Name :/ { print $3 }')
    
    if [[ "$user" == "loginwindow" || -z "$user" ]]; then
        return 1
    fi
    
    echo "$user"
    return 0
}

# Execute command as current user
run_as_user() {
    local user="$1"
    shift
    
    local userID
    userID=$(id -u "$user" 2>/dev/null) || return 1
    
    /bin/launchctl asuser "$userID" sudo -u "$user" "$@"
}

# Get current menu bar configuration
get_current_menubar_config() {
    local user="$1"
    local plist_path="/Users/$user/Library/Preferences/com.apple.systemuiserver.plist"
    
    if [[ ! -f "$plist_path" ]]; then
        echo "[]"
        return 1
    fi
    
    # Extract current menu extras
    local menu_extras
    menu_extras=$(run_as_user "$user" /usr/libexec/PlistBuddy -c "print menuExtras:" "$plist_path" 2>/dev/null | grep -E "\.menu$" | sed 's/^[ ]*//' || echo "")
    
    if [[ -z "$menu_extras" ]]; then
        echo "[]"
    else
        echo "$menu_extras" | jq -R -s 'split("\n") | map(select(length > 0))'
    fi
}

# Apply menu bar profile
apply_menubar_profile() {
    local profile_name="$1"
    local target_user="$2"
    
    log_action "Applying menu bar profile: $profile_name"
    
    # Get profile configuration
    local profile_config="${MENU_PROFILES[$profile_name]}"
    if [[ -z "$profile_config" ]]; then
        log_action "❌ Unknown profile: $profile_name"
        return 1
    fi
    
    # Get target users
    local users=()
    if [[ -n "$target_user" ]]; then
        users=("$target_user")
    else
        # Get all users with UID >= 500
        while IFS= read -r user; do
            users+=("$user")
        done < <(dscl . list /Users UniqueID | awk '$2 >= 500 {print $1}')
    fi
    
    # Apply profile to each user
    for user in "${users[@]}"; do
        log_action "Configuring menu bar for user: $user"
        
        local plist_path="/Users/$user/Library/Preferences/com.apple.systemuiserver.plist"
        
        # Backup current configuration
        backup_user_menubar_config "$user"
        
        # Clear existing menu extras
        run_as_user "$user" /usr/libexec/PlistBuddy -c "delete menuExtras:" "$plist_path" 2>/dev/null || true
        run_as_user "$user" /usr/libexec/PlistBuddy -c "add menuExtras: array" "$plist_path" 2>/dev/null
        
        # Add profile menu items
        IFS=',' read -ra ITEMS <<< "$profile_config"
        local index=0
        
        for item in "${ITEMS[@]}"; do
            local menu_path="${MENU_EXTRAS[$item]}"
            if [[ -n "$menu_path" && -f "$menu_path" ]]; then
                run_as_user "$user" /usr/libexec/PlistBuddy -c "add menuExtras:$index string '$menu_path'" "$plist_path" 2>/dev/null
                log_action "Added menu item: $item for user: $user"
                ((index++))
            else
                log_action "⚠️  Menu item not found: $item"
            fi
        done
        
        # Restart UI services
        run_as_user "$user" /usr/bin/killall cfprefsd 2>/dev/null
        run_as_user "$user" /usr/bin/killall SystemUIServer 2>/dev/null
        
        log_action "✅ Profile '$profile_name' applied to user: $user"
    done
    
    return 0
}

# Backup user menu bar configuration
backup_user_menubar_config() {
    local user="$1"
    local timestamp
    timestamp=$(date '+%Y%m%d_%H%M%S')
    
    local plist_path="/Users/$user/Library/Preferences/com.apple.systemuiserver.plist"
    local backup_file="$BACKUP_DIR/menubar_${user}_${timestamp}.plist"
    
    if [[ -f "$plist_path" ]]; then
        cp "$plist_path" "$backup_file" 2>/dev/null
        log_action "Backed up menu bar config for $user: $backup_file"
        echo "$backup_file"
    fi
}

# Custom menu bar configuration
configure_custom_menubar() {
    local items_string="$1"
    local target_user="$2"
    
    log_action "Applying custom menu bar configuration: $items_string"
    
    local users=()
    if [[ -n "$target_user" ]]; then
        users=("$target_user")
    else
        while IFS= read -r user; do
            users+=("$user")
        done < <(dscl . list /Users UniqueID | awk '$2 >= 500 {print $1}')
    fi
    
    # Parse items
    IFS=',' read -ra ITEMS <<< "$items_string"
    
    for user in "${users[@]}"; do
        local plist_path="/Users/$user/Library/Preferences/com.apple.systemuiserver.plist"
        
        # Backup and clear
        backup_user_menubar_config "$user"
        run_as_user "$user" /usr/libexec/PlistBuddy -c "delete menuExtras:" "$plist_path" 2>/dev/null || true
        run_as_user "$user" /usr/libexec/PlistBuddy -c "add menuExtras: array" "$plist_path" 2>/dev/null
        
        # Add custom items
        local index=0
        for item in "${ITEMS[@]}"; do
            # Remove whitespace
            item=$(echo "$item" | sed 's/^[ \t]*//;s/[ \t]*$//')
            
            local menu_path="${MENU_EXTRAS[$item]}"
            if [[ -n "$menu_path" && -f "$menu_path" ]]; then
                run_as_user "$user" /usr/libexec/PlistBuddy -c "add menuExtras:$index string '$menu_path'" "$plist_path" 2>/dev/null
                ((index++))
            fi
        done
        
        # Apply changes
        run_as_user "$user" /usr/bin/killall cfprefsd 2>/dev/null
        run_as_user "$user" /usr/bin/killall SystemUIServer 2>/dev/null
        
        log_action "✅ Custom configuration applied to user: $user"
    done
}

# Generate menu bar audit report
generate_menubar_audit() {
    log_action "Generating menu bar audit report"
    
    local report_file="$REPORTS_DIR/menubar_audit_$(date '+%Y%m%d_%H%M%S').json"
    
    cat > "$report_file" << EOF
{
    "audit_metadata": {
        "timestamp": "$(date -Iseconds)",
        "hostname": "$(hostname)",
        "os_version": "$(sw_vers -productVersion)",
        "generator": "MacFleet Menu Bar Manager"
    },
    "user_configurations": [
EOF

    local first=true
    local total_users=0
    
    # Audit each user
    for user in $(dscl . list /Users UniqueID | awk '$2 >= 500 {print $1}'); do
        total_users=$((total_users + 1))
        
        if [[ "$first" == true ]]; then
            first=false
        else
            echo "," >> "$report_file"
        fi
        
        local current_config
        current_config=$(get_current_menubar_config "$user")
        
        local last_login
        last_login=$(last -1 "$user" | head -1 | awk '{print $4, $5, $6, $7}' || echo 'Never')
        
        cat >> "$report_file" << EOF
        {
            "username": "$user",
            "current_menu_items": $current_config,
            "item_count": $(echo "$current_config" | jq 'length'),
            "last_login": "$last_login",
            "config_file_exists": $([ -f "/Users/$user/Library/Preferences/com.apple.systemuiserver.plist" ] && echo "true" || echo "false")
        }
EOF
        
        log_action "Audited user: $user"
    done
    
    cat >> "$report_file" << EOF
    ],
    "summary": {
        "total_users": $total_users,
        "available_menu_items": $(echo "${!MENU_EXTRAS[@]}" | tr ' ' '\n' | jq -R . | jq -s .),
        "available_profiles": $(echo "${!MENU_PROFILES[@]}" | tr ' ' '\n' | jq -R . | jq -s .)
    }
}
EOF

    log_action "✅ Menu bar audit completed: $report_file"
    echo "$report_file"
}

# Restore menu bar configuration from backup
restore_menubar_config() {
    local backup_file="$1"
    local target_user="$2"
    
    if [[ ! -f "$backup_file" ]]; then
        log_action "❌ Backup file not found: $backup_file"
        return 1
    fi
    
    log_action "Restoring menu bar configuration from: $backup_file"
    
    local users=()
    if [[ -n "$target_user" ]]; then
        users=("$target_user")
    else
        # Extract username from backup filename
        local extracted_user
        extracted_user=$(basename "$backup_file" | sed 's/menubar_\(.*\)_[0-9]*_[0-9]*.plist/\1/')
        if [[ -n "$extracted_user" ]]; then
            users=("$extracted_user")
        fi
    fi
    
    for user in "${users[@]}"; do
        local plist_path="/Users/$user/Library/Preferences/com.apple.systemuiserver.plist"
        
        # Create current backup before restore
        backup_user_menubar_config "$user"
        
        # Restore configuration
        if cp "$backup_file" "$plist_path" 2>/dev/null; then
            chown "$user:staff" "$plist_path" 2>/dev/null
            
            # Apply changes
            run_as_user "$user" /usr/bin/killall cfprefsd 2>/dev/null
            run_as_user "$user" /usr/bin/killall SystemUIServer 2>/dev/null
            
            log_action "✅ Configuration restored for user: $user"
        else
            log_action "❌ Failed to restore configuration for user: $user"
            return 1
        fi
    done
    
    return 0
}

# Monitor menu bar changes
monitor_menubar_changes() {
    local duration="${1:-3600}"  # 1 hour default
    local check_interval="${2:-60}"  # 1 minute default
    
    log_action "Starting menu bar monitoring for ${duration} seconds"
    
    local monitoring_report="$REPORTS_DIR/menubar_monitoring_$(date '+%Y%m%d_%H%M%S').json"
    local baseline_file="/tmp/menubar_baseline.json"
    
    # Create baseline
    generate_menubar_audit > "$baseline_file"
    
    cat > "$monitoring_report" << EOF
{
    "monitoring_metadata": {
        "start_time": "$(date -Iseconds)",
        "duration_seconds": $duration,
        "check_interval_seconds": $check_interval,
        "hostname": "$(hostname)"
    },
    "changes_detected": [
EOF

    local start_time end_time
    start_time=$(date +%s)
    end_time=$((start_time + duration))
    
    local first=true
    while [[ $(date +%s) -lt $end_time ]]; do
        sleep "$check_interval"
        
        # Check for changes
        local current_state="/tmp/menubar_current.json"
        generate_menubar_audit > "$current_state"
        
        if ! diff "$baseline_file" "$current_state" >/dev/null 2>&1; then
            if [[ "$first" == true ]]; then
                first=false
            else
                echo "," >> "$monitoring_report"
            fi
            
            cat >> "$monitoring_report" << EOF
        {
            "timestamp": "$(date -Iseconds)",
            "change_type": "menu_bar_configuration_change",
            "details": "Changes detected in menu bar configuration"
        }
EOF
            
            log_action "⚠️  Menu bar configuration changes detected"
            cp "$current_state" "$baseline_file"
        fi
        
        rm -f "$current_state"
    done
    
    cat >> "$monitoring_report" << EOF
    ],
    "end_time": "$(date -Iseconds)"
}
EOF

    log_action "✅ Menu bar monitoring completed: $monitoring_report"
    rm -f "$baseline_file"
    echo "$monitoring_report"
}

# Main execution function
main() {
    local action="${1:-audit}"
    local parameter="$2"
    local additional_param="$3"
    
    log_action "=== MacFleet Menu Bar Management Started ==="
    log_action "Action: $action"
    log_action "Parameter: ${parameter:-N/A}"
    
    setup_directories
    
    case "$action" in
        "profile")
            if [[ -z "$parameter" ]]; then
                echo "Available menu bar profiles:"
                for profile in "${!MENU_PROFILES[@]}"; do
                    echo "  - $profile: ${MENU_PROFILES[$profile]}"
                done
                echo ""
                echo "Usage: $0 profile <profile_name> [username]"
                exit 1
            fi
            apply_menubar_profile "$parameter" "$additional_param"
            ;;
        "custom")
            if [[ -z "$parameter" ]]; then
                echo "Available menu items:"
                for item in "${!MENU_EXTRAS[@]}"; do
                    echo "  - $item"
                done
                echo ""
                echo "Usage: $0 custom <item1,item2,item3> [username]"
                echo "Example: $0 custom clock,battery,wifi,vpn john.doe"
                exit 1
            fi
            configure_custom_menubar "$parameter" "$additional_param"
            ;;
        "audit")
            generate_menubar_audit
            ;;
        "monitor")
            monitor_menubar_changes "$parameter" "$additional_param"
            ;;
        "restore")
            if [[ -z "$parameter" ]]; then
                echo "Usage: $0 restore <backup_file> [username]"
                echo "Available backups:"
                ls -la "$BACKUP_DIR"/*.plist 2>/dev/null || echo "No backups found"
                exit 1
            fi
            restore_menubar_config "$parameter" "$additional_param"
            ;;
        "hide-vpn")
            local user
            if user=$(get_current_user); then
                hide_vpn_icon
            else
                echo "❌ No active user session"
                exit 1
            fi
            ;;
        "show-vpn")
            local user
            if user=$(get_current_user); then
                show_vpn_icon
            else
                echo "❌ No active user session"
                exit 1
            fi
            ;;
        *)
            echo "Usage: $0 {profile|custom|audit|monitor|restore|hide-vpn|show-vpn}"
            echo "  profile     - Apply predefined menu bar profile"
            echo "  custom      - Apply custom menu bar configuration"
            echo "  audit       - Generate menu bar audit report"
            echo "  monitor     - Monitor menu bar changes over time"
            echo "  restore     - Restore from backup"
            echo "  hide-vpn    - Hide VPN icon from menu bar"
            echo "  show-vpn    - Show VPN icon in menu bar"
            exit 1
            ;;
    esac
    
    log_action "=== Menu bar management completed ==="
}

# Execute main function
main "$@"

Menu Bar Profile Examples

Corporate Profile Setup

#!/bin/bash

# Apply corporate menu bar profile across all devices
deploy_corporate_profile() {
    echo "=== Corporate Menu Bar Deployment ==="
    
    # Corporate profile: clock, battery, wifi, vpn, timemachine
    local corporate_items="clock,battery,wifi,vpn,timemachine"
    
    # Get all users
    for user in $(dscl . list /Users UniqueID | awk '$2 >= 500 {print $1}'); do
        echo "Configuring corporate profile for: $user"
        
        # Apply configuration
        configure_custom_menubar "$corporate_items" "$user"
        
        # Verify application
        sleep 2
        local current_config
        current_config=$(get_current_menubar_config "$user")
        echo "Applied configuration: $current_config"
    done
    
    echo "✅ Corporate profile deployed to all users"
}

Kiosk Mode Configuration

#!/bin/bash

# Minimal menu bar for kiosk environments
setup_kiosk_menubar() {
    echo "=== Kiosk Menu Bar Setup ==="
    
    # Minimal items: clock and battery only
    local kiosk_items="clock,battery"
    
    local target_user="$1"
    if [[ -z "$target_user" ]]; then
        echo "Usage: setup_kiosk_menubar <username>"
        return 1
    fi
    
    configure_custom_menubar "$kiosk_items" "$target_user"
    
    echo "✅ Kiosk menu bar configured for: $target_user"
}

Advanced Menu Bar Features

Dynamic Profile Switching

#!/bin/bash

# Switch between different profiles based on conditions
smart_profile_switching() {
    local user="$1"
    
    echo "=== Smart Profile Switching ==="
    
    # Detect environment
    if pgrep -f "VPN" >/dev/null; then
        echo "VPN detected - applying corporate profile"
        apply_menubar_profile "corporate" "$user"
    elif [[ $(pmset -g batt | grep -c "Battery") -gt 0 ]]; then
        echo "Battery power detected - applying minimal profile"
        apply_menubar_profile "minimal" "$user"
    else
        echo "Standard environment - applying full profile"
        apply_menubar_profile "full" "$user"
    fi
}

Menu Bar Health Check

#!/bin/bash

# Verify menu bar configuration integrity
menubar_health_check() {
    echo "=== Menu Bar Health Check ==="
    
    local issues_found=0
    
    for user in $(dscl . list /Users UniqueID | awk '$2 >= 500 {print $1}'); do
        local plist_path="/Users/$user/Library/Preferences/com.apple.systemuiserver.plist"
        
        if [[ ! -f "$plist_path" ]]; then
            echo "⚠️  Missing configuration file for user: $user"
            issues_found=$((issues_found + 1))
            continue
        fi
        
        # Check if SystemUIServer is running
        if ! pgrep -u "$(id -u "$user")" SystemUIServer >/dev/null; then
            echo "⚠️  SystemUIServer not running for user: $user"
            issues_found=$((issues_found + 1))
        fi
        
        # Validate plist format
        if ! plutil -lint "$plist_path" >/dev/null 2>&1; then
            echo "❌ Corrupted plist file for user: $user"
            issues_found=$((issues_found + 1))
        fi
    done
    
    if [[ $issues_found -eq 0 ]]; then
        echo "✅ All menu bar configurations are healthy"
    else
        echo "⚠️  Found $issues_found issues requiring attention"
    fi
    
    return $issues_found
}

Best Practices

🎯 User Experience Optimization

  • Consistent branding across all devices with standardized menu bar layouts
  • Profile-based configurations for different user roles and environments
  • Minimal kiosk setups for public or restricted-use devices
  • Dynamic switching based on power state or network conditions

🔧 Enterprise Management

  • Centralized deployment of menu bar configurations across device fleets
  • Backup and restore capabilities for configuration management
  • Audit reporting for compliance and standardization verification
  • Change monitoring with automated detection and alerting

🔐 Security Considerations

  • Remove sensitive indicators from public-facing devices
  • Hide VPN status in environments where network information should be private
  • Standardize corporate displays to prevent information leakage
  • Monitor unauthorized changes to menu bar configurations

📊 Monitoring and Maintenance

  • Regular health checks to ensure configuration integrity
  • Automated profile enforcement to maintain consistency
  • Change detection with rollback capabilities
  • User experience feedback collection and optimization

Important Notes

  • macOS 12+ required for optimal compatibility with modern menu extras
  • User session active required for menu bar modifications
  • System restart may be needed for some changes to take full effect
  • Test thoroughly before deploying to production environments
  • Backup configurations before making changes to allow easy rollback

Tutorial

Neue Updates und Verbesserungen zu Macfleet.

Konfiguration eines GitHub Actions Runners auf einem Mac Mini (Apple Silicon)

GitHub Actions Runner

GitHub Actions ist eine leistungsstarke CI/CD-Plattform, die es Ihnen ermöglicht, Ihre Software-Entwicklungsworkflows zu automatisieren. Während GitHub gehostete Runner anbietet, bieten selbst-gehostete Runner erhöhte Kontrolle und Anpassung für Ihr CI/CD-Setup. Dieses Tutorial führt Sie durch die Einrichtung, Konfiguration und Verbindung eines selbst-gehosteten Runners auf einem Mac mini zur Ausführung von macOS-Pipelines.

Voraussetzungen

Bevor Sie beginnen, stellen Sie sicher, dass Sie haben:

  • Einen Mac mini (registrieren Sie sich bei Macfleet)
  • Ein GitHub-Repository mit Administratorrechten
  • Einen installierten Paketmanager (vorzugsweise Homebrew)
  • Git auf Ihrem System installiert

Schritt 1: Ein dediziertes Benutzerkonto erstellen

Erstellen Sie zunächst ein dediziertes Benutzerkonto für den GitHub Actions Runner:

# Das 'gh-runner' Benutzerkonto erstellen
sudo dscl . -create /Users/gh-runner
sudo dscl . -create /Users/gh-runner UserShell /bin/bash
sudo dscl . -create /Users/gh-runner RealName "GitHub runner"
sudo dscl . -create /Users/gh-runner UniqueID "1001"
sudo dscl . -create /Users/gh-runner PrimaryGroupID 20
sudo dscl . -create /Users/gh-runner NFSHomeDirectory /Users/gh-runner

# Das Passwort für den Benutzer setzen
sudo dscl . -passwd /Users/gh-runner ihr_passwort

# 'gh-runner' zur 'admin'-Gruppe hinzufügen
sudo dscl . -append /Groups/admin GroupMembership gh-runner

Wechseln Sie zum neuen Benutzerkonto:

su gh-runner

Schritt 2: Erforderliche Software installieren

Installieren Sie Git und Rosetta 2 (wenn Sie Apple Silicon verwenden):

# Git installieren, falls noch nicht installiert
brew install git

# Rosetta 2 für Apple Silicon Macs installieren
softwareupdate --install-rosetta

Schritt 3: Den GitHub Actions Runner konfigurieren

  1. Gehen Sie zu Ihrem GitHub-Repository
  2. Navigieren Sie zu Einstellungen > Actions > Runners

GitHub Actions Runner

  1. Klicken Sie auf "New self-hosted runner" (https://github.com/<username>/<repository>/settings/actions/runners/new)
  2. Wählen Sie macOS als Runner-Image und ARM64 als Architektur
  3. Folgen Sie den bereitgestellten Befehlen, um den Runner herunterzuladen und zu konfigurieren

GitHub Actions Runner

Erstellen Sie eine .env-Datei im _work-Verzeichnis des Runners:

# _work/.env Datei
ImageOS=macos15
XCODE_15_DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer
  1. Führen Sie das run.sh-Skript in Ihrem Runner-Verzeichnis aus, um die Einrichtung abzuschließen.
  2. Überprüfen Sie, dass der Runner aktiv ist und auf Jobs im Terminal wartet, und überprüfen Sie die GitHub-Repository-Einstellungen für die Runner-Zuordnung und den Idle-Status.

GitHub Actions Runner

Schritt 4: Sudoers konfigurieren (Optional)

Wenn Ihre Actions Root-Privilegien benötigen, konfigurieren Sie die sudoers-Datei:

sudo visudo

Fügen Sie die folgende Zeile hinzu:

gh-runner ALL=(ALL) NOPASSWD: ALL

Schritt 5: Den Runner in Workflows verwenden

Konfigurieren Sie Ihren GitHub Actions Workflow, um den selbst-gehosteten Runner zu verwenden:

name: Beispiel-Workflow

on:
  workflow_dispatch:

jobs:
  build:
    runs-on: [self-hosted, macOS, ARM64]
    steps:
      - name: NodeJS installieren
        run: brew install node

Der Runner ist bei Ihrem Repository authentifiziert und mit self-hosted, macOS und ARM64 markiert. Verwenden Sie ihn in Ihren Workflows, indem Sie diese Labels im runs-on-Feld angeben:

runs-on: [self-hosted, macOS, ARM64]

Best Practices

  • Halten Sie Ihre Runner-Software auf dem neuesten Stand
  • Überwachen Sie regelmäßig Runner-Logs auf Probleme
  • Verwenden Sie spezifische Labels für verschiedene Runner-Typen
  • Implementieren Sie angemessene Sicherheitsmaßnahmen
  • Erwägen Sie die Verwendung mehrerer Runner für Lastverteilung

Fehlerbehebung

Häufige Probleme und Lösungen:

  1. Runner verbindet sich nicht:

    • Überprüfen Sie die Netzwerkverbindung
    • Überprüfen Sie die Gültigkeit des GitHub-Tokens
    • Stellen Sie angemessene Berechtigungen sicher
  2. Build-Fehler:

    • Überprüfen Sie die Xcode-Installation
    • Überprüfen Sie erforderliche Abhängigkeiten
    • Überprüfen Sie Workflow-Logs
  3. Berechtigungsprobleme:

    • Überprüfen Sie Benutzerberechtigungen
    • Überprüfen Sie sudoers-Konfiguration
    • Überprüfen Sie Dateisystem-Berechtigungen

Fazit

Sie haben jetzt einen selbst-gehosteten GitHub Actions Runner auf Ihrem Mac mini konfiguriert. Diese Einrichtung bietet Ihnen mehr Kontrolle über Ihre CI/CD-Umgebung und ermöglicht es Ihnen, macOS-spezifische Workflows effizient auszuführen.

Denken Sie daran, Ihren Runner regelmäßig zu warten und ihn mit den neuesten Sicherheitspatches und Software-Versionen auf dem neuesten Stand zu halten.

Native App

Macfleet native App

Macfleet Installationsanleitung

Macfleet ist eine leistungsstarke Flottenmanagement-Lösung, die speziell für Cloud-gehostete Mac Mini-Umgebungen entwickelt wurde. Als Mac Mini Cloud-Hosting-Anbieter können Sie Macfleet verwenden, um Ihre gesamte Flotte virtualisierter Mac-Instanzen zu überwachen, zu verwalten und zu optimieren.

Diese Installationsanleitung führt Sie durch die Einrichtung der Macfleet-Überwachung auf macOS-, Windows- und Linux-Systemen, um eine umfassende Übersicht über Ihre Cloud-Infrastruktur zu gewährleisten.

🍎 macOS

  • Laden Sie die .dmg-Datei für Mac hier herunter
  • Doppelklicken Sie auf die heruntergeladene .dmg-Datei
  • Ziehen Sie die Macfleet-App in den Anwendungsordner
  • Werfen Sie die .dmg-Datei aus
  • Öffnen Sie Systemeinstellungen > Sicherheit & Datenschutz
    • Datenschutz-Tab > Bedienungshilfen
    • Aktivieren Sie Macfleet, um Überwachung zu erlauben
  • Starten Sie Macfleet aus den Anwendungen
  • Die Verfolgung startet automatisch

🪟 Windows

  • Laden Sie die .exe-Datei für Windows hier herunter
  • Rechtsklick auf die .exe-Datei > "Als Administrator ausführen"
  • Folgen Sie dem Installationsassistenten
  • Akzeptieren Sie die Allgemeinen Geschäftsbedingungen
  • Erlauben Sie in Windows Defender, wenn aufgefordert
  • Gewähren Sie Anwendungsüberwachungsberechtigungen
  • Starten Sie Macfleet aus dem Startmenü
  • Die Anwendung beginnt automatisch mit der Verfolgung

🐧 Linux

  • Laden Sie das .deb-Paket (Ubuntu/Debian) oder .rpm (CentOS/RHEL) hier herunter
  • Installieren Sie mit Ihrem Paketmanager
    • Ubuntu/Debian: sudo dpkg -i Macfleet-linux.deb
    • CentOS/RHEL: sudo rpm -ivh Macfleet-linux.rpm
  • Erlauben Sie X11-Zugriffsberechtigungen, wenn aufgefordert
  • Fügen Sie den Benutzer zu entsprechenden Gruppen hinzu, falls erforderlich
  • Starten Sie Macfleet aus dem Anwendungsmenü
  • Die Anwendung beginnt automatisch mit der Verfolgung

Hinweis: Nach der Installation auf allen Systemen melden Sie sich mit Ihren Macfleet-Anmeldedaten an, um Daten mit Ihrem Dashboard zu synchronisieren.