Welcome the (unofficial) Azure Functions Container CLI
Tags: azure, functions, docker, kubernetes
Published: 2022-01-03 09:48:02

## Introduction

May I introduce you to the **unofficial Azure Functions Container CLI**. You find the NPM package at npm at [@lechnerc77/create-funcdocker-cli](https://www.npmjs.com/package/@lechnerc77/create-funcdocker-cli)

The source code (including a README) is available at [GitHub](https://github.com/lechnerc77/create-funcdocker-cli)

Now to the interesting question: why such a CLI? 

## Why

As you might know _Azure Functions_ are _open source_ since day one. In addition to this it is also possible to embed the Azure Functions (including their runtime) in a Docker container and deploy them e. g. to a Kubernetes Cluster. 

You might ask now: isn't this a bit of an _exotic scenario_? Why not use Azure Functions on Azure and benefit from all the nice features that come along with it?
 
The answer to that is a clear "yes and no": if you (and probably your company/employer/regulatory requirements/constraints in your line of business) are fine with that, then use Azure Functions on Azure - so a clear YES under these circumstances.

However, there might be constraints that do not allow you to fully buy-in to Azure and you are forced to use some vendor-agnostic approach to build your business applications. When writing this blog post, you will probably end up at a Kubernetes-based deployment of your business applications. 

In the same level this is good for the requirement to be vendor-agnostic and portable, this is a pain for application developers as their backlog of responsibilities and technical knowledge just grew. Consequently, developers must wrap their head around technology and have less time for solving business problems. 

In my opinion it is a good approach to mitigate this by mimicking the developer experience of Azure Functions and bring the focus back to the business problem. This is exactly where putting Azure Functions into containers enters the stage and allows developers to make use of the excellent developer experience of Azure Functions and brings their focus back onto code that solves a business problem (for sure the complexity of Kubernetes does not magically disappear and the Azure Functions need to be wrapped into containers and then deployed to Kubernetes etc., but a step in the right direction) 

The official [Azure Functions CLI](https://github.com/Azure/azure-functions-core-tools) brings along a [feature](https://github.com/Azure/azure-functions-core-tools#getting-started-on-kubernetes) that enables developers to create a basic `Dockerfile` as well as `.dockerignore` file in an Azure Functions project. So problem solved, right? 

Well, sort of. The CLI is a good starting point, and I used this feature quite often. However, the more I used it the more I recognized that the functionality is limited to a very basic setup that I adjusted very often. As I am lazy and often forget about the options I need to set (which means I need to look those up in some old projects which contradicts my laziness) I thought it might be worth to create a CLI that focuses on the use-case of wrapping Azure Functions into a container in a more _comfortable_ and _interactive_ way.  

As the title says the result is an _unofficial CLI_ (so no support by Microsoft) to do so. And as I might not be the only person on the planet with this use-case I made the CLI open source. 

Let us take a look at what the CLI can do for us.            

## Features

The CLI creates the following files based on some input parameters.

### Dockerfile

The CLI allows you to create a `Dockerfile` based on your:

- Azure Functions language (like Node.js, Python etc.)
- Language version
- Azure Functions Core version

In addition, it gives you the option to select the fitting official Docker base image for your language, language version and Azure Functions Core version.

This can be further refined by:

- Switching off the Azure Functions Core homepage
- Defining a custom port to expose the Azure Function endpoint

### .dockerignore

As in the official CLI this is a static file but contains some more file types than the one from the official CLI.

### Makefile

As I do not like to create and push the container images manually, I usually create a `Makefile` for these tasks. And so does the CLI. The `Makefile` contains commands to:

- Build the image
- Push the image to the Docker registry
- Build and push the image in one step
- Run the image locally

You can specify the _DockerID_, the _application name_ and the _application version_ when generating these files. The creation of this file is optional.  

### Kubernetes

The CLI gives you the option to create a basic `deployment.yaml` file consisting of a Kubernetes [deployment](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/) and a Kubernetes [service](https://kubernetes.io/docs/concepts/services-networking/service/). It uses the parameters from the `Makefile` to specify the container image to pull and also fills in the metadata based on this input. The creation of this file is optional.

## How to use the CLI

As the CLI is a npm package the installation is straight forward using: 

```shell
npm i @lechnerc77/create-funcdocker-cli
```
The CLI can be executed without any connection to an Azure Functions project, so you can try it out in an empty folder to see what happens.

The CLI comes with a ton of optional parameters as you can see at the [README section](https://github.com/lechnerc77/create-funcdocker-cli) of the GitHub repository. All these parameters are *optional*. You can enter none, some or all relevant for the file creation process. In case information is missing or not correct, the CLI will guide you through the options interactively.

### Basic interactive mode

The easiest way to start the CLI is to enter

```shell
create-funcdocker
```
This will start the CLI in interactive mode and it will guide you through all the options.

![CLI first steps](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hmzsed0wvhcu38jdhj80.png)

To get a look at the available options, you need to provide the parameter `--help` or short `-h` to the CLI:

![Help description of CLI](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xkp7f8iaa5r7mwtbs46t.png)

You can also do a mix between parameters provided via the CLI and interactive mode. Example would be you already specify the runtime (e.g. `dotnet`), the version (e.g. `dotnet 5.0 (isolated)`) and the Azure Functions Core Version (e.g. `4`) when calling the CLI. Then the CLI will only prompt for the missing information.

![Mixed CLI Usage](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yy9qp8x9vn5r7ng0moem.png)

After all parameters are set the corresponding files are created in the directory you executed the CLI.

![Complete Execution of CLI](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f1m6oxu8c1jwr8meu95e.png)

### Execution in an Azure Functions Project

In case the CLI is executed in an Azure Functions project, it will try to fetch as much information as possible from the configuration files. This information is limited and sometimes hidden, do not expect too much of this. I did not find a very systematic way how things are stored in the configuration files, but maybe I looked at the wrong places. 

You can deactivate this option, so even when executing the CLI in an Azure Functions project the CLI will ignore the information available there.

### Dry-Run

In case you do not want to write the files at a first try but want to take a look at them in console, the CLI offers a dry-run mode to have you covered. The gathering of the information for the file generation stays the same, but the result will not be written to disk but instead displayed in your console. 

![CLI Execution in dry-run mode](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oxo6n1sbdb46pqwzbrjg.png)

### Kubernetes

Besides the container-based files I also find it useful to have a basic Kubernetes deployment and service file at hand to make a test deployment and see if things work as expected. The CLI has an option to do so, and you will end up with one yaml-file in a directory called `k8s`. This file contains a deployment and a service which should give you a quick start when deploying your containerized Azure Function to a Kubernetes Cluster.

![Kubernetes Deployment File](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jxr5rdb6zp953jgo0na6.png) 

### Limitation

There are also some limitations that I want to mention:

- Version 0.1.0 has no support for Java as a language. 
- The CLI contains some basic checks, but I am pretty sure that I might have missed some combinations, so be aware of that (and open an issue in case you come across this)   
- Only Docker is supported as of now (Maybe I will also check `nerdctl` but not sure when)

## Status Quo

When writing this blog post, the version of the CLI is 0.1.0. So there are certainly some rough edges and I am happy to smooth them. In case you use the CLI and come across a bug, feel free to report it in the [GitHub repository](https://github.com/lechnerc77/create-funcdocker-cli)

In addition, there might be improvements, so happy to hear about them to, just file an issue in the GitHub repository from above and I will see what I can do.

Of course, I am also happy to receive contributions :-)