In this blog-tutorial you will:
- Use GitHub Codespaces (or your own IDE)
- Create a simple Go web server application
- Run unit tests on the application
- Build the application into a multi-stage Docker Image
- Use the Azure Container Registry (ACR) to store your Docker Images
- Deploy the application into Azure App Services
- Automate the delivery pipeline utilising GitHub Actions
Note Using GitHub Codespaces can incur costs. At the time of writing this tutorial, GitHub free accounts get 120 core-hours of Codespaces compute and 15GB of Codespaces storage for free. Please do consult the GitHub Codespaces pricing page for the most up to date information.
This application will be built entirely from within your browser. To do this, you will be using the items listed below in the prerequisites. If you want to run this locally using VSCode or another IDE, please also install the items marked as “Optional” in the list below.
Prerequisites
- You will need access to an Azure account. You can either use an existing one or sign up for a free one – Free Azure Account
- Alternatively, If you are a student then you can sign up for Azure for Students
- GitHub Account
- Access to Codesspaces (or your own IDE) – Codespaces
- Go (Optional: if running locally)
- Docker (Optional: if running locally)
- Azure CLI (Optional: if running locally)
Example Code Repository
Build, Test and Deploy to Azure
Assumption(s)
- You are using the example code repository
- You are using Codespaces to open and run the application
Overview
This hands-on tutorial provides you with an existing Go web application that you can build upon. To use the existing code repository click on the “Build, Test and Deploy to Azure” link above and this will open the GitHub repository in your browser. Click the “Fork” button in the top right-hand corner of the screen and this will create a copy of the repository in your GitHub account.
The repository contains a Go web server that uses handlebars templates, basic unit tests and an Azure CLI Codespaces image configuration in the .devcontainer
directory. A Dockerfile is also included that creates a multi-stage Docker Image, along with a GitHub Actions workflow to build, test, and deploy the app to Azure App Services.
Note We are using
Devcontainers
as this provides a clean and consistent experience for everyone.Devcontainers
are designed for ease of use and allow you to develop complex solutions from within your browser window.
Open your forked code repository in Codespaces
Navigate to your fork of the example code repository and click on the Code
button and select Codespaces on the top ribbon. Now click on the button Create codespace on main
and wait for the Codespace to be created (this could take a minute or two).
Once Codespaces has been created, you will be able to see the application and all the files in the Explorer
tab on the left-hand side of the screen. You can also open a new terminal by clicking on the +
button in the terminal tab, however, one should open automatically.
Before going any further, test the application is running by running the following command in the terminal:
go run main.go
You should see the following output:
┌───────────────────────────────────────────────────┐
│ Fiber v2.42.0 │
│ http://127.0.0.1:3000 │
│ (bound on host 0.0.0.0 and port 3000) │
│ │
│ Handlers ............. 2 Processes ........... 1 │
│ Prefork ....... Disabled PID .............. 6209 │
└───────────────────────────────────────────────────┘
This output indicates the program is running and listening on port 3000. You should now see a new port within the Ports
terminal tab and see the application running in Codespaces. Click on the local address or the green popup button “Open in Browser” to open the running application in the browser.
To close the server down, press Ctrl + C
in the terminal.
Now you have seen the application running, it is time to run the tests. To do this, navigate to the root project directory and run the following command in the terminal:
go test ./... -v
You should see the following output:
=== RUN Test_filesExist
--- PASS: Test_filesExist (0.00s)
PASS
ok github.com/build-test-and-deploy-to-azure 0.005s
This output indicates that the test file has run successfully. The tests are only checking for important files to be present but you can add your own tests to the main_test.go
file to test your application code as it grows.
The a multi-stage Docker Image
Lets turn our attention to the root of the project where you will find a Dockerfile
that builds the application into a multi-stage Docker Image. This is a best practice that is followed as it reduces the size of the image and therefore reduces the time it takes to push/pull the image to/from the registry.
If you do not use a multi-stage Docker Image, this image will be ~350mb compared to using a multi-stage build resulting in the image being ~15mb. This is a huge difference and will help with data transfer costs, storage costs and speed up the deployment process. The Dockerfile is as follows:
FROM golang:1.19.5-alpine3.17 as build
ENV GOPATH /go
WORKDIR $GOPATH/src/app
COPY . .
RUN go mod download
RUN GOOS=linux GOARCH=amd64 go build -ldflags "-s -w" -o website
RUN chmod +x website
FROM alpine:3.17
COPY --from=build go/src/app/views /views
COPY --from=build go/src/app/website /
EXPOSE 3000
ENTRYPOINT [ "/website" ]
Creating a new Azure Container Registry (ACR)
The next step is to set up an Azure Container Registry (ACR) to store the build assets. You can also use alternative registries such as Docker Hub, but ACR is being used in this tutorial.
Note You need to change
myResourceGroup
andmyregistry
to something more meaningful to you. For example,deploytestresourcegroup
anddeploytestregistry
. Please ensure you are changing it throughout all commands in this tutorial.
Step 1 – Open a new terminal in Codespaces and run the following command and follow the prompts to login to your Azure Account:
az login --use-device-code
Step 2 – To create a new Azure Container Registry (ACR) and enable admin access for deployment, run the following commands:
// Create a new resource group
az group create --name myResourceGroup --location westeurope
// Create a new ACR
az acr create --resource-group myResourceGroup --name myregistry --sku Basic
// Enable admin access
az acr update --name myregistry --admin-enabled true
Step 3 – login to the ACR using the following command:
az acr login --name myregistry
Build and push Docker Image to ACR
Once the ACR has been created, the Docker Image can be built and pushed to the registry. The docker commands used here can be run locally (if you have Docker installed) or in Codespaces as a Docker client is provided.
Note You can change the name of the image,
devops-container
to something more meaningful to you but be sure to change it in all commands.
Step 1 – Build the Docker Image using the following command:
docker build --platform linux/amd64 --tag docker.io/devops-container:v1 .
Step 2 – Check the image has been built
docker images
Step 3 – tag the image using the following command:
docker tag docker.io/devops-container:v1 myregistry.azurecr.io/devops-container:v1
Repeat step 2 to check the image has been tagged correctly.
Step 4 – push the image to the ACR using the following command:
docker push myregistry.azurecr.io/devops-container:v1
Deploy application to Azure App Services
Step 1 – Create a new App Service Plan using the following command:
az appservice plan create --name myAppServicePlan --resource-group myResourceGroup --sku B1 --is-linux
Step 2 – Create a new App Service using the following command:
az webapp create --resource-group myResourceGroup --plan myAppServicePlan --name myAppService --deployment-container-image-name myregistry.azurecr.io/devops-container:v1
Note If you see this error in the terminal when you run the command above, then you need to chose a different name for your application: “Webapp ‘myAppService’ already exists. The command will use the existing app’s settings. Unable to retrieve details of the existing app ‘myAppService’. Please check that the app is a part of the current subscription”
Step 3 – Open the App Service in a browser using the following command:
az webapp browse --resource-group myResourceGroup --name myAppService
Warning The app may take a few minutes to start up due to infrastructure being used in this tutorial. If you see an application error, wait a few minutes and reload the page. You can also check the logs in the Azure Portal to see if the application has started.
Create a GitHub Actions Workflow
Now the application has been deployed to App Services, we can create a GitHub Actions Workflow. The workflow is our continuous integration and continuous deployment (CI/CD) pipeline that will build, test and automatically deploy the application to Azure.
In the project root directory there is a .github
directory that contains a workflows
directory. In the workflows
directory there is a deployment.yml
file that contains the GitHub Actions workflow. The code is written in YAML and is whitespace-sensitive so be sure to bare this in mind if you edit the file.
The workflow is as follows:
name: Build a Docker image and push it to ACR
on:
push:
branches: [main]
workflow_dispatch:
env:
TAG: v1
SERVER: myregistry.azurecr.io
IMAGE: devops-container
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.19.5
- name: Test
run: go test -v ./...
- uses: azure/docker-login@v1
with:
login-server: ${{ env.SERVER }}
username: ${{ secrets.ACR_USERNAME }}
password: ${{ secrets.ACR_PASSWORD }}
- run: |
docker build . -t ${{ env.SERVER }}/${{ env.IMAGE }}:${{ env.TAG }}
docker push ${{ env.SERVER }}/${{ env.IMAGE }}:${{ env.TAG }}
Note Make sure to change the
SEVER
,IMAGE
andTAG
values to the same name you changed these too in earlier steps.
This workflow will: – Run on every push to the main branch (or when manually triggered) – Use the latest Ubuntu image – Checkout the repository – Setup Go – Run the repository tests – Login to the ACR – Build the Docker Image and push it to the ACR
Now the workflow is created, we need to add the ACR username and password as secrets to the repository. To do this, go to the repository Settings
and click on Secrets and variables
in the left-hand menu. In this drop-down list click on Actions
and then click the green button New repository secret
. This allows you to store sensitive information in the repository without it being exposed.
Add the following secrets:
- ACR_USERNAME
- ACR_PASSWORD
The values for these secrets can be found in the Azure Portal under the ACR resource or alternatively, you can use the Azure CLI to get the values by running the following command in the terminal:
az acr credential show --name myregistry
Make a change to the application
After successfully deploying and running the application, you will need to enable continuous deployment for the App Service application in the Azure portal by toggling a switch.
To do this, go to the deployed App Service resource in the Azure Portal and click on Deployment Center
in the left-hand menu. In the Settings
blade, scroll to the bottom of the page and turn on Continuous deployment
and then click on Save
.
Now that the workflow is created, it will trigger when there is a change to your main branch, optionally you can manually trigger the workflow. This will deploy changes to your application deployed in Azure.
To test this, go to your application code in your Codespaces environment and create a new branch and make a change to the main.go
file. For example, change the heading title. Save the file and commit and push the change to the repository. Create a Pull Request from the development branch to the main branch on your fork and merge the Pull Request into the main branch.
Alternatively, if you have not created a development branch, you can commit the change directly to the main branch. Either method will trigger the workflow and deploy the changes to the application in Azure App Services.
Give it a go!
Conclusion
This post has encapsulated the core aspects of the DevOps lifecycle and has shown how we can use GitHub Codespaces, GitHub Actions, Azure Container Registry and Azure App Services to create a continuous delivery pipeline that will automatically deploy our application to Azure when a change is made.
Useful resources
Microsoft Learn Modules:
- Explore Azure App Service
- Manage container images in Azure Container Registry
- Introduction to GitHub Actions
YouTube Channels:
0 comments