TL;DR: I made a fun CLI āwrapperā for working with web apps and Azure in a very Heroku way. Itās called āAZXā and you can read a full walkthrough and installation instructions from the GitHub repo.
One of my jobs at Microsoft is to help product teams understand how developers work in other ecosystems. In other words: places other than the .NET/Azure world. Thatās a pretty big place, so Iāve decided to stay focused on an experience I love: Heroku.
Iāve used Heroku for years and years and love the simplicity. You can do similar things nowadays with AWS, DigitalOcean, Netlify and yes, even Azure. The whole idea of git push
deployment is pretty standard - in fact itās kind of passĆ©.
Either way, the experience that Heroku pioneered is still compelling. Once you install the CLI and login you simply:
- Create a project locally with
heroku create
- Work on your app and when youāre ready
- Deploy your app using Git:
git push heroku main
Thatās it. Heroku will āguessā what stack it needs to use, provision a set of free resources for it, and before you know it youāre up and running.
Scaling With You
Of course applications are much more complex than that. Youād likely want a database, a cache of some kind (like Redis), more capable logging and so on. Youāre also going to quickly outgrow the free tier - and this, to me, is whatās super groovy about Heroku: itās there with you for all of this.
When you want to scale things up you can use heroku ps:scale web=1
from your local dev directory and boom, youāre scaled. To add better logging you simply heroku addons:create papertrail
.
Adding a database, such as PostgreSQL (becauseā¦ why wouldnāt you?) you need to look up the plan name you want and then heroku addons:create heroku-postgresql:<PLAN_NAME> --version=12
.
The fun part is that everything is configured and wired for you on the back end - thereās nothing you need to do aside from make sure you use āconventionalā environment variables (like DATABASE_URL
, REDIS_URL
etc).
You can access all of these resources locally with the heroku
tool. For instance, to read your logs you can heroku addons:open papertrail
and there are your app logs!
Cool service - and it got me wondering how difficult would it be to do this with Azure?
A Rite of Passage
I told Burke Holland my idea and he started laughing and quipped:
I think thatās a rite of passage here at Microsoft - everyone wants to create a Heroku clone!
Fair enough! Challenge accepted.
To be honest I never thought this would see the light of day but my fellow friends in Cloud Advocacy pushed me to open it up, so here goes.
A Localized Azure Experience
The idea with this project is straightforward: letās bring Azure to you instead of you to Azure. The Azure CLI is outstanding but, if Iām honest, itās aimed at IT people and not developers. The good news is that, with a little love and imagination, you can leverage the CLI and have a little magic happen. Letās seeā¦
I have a local Python application, the Tailwind Starter site that Iāve been working on and I want to get it up and live on Azure. Iāve installed azx
using NPM:
npm install -g @robconery/azx
I then head into my project directory and run azx
:
cd ~/Tailwind
azx
This will display the help screen:
AZX is seeing that thereās no local settings file, which would be saved in .azure
so itās telling me what choices I have at this point and offering me a tip. My goal with this is to decrease the cognitive load that comes with something as complex as Azure (or any cloud service).
Here, we have 3 choices:
-
init
which creates our project -
get
which will load an existing project (more on that in a minute) and -
lookup
which provides supporting information like regions, runtime names and SKUs.
Thatās it - and I love the sparseness of it. Letās keep rolling by creating our project.
Creating an Azure Project
An āAzure projectā is something I made up - itās not an Azure term. To create one, we just need to run azx init
:
Running azx init
does a couple of things, most notably:
- It creates a āResource Groupā on Azure for us, which is a virtual ābucketā for all the Azure stuff weāll be creating for this project.
- It decides a name for us because naming is hard. You can override this if you want, but I like Herokuās way of doing this - it keeps things simple.
- Our local project settings directory,
.azure
is created and in it is a JSON file with our project settings. Weāll see that in a minute.
Notice also that weāre given a tip about what to do next: azx app create
. That wasnāt a choice before, but it is now:
Another example of keeping the cognitive load to a minimum - it just doesnāt make sense to show a command choice if you canāt run that command, which we couldnāt before. Now that we have a project, we can setup our application on Azure.
Setting Up Our App Service
Each subcommand, just like the Azure CLI, has a help screen dedicated to it. If we run azx app create
--``help
weāll see that we have only one command available to us: azx app create <runtime>
. Once again, this is by design.
Following our tip, we can now create setup where our app is going to live on Azure. If we donāt know the runtime choice to enter we can ask the CLI by using azx lookup runtimes
and weāll see a list. In my case I need azx app create python
because Iām using Django:
A bunch of goodness happened here:
- An App Service āPlanā was created and youāre told that this is basically a VM. It tried to create a free one as a logical first step but couldnāt because my account is limited to only 1 free (F1) App Service. You donāt care about any of that - so AZX just set it up for you. All of this can be overridden by specifying
--sku
. - The location of the App Service, something you normally need to specify, was set to
West US
by default. You can override that too - but if youāre kicking the tires on Azure ā¦ why think about this stuff? - A web application, on Azure, was created with local Git deployment - meaning you can
git push
just like with Heroku. This can be changed, easily, later on. - Comprehensive logging was set up, which is not turned on by default.
- Deployment credentials were created for you using a random name and a GUID for a password. These credentials were added to your local Git repository under the
azure
remote.
Thatās a lot of stuff you would have needed to understand before deploying your application. Itās a good idea to understand it at some point, but often if youāre coming to a service for the first time, itās kind of nice if you donāt have to fiddle with every knob. In our case, a lot of this stuff is basic (like logging) and can just be turned on.
Notice that weāre given another tip - how to set up our database. We didnāt have an azx db
choice before, but now we do because we have an application!
Setting Up the Database
We have three choices (as of now) for databases: PostgreSQL (the correct choice), MySQL or Mongo DB (which is actually Cosmos DB using the Mongo DB driver). As you might expect, my database will be PostgreSQL.
To set that up, we can follow the tip that you see there at the top of the help screen. Notice that, just above the tip, we can see the basic description of our application. We see the name (cold-dust-76) and also that itās a web application.
Letās push on and create the database using azx db create postgres
. If we wanted to know more about our choices we could use azx db create
--``help
and see that the only choice we have is to create a database with the specified engine.
Off we goā¦
This takes a few minutes to run and youāre told that straight off. On average, provisioning a PostgreSQL server takes about 3-4 minutes. Cosmos DB takes a bit longer - up to 6 minutes - but the nice thing is what comes next: all the minutiae is handled for you. You can, if you want, get up and go for a walk or write in your bullet journal - this time is given back to you!
So, what happened here? A lot of things that would normally take you 20 clicks in the portal, or more:
- A PostgreSQL server was created for you with a conventional name that you can override (a ā-dbā was added to the end of your project name).
- A firewall rule was added so your web app can see your database.
- Another firewall rule was added using your local IP address so that you could see your database.
- Admin credentials were created for you, which is the way (in my mind) it should be. Once again, a semi-randomized name (like
admin-451
) was used with a GUID password. These credentials were then used to construct access credentials for your application (aDATABASE_URL
) and those credentials were added to your Azure web app configuration settings for you. - Those same credentials were added to a local
.env
file inside of the.azure
directory.
We can now access our database using azx db connect
:
Note: this only works if you have the PostgreSQL binaries installed locally.
From here we can, once again, follow the tip and set up our application database by sending in a SQL file. Given that weāre working with the local client binaries, we can redirect STDIN in the same way we might with psql
:
Weāre ready to go! At this point we have about 7 total minutes elapsed. But what do we do now?
One of my main goals with this tool is to have it help you as much as possible, without doing too much or overloading you with concepts. The only thing you need to remember is to run azx
when you donāt know what to do next:
Things have changed once again, and this is because we have a database to go with our application. We have a few tips at the top - the first of which is telling us how we can deploy our application using Git. Weāll talk about scaling and other things in just a minute.
Deployment
We have Git deployment set up and an azure
remote has been added for us with our deployment credentials embedded in the remote URL, all thatās left to do is git push azure master
(or main
):
Off we go. What you see here is Oryx, the build tool used by Azureās App Services. Itās received our code and, using a post-receive hook, is setting things up for us. In this case itās a Python environment but this also works with Node and Rails, etc.
It takes a minute - for Django it takes about 4 minutes for a full deployment to happen. This is due to the project settings and packages being setup completely on the first run.
After a few minutes weāre done and, hopefully, ready to go!
Ready to goā¦ where exactly? What do we do now? Hopefully at this point you get the idea: ask AZX:
Our app menu has a bunch of new choices. We can change configuration settings on Azure, scale things, look at the logs (which weāll do in a minute) and finally open
it! Thatās what I want to doā¦
Note: if youāre running this inside WSL youāll get an error due to access permissions to Windows executables. If that happens, you can use *azx app get_settings*
to see your appās URL.
It takes a few seconds to load up on first run, but here we go!
Weāre live and our site is happily pulling data from our database. We have a problem, however, in that our images arenāt showing up for some reason. Letās troubleshoot.
Troubleshooting and Moving On
This CLI has gone through a few iterations and I showed it once to executive types at Microsoft, which went pretty well, but there was one very important bit of feedback:
Helping people use Azure is great, but we need to be sure we support them into the future and not back them into the corner
Makes perfect sense. To that end, I added as much as I could to help you out as you work with your application, specifically:
- The ability to scale your App Service up or down.
- The ability to scale your Database Server up or down.
- Rotating your database password (which also updates your web app).
- Viewing your application logs.
That last is what we need now because our images arenāt showing up. Letās see what happened using azx app logs
:
Doing this will tail
the logs so you can see whatās happening realtime and, digging in, I shortly find out that I didnāt set my STATIC_ROOT
properly so my images arenāt showing. I need to have that set for productionā¦ but how?
Letās take a look at our web app configuration settings using azx app get_settings
:
What we need to do is update these settings with a STATIC_URL
that points to a CDN somewhere that stores our images. How do we write these settings? Letās ask AZX!
As I mentioned (briefly) before, a .env
file containing all of our application secrets lives inside of our .azure
directory. We can update that file and then save it up to Azure. Hereās what it looks like:
All of these settings were created when our database was created and, yes, thereās a .gitignore
file that was created as well to ensure that we donāt commit this to source control. All we need to do now is to add a setting in here for STATIC_ROOT
:
Now we just need to use azx app write_settings
:
Heading to the Azure portal to confirm:
Great! We just saved ourselves another 10 or so clicks, including restarting our App Service so these changes are picked up.
Thereās More To Do!
Iāve had tons of fun putting this project together. It was supposed to be a quick prototype but I figured it could also help someone too. There are a few more things Iād like to get done, including caching, deployment slots and more.
The main thing is that you can get to a solid point with your application and then jump over to the regular CLI or to the portalā¦ the hard part being behind you.
Join over 15,000 programmers just like you and me
I have a problem when it comes to trying new things and learning about computer science stuff. I'm self-taught, so it's imperative I keep up with what's going on. I love sharing, so sign up and I'll send along what I've learned right to your inbox.