Voting app with two containers
A simple voting app that uses Redis for a data store and a Python Flask app for the frontend. The example has been ported from https://github.com/Azure-Samples/azure-voting-app-redis.
The example shows how easy it is to deploy containers into production and to connect them to one another. Since the example defines a custom container, Pulumi does the following:
- Builds the Docker image
- Provisions AWS Container Registry (ECR) instance
- Pushes the image to the ECR instance
- Creates a new ECS task definition, pointing to the ECR image definition
To use this example, make sure Docker is installed and running.
Deploying and running the program
Configure the deployment
Note: some values in this example will be different from run to run. These values are indicated
Create a new stack:
$ pulumi stack init voting-app-testing
Set AWS as the provider:
$ pulumi config set cloud:provider aws
Configure Pulumi to use AWS Fargate, which is currently only available in
$ pulumi config set aws:region us-west-2 $ pulumi config set cloud-aws:useFargate true
Set a value for the Redis password. The value can be an encrypted secret, specified with the
--secretflag. If this flag is not provided, the value will be saved as plaintext in
testingis the current stack name).
$ pulumi config set --secret redisPassword S3cr37Password
- Restore NPM modules via
Preview and deploy
Ensure the Docker daemon is running on your machine, then preview and deploy the program with
pulumi up. The program deploys 24 resources and takes about 10 minutes to complete.
View the stack output properties via
pulumi stack output. The stack output property
frontendUrlis the URL and port of the deployed app:
$ pulumi stack output frontendURL ***.elb.us-west-2.amazonaws.com
In a browser, navigate to the URL for
frontendURL. You should see the voting app webpage.
When you're done, run
pulumi destroy to delete the program's resources:
$ pulumi destroy This will permanently destroy all resources in the 'testing' stack! Please confirm that this is what you'd like to do by typing ("testing"): testing
About the code
At the start of the program, the following lines retrieve the value for the Redis password by reading a configuration value. This is the same value that was set above with the command
pulumi config set redisPassword <value>:
let config = new pulumi.Config(); let redisPassword = config.require("redisPassword");
In the program, the value can be used like any other variable.
The program provisions two top-level resources with the following commands:
let redisCache = new cloud.Service("voting-app-cache", ... ) let frontend = new cloud.Service("voting-app-frontend", ... )
The definition of
redisCache uses the
image property of
cloud.Service to point to an existing Docker image. In this case, this is the image
redis at tag
alpine on Docker Hub. The
redisPassword variable is passed to the startup command for this image.
The definition of
frontend is more interesting, as it uses
build property of
cloud.Service to point to a folder with a Dockerfile, which in this case is a Python Flask app. Pulumi automatically invokes
docker build for you and pushes the container to ECR.
So that the
frontend container can connect to
redisCache, the environment variables
REDIS_PORT are defined. Using the
redisCache.endpoints property, it's easy to declare the connection between the two containers.
The Flask app uses these environment variables to connect to the Redis cache container. See the following in
redis_server = os.environ['REDIS'] redis_port = os.environ['REDIS_PORT'] redis_password = os.environ['REDIS_PWD']