Page 44 - MSDN Magazine, October 2017
P. 44
Step 0: Initial Disentanglement
This step is where a lot of disentangling happens. By taking time to see how current processes, scripts and templates are deeply coupled to each other, you can reap many of the benefits of immutability by having a more reproducible deployment strategy:
• Immutable deployments forbid in-place upgrades of your code. • Choose the fastest path that allows for image-based deploy- ments instead of in-place upgrades. There are several ways to tackle this: You can snapshot your current VM and use that as the base image and replace the code on each deployment, forinstance,oryoucantweakyourconfigmanagementsoft-
ware to fully configure a vanilla image.
• With the new model you’ll deploy each instance as a new
image. That means you must be able to switch traffic to new instances either at the DNS level or in the HTTP front end, be it load balancers, HTTP servers, caching layers or the like.
• Critical data must be stored outside of the image file system, either externally or in a mounted volume. This will continue to be a requirement in all subsequent steps.
At this stage, many things can fail—for example, you might not be able to download a system package dependency or the system could fail to configure properly due to a race condition or unex- pected version skew. Rebuilding the whole image each time in one way or another will usually take a significant amount of time.
Step 1: Isolate from the OS
Once you’ve completed step 0, the next target is to untangle your- self from the OS layer. Doing this lets you start many different services and deployments from the same, well-known barebones image. It can also reduce the number of images being maintained and speed up the build process. Among things to keep in mind:
• Start by moving all your dependencies out of system directories. • Programming languages and frameworks are generally well-suited to the separation required in this step. For example, Python’s Virtualenv, Ruby’s Gemfiles and PHP’s Composer all have easy ways to isolate dependencies from the rest of
the system by using relative paths to store them by default. • Compiled dependencies can be more difficult to handle, because they often expect to find dependencies on specific system paths. • At this stage you’ll be replacing the whole server on each deployment, so you’ll need to make sure you don’t throw away valuable data. It’s important that system-level logs be
stored externally to the instance.
Step 2: Isolate from the Runtime
So you’ve untangled your service from the underlying OS. Now you need to make sure your language runtime is predictable and reliable. Roll your language runtime into your base image— including any language configuration options you may need to set by default—and you’ll know you can rely on the same behav- ior from it in every instance:
• Runtimes are trivial to update. They don’t change that often and are easy to keep up-to-date even when rolled into base images. • Rolling runtimes into base images lets you control when updates happen, which is important because updates can
break compatibility and force you to port applications.
• An isolated runtime can eliminate baffling production challenges produced by small configuration differences, like
between an 8MB and 64MB memory_limit.
• Immutability at this step is still easy to achieve because both the OS and the language runtime are amenable to isolation
from everything else on the system.
Step 3: Isolate from the Framework
If you got to this step, you’ve probably got the hang of this immu- tabilitything.Youcanstarttoseewhytheimmutableladderis worth climbing. With step 3, your commitment will get tested, as some unique challenges start to show themselves when working with frameworks. Among them:
• Frameworks change a bit more often than runtimes, so you’ll have to update base images more often. That said, being able to manage framework updates on your own schedule is important, as even minor updates can break compatibility.
• Frameworks often present more security issues, because their surface of attack is wider and usually exposed to the Internet. For instance, Python produces 26 common vulner- abilities and exposures (CVE) versus 48 CVEs for Django.
• Disentangling your deployments gets tougher at this stage, because frameworks tend to assume they’re part of your code base. You must learn more about the inner workings of your framework to understand the best way to manage the separation between code and framework.
Step 4: Fully Baked Image per Deploy
You’ve made the climb! This is your destination. When your images boot, they’re ready for action. There’s no downloading, initializing or major configuring of any software in the image. The only things that need tweaking at this stage are minor per-instance values, such as IP addresses or instance names:
• Your app code and data are completely separate from the underlying OS, runtime and framework. Bake those three underlying elements into your base image, and you can update code and data independently.
• You don’t need to rebuild your service from scratch to get here, but some extra effort may be needed to ensure you’re only writing in specific places.
• Once you’ve managed to set everything up to match this step, you can use auto-scale solutions to spin images up or down quickly and reliably.
Bonus Side Step: Immutable + Stateless
Not all services will fit into this model. However, if you happen to have a stateless service such as a worker farm, a caching system or a static Web site, this approach allows you to keep all the data in the image itself. This arrangement reduces the complex- ity of your deployment by serving it directly from the instance, and is ideal for:
•Read-onlydatalikestaticWebsites(noruntimeinproduction). • Workers that process data and farm out to a queue (same
runtime, no local state).
40 msdn magazine
Cloud Development