Virtual machines or VMs create a copy of a computer system that makes it possible for a single server to host several VMs that each act as if it were a separate piece of hardware. VMs do not interact with other VMs on the same server at all—each VM is a self-contained unit and contains a copy of everything, from the operating system to libraries and databases.
Containers, on the other hand, share resources with other containers on the host system, including the operating system kernel and libraries. Containers are much lighter than VMs, and take much less time to start. This also makes it possible to pack many more applications into a server—hundreds or thousands of containers can run on a server, while only a couple dozen VMs can run on the same hardware.
Crucially, though, VMs and containers are not an either/or choice. Containers can run on bare metal or on top of VMs, so there are plenty of deployments that use both as part of the overall stack.
Why Move to Containers?
Containers offer a number of benefits over running directly on a virtual machine. First of all, containerized applications are portable, and can move between cloud environments or back on to an on-premise datacenter, helping companies avoid vendor lock-in.
Using containers also facilitates building a CI/CD pipeline, releasing more frequent updates and creating repeatable deployment processes. This is possible because of container’s lightweight, agile nature, because each container contains much less code than if updating an entire VM and because containers run in exactly the same environment at every stage of development, so there’s little risk that a containerized application will work perfectly in development and then fail in production.
How to Move to Containers
There isn’t one flow-chart to tell you how to move an application from a virtual machine to containers, because the exact steps will depend on your individual application—does it have state? What are the storage requirements? What about security? Is it being deployed on a public or private cloud?
However, there are two general strategies for containerizing workloads. One involves taking the VM-based, monolithic app and strategically breaking it apart into microservices, then packaging each microservice in a container. This is the ideal way to move forward, but requires more work re-architecting the entire application and isn’t always practical for large enterprise applications.
Secondly, you could package the entire application in a container and deploy the app to a Kubernetes cluster in a ‘lift and shift’ operation.
Regardless, there are a number of problems to solve, most of which do not have one-size-fits-all answers. Here are some examples:
- Do you run your database inside the cluster or do you use a Database as a Service from a third party?
- Where do you store your data? This is particularly important for any application that requires persistent storage, because any data that is stored in a container will be lost when the container is shut down.
- How do containers connect to storage and maintain their mobility and portability?
- What size clusters do you need?
As you start preparing the actual code for a container-based system, it’s best practice to follow the 12-factor principles. These include:
- Tracking all your source code in a version control system
- Strictly separate the build, release and run stages (this can be done automatically with CI/CD pipeline tools like Spinnaker)
- Store all your configuration information in environment variables, not code.
- Don’t store credentials of any kind inside the code.
Once you’ve solved those puzzles, there are other containerization best practices to consider—each container should only do one thing, you should embrace automation whenever possible, take steps to avoid cloud clock-in and, of course, continuously test and deliver.
Containers are necessary to take advantage of continuous delivery platforms like Spinnaker, and to work towards continuously improving applications. They help companies ship better software, faster.