Time: Approximately 15 minutes
Difficulty: Easy
- Docker App Parameters
- Using a Parameter to Change Voting Options
- Upgrading a Deployed Application
- More practice: Prepare for production
By the end of this exercise, you will have:
- Learned about Docker App parameters
- Added parameters to the voting app application
- Learned how to deploy an update to an already-deployed application
In addition to using environment variables, Docker App allows you to define parameters for an application that can be overridden at deploy-time. Examples of parameters might include port mappings, cpu/memory limits, number of replicas, label definitions, or network names. Almost everything in the Docker App compose file can be parameterized, except for the image names.
By default, the vote and results services let you vote between Dogs and Cats. However, wouldn't it be neat if we could change that? Conveniently, both the vote
and results
services allow the definition of two environment variables (OPTION_A
and OPTION_B
) to let us change the voting choices. This sounds like a great opportunity for parameters!
-
In both the
vote
andresults
services, add environment variables namedOPTION_A
andOPTION_B
with a value of${options.A}
and${options.B}
. The values are simply placeholders for the parameters.Solution
services: vote: environment: OPTION_A: ${options.A} OPTION_B: ${options.B} results: environment: OPTION_A: ${options.A} OPTION_B: ${options.B}
-
Before setting the parameter, run
docker app build voting-app -t username/voting-app:0.1.0 && docker app inspect username/voting-app:0.1.0 --pretty
to see what happens.Full Output
$ docker app build voting-app -t username/voting-app:0.1.0 && docker app inspect username/voting-app:0.1.0 … # Build log inspect failed: Action "com.docker.app.inspect" failed: failed to load Compose file: invalid interpolation format for services.vote.environment.OPTIONS_A: "required variable options.A is missing a value". You may need to escape any $ with another $.
What happened? The command fails because "required variable options.A is missing a value." In other words, all parameters are required to have default values. Those default values are specified in the
parameters.yml
file. -
Specify the default values for
options.A
andoptions.B
in theparameters.yml
file. Let's setoptions.A
to "Cats" andoptions.B
to "Dogs". Remember that this file is a YAML file.Solution
options: A: Cats B: Dogs
-
Now, re-run the
docker app inspect --pretty
command to look at the output. Do not forget to rebuild the application image. You should see the parameters with their default values in the output now!Full output
$ docker app build voting-app -t username/voting-app:0.1.0 … $ docker app inspect --pretty username/voting-app:0.1.0 version: 0.1.0 name: voting-app description: "" maintainers: - name: root email: "" Services (5) Replicas Ports Image ------------ -------- ----- ----- db 1 postgres:9.4 worker 1 dockersamples/examplevotingapp_worker result 1 5001 mikesir87/examplevotingapp_result vote 2 5000 mikesir87/examplevotingapp_vote redis 1 redis:alpine Networks (2) ------------ backend frontend Volume (1) ---------- db-data Parameters (2) Value -------------- ----- options.A Cats options.B Dogs
-
At this point, go ahead and deploy the Docker App
Full output
$ docker app run username/voting-app:0.1.0 --name voting-app --target-context=swarm Creating network back-tier Creating network front-tier Creating service voting-app_redis Creating service voting-app_db Creating service voting-app_worker Creating service voting-app_results Creating service voting-app_vote Application "voting-app" installed on context "swarm"
Once it's deployed, go ahead and check out the vote and results apps. You should see that we're now using Cats vs Dogs!
With the app deployed, let's change the settings by "upgrading" the application bundle. To do so, we can use the docker app upgrade
command. While we will change settings in the upgrade here, you can use this command to actually deploy an updated version of the app.
Suddenly the project manager and the design team changed their minds. Cats and Dogs are so 2018, voting options must be changed to Moby and Molly. Add the -s
flag to upgrade command to set options.A to "Moby" and optionB to "Molly".
Solution/Output
$ docker app upgrade voting-app -s options.A=Moby -s options.B=Molly --target-context=swarm
Updating service voting-app_results (id: tpugiytt4eq9p88lvb8900pmq)
Updating service voting-app_vote (id: d49hxltgvg5faie0kc735oy42)
Updating service voting-app_redis (id: x9hpof20yumf2gv3mbbd9g1i5)
Updating service voting-app_db (id: nwssvpk4r8gklcfnvd47w7tzx)
Updating service voting-app_worker (id: qoyl03yaxtdyefb5oh6u9m698)
Application "voting-app" upgraded on context "swarm"
After a moment, you should be able to open either service and see the options have been updated. Welcome to 2019! 🎉
While we added parameters to change the options, we can set parameters for almost anything in the compose file.
As a practice:
- Turn the exposed ports into parameters (
vote.exposedPort
andresults.exposedPort
) and allow them to be overridden. - Add a parameter to all the
replicas
sections, don't forget the default value - Add a
resources
section underdeploy
:
services:
service:
deploy:
resources:
limits:
cpus: '${service.cpu_limit}'
memory: ${service.memory_limit}
docker-compose.yml
version: "3.7"
services:
vote:
image: mikesir87/examplevotingapp_vote
networks:
- frontend
depends_on:
- redis
ports:
- ${vote.exposedPort}:80
deploy:
replicas: ${vote.replicas}
resources:
limits:
cpus: '${vote.cpu_limit}'
memory: ${vote.memory_limit}
update_config:
parallelism: 2
restart_policy:
condition: on-failure
environment:
OPTION_A: ${options.A}
OPTION_B: ${options.B}
redis:
image: redis:alpine
networks:
- frontend
deploy:
replicas: ${redis.replicas}
resources:
limits:
cpus: '${redis.cpu_limit}'
memory: ${redis.memory_limit}
update_config:
parallelism: 2
delay: 10s
restart_policy:
condition: on-failure
worker:
image: dockersamples/examplevotingapp_worker
networks:
- frontend
- backend
deploy:
replicas: ${worker.replicas}
resources:
limits:
cpus: '${worker.cpu_limit}'
memory: ${worker.memory_limit}
restart_policy:
condition: on-failure
delay: 10s
max_attempts: 3
window: 120s
placement:
constraints: [node.role == manager]
db:
image: postgres:9.4
networks:
- backend
deploy:
placement:
constraints: [node.role == manager]
results:
image: mikesir87/examplevotingapp_result
networks:
- backend
depends_on:
- db
ports:
- target: 80
published: ${results.exposedPort}
protocol: tcp
mode: host
deploy:
replicas: ${results.replicas}
resources:
limits:
cpus: '${results.cpu_limit}'
memory: ${results.memory_limit}
update_config:
parallelism: 2
delay: 10s
restart_policy:
condition: on-failure
environment:
OPTION_A: ${options.A}
OPTION_B: ${options.B}
networks:
frontend:
name: front-tier
backend:
name: back-tier
parameters.yml
options:
A: Cats
B: Dogs
vote:
replicas: 2
cpu_limit: 1
memory_limit: 512M
exposedPort: 5000
redis:
replicas: 1
cpu_limit: 1
memory_limit: 512M
worker:
replicas: 1
cpu_limit: 1
memory_limit: 512M
results:
replicas: 1
cpu_limit: 1
memory_limit: 512M
exposedPort: 5001
Now we will create a new parameters file for production, with different parameters:
- more replicas
- more realistic constraints on cpu and memory limits
Then we are ready for installation:
$ docker app run username/voting-app:0.1.0 --parameters-file=production.yml --target-context=swarm