Si estás desarrollando tu aplicación web o API en Go es posible que quieras valorar el uso de Azure App Service para hospedarla. Si bien todavía está en fase experimental, en este artículo te comparto cómo puedes probarlo de forma sencilla.
Aplicación de ejemplo
Para poder mostrarte cómo hacerlo he usado una versión de mi API de Tour of Heroes en Go 🤓. En ella he usado Gin para crear mi API y GORM para interactuar con un SQL Server, ya sea en local usando Docker o en Azure con SQL Database.
Nota: Para este artículo se asume que tienes instalado Go 1.19 en tu local y Docker.
Si quieres ejecutar el ejemplo en local, puedes crear la base de datos con los siguientes comandos:
# Create a network
docker network create sqlserver-vnet
# Create a container with Azure SQL edge
docker run \
--name azuresqledge \
--network sqlserver-vnet \
--cap-add SYS_PTRACE -e 'ACCEPT_EULA=1' \
-e 'MSSQL_SA_PASSWORD=Password1!' \
-v mssqlserver_volume:/var/opt/mssql \
-p 1433:1433 \
-d mcr.microsoft.com/azure-sql-edge
#Create a database
docker run -it --network sqlserver-vnet mcr.microsoft.com/mssql-tools
sqlcmd -S azuresqledge -U SA -P 'Password1!' -Q 'CREATE DATABASE [heroes]'
exit
Este código utiliza un archivo .env para almacenar las variables de entorno que usarás en tu local y que posteriormente se sobreescribirán con las que configuremos en App Service.
DB_CONNECTION_STRING="sqlserver://sa:Password1!@localhost:1433?database=heroes"
PORT=3030
Puedes revisar el código de la API en el repositorio de GitHub, pero si te fijas en el archivo main.go verás la definición de una API REST con varios HTTP Verbs configurados.
package main
import (
"fmt"
"os"
"tour-of-heroes-api-go/controllers"
"tour-of-heroes-api-go/models"
"github.com/gin-gonic/gin"
"github.com/joho/godotenv"
)
func main() {
// Load the .env file in the current directory
godotenv.Load()
router := gin.Default()
router.GET("/", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "Welcome to the Tour of Heroes API",
})
})
router.GET("/api/hero", controllers.GetHeroes)
router.POST("/api/hero", controllers.CreateHero)
router.GET("/api/hero/:id", controllers.FindHero)
router.PATCH("/api/hero/:id", controllers.UpdateHero)
router.DELETE("/api/hero/:id", controllers.DeleteHero)
models.ConnectDatabase()
port := os.Getenv("PORT")
err := router.Run(fmt.Sprintf(":%v", port))
if err != nil {
return
}
}
Si ejecutas el código a través del siguiente comando:
go run .
Podrás acceder a la API a través de http://localhost:3030 y jugar con las diferentes rutas mostradas en main.go. Para poder interactuar un poco con la misma puedes utilizar el archivo client.http, que forma parte del repo, para que puedas recuperar, añadir, modificar y eliminar héroes.
Ahora que ya has visto que todo funciona correctamente en tu local, te muestro cómo desplegarlo en Azure.
Desplegar la aplicación de ejemplo en Azure App Service (y SQL Database)
Como has podido ver en el apartado anterior, esta aplicación consta de dos partes: una web desarrollada en Go y la base de datos donde almacena los héroes. Empecemos por la web:
Para desplegar el código incluido este repo tenemos un comando de Azure CLI que nos facilita enormemente trabajo, que es az webapp up:
# Variables
APP_NAME="tour-of-heroes-api-go"
RESOURCE_GROUP="tour-of-heroes-golang"
LOCATION="westeurope"
SQL_SERVER_NAME="tour-of-heroes-sql"
DB_NAME="tour-of-heroes-db"
# Deploy API to Azure
az webapp up \
--runtime "GO:1.19" \
--name $APP_NAME \
--resource-group $RESOURCE_GROUP \
--sku B1 \
--os linux \
--location $LOCATION
Este podría recibir menos parámetros de los que te muestro, pero en mi caso quería indicarle directamente el runtime a utilizar, el nombre que quiero para la web, así como el grupo de recursos donde quiero desplegar mi aplicación. Si te fijas, este comando va a generar incluso el grupo de recursos por mi y también va a empaquetar todo el código incluido en la ruta desde donde lanzo el comando para desplegarlo en el App Service que genere.
Sin embargo, para que este ejemplo funcione correctamente es necesario desplegar además una base de datos que nuestra API sea capaz de alcanzar. Para ello, necesitas ejecutar los siguientes comandos:
# Create SQL Server
SQL_USER_NAME="tour-of-heroes"
SQL_PASSWORD='Password1!'
az sql server create \
--resource-group $RESOURCE_GROUP \
--name $SQL_SERVER_NAME \
--location $LOCATION \
--admin-user $SQL_USER_NAME \
--admin-password $SQL_PASSWORD
# Allow Azure App Service to access SQL Server
az sql server firewall-rule create \
--resource-group $RESOURCE_GROUP \
--server $SQL_SERVER_NAME \
--name "AllowAzureServices" \
--start-ip-address 0.0.0.0 --end-ip-address 0.0.0.0
# Create SQL Database
az sql db create \
--resource-group $RESOURCE_GROUP \
--server $SQL_SERVER_NAME \
--name $DB_NAME
Una vez que la base de datos está generada, el último paso es actualizar las settings de la web app con la cadena de conexión a esta:
# Add environment variable to Azure App Service
az webapp config appsettings set \
--resource-group $RESOURCE_GROUP \
--name $APP_NAME \
--settings "DB_CONNECTION_STRING=sqlserver://$SQL_USER_NAME:$SQL_PASSWORD@$SQL_SERVER_NAME.database.windows.net:1433?database=$DB_NAME"
Cuando se reinicie el sitio, debido a estos cambios, podremos acceder a la URL generada, utilizando este comando:
# Browse to the Azure App Service
az webapp browse --resource-group $RESOURCE_GROUP --name $APP_NAME
y deberíamos de ver algo como lo siguiente:
Puedes revisar también los logs generados por tu app con este otro comando:
# See logs
az webapp log tail --resource-group $RESOURCE_GROUP --name $APP_NAME
Por último reutiliza el archivo client.http, modificando la URL de las peticiones, para comprobar que efectivamente nuestra API en Go funciona perfectamente en Azure App Service.
¡Saludos!