Public cloud offerings
Before we delve into the core subject of this book and start working with Kubernetes, we should have a look at the alternatives; after all, the services we are going to be covering in upcoming chapters are nearly all loosely based off these services.
The three main public cloud providers all provide a serverless service:
- AWS Lambda from AWS (https://aws.amazon.com/lambda/)
- Azure Functions by Microsoft (https://azure.microsoft.com/en-gb/services/functions/)
- Cloud Functions from Google (https://cloud.google.com/functions/)
Each of these services has the support of several different code frameworks. For the purposes of this book, we will not be looking at the code frameworks in too much detail as using these is a design decision which has to based on your code.
We are going to be looking at two of these services, Lambda from AWS and Functions by Microsoft Azure.
AWS Lambda
The first service we are going to look at is AWS Lambda by AWS. The tagline for the service is quite a simple one:
"Run code without thinking about servers."
Now those of you who have used AWS before might be thinking the tagline makes it sound a lot like the AWS Elastic Beanstalk service. This service inspects your code base and then deploys it in a highly scalable and redundant configuration. Typically, this is the first step for most people in moving from pets to cattle as it abstracts away the configuration of the AWS services which provide the scalability and high availability.
Before we work through launching a hello world example, which we will be doing for all of the services, we will need an AWS account and its command-line tools installed.
Prerequisites
First of all, you need an AWS account. If you don't have an account, you can sign up for an account at https://aws.amazon.com/:

While clicking on the Create a Free Account
and then following the onscreen instructions will give you 12 months' free access to several services, you will still need to provide credit or debit card details and it is possible that you could incur costs.
Note
For more information on the AWS free tier, please see https://aws.amazon.com/free/. This page lets you know which instance sizes and services are covered by the 12 months of free service, as well as letting you know about non-expiring offers on other services, which include AWS Lambda.
Once you have your AWS account, you should create a user using the AWS Identity and Access Management (IAM) service. This user can have administrator privileges and you should use that user to access both the AWS Console and the API.
For more details on creating an IAM user, see the following pages:
- Getting started with IAM: http://docs.aws.amazon.com/IAM/latest/UserGuide/getting-started.html
- IAM best practices: http://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html
Note
Using your AWS root account to launch services and access the API is not recommended; if the credentials fall into the wrong hands you can lose all access to your account. Using an IAM rather than your root account, which you should also lock down using multi-factor authentication, means that you will always have access to your AWS account.
The final prerequisite is that you need access to the AWS command-line client, where I will be using macOS, but the client is also available for Linux and Windows. For information on how to install and configure the AWS command-line client, please see:
- Installing the AWS CLI: http://docs.aws.amazon.com/cli/latest/userguide/installing.html
- Configuring the AWS CLI: http://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html
Note
When configuring the AWS CLI, make sure you configure the default region as the one you will be accessing in the AWS web console, as there is nothing more confusing than running a command using the CLI and then not seeing the results in the web console.
Once installed, you can test that you can access AWS Lambda from the command-line client by running:
$ aws lambda list-functions
This should return an empty list of functions like the one shown in the following screenshot:

Now that we have an account set up, created, and logged in using a non-root user, and we have the AWS CLI installed and configured, we can look at launching our first serverless function.
Creating a Lambda function
In the AWS Console, click on the Services
menu in the top-left of the screen and select Lambda
by either using the filter box or clicking on the service in the list. When you first go to the Lambda service page within the AWS Console, you will be presented with a welcome page:

Clicking on the Create a function
button will take us straight to the process of launching our first serverless function.
There are four steps to creating a function; the first thing we need to do is select a blueprint:

For the basic hello world function, we are going to be using a pre-built template called hello-world-python
; enter this into the filter and you should be presented with two results, one is for Python 2.7 and the second uses Python 3.6:

Selecting hello-world-python
and then clicking Export
will give you the option of downloading the code used in the function in the lambda_function.py
file and the template which is used by Lambda during step 3. This can be found in the template.yaml
file.
The code itself, as you would imagine, is pretty basic. It does nothing other than return a value it is passed. If you are not following along, the contents of the lambda_function.py
file are:
from __future__ import print_function import json print('Loading function') def lambda_handler(event, context): #print("Received event: " + json.dumps(event, indent=2)) print("value1 = " + event['key1']) print("value2 = " + event['key2']) print("value3 = " + event['key3']) return event['key1'] # Echo back the first key value #raise Exception('Something went wrong')
The template.yaml
file contains the following:
AWSTemplateFormatVersion: '2010-09-09' Transform: 'AWS::Serverless-2016-10-31' Description: A starter AWS Lambda function. Resources: helloworldpython: Type: 'AWS::Serverless::Function' Properties: Handler: lambda_function.lambda_handler Runtime: python2.7 CodeUri: . Description: A starter AWS Lambda function. MemorySize: 128 Timeout: 3 Role: !<tag:yaml.org,2002:js/undefined> ''
As you can see, the template file configures both the Runtime
, which in our case is python2.7
, and some sensible settings for the MemorySize
and Timeout
values.
To continue to step 2, click on the function name, which for us is hello-world-python
, and you will be taken to the page where we can choose how the function is triggered:

We are not going to be using a trigger just yet and we will look at these in a little more detail in the next function we launch; so for now, click on Next
.
Step 3 is where we configure our function. There is quite a bit of information to enter here, but luckily a lot of the detail we need to enter has been pre-populated from the template we looked at earlier, as you can see from the following screenshot:

Note
The details we need to enter are as follows: anything with a * is required and the information in italics was pre-populated and can be left as-is.
The following list shows all of the form fields and what should be entered:
- Basic information:
- Name*:
myFirstFunction
- Description: A starter AWS Lambda function
- Runtime: Python 2.7
- Name*:
- Lambda function code:
- Code entry type: This contains the code for the function, there is no need to edit this
- Enable encryption helpers: Leave unticked
- Environment variables: Leave empty
- Lambda function handler and role:
- Handler*: lambda_function.lambda_handler
- Role*: Leave Create new role from template(s) selected
- Role name*: myFirstFunctionRole
- Policy templates: We do not need a policy template for this function, leave blank
Leave the Tags
and Advanced settings
at the default values. Once the preceding information has been entered, click on the Next
button to take us to step 4, which is the final step before our function is created.
Review the details on the page. If you are happy that everything has been entered correctly, click on the Create function
button at the bottom of the page; if you need to change any information, click on the Previous
button.
After a few seconds, you will receive a message confirming that your function has been created:

In the preceding screenshot, there is a Test
button. Clicking this will allow you to invoke your function. Here you will be able to customize the values posted to the function. As you can see from the following screenshot, I have changed the values for key1
and key2
:

Once you have edited the input, clicking on Save and test
will store your updated input and then invoke the function:

Clicking on Details
in the Execution result
message will show you both the results of the function being invoked and also the resources used:
START RequestId: 36b2103a-90bc-11e7-a32a-171ef5562e33 Version: $LATEST value1 = hello world value2 = this is my first serverless function value3 = value3 END RequestId: 36b2103a-90bc-11e7-a32a-171ef5562e33
The report for the request with the 36b2103a-90bc-11e7-a32a-171ef5562e33
ID looks like this:
Duration: 0.26 ms
Billed Duration: 100 ms
Memory Size: 128 MB
Max Memory Used: 19 MB
As you can see, it took 0.26 ms
for the function to run and we were charged the minimum duration of 100 ms
for this. The function could consume up to 128 MB
of RAM, but we only used 19 MB
during the execution.
Returning to the command line, running the following command again shows that our function is now listed:
$ aws lambda list-functions
The output of the preceding command is as follows:

We can also invoke our function from the command line by running the following command:
$ aws lambda invoke \ --invocation-type RequestResponse \ --function-name myFirstFunction \ --log-type Tail \ --payload '{"key1":"hello", "key2":"world", "key3":"again"}' \ outputfile.txt
As you can see from the preceding command, the aws lambda invoke
command requires several flags:
--invocation-type
: There are three types of invocation:RequestResponse
: This is the default option; it sends the request, which in our case is defined in the--payload
section of the command. Once the request has been made, the client waits for a response.Event
: This sends the request and triggers an event. The client does not wait for a response and instead you receive an event ID back.DryRun
: This calls the function, but never actually executes it—this is useful when testing that the details used to invoke the function actually have the correct permissions.
--function-name
: This is the name of the function we want to invoke.--log-type
: There is currently a single option here,Tail
. This returns the result of the--payload
, which is the data we want to send the function; typically this will be JSON.outputfile.txt
: The final part of the command defines where we want to store the output of the command; in our case it is a file calledoutputfile.txt
which is being stored in the current working directory.
When invoking the command from the command line, you should get something like the following result:

Returning to the AWS Console and remaining on the myFirstFunction
page, click on Monitoring
and you will be presented with some basic statistics about your function:

As you can see from the preceding graphs, there are details on how many times your function has been invoked, how long it takes, and also if there are any errors.
Clicking on View logs in CloudWatch
will open a new tab which lists the log streams for myFirstFunction
. Clicking on the name of the log stream will then take you to a page which gives you the results for each time the function has been invoked both as testing in the AWS Console and also from the command-line client:

Both the Monitoring
page and logs are extremely useful when it comes to debugging your Lambda functions.
Microsoft Azure Functions
Next up, we are going to take a look at Microsoft's serverless offering, Azure Functions. Microsoft describes this service as:
"Azure Functions is a solution for easily running small pieces of code, or "functions," in the cloud. You can write just the code you need for the problem at hand, without worrying about a whole application or the infrastructure to run it."
Like Lambda, there are several ways your Function can be invoked. In this quick walkthrough, we will be deploying a Function which is called using an HTTP request.
Prerequisites
You will need an Azure account to follow along with this example. If you don't have an account, you can sign up for a free account at https://azure.microsoft.com/:

At the time of writing, Microsoft is crediting all new accounts with $200 to spend on Azure services, and like AWS, several services have a free tier.
Note
While you are credited with $200, you will still need to provide credit card details for verification purposes. For more information on the services and limits in the free tier, please see https://azure.microsoft.com/en-gb/free/pricing-offers/.
Creating a Function app
All of the work we are going to be doing to create our first Function app will be using the web-based control panel. Once you have your account, you should see something like the following page:

Note
One thing you should note about the Microsoft Azure control panel is that it scrolls horizontally, so if you lose where you are on a page you can typically find your way back to where you need to by scrolling to the right.
As you can see from the preceding screenshot, there are quite a few options. To make a start creating your first Function, you should click on + New
at the top of the left-hand side menu.
From here, you will be taken to the Azure Marketplace
. Click on Compute
and then in the list of featured marketplace items you should see Function App
. Click on this and you will be taken to a form which asks for some basic information about the Function you want to create:
App name
: Call this what you want; in my case I called itruss-test-version
. This has to be a unique name and, if your desiredApp name
has already been used by another user, you will receive a message that your chosenApp name
is not available.Subscription
: Choose the Azure subscription you would like your Function to be launched in.Resource Group
: This will be automatically populated as you type in theApp name
.Hosting Plan
: Leave this at the default option.Location
: Choose the region which is closest to you.Storage
: This will automatically be populated based on theApp name
you give, for our purpose leaveCreate New
selected.Pin to dashboard
: Tick this as it will allow us to quickly find our Function once it has been created.
If you are not following along in your account, my completed form looks like the following screenshot:

Once you have filled out the form, click on the Create
button at the bottom of the form and you will be taken back to your Dashboard
. You will receive a notification that your Function is being deployed as you can see from the box at the right-hand side in the following screenshot:

Clicking on the square in the Dashboard
or on the notification in the top menu (the bell icon with the 1
on it) will take you to an Overview
page; here you can view the status of the deployment:

Once deployed, you should have an empty Function app ready for you to deploy your code into:

To deploy some test code, you need to click on the +
icon next to Functions
in the left-hand side menu; this will take you to the following page:

With Webhook + API
and CSharp
selected, click on Create this function
; this will add the following code to your Function app:
using System.Net; public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log) { log.Info("C# HTTP trigger function processed a request."); // parse query parameter string name = req.GetQueryNameValuePairs() .FirstOrDefault(q => string.Compare(q.Key, "name", true) == 0) .Value; // Get request body dynamic data = await req.Content.ReadAsAsync<object>(); // Set name to query string or body data name = name ?? data?.name; return name == null ? req.CreateResponse(HttpStatusCode.BadRequest, "Please pass a name on the query string or in the request body") : req.CreateResponse(HttpStatusCode.OK, "Hello " + name); }
This code simply reads in the variable name
, which it has passed via the URL and then prints back to the user as Hello <name>
.
We can test this by clicking on the Run
button at the top of the page. This will execute our Function as well as giving you the output and logs:

The logs for the test run look like this:
2017-09-09T15:28:08 Welcome, you are now connected to log-streaming service.2017-09-09T15:29:07.145 Function started (Id=4db505c2-5a94-4ab4-8e12-c45d29e9cf9c)2017-09-09T15:29:07.145 C# HTTP trigger function processed a request.2017-09-09T15:29:07.176 Function completed (Success, Id=4db505c2-5a94-4ab4-8e12-c45d29e9cf9c, Duration=28ms)
You can also view more information on your Function app by clicking on Monitor
in the inner left-hand side menu. As you can see from the following screenshot, we have details on how many times your Function has been called, as well as the status of each execution and the duration for each invocation:

Note
For more detailed information on the invocation of your Function app, you can enable Azure Application Insights, and for more information on this service, please see https://azure.microsoft.com/en-gb/services/application-insights/.
Being able to test within the safety of the Azure Dashboard
is all well and good, but how do you directly access your Function app?
If you click on HttpTriggerCSharp1
, which will take you back to your code, above the code block you will have a button which says Get function URL
, and clicking on this will pop up an overlay box with a URL in it. Copy this:

For me, the URL was:
https://russ-test-function.azurewebsites.net/api/HttpTriggerCSharp1?code=2kIZUVH8biwHjM3qzNYqwwaP6O6gPxSTHuybdNZaD36cq3HptD5OUw==
Note
The preceding URL will no longer work as the Function has been removed; it has been provided for illustration purposes only, and you should replace it with your URL. To interact with URLs on the command line, I am going to be using HTTPie, which is a command-line HTTP client. For more detail on HTTPie, see the project's homepage at https://httpie.org/.
Call that URL on the command line using HTTPie with the following command:
$ http "https://russ-test-function.azurewebsites.net/api/HttpTriggerCSharp1?code=2kIZUVH8biwHjM3qzNYqwwaP6O6gPxSTHuybdNZaD36cq3HptD5OUw=="
This gives us the following result:

As you can see from what is returned, our Function app has returned the HttpStatusCode BadRequest message. This is because we are not passing the name
variable. To do this, we need to update our command to:
$ http "https://russ-test-function.azurewebsites.net/api/HttpTriggerCSharp1?code=2kIZUVH8biwHjM3qzNYqwwaP6O6gPxSTHuybdNZaD36cq3HptD5OUw==&name=kubernetes_for_serverless_applications"
As you would expect, this returns the correct message:

You can also enter the URL in your browser and see the message:
