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:
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
:
FROM gradle:7.2.0-jdk16 as builder
USER rootARG COMMIT_SHA
ADD . .
RUN printf %s ".${COMMIT_SHA}" >> VERSION
RUN gradle --parallel --build-cache -Dorg.gradle.console=plain -Dorg.gradle.daemon=false :shadowJar
###########################################################################FROM openjdk:16-alpine
ENV PORT 80
WORKDIR /app
COPY --from=builder /home/gradle/build/libs/backend_api.jar backend_api.jar
EXPOSE $PORT
CMD java -Xms256m -Xmx256m -Xss512k -jar backend_api.jar
Para probar que nuestra API esta funcionando correctamente dentro de un container, debemos buildearla y correrla.
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
)
![registry](/_astro/registry.DpzxGIqq_1n2QzF.webp)
Le damos al boton “Next” hasta crearlo.
Y si vamos a Container Registry devuelta, podemos ver que ya esta creado:
![cr](/_astro/container-registries.CEJaJ5kA_26avoG.webp)
Dentro de nuestro registry debemos ir a update:
![crd](/_astro/container-registry-detail.VVvr7stf_Z1OLoVk.webp)
Y activar el Admin user
![up](/_astro/update-registry.CcNIccPh_Z1NkjwY.webp)
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.
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:
ldamore@Desktop/azure-container-apps:~ $ az group show --name <your-resource-group-name>
Para crear el “service principal”:
ldamore@Desktop/azure-container-apps:~ $ az ad sp create-for-rbac --scope $resourceGroupId --role Contributor --sdk-auth
Obtendremos un resultado similar a este:
{ "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:
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.
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
:
name: Deploy api
on: push: branches: - main
jobs: build: runs-on: ubuntu-latest
steps: - name: Checkout to the branch uses: actions/checkout@v2 with: path: main
- name: Set up Docker Buildx uses: docker/setup-buildx-action@v1
- name: Log in to container registry uses: docker/login-action@v1 with: registry: kotlinapi.azurecr.io username: ${{ secrets.REGISTRY_USERNAME }} password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Build and push container image to registry uses: docker/build-push-action@v2 with: push: true tags: kotlinapi.azurecr.io/kotlinapi:${{ github.sha }} file: ./Dockerfile
Pushear y comittear
Luego en nuestro repositorio podemos ver que el action se habra activado
![bw](/_astro/build-workflow.CguaeBri_Z1x0QSs.webp)
Y si vemos nuestros repositories en Azure veremos que hay una nueva imagen pusheada.
![imgre](/_astro/image-registry.CEW5FnZa_Z11tlYk.webp)
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”
![cra1](/_astro/create-container-app-1.CoY6UI03_1dsNJg.webp)
En la seccion de App settings debemos desmarcar la opcion “Use quickstart image”. Luego debemos seleccionar nuestro registry, la imagen y el tag.
![cra2](/_astro/create-container-app-2.Ct9gGNX2_Z18rVKB.webp)
En mi caso agregue las environment variables que necesita mi API. Y tambien active para que sea accesible por la internet publica.
![cra1](/_astro/create-container-app-3.Bcszwx_s_Z22ladF.webp)
Una vez creado si volvemos a Container Apps podemos ver que nuestro Container App esta creado y si lo seleccionamos nos saldra la URL.
![cra1](/_astro/created-container-app.BhnSZLmG_Z2wsaos.webp)
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
:
name: Deploy api
on: push: branches: - main
jobs: build: runs-on: ubuntu-latest
steps: - name: Checkout to the branch uses: actions/checkout@v2 with: path: main
- name: Set up Docker Buildx uses: docker/setup-buildx-action@v1
- name: Log in to container registry uses: docker/login-action@v1 with: registry: kotlinapi.azurecr.io username: ${{ secrets.REGISTRY_USERNAME }} password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Build and push container image to registry uses: docker/build-push-action@v2 with: push: true tags: kotlinapi.azurecr.io/kotlinapi:${{ github.sha }} file: ./Dockerfile deploy: runs-on: ubuntu-latest needs: build
steps: - name: Azure Login uses: azure/login@v1 with: creds: ${{ secrets.AZURE_CREDENTIALS }}
- name: Deploy to containerapp uses: azure/CLI@v1 with: inlineScript: | echo "Installing containerapp extension" az extension add --name containerapp --yes echo "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”