Deploying stacks

There are two ways to deploy your applications with UCP, which are analogous to deploying individual services with docker service create, and deploying a full compose file with docker stack deploy. Stacks are the easiest to deploy and will let you use a compose file that you've verified in pre-production environments.

In the source code for this chapter, the folder ch08-docker-stack contains the deployment manifests to run NerdDinner on Docker Enterprise, using swarm mode. The core docker-compose.yml file is the same as the one mentioned in Chapter 7, Orchestrating Distributed Solutions with Docker Swarm, but there are some changes in the override file to deploy to my production cluster. I'm taking advantage of the hybrid cluster I have in Docker Enterprise, and I'm using Linux containers for all the open source infrastructure components.

There are only two changes for a service to use Linux containers instead of Windows: the image name, and a deployment constraint to ensure containers are scheduled to run on Linux nodes. Here's the override for the NATS message queue in the file docker-compose.hybrid-swarm.yml:

message-queue:
image: nats:1.4.1-linux
deploy:
placement:
constraints:
- node.platform.os == linux

I've used the same approach as Chapter 7, Orchestrating Distributed Solutions with Docker Swarm with docker-compose config to join the override files together and export them into docker-swarm.yml. I could connect my Docker CLI to the cluster and deploy the application with docker stack deploy, or I could use the UCP UI. From the Stacks view, under Shared Resources, I can click on Create Stack and select the orchestrator and upload a compose YML file:

UCP validates the contents and highlights any issues. Valid compose files are deployed as a stack, and you will see all the resources in UCP: networks, volumes, and services. After a few minutes, all the images for my application are pulled on to the cluster nodes and UCP schedules replicas for each of the services. The service list shows me that all the components are running at the required level of scale:

My modernized NerdDinner application is now running across 15 containers in a six-node Docker Enterprise swarm. I have high availability and scale in a supported production environment, and I've switched the four open source components from my custom images to the official Docker images, without any changes to my application images.

Stacks are the preferred deployment model, as they continue to use the known compose file format, and they automate all the resources. But stacks are not suitable for every solution, particularly when you're moving legacy applications to containers. In a stack deployment, there's no guarantee about the order in which the services will be created; the depends_on option used by Docker Compose doesn't apply. This is a deliberate design decision based on the idea that services should be resilient, but not all services are.

Modern applications should be built for failure. If a web component can't connect to the database, it should use a policy-based retry mechanism to reconnect repeatedly rather than failing to start. Traditional applications usually expect their dependencies to be available and don't have graceful retries built in. NerdDinner is like that, so if I deploy a stack from the compose file, the web app could start before the database service is created, and it will fail.

In this case, the container should exit, so Docker knows the application is not running. Then it will schedule a new container to run, and by the time it starts up, the dependency should be available. If not, the new container will end, and Docker will schedule a replacement, and this will keep happening until the application is working correctly. If your legacy applications don't have any dependency checks, you can build this logic into the Docker image, using startup checks and health checks in the Dockerfile.

In some cases, that might not be possible, or it might be that new containers starting repeatedly cause a problem with your legacy application. You can still manually create services rather than deploying a stack. UCP supports this workflow too, and this lets you manually ensure that all the dependencies are running before you start each service.

This is the imperative approach to managing your apps, which you really should try to avoid. It's far better to encapsulate your application manifest in a simple set of Docker Compose files that can be managed in source control, but it may be difficult to do that with some legacy apps.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.189.180.43