Upgrading application services

If you run docker compose up repeatedly from the same Compose file, no changes will be made after the first run. Docker Compose compares the configuration in the Compose file with the active containers at runtime and won't change resources unless the definition has changed. This means you can use Docker Compose to manage application upgrades.

My Compose file is currently using the database service from the image I built in Chapter 3, Developing Dockerized .NET Framework and .NET Core Applications, tagged dockeronwindows/ch03-nerd-dinner-db:2e. For this chapter, I've added audit fields to the tables in the database schema and built a new version of the database image, tagged dockeronwindows/ch06-nerd-dinner-db:2e.

I have a second Compose file in the same ch06-docker-compose directory, called docker-compose-db-upgrade.yml. The upgrade file is not a full application definition; all it contains is a single part of the database service definition, using the new image tag:

version: '3.7'
services:
nerd-dinner-db:
image: dockeronwindows/ch06-nerd-dinner-db:2e

Docker Compose supports override files. You can run docker-compose commands and pass multiple Compose files as arguments. Compose will join all the files together in the order specified in the command, from left to right. Override files can be used to add new sections to the application definition, or they can replace existing values.

While the application is running, I can execute docker compose up again, specifying both the original Compose file, and the db-upgrade override file:

> docker-compose `
-f docker-compose.yml `
-f docker-compose-db-upgrade.yml `
up -d

ch06-docker-compose_reverse-proxy_1 is up-to-date
ch06-docker-compose_nerd-dinner-homepage_1 is up-to-date
ch06-docker-compose_elasticsearch_1 is up-to-date
ch06-docker-compose_message-queue_1 is up-to-date
ch06-docker-compose_kibana_1 is up-to-date
Recreating ch06-docker-compose_nerd-dinner-db_1 ... done
Recreating ch06-docker-compose_nerd-dinner-web_1 ... done
Recreating ch06-docker-compose_nerd-dinner-save-handler_1 ... done
Recreating ch06-docker-compose_nerd-dinner-api_1 ... done

This command uses the db-upgrade file as an override to the main docker-compose.yml file. Docker Compose merges them both, so the final service definition contains all the values from the original file, except the image specification that comes from the override. The new service definition doesn't match what's running in Docker, so Compose recreates the database service.

Docker Compose recreates services by removing the old container and starting a new one, using the new image specification. Services that don't depend on the database are left as they are, with the log entry up-to-date, and any services that do depend on the database are also recreated once the new database container is running.

My database container uses the pattern I described in Chapter 3Developing Dockerized .NET Framework and .NET Core Applications, with a volume to store the data and a script that can upgrade the database schema when a container is replaced. In the Compose file, I use a default definition for the volume called db-data, so Docker Compose creates it for me. Just like the containers created by Compose, volumes are a standard Docker resource and can be managed with the Docker CLI. The docker volume ls lists all the volumes on the host:

> docker volume ls

DRIVER VOLUME NAME
local ch06-docker-compose_db-data
local ch06-docker-compose_es-data

I have two volumes for my NerdDinner deployment. They both use the local driver, which means the data is stored on the local disk. I can inspect the SQL Server volume to see where the data is physically stored on the host (in the Mountpoint attribute) and then check the contents to see the database files:

> docker volume inspect -f '{{ .Mountpoint }}' ch06-docker-compose_db-data
C:ProgramDatadockervolumesch06-docker-compose_db-data\_data

> ls C:ProgramDatadockervolumesch06-docker-compose_db-data\_data

Directory: C:ProgramDatadockervolumesch06-docker-compose_db-data\_data

Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 12/02/2019 13:47 8388608 NerdDinner_Primary.ldf
-a---- 12/02/2019 13:47 8388608 NerdDinner_Primary.mdf

The volume is stored outside of the container, so when Docker Compose removes the old container database, all the data is preserved. The new database image bundles a Dacpac and is configured to do schema upgrades for the existing data file in the same way as the SQL Server database from Chapter 3, Developing Dockerized .NET Framework and .NET Core Applications.

When the new container has started, I can check the logs and see that the new container attached the database files from the volume and then altered the Dinners table to add the new audit column:

> docker container logs ch06-docker-compose_nerd-dinner-db_1

VERBOSE: Starting SQL Server
VERBOSE: Changing SA login credentials
VERBOSE: Data files exist - will attach and upgrade database
Generating publish script for database 'NerdDinner' on server '.SQLEXPRESS'.
Successfully generated script to file C:initdeploy.sql.
VERBOSE: Changed database context to 'NerdDinner'.
VERBOSE: Altering [dbo].[Dinners]...
VERBOSE: Update complete.
VERBOSE: Deployed NerdDinner database, data files at: C:data

The new audit column adds a timestamp when rows are updated, so now when I create a dinner through the web UI, I can see when the row was last updated in the database. In my development environment, I haven't published the SQL Server port for client connections, but I can run docker container inspect to get the container's local IP address. Then I can connect my SQL client directly to the container and run a query to see the new audit timestamp:

Docker Compose looks for any differences between resources and their definitions, and not just the name of the Docker image. If you change the environment variables, port mappings, volume setup, or any other configuration, Docker Compose will remove or create resources to bring the running application to the desired state.

You need to be careful with modifying Compose files to run applications. If you remove the definition for a running service from the file, Docker Compose won't recognize that the existing service containers are part of the application, so they won't be included in the difference checks. You can end up with orphaned service containers.
..................Content has been hidden....................

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