- Follow the Established Pattern: Always respect the established architecture patterns across services (Dockerfile, entrypoint script, management script).
- Separate Concerns: Keep build-time operations in Dockerfile, initialization in entrypoint scripts, and user operations in management scripts.
- Delegate Appropriately: Entrypoint scripts should handle environment initialization; management scripts should provide a clean interface.
- Minimize Verbosity: Management scripts should be concise in output; verbose operations belong in entrypoint scripts.
- Use Defaults Wisely: Always provide sensible defaults for environment variables.
- Check Dependencies: Explicitly check for required dependencies (database, Redis, other services).
- Respect Technology Specifics: Recognize and accommodate technology-specific patterns (rake vs rails, Node vs Ruby).
- Be Explicit About Ports: Never assume default ports; always specify them explicitly.
- Maintain Consistency: Keep script structure consistent across services.
- Avoid Premature Optimization: Don't optimize scripts until the basic pattern works.
- Reduce Duplication: Extract common patterns into shared scripts where possible.
- Document Special Cases: Clearly identify and document service-specific requirements.
- Follow Existing Patterns: Adhere to command patterns documented in READMEs (e.g., using
setup
instead ofdb migrate
for Rails applications).
- Wait for Databases: Always implement wait logic for database availability.
- Check Database Existence: Verify database existence before attempting operations.
- Handle Migration Patterns: Respect service-specific migration patterns.
- Use Appropriate Commands: Use the correct command pattern (rake vs rails) for the service.
- Be Explicit About Networks: Always specify the Docker network explicitly.
- Verify Network Existence: Check that the specified network exists before attempting to connect.
- Use Service Discovery: Leverage container names for service discovery when possible.
- Document Network Dependencies: Clearly document network dependencies in README files.
- Document Directory Structure: Clearly explain the purpose of each file and directory.
- Provide Usage Examples: Include concrete examples for common operations.
- Explain Special Requirements: Detail service-specific requirements and how to address them.
- Include Troubleshooting Guidance: Anticipate common issues and provide solutions.
- Fail Fast and Clearly: Scripts should fail immediately with clear error messages.
- Check Prerequisites: Verify all prerequisites before attempting operations.
- Clean Up After Failures: Ensure resources are cleaned up if an operation fails.
- Log Useful Information: Log information useful for troubleshooting, not just success/failure.
- Understand Before Implementing: Analyze existing patterns thoroughly before suggesting changes.
- Implement Small Changes First: Make incremental changes rather than rewriting everything at once.
- Verify Syntax Carefully: Double-check shell script syntax, especially variable expansion and quoting.
- Show Your Reasoning: Explain why you're following certain patterns or making changes.
- Test Commands Individually: When creating scripts, test each component command individually when possible.
- Ignoring Service-Specific Details: Not recognizing when a service has unique requirements.
- Hardcoding Environment Values: Embedding environment-specific values in scripts rather than using variables.
- Skipping Health Checks: Not implementing proper health checks for containers.
- Overlooking Permission Issues: Failing to set correct permissions on scripts and SSH keys.
- Complex Startup Logic: Making container startup too complex, leading to difficult debugging.
- Missing Dependencies: Failing to check and wait for required dependencies before starting the service.
- Orphaned PID Files: Not handling PID files left behind when services like Rails are shut down improperly, which can prevent restart.
- Ignoring Documented Patterns: Not following established command patterns documented in READMEs, leading to inconsistent behavior.
- Check Container Logs First: Always check container logs as the first debugging step.
- Use Interactive Mode: Run containers in interactive mode to debug initialization issues.
- Verify Network Access: Test network connectivity between containers.
- Inspect Environment Variables: Verify that expected environment variables are set correctly.
- Step Through Scripts: Test scripts step by step to identify failure points.
- Use Explicit Exit Codes: Ensure scripts use meaningful exit codes to signal different types of failures.
- Check for Stale PID Files: When services fail to start, check for orphaned PID files from previous runs.
Before considering a containerization task complete, verify:
- Dockerfile builds successfully
- Entrypoint script initializes the service properly
- Management script provides all required operations
- Container starts and passes health checks
- Database operations work correctly
- Comprehensive README documents the approach
- Error handling covers common failure modes
- Service-specific requirements are implemented
- Proper cleanup of PID files and other temporary files is implemented
- Scripts follow established patterns documented in service READMEs Following these rules will lead to more consistent, maintainable, and reliable Docker containerization implementations across services.