Planning Your Docker-Based Microservice Stack
Moving to a microservice architecture requires some up-front planning to avoid it becoming fragile, resulting in a distributed monolith.
Join the DZone community and get the full member experience.
Join For FreeDocker continues to grow in popularity, primarily because of its ease of packaging and distributing code across any environment. Combined with a microservice architecture, Docker empowers developers to build software in smaller, more modular components that can be combined to create solutions to complex problems.
Moving to a microservice architecture requires some up-front planning to avoid it becoming fragile, resulting in a distributed monolith. From service design to deployment and monitoring, there are several considerations for deploying a microservice architecture using Docker. Building on our earlier post of "9 Critical Decisions for Running Docker in Production", let's now look at planning a successful microservice architecture on Docker.
Design for one service per container
As new microservices are created, it may be tempting to optimize the deployment model by placing multiple services per container. However, services cannot be scaled independently from one another when they occupy the same container instance.
Planning tip #1: Adopt a one service per container approach to support scaling your microservices based on demand without consuming additional memory and CPU overhead demanded of poly-service containers.
Implement a service discovery solution
To achieve scale and high availability, microservices will need to be distributed across multiple Docker hosts. Hard-coding your app with the hostnames or IP addresses of containers running your service isn't an option. Instead, you will need to manage the service discovery between your code, which needs to locate a service by name, and your Docker infrastructure that is managing one or more container instances.
Planning tip #2: Select a service discovery strategy that can be kept up-to-date automatically as you scale container instances up and down. Options include: ZooKeeper, Consul, Etcd, Eureka, or using an internal DNS strategy.
For most web applications, there will be shared assets, such as images, stylesheets, and JavaScript libraries. If you use a framework such as Ruby on Rails, the asset pipeline can be a useful tool for managing this process. However, it is also difficult to manage in a production environment. The assets generated from the pipeline within a single container can't be shared across containers easily. There are two options: have each container instance generate and serve the assets (not ideal), or push assets to a single, shared location.
Planning tip #3: Utilize CDNs for serving your static and dynamically generated assets. Doing so will improve browsing performance and offload the work from your container instances designed to process incoming API requests. It will also simplify your container infrastructure, as you will not have to find a way to share assets across container instances.
Externalize, monitor, and manage your microservices
As with a typical cloud native architecture, incoming HTTP requests need to be balanced across server instances. However, most cloud-based load balancers only route to servers, not to multiple containers on the server. By installing a reverse proxy in front of your HTTP-based microservices, incoming requests can be distributed across any number of container instances spanning multiple Docker hosts.
Beyond load balancing, your HTTP-based microservices will most likely require authentication, authorization, and rate limiting. Services exposed for mobile or public/partner developers will also require spike arrest to prevent DoS attacks, and routing from a single external URL structure to internal microservices (e.g. http://api.example.com/products/ -> http://products.myapp.local/).
Planning tip #4: Install a reverse proxy and/or API management platform. There are a variety of commercial and free open source options, including: 3scale, Apigee, Kong, or by customizing nginx.
Learn more about API management platforms from our resource page.
Unlike a traditional cloud server with a network-based block storage device, containers have an isolated filesystem separate from the host. Data inside containers is lost once the container is destroyed. Additionally, we cannot depend on containers to remain on the same host for a long period of time. Therefore, mounting the host filesystem as an external volume won't guarantee data longevity in a production database without a considerable amount of work. We need a better plan for databases in our stack to ensure our data is safe and high performance.
Planning tip #5: Setup and deploy your databases outside of your container. Use a Database-as-a-Service to remove the need to manage your own instances, or roll-your-own managed database solution outside of containers. The only exception is when your microservice has read-only data that can be packaged into the container during image creation time.
Want to accelerate your deployment process?
Cloud 66 offers many of the features described above, such as container hosting, service discovery using DNS, reverse-proxies, and database-as-a-service. You can learn more about the services provided by viewing the details of Cloud 66 for Docker. Once you have had a chance to see how it works, signup for Cloud 66 and start deploying containers to your favorite cloud provider.
Published at DZone with permission of James Higginbotham, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments