Deploy Kotlin API to Azure Container Apps
En este tutorial veremos como deployar una API en Kotlin dockerizada a Azure Container Apps
Contenido
- Crear un repositorio para nuestra API
- Crear una api en kotlin y dockerizarla
- Crear un Azure Container Registry para guardar la imagen de nuestra api
- Buildear y pushear la imagen de nuestra API
- Crear una Azure Container App para deployar la imagen de nuestra api
- Automarizar deploys con GitHub Actions
Crear un repositorio para nuestra API
Lo primero es crear el repositorio de GitHub para luego poder automatizar los deploys con github actions.
Para eso ejecutaremos los siguiente comandos:
bash
ldamore@Desktop:~ $ mkdir azure-container-appsldamore@Desktop:~ $ cd azure-container-appsldamore@Desktop/azure-container-apps:~ $ echo "# azure-container-apps" >> README.mdldamore@Desktop/azure-container-apps:~ $ git initldamore@Desktop/azure-container-apps:~ $ git add README.mdldamore@Desktop/azure-container-apps:~ $ git commit -m "first commit"ldamore@Desktop/azure-container-apps:~ $ git branch -M mainldamore@Desktop/azure-container-apps:~ $ git remote add origin [your-origin]ldamore@Desktop/azure-container-apps:~ $ git push -u origin main
Crear una api en kotlin y dockerizarla
El codigo de la API pueden sacarlo de este repositorio. O pueden codear su propia api. En la de este ejemplo es un simple aplicacion que levanta un http server y escucha peticiones en el puerto que pongas como variable de entorno. Y al enviar un GET a / resibiremos un texto con la frase “Hello World!”
Una vez descargado el codigo (o habiendo creado su propia API) debemos dockerizarla.
Para eso crearemos un archivo .Dockerfile en la raiz del proyecto
En .Dockefile
:
docker
FROM gradle:7.2.0-jdk16 as builderUSER rootARG COMMIT_SHAADD . .RUN printf %s ".${COMMIT_SHA}" >> VERSIONRUN gradle --parallel --build-cache -Dorg.gradle.console=plain -Dorg.gradle.daemon=false :shadowJar###########################################################################FROM openjdk:16-alpineENV PORT 80WORKDIR /appCOPY --from=builder /home/gradle/build/libs/backend_api.jar backend_api.jarEXPOSE $PORTCMD java -Xms256m -Xmx256m -Xss512k -jar backend_api.jar
Para probar que nuestra API esta funcionando correctamente dentro de un container, debemos buildearla y correrla.
bash
ldamore@Desktop/azure-container-apps:~ $ docker image build -t kotlin-api .ldamore@Desktop/azure-container-apps:~ $ docker container run -p 80:80 kotlin-api
Si vamos a http://localhost:80 deberiamos ver lo que nos responde nuestra API.
Crear un Azure Container Registry para guardar la imagen de nuestra api
Debemos entrar a nuestra cuenta en https://portal.azure.com/ y crear un nuevo recurso. El recurso que crearemos sera “Container Registry”.
Luego en Container Registry debemos crear un nuevo resource grupo (en mi caso container-app-example
). Y debemos ponerle un nombre a nuestro registry (en mi caso kotlinapi
)

Le damos al boton “Next” hasta crearlo.
Y si vamos a Container Registry devuelta, podemos ver que ya esta creado:

Dentro de nuestro registry debemos ir a update:

Y activar el Admin user

Buildear y pushear la imagen de nuestra API
Cuando usamos herramientas de CI/CD como github actions para deployar recursos a Azure, necesitamos crear un “service principal” que este autorizado a hacer eso.
Para eso debemos descargar el CLI de Azure y logearnos.
bash
ldamore@Desktop/azure-container-apps:~ $ az login
Una vez logeados, lo primero es obtener el id del resource group donde crearemos un “service principal” y luego crearemos el “service principal”.
Para obtener el resource group id:
bash
ldamore@Desktop/azure-container-apps:~ $ az group show --name <your-resource-group-name>
Para crear el “service principal”:
bash
ldamore@Desktop/azure-container-apps:~ $ az ad sp create-for-rbac --scope $resourceGroupId --role Contributor --sdk-auth
Obtendremos un resultado similar a este:
json
{"clientId": "xxxx6ddc-xxxx-xxxx-xxx-ef78a99dxxxx","clientSecret": "xxxx79dc-xxxx-xxxx-xxxx-aaaaaec5xxxx","subscriptionId": "xxxx251c-xxxx-xxxx-xxxx-bf99a306xxxx","tenantId": "xxxx88bf-xxxx-xxxx-xxxx-2d7cd011xxxx","activeDirectoryEndpointUrl": "https://login.microsoftonline.com","resourceManagerEndpointUrl": "https://management.azure.com/","activeDirectoryGraphResourceId": "https://graph.windows.net/","sqlManagementEndpointUrl": "https://management.core.windows.net:8443/","galleryEndpointUrl": "https://gallery.azure.com/","managementEndpointUrl": "https://management.core.windows.net/"}
Debemos guardar este JSON porque nos servira mas tarde.
El siguiente paso es actualizar el “service principal” para que tenga permisos de pushear y pullear una imagen de nuestro container registry.
Para eso debemos tener el id de nuestro container registry:
bash
ldamore@Desktop/azure-container-apps:~ $ az acr show --name <registry-name> --resource-group <resource-group-name>
Y actualizarlo con el id de nuestro registry y el ClientId del JSON del paso anterior.
bash
ldamore@Desktop/azure-container-apps:~ $ az role assignment create --assignee <ClientId> --scope $registryId --role AcrPush
Una vez hecho esto debemos guardar nuestras credenciales en nuestro Repo:
- Entra a tu repo y navega a Settings > Secrets > Actions.
- Selecciona New repository secret y agrega los siguientes secretos AZURE_CREDENTIALS: el json del paso anterior REGISTRY_USERNAME: el clientId del json del paso anterior REGISTRY_PASSWORD: el clientSecret del json del paso anterior
Por ultimo debemos agregar nuestro script de GitHub Actions que buildeara la imagen y pusheara al registry. En la raiz de nuestro proyecto crearemos una carpeta .github
y dentro de ella una carpeta llamada workflows
dentro de workflows crearemos nuestro script llamado api.yml
Dentro de .github/workflows/api.yml
:
yaml
name: Deploy apion:push:branches:- mainjobs:build:runs-on: ubuntu-lateststeps:- name: Checkout to the branchuses: actions/checkout@v2with:path: main- name: Set up Docker Buildxuses: docker/setup-buildx-action@v1- name: Log in to container registryuses: docker/login-action@v1with:registry: kotlinapi.azurecr.iousername: ${{ secrets.REGISTRY_USERNAME }}password: ${{ secrets.REGISTRY_PASSWORD }}- name: Build and push container image to registryuses: docker/build-push-action@v2with:push: truetags: kotlinapi.azurecr.io/kotlinapi:${{ github.sha }}file: ./Dockerfile
Pushear y comittear
Luego en nuestro repositorio podemos ver que el action se habra activado

Y si vemos nuestros repositories en Azure veremos que hay una nueva imagen pusheada.

Crear una Azure Container App para deployar la imagen de nuestra api
Una vez que ya tenemos el mecanismo para buildear y pushear la imagen a nuestro registry, podemos crear un Container App que tome la imagen de nuestro registry.
Para eso debemos crear un nuevo recurso llamado “Container App”
Luego en Container App debemos seleccionar nuestro resource group y un Container Apps Environment, si no tenemos uno debemos crearlo. En mi caso lo cree con el nombre “staging”

En la seccion de App settings debemos desmarcar la opcion “Use quickstart image”. Luego debemos seleccionar nuestro registry, la imagen y el tag.

En mi caso agregue las environment variables que necesita mi API. Y tambien active para que sea accesible por la internet publica.

Una vez creado si volvemos a Container Apps podemos ver que nuestro Container App esta creado y si lo seleccionamos nos saldra la URL.

Automarizar deploys con GitHub Actions
Una vez ya creado nuestro Container App, podemos automatizar los deploys mediante GitHub Actions. A nuestro workflow ya creado (que buildea la imagen y pushea a nuestro registry), le debemos agregar ahora que update el container con la nueva version de la imagen buildeada.
En .github/workflows/api.yml
:
yaml
name: Deploy apion:push:branches:- mainjobs:build:runs-on: ubuntu-lateststeps:- name: Checkout to the branchuses: actions/checkout@v2with:path: main- name: Set up Docker Buildxuses: docker/setup-buildx-action@v1- name: Log in to container registryuses: docker/login-action@v1with:registry: kotlinapi.azurecr.iousername: ${{ secrets.REGISTRY_USERNAME }}password: ${{ secrets.REGISTRY_PASSWORD }}- name: Build and push container image to registryuses: docker/build-push-action@v2with:push: truetags: kotlinapi.azurecr.io/kotlinapi:${{ github.sha }}file: ./Dockerfiledeploy:runs-on: ubuntu-latestneeds: buildsteps:- name: Azure Loginuses: azure/login@v1with:creds: ${{ secrets.AZURE_CREDENTIALS }}- name: Deploy to containerappuses: azure/CLI@v1with:inlineScript: |echo "Installing containerapp extension"az extension add --name containerapp --yesecho "Starting Deploying"az containerapp update -n <container-app-name> -g <resource-group-name> -i kotlinapi.azurecr.io/kotlinapi:${{ github.sha }} --set-env-vars "PORT=80" --debug
Recuerde cambiar los nombres en “container-app-name” y “resource-group-name”