In This Series: DevOps Best Practices
You can't just say "we do DevOps" anymore. If DevOps best practices aren't followed, teams inevitably waste the potential gains that DevOps practices enable, and infrastructure problems still aren't resolved.
With the continued success of DevOps and Infrastructure as Code(IaC) conversions, it's no wonder that IT teams across the world are adopting these new practices.
Ready to get started? The first DevOps best practice you need to know is the separation of application and operations repositories. Avoid common pitfalls by using Bitovi's recommended DevOps practices. You'll learn what an OpsRepo is and why and how to separate your application and operation logic into their own repositories.
What Happens Without Best Practices?
When your DevOps team doesn't invest in proper operation management practices, you end up with slow, unaware infrastructure provisioning, redundant resources eating up infrastructure budget, and a critical failure point where all the knowledge of the infrastructure and its configuration is held by just one or two people.
Managing application infrastructure can be frustrating and prone to error. Configuration, builds, tagging and deployments are just a few of the many vectors SREs need to consider to create successful CI/CD pipelines.
And if these resources are handled through logging on to a server or clicking buttons on a cloud console, aka ClickOps, the complexity of configuration management and the likelihood for error grows.
Configuration needs to be replicated for each environment and that configuration needs to be managed by someone who has a thorough understanding of the provisioned resources and their required states.
The provisioned resources are tied to the ClickOps provisioning and the configuration is at best stored in a Word doc - or at worst, in the brain of a person who just left the company.
Why Change Your Repo Practices?
The first step in achieving solid infrastructure awareness is separating the application from the operation. As an analogy, think of cooking a recipe from a cookbook. The recipe is made up of two components:
- The ingredients (Application)
- The instructions (Operations)
Think of the application as the ingredients. Each ingredient is a specialized component used to achieve a desired flavor (or result in our case). It's great having these individual ingredients, but without knowing what to do with them, they won't be very tasty or useful to us.
What's an Ops Repo?
The operations repository, or Ops Repo, contains a definition of the desired infrastructure state and the configuration context to run the application. It's similar to the cooking instructions that explain how to cut, combine and cook the raw ingredients so you can transform them into a complete dish.
You could package your instructions and ingredients together, as one does in a meal prep service, but if you do, you'll need to change your instructions every time you change your ingredients and vice versa. You'd be pretty confused if the instructions say to add 2 cups of flour but there's only 1 cup of flour in the provided ingredients, right?
If your change to the ingredients (the application) doesn't work out, you have to revert. If your App and Ops repo are tied together in a single repo, then rolling back is very difficult and you run the risk of taking out other people's work reverting back.
The alternative preferred approach is to package the ingredients and instructions separately. Your instructions live in the cookbook and you'll find ingredients to match those instructions when you're ready to try this recipe.
This separate-bundling approach gives you the freedom to experiment with modifying your recipe without ever losing the base instructions. You can say to yourself "I'll add four cloves of garlic instead of two this time" without ever changing the primary source of instructions. In terms of separating your repos, this means you can just change the application repo and not touch the operations repo.
Putting an Ops Repo into Practice
Let's now work with a real use case. Say you have a webapp application repo that contains both application and operation logic and a CI process that creates a new build whenever a commit is made. You, the developer have just completed a small section of code and would like for a few things to happen.
- You want to push the code to the application repo so that your fellow workers have access to the new functionality
- You want the CI pipeline to trigger and create a new image for archive and testing
Unfortunately, the operations logic is also contained in the same repo as the application. If an image is built, the operation code is captured within the image, where it will never be used and takes up space. How messy!
Or say you want to make a small change to the operations logic. With the current setup, a new application image would be created when the operations logic was updated. If nothing has changed for the application, why create a new build?
And this is just for testing. What about the development, staging and production environments? The complexity of operations grows quickly as scaling begins and if operations and application logic is tied together it makes managing the code a more challenging task than it needs to be.
To fix this we simply need to separate our application and operation logic into their own repositories! Doing so will separate the application and operation life-cycles, which from the above we can see accomplishes two different tasks, image creation for the former and image deployment for the latter.
Application repositories need to be updated to only contain the logic for the application. All environment awareness is removed from the application and is replaced with substitution. The application CI pipeline is solely responsible for creating new images of the application and as an added bonus, the application images aren't environment specific, so that image can be deployed to any environment.
An operations repository will need to be created to house the operations logic. Bitovi suggests using `<application-name>-operations` naming format to keep things concise. The operations repository will contain logic for an applications infrastructure provisioning and deployment+configuration. Secrets, certificates and environment variables can be stored elsewhere and pulled into the project based on the environment that's being provisioned and deployed to.
Here's what you're working towards:
Clean and concise. Now a change to the application repository will create a new build, and a change to the operations repository will update provisioned resources and deploy the latest build.
By using a `separation of repository` approach, you can lessen multi-environment complexity, manage repository life cycles, and limit resource waste by enabling more granular control over your application, operations and configuration.
With your new understanding of creating application repos separate from operations repos, it's time for you to form your plan! Break down your troublesome repositories, separate application from operation and take your first step towards achieving infrastructure confidence.
Check out these BitOps examples for more!