We have a team working to dockerize a few of our applications to Docker over the past few months. As we went through this dockerization process, we have collected a set of challenges and best practices in using Docker. We don’t yet have all the answers but at least we know the questions and issues that any application team will face when converting a traditional application into Docker containers. Broadly, we have categorized our best practices into 3 categories:
- Design containers for your apps
- Getting the devops pipeline ready
- Running containerized app in operations (production)
We will cover each of these in three parts.
1. Design your containerized App
Break your app down
One of the first steps is to understand the overall architecture of your application in terms of tiers, complexity, stateful/stateless, datastore dependencies and such. It would also be useful to know the running state of the application, such as the number of processes as well as the distributed nature of the application. Based on this information, it might be useful to break a monolithic application into components that would each represent a container or keep the monolithic application as one container. If there are multiple containers, then the complexity of the solution increases as communication/links between containers will need to be designed. Of course, keeping one big monolothic container is also difficult to use if it becomes huge (multiple GB) and replacing components would require a full fork lift upgrade where you lose the container benefits. The rest of the discussion applies to each component container.
Base image selection – standardize and keep it updated
It is important to standardize on a base image or a small set of base images that you need for your containers. These can be RHEL, Ubuntu or other operating system images. Traditionally, these are maintained by an infrastructure team or can be maintained by apps team as well. Note that these images will go through a number of compliance and possible patching and rebuilt due to vulnerabilities and hence require careful selection and attention during their lifecycle to keep it updated. Finally, standardization is a key aspect so that multiple application teams use a common set of base images. This will help enterprises achieve simplification in day 2 operations and management of these images.
Configuration and Secrets
Configuration and secrets should never be burned into a container (Docker) image and must always be externalized. There are a number of ways to achieve this such as through environment variables, through scripts with Chef/Puppet and through tools such as Zookeeper and Consul. Secrets also require a store outside the container ecosystem especially in production such as vault and many others such as Keywhiz, HSM and others. Externalizing configurations help in making sure that when the containers are provisioned in DEV or QA or PROD, each have a different set of environment variables and secrets.
Datastores and databases
The stateful containers such as databases and datastores require a careful analysis of whether these should be containerized or not. It is alright to keep them non-containerized in the initial releases of the application. There are ways in Docker to use data containers and mounted volumes but we haven’t investigated this further.
Once you have taken a few of the above critical decisions on a plan to containerize your application, you are on your way. In part-II, we will cover how to build DevOps pipeline and best practices for tagging builds and testing images. And finally, in part-III, we will cover the best practices for running container applications in production.