Objectifs
L’intégration continue (CI) et le déploiement continue (CD) sont des pratiques indispensables aujourd’hui. Tant pour construire, déployer ou encore configurer une plateforme. Elles sont progressivement absorbées par les pratiques DevOps. Ces pratiques CICD ont pour principaux objectifs de:
- automatiser le build des artefacts,
- automatiser le déploiement de ces artefacts vers des environnements cibles.
Dans le cas de l’API Management pour Azure, il est nécessaire de déployer les éléments suivants:
- les API et leurs contrats respectifs,
- les Policies, stratégies ou traitements internes,
- les BackEnds, cibles des API,
- les NamesValues, ou tables de références externes.
Une version d’une API est alors la combinaison de tous ces éléments. C’est leur combinaison qui est le résultat d’un déploiement vers une plateforme de Recette ou de Production, par exemple.
Chaque API possède son propre cycle de vie. Les étapes de construction, de validation et de déploiement sont temporellement décorrélées les unes des autres API. Au quotidien, chaque API doit être gérée de manière unitaire.
Contextualisation ou Variabilisation
L’automatisation est un point important mais il s’accompagne systématiquement par la capacité à déployer dans plusieurs environnements. Pour cela, il est nécessaire d’intégrer des variables externes aux scripts CI/CD. Un livrable d’un environnement n’est donc pas égal à celui d’un autre.
Avec quels outils ?
Microsoft propose plusieurs outils, complémentaires ou non, pour supporter ces actions. La richesse et la multiplicité des solutions n’aide pas toujours…
Cet article détaille le résultat de mes travaux qui ont pour objectifs de mettre en place un socle de CI/CD complet et efficace pour l’ API Management Azure.
Déploiement par ARM
Description
Par défaut, Microsoft propose une méthode de manipulation de ses ressources avec Azure Resource Manager. Il s’agit de fichiers descriptifs des ressources Azure.
La gestion est guidée par une démarche de gestion de branches git. Par exemple, la production sert de référence. Elle est modifiée dans une branche, testée en recette, qui est réintégrée par la suite.
Exemple
Ci dessous, la définition de l’opération “monOperation” de l’API “monAPI” en JSON.
{
"eTag": ""ABCDEFGBSMs="",
"cache-control": "no-cache",
"connection": "close",
"content-length": "2360",
"content-type": "application/json; charset=utf-8",
"date": "Mon, 07 Mar 2022 09:28:32 GMT",
"expires": "-1",
"pragma": "no-cache",
"server": "Microsoft-HTTPAPI/2.0",
"strict-transport-security": "max-age=31536000; includeSubDomains",
"x-content-type-options": "nosniff",
"x-ms-correlation-request-id": "abcdefgh-512d-4a07-b4b9-123456789",
"x-ms-ratelimit-remaining-subscription-reads": "12345",
"x-ms-request-id": "123456-1234-1234-1234-123456",
"x-ms-routing-request-id": "FRANCECENTRAL:123456789",
"id": "/subscriptions/12345678-1234-1234-1234-123456789/resourceGroups/RG-API-MGMT/providers/Microsoft.ApiManagement/service/Mon-API-Portail/apis/apiName/operations/operationName",
"name": "operationName",
"type": "Microsoft.ApiManagement/service/apis/operations",
"templateParameters": [
{
"name": "id",
"description": "ID du bien.",
"type": "string",
"required": true,
"values": []
}
],
"description": "Ceci est une description.",
"request": {
"queryParameters": [],
"headers": [],
"representations": []
},
"responses": [
{
"statusCode": 200,
"description": "Succès.",
"representations": [
{
"contentType": "application/json",
"sample": "{rn "id": "abc",rn "nom": "demo",rn}",
"schemaId": "621ce69ae774db0464d4dc82",
"typeName": "MonType"
}
],
"headers": []
}
],
"policies": null,
"displayName": "operationName",
"method": "GET",
"urlTemplate": "/chemin/{id}"
}
Avantages
- L’état de chaque ressource est stable.
- Toutes les options de l’API Management sont disponibles via cette méthode descriptive.
- Le déploiement est portable et autonome avec l’aide de Azure CLI (cf ci-dessous).
Inconvénients
- La description des opérations est double: dans le schéma OpenAPI et dans le fichier ARM.
- La démarche proposée nécessite de calquer les environnements API Management sous-jacents sur un 1er.
- Le déploiement par API n’est pas évident. Le merge vers l’environnement de production est cumulatif alors que le déploiement opérationnel des versions ne suit pas le même rythme.
Déploiement avec l’extension Azure DevOps
Description
La 2nde méthode expérimentée est une extension à Azure DevOps, dédiée à l’API Management, développée par Stéphane Eyskens. Celle-ci est opensource et disponible:
- sur GitHub à azure-apim-extension
- sur le portail Azure à stephane-eyskens.apim
Cela permet de définir des tâches dans des Pipeline DevOps pour déclencher des actions sur le socle API Management.
De fait, son intégration est bonne avec les éditeurs éditeurs DevOps.
Exemple
Cet exemple illustre le déploiement d’une policy pour une opération d’API. Cette policy est décrit dans un fichier externe xml.
- task: apimoperationpolicies@5
displayName: 'getIntituleDecompte'
inputs:
ConnectedServiceNameARM: '$(APIM.ARM)'
ResourceGroupName: '$(APIM.resourceGroupName)'
ApiPortalName: '$(APIM.portalName)'
ApiName: '$(ApiKey)$(ApiVersion)'
OperationName: 'getIntituleDecompte'
CurrentRevision: true
MicrosoftApiManagementAPIVersion: '$(MicrosoftApiVersion)'
TemplateSelector: 'Artifact'
policyArtifact: '$(System.DefaultWorkingDirectory)/$(ApiKey)/policies/getIntituleDecompte.xml'
Avantages
- L’intégration aux éditeurs en ligne et à VisualStudio Code.
- Les opérations sont nombreuses: déploiement d’API, d’opérations, etc.
Inconvénients
- L’extension ne prend pas en compte le déploiement par raw-xml. Cela empêche le déploiement de policies complexes avec du C#.
Par exemple, pour un code C# qui contient des éléments de typage, comme:
// Recherche dans la liste issue du referentiel
IList<JToken> itemsPays = listPays.SelectTokens("[?(@.code=='"+pays+"')].id").ToList();
Cela génère des erreurs telles que:
@{code=ValidationError; target=representation; message=The 'JToken' start tag on line 24 position 12 does not match the end tag of 'value'. Line 31, position 16.}
##[error]The remote server returned an error: (400) Bad Request.
- L’autre point négatif est que cette extension n’est pas maintenue depuis 01/2021.
- Il manque des opérations pour les Backend et les NameValues.
Déploiement par Ansible
Description
J’utilise depuis longtemps Ansible dans mes projets DevOps. J’ai tout naturellement tenté de mettre en oeuvre ce mécanisme.
Il existe une collection assez riche pour la partie Azure: azcollection. Elle contient des opérations dédiées à l’API Management:
- azure_rm_apimanagement – Manage Azure api instances
- azure_rm_apimanagement_info – Get the infomation of the API Instance
- azure_rm_apimanagementservice – Manage Azure ApiManagementService instance
- azure_rm_apimanagementservice_info – Get ApiManagementService info.
Exemple
Cet exemple déploie une API à partir de sa définition.
- name: Update an existing API instance.
azure_rm_apimanagement:
resource_group: myResourceGroup
service_name: myService
api_id: testApi
display_name: newTestAPI
service_url: 'http://testapi.example.net/api'
path: myapiPath
protocols:
- https
Avantages
- Les opérations sont intégrés à des scripts ansible.
Inconvénients
- Cette collection n’est pas “utilisable” car elle ne couvre qu’une petite partie du scope. En autre, il n’existe pas de tâche pour manipuler les policies des API.
Déploiement par Script Azure CLI
Description
Microsoft met à disposition un outils de gestion de sa plateforme Azure, en ligne de commande, Azure CLI. Il permet de manipuler les notions Azure par un administrateur ou des bots.
L’option apim de “az” offre ne un panel très large pour manipuler l’ API Management telles que:
- api pour la gestion des API,
- versionset pour la gestion des groupes de révision
- operation pour la gestion des opérations,
- release et revision pour le versionning,
- nv pour les namevalues
- product pour les produits.
Exemple
Cet exemple illustre un script en charge du déploiement d’une API avec azure cli.
az apim api import --path $ApiKey
--resource-group $APIM_resourceGroupName
--service-name $APIM_portalName
--display-name $ApiKey
--specification-format OpenApiJson
--api-revision $ApiRevision
--api-id $API_ID
--api-version $ApiVersion-tests
--api-version-set-id $ApiKey
--protocols https
--specification-path "$ApiKey-v$ApiVersion.json"
--subscription-required true
Avantages
- L’intégration a du script bash offre une souplesse dans la personnalisation. La manipulation des variables est très alors flexible depuis un Pipeline DevOps, par exemple.
- Les actions sont nombreuses.
- 1 seul outil pour manipuler la plateforme Azure.
Inconvénients
- Cet outil en ligne de commande ne publie pas malheureusement pas de policies. La commande operation update ouvre des possibilités mais pas de policies… C’est étrange. Peut-être cela sera-t-il complété dans les prochaines version.
az apim api operation update --api-id $ApiKey-$ApiVersion
--operation-id "$OperationId"
--resource-group $APIM_resourceGroupName
--service-name $APIM_portalName
Déploiement par Script PowerShell
Description
Azure PowerShell est en une bibliothèque de fonctions et de types pour Microsoft PowerShell.
Avec cet outil, il s’agit de construire des tâches par script. De nombreuses fonctions sont mises à disposition telles que:
- Get-AzApiManagementApiSchema: pour l’import d’API depuis un shéma OpenAPI par exemple,
- Set-AzApiManagementOperation: pour la création d’opération,
- Set-AzApiManagementPolicy: pour le chargement de policies XML.
Exemple
Déploiement d’une API avec PowerShell:
$apimContext = New-AzApiManagementContext -ResourceGroupName $env:APIM_resourceGroupName -ServiceName $env:APIM_portalName
$apiId = $env:ApiKey + $env:ApiVersion
Set-AzApiManagementPolicy -Context $apimContext `
-ApiId $apiId `
-OperationId $env:OperationId `
-Format "application/vnd.ms-azure-apim.policy.raw+xml" `
-PolicyFilePath .$env:ApiKeypolicies$env:OperationId.xml
Les tâches de Pipeline sont alors de simples appels de script PowerShell.
- task: AzurePowerShell@5
displayName: "Update policy of monOperation"
inputs:
azureSubscription: '${{ parameters.ServiceARM }}'
ScriptType: 'FilePath'
ScriptPath: '$(Build.SourcesDirectory)setOperationPolicy.ps1'
preferredAzurePowerShellVersion: latestVersion
env:
OperationId: monOperation
ApiKey: $(ApiKey)
ApiVersion: '${{ parameters.ApiVersion }}'
APIM_resourceGroupName: '${{ parameters.APIM_resourceGroupName }}'
APIM_portalName: '${{ parameters.APIM_portalName }}'
Avantages
- Toutes les opérations sont à disposition: Policies, API, NamedValues, etc.
- Le scripting permet d’adapter les environnements sans les figer.
- La variabilisation du scripting shell facilite son intégration dans les Pipelines CI/CD.
Inconvénients
- Avec PWSH, les actions sont unitaires.
- Il faut apprendre le PowerShell.
Conclusion
Comme vous l’avez peut-être compris, il n’y a que 2 outils qui permettent de répondre aux besoins complets de l’Intégration Continue et du Déploiement Continue pour Azure API Management:
- Azure Resource Manager,
- Azure PowerShell.
Le choix entre ces 2 outils est à mon sens une histoire de principe et de doctrine. Azure Resource Manager configure les ressources par description. Azure PowerShell exécute des actions quelque soit son état.