Deploying Go applications to App Service Linux with GitHub Actions
This post will cover deploying Go applications to Azure App Service Linux with Go “Blessed” images using GitHub Actions.
Overview
Note: Go “Blessed Images” are currently marked as experimental - these images and behavior on App Service are subject to change. This is also not recommended for production.
Prerequisites
Application Logs
IMPORTANT: Ensure that App Service Logs are enabled - review this document on how to do so.
This is important incase the application crashes due to misconfiguration of any of these profilers - given this is all at the application level, we need these logs enabled to see what may have gone wrong. You can view logging in a few ways:
- Diagnose and Solve Problems -> Application Logs
- Log Stream
- Directly through the Kudu site - such as the /newui endpoint (https://sitename.scm.azurewebsites.net/newui) or the normal Kudu site
- An FTP client to view logfiles under
/home/LogFiles
GitHub repository
To enable CI/CD with GitHub Actions, you must have a GitHub account and a GitHub repository for your source code created.
Quickstart
Go “Blessed Images” expose port 8080 - which Go application HTTP servers should be listening on. For example:
err := http.ListenAndServe(":8080", nil)
You can however change this with the PORT
App Setting - the HTTP listening port in the application would need to be updated.
If you wanted to listen for PORT
, you could do the following:
port := ":" + os.Getenv("PORT")
log.Fatal(app.Listen(port))
See: Default exposed ports of Azure App Service Linux Blessed Images
For this example, we’re going to be using the Fiber example from here azureossd - go-devops-examples. You can bring your own code as well.
Local development
We can quickly get started with a Go project using Fiber with the following:
- Create a
main.go
file - Create a
go.mod
file by runninggo mod init yourmodulename
- Install Fiber with
go get github.com/gofiber/fiber/v2
- In the
main.go
file, add the following:
package main
import (
"log"
"github.com/gofiber/fiber/v2"
)
func main() {
app := fiber.New()
app.Get("/", func (c *fiber.Ctx) error {
return c.SendString("Hello, World - From Fiber!")
})
log.Fatal(app.Listen(":8080"))
}
- Run the application with
go run .
, you should now see the below in your terminal:
$ go run .
┌───────────────────────────────────────────────────┐
│ Fiber v2.48.0 │
│ http://127.0.0.1:8080 │
│ (bound on host 0.0.0.0 and port 8080) │
│ Handlers ............. 2 Processes ........... 1 │
│ Prefork ....... Disabled PID ............. 24812 │
└───────────────────────────────────────────────────┘
- You should now be able to access the application over
localhost:8080
Create an App Service
Follow this documentation on creating a Go 1.19 App Service on Linux - Deploy a Go web app to Azure App Service
Enable GitHub Actions (Manual creation)
Deploy with a Publish Profile
You can deploy to App Service Linux by using a Publish Profile
- Go to the Azure Portal for your application and navigate to Deployment Center. Download the Publish Profile by selecting “Manage publish profile” and then “Download publish profile”.
- Go to the GitHub repository being used for this code and select Settings -> Actions -> Secrets and Variables.
- Click on New Repository Secret - add a variable named
AZUREAPPSERVICE_PUBLISHPROFILE
-
Copy the entire contents within the Publish Profile
.xml
tha was downloaded and add it as the value to theAZUREAPPSERVICE_PUBLISHPROFILE
secret on the GitHub side. -
Next, on the GitHub side - under Actions - select New Workflow.
NOTE: If desired, you can instead manually create a path of
.github/workflows/somework.yaml
in the root of your project - this will kick off a workflow run when commited to your repository
- Add the following file to your new workflow - replace the App Service name where needed:
name: Go
on:
push:
branches:
- main
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v3
with:
# Change your go version as needed
go-version: 1.19
- name: Build
run: go build -v ./...
- name: Upload artifact for deployment jobs
uses: actions/upload-artifact@v2
with:
name: go-app
path: |
.
deploy:
runs-on: ubuntu-latest
needs: build
environment:
name: 'Production'
url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}
steps:
- name: Download artifact from build job
uses: actions/download-artifact@v2
with:
name: go-app
path: .
- name: 'Deploy to Azure Web App'
uses: azure/webapps-deploy@v2
id: deploy-to-webapp
with:
app-name: 'yourapp'
slot-name: 'Production'
publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE }}
What does the above file do?:
- It runs
go build
to build the binary - It uses
actions/upload-artifact@v2
to upload the binary to the “deploy” stage - It downloads the
actions/download-artifact@v2
binary with the alias “go-app” - It then deploys the binary to the App Service
Deploy with a Service Principal
-
Generate a Service Principal by following the documentation here - Generate deployment credentials. Save the JSON output for the next step.
-
Following the section above on how to add GitHub Action Secrets, add a secret named
AZURE_CREDENTIALS
with the output from the credential creation in step 1. -
Use the following
.yaml
, below is a complete example - the only major change we do in this one is to remove thepublish-profile
property from theazure/webapps-deploy@v2
task and add theazure/login@v1
task as a replacement for authentication.
name: Go
on:
push:
branches:
- main
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v3
with:
# Change your go version as needed
go-version: 1.19
- name: Build
run: go build -v ./...
- name: Upload artifact for deployment jobs
uses: actions/upload-artifact@v2
with:
name: go-app
path: |
.
deploy:
runs-on: ubuntu-latest
needs: build
environment:
name: 'Production'
url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}
steps:
- name: Download artifact from build job
uses: actions/download-artifact@v2
with:
name: go-app
path: .
- uses: azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
- name: 'Deploy to Azure Web App'
uses: azure/webapps-deploy@v2
id: deploy-to-webapp
with:
app-name: 'some-app'
slot-name: 'Production'
- name: logout
run: |
az logout
Enable GitHub Actions (Azure Portal)
At this current time while in expiremental status, using the Azure Portal to set up GitHub Actions and commit a workflow file does not work for Go “Blessed” images. It will not create a GitHub Actions workflow (thus not committing to it the repository to kick off a workflow run).
Important notes
In the go build section, we don’t specify anything like -o
, for any named execuable output.
This is because, at the current time, SCM_DO_BUILD_DURING_DEPLOYMENT
is not honored on Go “Blessed” images. oryxBuilder will always be the builder used.
The executable is built by Oryx - and named oryxBuildBinary
and placed in /home/site/wwwroot
.