- Preface
- Why I Wrote This Book
- What This Book Is and Isn’t
- Who This Book Is For
- Principles, Practices, and Patterns
- The FoodSpin Examples
- For More
- Conventions Used in This Book
- O’Reilly Online Learning
- How to Contact Us
- Acknowledgments
- I. Foundations
- 1. What Is Infrastructure as Code?
- Infrastructure as Code
- From the Iron Age to the Cloud Age
- Cloud Age Approaches to Change Management
- The Path to the Cloud Age
- Strategic Goals and Infrastructure as Code
- System Architecture Goals and Infrastructure as Code
- Use Infrastructure as Code to Optimize for Change
- Myth: Infrastructure Doesn’t Change Very Often
- Myth: We Can Build the Infrastructure First and Automate It Later
- Myth: Speed and Quality Are Trade-Offs
- The Four Key Metrics
- Core Practices for Infrastructure as Code
- Define Everything as Code
- Continually Test and Deliver All Work in Progress
- Build Small, Simple Pieces That Can Change Independently
- Conclusion
- 2. Principles of Cloud Infrastructure
- Assume Systems Are Unreliable
- Make Everything Reproducible
- Avoid Snowflake Systems
- Create Disposable Things
- Minimize Variation
- Ensure That Any Procedure Can Be Repeated
- Apply Software Design Principles to Infrastructure Code
- Conclusion
- 3. Infrastructure Platforms
- Infrastructure Platforms
- Infrastructure Resources
- IaaS in the Data Center
- Multicloud
- Engineering Platforms
- Platform Services
- Providing Platform Service Functionality
- Platform Delivery Services
- Application Delivery Services
- Infrastructure Delivery Services
- Platform Management Services
- Conclusion
- 4. Infrastructure as Code Tools and Languages
- Coding Infrastructure
- Moving Beyond Task-Based Scripting
- Understanding What You Can Define as Code
- Code or Configuration?
- Defining Configuration as Code
- Managing Your Code in a Source Code Repository
- Infrastructure Code Processing
- Understanding When Code Executes
- Processing and Deploying Infrastructure Code
- Previewing Changes
- Tracing Infrastructure Code Execution
- Managing Infrastructure State
- Infrastructure as Code Tools
- Types of Languages for Coding Infrastructure
- Procedural and Idempotent Code
- Imperative and Declarative Languages and Tools
- Domain-Specific and General-Purpose Languages
- Low-Level and High-Level Languages
- Infrastructure from Code
- Conclusion
- II. Design
- 5. Design Principles for Infrastructure as Code
- Design Considerations for Infrastructure as Code
- CUPID Properties for Design
- Cohesion and Coupling
- Providers, Consumers, and Interfaces
- Management of Interfaces Between Components
- Use of Interfaces for Composability
- Design Across Infrastructure Code Lifecycle Stages
- Design Forces
- Design Forces for Source Code
- Design Forces for Infrastructure Packaging and Deployment
- Design Forces for Runtime
- Design Forces Across Lifecycle Stages
- Conclusion
- 6. Infrastructure Components
- The Infrastructure Components
- The Start of Infrastructure Design: Workloads
- Infrastructure Compositions
- Infrastructure Deployment Stacks
- Infrastructure Code Libraries
- Libraries as Deployable Stacks
- Sharing and Reuse of Infrastructure Code
- Sharing Infrastructure Code Components
- Sharing Stack Code Across Multiple Instances
- Sharing Stack Instances Across Workloads
- Application-Driven Infrastructure Design
- Horizontal Design
- Vertical Design
- Shared Infrastructure Included in Vertical Design
- Reference Application-Driven Infrastructure Design
- Design Workflow
- Conclusion
- 7. Designing Deployable Infrastructure Stacks
- Patterns for Sizing and Structuring Stacks
- Full System Stack
- Monolithic Stack
- Application Group Stack
- Single Service Stack
- Micro Stacks
- Shared Stack
- Stack Patterns for Multiple Instances of Infrastructure
- Multi-Environment Stack
- Snowflakes as Code
- Reusable Stack
- Conclusion
- 8. Configuring Infrastructure Stack Instances
- Key Concepts
- Use Stack Parameters to Create Unique Identifiers
- Keep Parameters Simple
- Example Stack
- Patterns for Configuring Stacks
- Configuration in Code
- Manual Stack Parameters
- Stack Environment Variables
- Scripted Parameters
- Stack Configuration Files
- Deployment Wrapper Stack
- Pipeline Stack Parameters
- Stack Parameter Registry
- Implementing a Configuration Registry
- Integrated Infrastructure Automation Tool Registries
- Standalone Packaged Configuration Registries
- IaaS Platform Registry Services
- Your Own Configuration Registry
- Single or Multiple Configuration Registries
- Handling Secrets
- Generating Secrets
- Storing Secrets in Encrypted Files
- Using a Secrets Storage Service
- Injecting Secrets at Runtime
- Conclusion
- 9. Integrating Infrastructure Stacks
- Example Infrastructure Deployment Stacks
- Resource Discovery Patterns
- Resource Matching
- Stack State Lookup
- Integration Registry Lookup
- Implementing Resource Discovery
- Implementing Discovery in Stack Code
- Using Dependency Injection
- Managing Dependencies in a Deployment Script
- Wiring Stacks Together with a Composition
- Conclusion
- 10. Designing Infrastructure Code Libraries
- Facade Module
- Also Known As
- Motivation
- Applicability
- Consequences
- Implementation
- Related Patterns
- Obfuscation Module
- Motivation
- Applicability
- Consequences
- Implementation
- Related Patterns
- Unshared Module
- Motivation
- Applicability
- Consequences
- Implementation
- Bundle Module
- Motivation
- Applicability
- Consequences
- Implementation
- Related Patterns
- Spaghetti Module
- Motivation
- Consequences
- Implementation
- Related Patterns
- Infrastructure Domain Entity
- Motivation
- Applicability
- Implementation
- Related Patterns
- Stack Module
- Also Known As
- Motivation and Applicability
- Implementation
- Modular Monolith
- Motivation
- Consequences
- Implementation
- Related Patterns
- Conclusion
- 11. Building Servers as Code
- Defining Servers
- What’s on a Server
- Where Things Come From
- Server Configuration Code
- Server Roles
- Creating and Provisioning a New Server Instance
- Creating a Server by Using Network Provisioning
- Creating an IaaS Server by Hand
- Creating a Server as Part of a Stack
- Creating a Server from an Event
- Configuring a New Server Instance
- Baking Images and Frying Instances
- Pull Configuration with Initialization Scripts
- Push Configuration with External Commands
- Updating and Changing Servers
- Push on Change
- Continuous Configuration Synchronization
- Changing Servers by Replacement
- Immutable Server
- Building Server Images
- Hot-Cloning an Existing Server
- Booting an OS Installer
- Modifying a Stock Image
- Orchestrating Image Building
- Conclusion
- 12. Designing Environments
- Multi-Environment Architectures
- Multiple Delivery Environments
- Environments Split for Alignment
- Aligning Environments to System Architecture
- Aligning Environments to Organizational Structure
- Aligning Environments to Governance Concerns
- Multiple Environment Replicas
- Designing Environments for Operability Scenarios
- Distributing Environments Geographically
- Replicating Environments for User Bases
- Environment Implementation Layers
- Using Design Forces to Choose the Environment
Implementation Layer
- Testing and Delivering Changes to Environment Infrastructure
- IaaS Resource Groups and Environments
- Environments with Multiple Stacks
- Conclusion
- 13. Providing Application
Runtime Infrastructure
- Application-Driven Infrastructure Design
- Application Runtime Platforms
- Servers as Code
- Server Clusters as Code
- Application Clusters as Code
- Serverless Application Infrastructure
- Cluster Topologies
- Multiple Environments in One Cluster
- One Cluster per Environment
- Multiple Clusters per Environment
- Cross-Environment Clusters
- Conclusion
- III. Delivery
- 14. Core Infrastructure Delivery Workflows
- Continuous Delivery Principles for Infrastructure as Code
- Automate the Full Process
- Make Changes Using Only the Automated Process
- Ensure That Environments Are Consistent
- Deliver Changes Comprehensively
- Keep Delivery Cycles Short
- Keep All Code Production-Ready
- Ensure That Code and Deployed Resources Are Consistent
- Minimize Disruption When Deploying Changes
- Core Infrastructure Delivery Workflow
- Development Stage
- Build Stage
- Test Stages
- Release Stage
- Run Stage
- Workflow Cycles
- Workflows and Team Topologies for Delivering Software and Infrastructure
- Infrastructure Instance Management Teams
- Full Stack Infrastructure Team
- Infrastructure Enablement Team
- Measuring Infrastructure Delivery Effectiveness
- Conclusion
- 15. Building and Distributing
Infrastructure as Code
- Build Stage: Preparing for Distribution
- Code Processing Steps for Building and Deploying
- Build on Deploy Workflow
- Build Once, Deploy Many Workflow
- Bundling or Locking Dependencies
- Pull Requests and Trunk-Based Development
- Distribution of Infrastructure Code
- Distributing Code Branches as Artifacts
- Distributing Stack Packages as Artifacts
- Distributing Libraries as Artifacts
- Integration Workflows
- Fan-in: Integrating Components During Delivery
- Federation: Integrating Components at Runtime
- Monorepo: Integrating Components in the Build
- Pretesting Infrastructure
- Infrastructure Service Teams
- Shared Infrastructure as a Service
- Provisioning an Infrastructure Instance on Demand
- Providing Deployable Infrastructure as a Component
- Multiple Infrastructure Platform Teams
- Conclusion
- 16. Implementing Infrastructure
Delivery with Pipelines
- Organizing Projects in a Codebase
- Organizing Build Projects and Repositories
- Organizing Types of Code
- Working on Code Locally
- Local IaaS Emulators
- Personal IaaS Environments
- Just Enough Environment
- Designing Infrastructure Delivery Pipelines
- Pipeline Stage Content
- Pipeline Stage Actions
- Pipeline Stage Context
- Delivery Pipeline Software and Services
- Using Delivery Orchestration Scripts
- Conclusion
- 17. Infrastructure Code Testing Strategy
- Why Continually Test Infrastructure Code?
- What Continual Testing Means
- Immediate Testing and Eventual Testing
- What Should We Test with Infrastructure?
- Challenges with Testing Infrastructure Code
- Tests for Declarative Code Often Have Low Value
- Unit Testing Code Generation
- Testing Infrastructure Code Is Slow
- Dependencies Complicate Testing Infrastructure
- Progressive Testing
- Test Pyramid
- Swiss Cheese Testing Model
- Testing in Production
- What You Can’t Replicate Outside Production
- Managing the Risks of Testing in Production
- Conclusion
- 18. Infrastructure Code Testing Implementation
- Offline Testing Stages for Stacks
- Syntax Checking
- Offline Static Code Analysis
- Connected Static Code Analysis
- Supply-Chain Checks
- Local Infrastructure Emulators
- Use Test Fixtures to Handle Dependencies
- Use Test Fixtures to Replace Providers
- Use Test Fixtures to Replace Consumers
- Refactor Components So They Can Be Isolated
- Online Testing Stages for Stacks
- Preview: Seeing What Changes Will Be Made
- Verification: Making Assertions About Infrastructure Resources
- Outcomes: Proving Infrastructure Works Correctly
- Test Instance Lifecycles
- Persistent Test Stack
- Ephemeral Test Stack
- Dual Persistent and Ephemeral Stack Stages
- Periodic Stack Rebuild
- Continuous Stack Reset
- Test Orchestration
- Consider Test Orchestration Tools
- Support Local Testing
- Avoid Tight Coupling with Pipeline Tools
- Conclusion
- 19. Deploying Infrastructure
- Understanding Software Deployment Strategies
- Push Deployment for Software
- Pull Deployment for Software
- GitOps Deployment for Software
- Using Infrastructure Deployment Strategies
- Siloed Infrastructure Deployment
- Application Infrastructure Descriptor
- Infrastructure from Code
- Running Infrastructure Deployments
- Deploying Infrastructure Code from Your Computer
- Deploying from a Central Service
- Deploying from a Delivery Pipeline
- Using an Infrastructure Code Deployment Service
- Infrastructure as Data
- Infrastructure Deployment Scripts
- Triggering Infrastructure Deployments
- Using Input Materials for Deployment
- Manually Triggering Deployment
- Automatically Triggering Deployment
- Implementing Triggers
- Conclusion
- 20. Changing Existing Infrastructure
- Changing a System Incrementally
- Break a Change into Increments
- Handle Incomplete Changes
- Safely Changing Live Infrastructure
- Manually Remap Live Infrastructure
- Remap Live Infrastructure in Pipelines
- Define Changes to Live Infrastructure in Code
- Script Live Infrastructure Changes
- Use Expand and Contract to Incrementally Change Live Infrastructure
- Minimizing Disruption When Deploying Changes
- Blue-Green Deployments
- Rolling Upgrades and Canary Releases
- Managing Data When Changing Live Infrastructure
- Store and Load
- Use Continuous Data Transfer
- Segregate Data Infrastructure
- Separate Software and Data Changes
- Use Continuous Disaster Recovery
- Conclusion
- 21. Governance
- Shift Left
- Workflow for Shifting Left
- Team Topologies for Shifting Left
- Compliance as Code
- Controls by Component Design Layer
- Controls by Workflow
- Conclusion
- Index
- About the Author