potatoqualitee / devcontainers

Dev Containers, Codespaces and more for Azure PowerShell Function Apps

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Dev Containers, Codespaces and more for Azure PowerShell Function Apps

Recently, I listened to the PowerShell Podcast episode with Barbara Forbes and she mentioned devcontainers and her blog post: Use GitHub Codespaces for Azure PowerShell Function apps

I've heard so much dev containers, like Brett Miller talks about them all the time, too.

image

In addition to Brett, other PowerShell friends, including Jess Pomfret and Rob Sewell and Shawn Melton are suggesting devcontainers, so the moment I was back at my computer, I read Barbara's blog post, cloned the repo and messed around.

This repository is the result.

About this repo

There are a few key differences between my repo and Barbara's; primarily I updated the devcontainer version to PowerShell v7 and the Azure Functions to v4. I also added a sample Azure Function and removed a few default OS-related errors/warnings.

Here's a gem: according to DevContainers for Azure and .NET, here's the build order for devcontaineres.

  1. Build the Docker container. If you add the shell script through the RUN command in Dockerfile, the shell script is run this time.
  2. Run features declared in the features section of devcontainer.json while building the Docker container.
  3. Run commands declared in the postCreateCommand attribute of devcontainer.json.
  4. Apply dotfiles after postCreateCommand, if you have it.
  5. Apply both extensions and settings of devcontainer.json at the startup of the DevContainer.

So here's directory structure for what I think I'll be using a template for my Azure Function repos.

.
├── .devcontainer
│   ├── Dockerfile
│   └── devcontainer.json
├── .github
│   └── workflows
│       └── function.yml
├── .gitignore
├── .vscode
│   ├── extensions.json
│   ├── launch.json
│   ├── settings.json
│   └── tasks.json
├── README.md
└── functions
    ├── .gitignore
    ├── Modules
    │   └── azHelper
            ├── azHelper.psd1
            └── azHelper.psm1
    ├── host.json
    ├── local.settings.json
    ├── profile.ps1
    ├── requirements.psd1
    ├── templates
    └── greeting
        ├── function.json
        └── run.ps1

.devcontainer

This directory contains a Dockerfile that builds the container. I could also add in a docker-compose.yml file which I probably will later with more advanced setups when I want to include a "network" of containers, like for SQL Server projects.

I added more VS Code customizations into the devcontainer.json to address warnings that pop up about Windows PowerShell not existing, so I forced the dev container to look for PowerShell on Linux.

image

I also removed the following line:

"ghcr.io/devcontainers/features/azure-cli:1": {}

I saw GitHub's Dev Container Features used by others, including Jess who uses it to install both the azurecli and git. I think features are literally compiled to ensure they work well (maybe?) because it took a long time for the features to install on my container.

Just figured it out! I was installing git and the feature literally says "(from source)" so it was indeed compiling git.

Ultimately, the updated Azure Functions container already has the Azure CLI installed and I just used apt get to install whatever else I wanted in the Dockerfile. This seemed much faster.

I'll probably revist this decision in the future, though, because the list of features seems super useful.

.github

Azure Functions can be published automatically from GitHub Actions! I haven't done it yet but this folder contains is the workflow template that was provided by Microsoft.

.gitignore

That Azurite Azure Storage Emulator creates a ton of files named like __azurite_db_blob_extent__.json so I ignore them all in git and VS Code.

.vscode

launch.json

The VS Code files are pretty standard but I did add a Node entry to launch.json because it worked well for me in the past (and it ran PowerShell Azure Functions) and I like options. So far, though, the PowerShell entry is my default.

settings.json

This has an important setting: the root location of my Azure Functions, which I simply named functions.

"azureFunctions.deploySubpath": "functions",

I also reiterated the location of PowerShell on Linux. Without this one (or maybe the other entry in devcontainer.json), I get the following error when attempting to debug:

image

If you see that, btw, try just restarting your VS Code and that often times can help.

Oh, and I ignored all those files that Azurite generates.

functions

Took me a while but this is what I decided to name the folder that contains the actual functions. There doesn't seem to be a standard in Azure Function repos and I like this one.

Modules

This folder is important in PowerShell projects! The path is essenetially added to the system's $env:PSModulePath.

Rob likes to place all module dependencies here, saying..

the reason is to speed up function load time - because if we are on pay per minute we are paying to install the module every time so I was going to do a build of the repo every night and inject the latest dbatools release. Ultimately, putting the modules inside the container saves money and pins the version at the cost of requiring effort to maintain and update. Using requirements risks upstream dependencies breaking your shit but is much easier and simpler to add and remove new ones.

He's got a point there, especially considering how often the PowerShell Gallery fails :/ He went on to say

It depends on each projects specifical requirements. But i think using requirements up front means that people don't need to know or worry about dealing with containers. So it's easier and when you have problems you need to come back and revisit

Barbara prefers requirements.psd1, saying..

I would use requirements.psd1 unless there is a good reason not to. Good reason being that the modules are not in the Gallery, for example. Getting them from the Gallery means you have less management and always have the latest (major) version. Another reason can be very large modules. If you load the complete Az module, it takes more than 5 minutes and that ruins your start-time. So with Az you can use submodules, which will resolve that issue.

I'm still undecided (considering the Gallery's instability) but I think I'll use requirements.psd1 for modules in the PowerShell Gallery and the Modules folder for internal modules or modified public modules.

templates

This is where I'll store my ARM templates or bicep or whatever, probably.

greeting

This is my actual test function! The folders will be named like this:

  • vm
  • storage

While the routes will look like this

  • /vm/get
  • /vm/new
  • /vm/stop
  • /storage/create
  • /storage/delete

PREVIOUSLY, my folder structure looked like this

  • vm
  • vmNew
  • vmStop
  • storageCreate
  • storageDelete

But then I found an awesome approach from Davide Mauri and adapted. All methods are stored in one folder/function and handled with a with a METHOD switch.

host.json

This has a bunch of non-default values that I found in a repo and I imagine it'll come in handy. One day, I'll find out why they used these values haha.

profile.ps1

I love that they enable profile loading! In my more advanced module, I used it to create a few quick functions. I also used it to explicitly load a slow-loading module and set some things like $PSDefaultParameterValues.

requirements.psd1

I don't need allllll of Az so I'm just loading some that I'll imagine I'll need as a SQL Server-centric developer.

Hope this was helpful for you if you're new to all of this!

Using this repository as a Codespace

VS Code can run in a browser! It's wild. For me, I had to see it to understand so let's jump in with some screenshots.

First, click the green Code button then Create codespace on main.

image

Then it starts building a container!

image

And now VS Code appears, whaaaat! Check out my browser tabs at the top.

image

Then if you want to see a list, you can go to your Codespaces page.

image

Here, you can even increase the size of your codespace. I haven't yet because I don't know what impact that has on the monthly free hours.

Alright, so next, let's get the Azure Functions App running by hitting debug.

image

Wait until a prompt that pops up saying that your application is running on port 7071 (when this screenshot was created, the folder was named vm and not greeting).

I'm including the whole VS Code screenshot because when I started doing functions, I wanted the tutorial to show what I'm supposed to be seeing.

image

Go ahead and Open in Browser to be amazed!

image

Next up, we'll execute the function. Click the Azure Extension, expand the workspace tab at the bottom, then right click on greeting. Then click Execute Function Now...

image

A prompt will appear in the settings bar at the top and you can change the default name of Azure to anything you like.

image

I changed it to blog reader. And here it is, successfully running!

image

:mindblown:

Using a devcontainer

To use the devcontainer which contains everything you need, clone the repo however you do then open it in VS Code.

Ensure that the Dev Containers VS Code extension is installed. I imagine Docker alao has to be installed and running.

Once the extension is installed, a remote icon should appear in the lower-left hand corner.

image

Click on it, then a drop-down will appear at the top. Select Reopen in Container in the Dev Containers group.

image

Code will restart as a devcontainer!

image

Woo! Now you're set and you can follow all the last few steps in the Codespaces section, starting after Alright, so next, let's get the Azure Functions App running by hitting debug. because it's all the same :O

About

Dev Containers, Codespaces and more for Azure PowerShell Function Apps


Languages

Language:PowerShell 89.8%Language:Dockerfile 10.2%