Goal: Setup Pulumi to manage a simple existing App Service and Database
You should find that some resources (including an Azure App Service and an SQL DB) have been created for you in advance for this exercise and are available in your workshop resource group. Ask a trainer if you're not sure what resources that includes
- Install Pulumi
- We'll use the local backend rather than signing up for pulumi
pulumi login --local
- For passphrases just set any value for now e.g. "passphrase"
- Run
export PULUMI_CONFIG_PASSPHRASE=passphrase
in shell or$ENV:PULUMI_CONFIG_PASSPHRASE="passphrase"
in PowerShell.
- Run
- Make sure you're logged into the Azure cli
pulumi new azure-python
- Name: e.g.
move-to-iac
- Location:
uksouth
- The output may suggest you try running
pulumi up
, but this will fail. We first want to replace the generated example code - follow the instructions below.
If you hit problems installing or setting up Pulumi then you can do the exercise inside Docker, see pulumi_docker_setup.md. The image download is large (2.7GB), so you may want to pull it down in the morning:
docker pull corndeldevopscourse/pulumi-starter
- Confirm the correct status of the existing webapp by browsing to its URL via Azure portal.
- We need to import the existing resources.
- Starting with the resource group
- First work out its id
- browse to it in the Azure portal
- hit JSON view in the top right
- Press copy next to the "Resource Id"
- Then run
pulumi import azure-native:resources:ResourceGroup resource_group <id from above>
- First work out its id
The
resource_group
parameter here is the resources logical name - you can read more about this in Pulumi's docs
- This will generate some code that can be copy-pasted into the
__main.py__
file - You should delete the existing code and replace with the imported code
Windows users may have better success using PowerShell, if using git-bash then all commands containing resource-ids need to be prepended with
MSYS_NO_PATHCONV=1
, as per this known issue.
- Now repeat that import process (appending the outputted code) for each of the four resources inside the resource group. Use the following resource types instead of
azure-native:resources:ResourceGroup
and pick an appropriate variable name instead ofresource_group
.azure-native:web:AppServicePlan
azure-native:web:WebApp
azure-native:sql:Server
azure-native:sql:Database
- Replace all references to other names and ids with a reference to the other resource e.g.:
resource_group_name=resource_group.name
server_name=sqlserver.name
server_farm_id=app_service_plan.id
- Remove all 'name' properties (at the top level of each resource, not nested ones) - Pulumi will generate these for you
We're going to use the RandomPassword resource to generate a new random database password.
- Install the provider
- Add
pulumi-random>=3.1.1
as a new line in yourrequirements.txt
file. - Run
./venv/Scripts/pip install -r requirements.txt
on Windows or./venv/bin/pip install -r requirements.txt
on a Mac. This will update the dependencies in Pulumi's virtual environment.
- Add
- Add a new variable to store the resource (this code assumes you do
import pulumi_random as random
as per the docs):db_password = random.RandomPassword("db_password", length=16, special=True)
Beware of the location of variable initialisations in the file - they have to be placed above other resources that reference them.
- Use this resource's
result
output in the config for the sqlserver resourcesqlserver = azure_native.sql.Server("sqlserver", administrator_login="db", administrator_login_password=db_password.result, ... )
- Create the connection string as a new variable
connection_string = pulumi.Output.all(sqlserver.fully_qualified_domain_name, db.name, sqlserver.administrator_login, db_password.result) \ .apply(lambda args: f'Server=tcp:{args[0]},1433;Initial Catalog={args[1]};Persist Security Info=False;User ID={args[2]};Password={args[3]};MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;' )
- Add it as an app setting for the Web App, along with a new value for the
DEPLOYMENT_METHOD
environment variablesite_config = azure_native.web.SiteConfigArgs( app_settings=[ azure_native.web.NameValuePairArgs(name="CONNECTION_STRING", value=connection_string), azure_native.web.NameValuePairArgs(name="DEPLOYMENT_METHOD", value="pulumi") ]),
- Run
pulumi up
Only a
create
for thedb_password
andupdate
s for the sqlserver and webapp should be necessary, if anydelete
orreplace
items are listed in the given preview then abort and double-check your configuration. - Browse to your webapp's endpoint and confirm the database connection still works, and the
deploymentMethod
output has changed.it may take a few minutes for the new database password to propogate, so if login fails then wait a bit and try again.
Currently all of our infrastructure's state is being stored on your local machine so only you can make consistent changes; neither you nor your teammates will appreciate that if you ever want to go on holiday! We should instead store our state in a shared location that other team members can access.
- Create a storage account in your resource group
- Do this manually through the Azure CLI or portal
- Export a checkpoint from your existing state
- Log in with Pulumi to the Azure Storage backend
- Note that the "container-path" is just the name of the relevant container within your storage account
- Import your checkpoint
- Check that the state is now created in the blob storage - you should see a
.pulumi
folder - Run
pulumi up
, and verify that there would be no changes as the state should match
We should make sure we have a staging environment that matches our production infrastructure. We already have a template for that infrastructure, so we'd like to parameterise it to be able to use it in multiple environments. Pulumi's solution to managing this is using different 'stacks'
- Create a new stack with
pulumi stack init <stack_name>
- Import the resource group again - for this exercise we'll share that between both stacks (though in a real project we might separate the resources)
- Add a stack_name of staging to your pulumi config
- Use the stack name in your code to prefix your resources logical names
My names are erroring?
You will find that Pulumi is now creating resources with the names you gave (plus some random noise), rather than the names the resources had when you imported them. Some of the names you provided previously may lead be names Azure won't allow, e.g. underscores in `sql_server` or `web_app`- Run pulumi up, and check if the resources create successfully
- You may discover here that pulumi import is not perfect - track down any missing/incorrect fields
Hint: Can you spot any differences in the portal between your new staging application and the existing one?
Hint
How is Pulumi tracking your docker image?Hint
You may want to look at adding a Pulumi firewall rule
- Our app doesn't automatically perform database migrations; once your staging app can communicate with the DB you may want to add an appropriate table to the database
- Switch back to the production environment - will
pulumi up
make any changes?
Pulumi provide a wide range of example setups that you could want to configure - take a look at those and see how else you could extend your system.