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.

Diffusion d’une API versionnée dans les environnements cibles.

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.

alt

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:

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:

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:

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:

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.

CI/CD avec l’API Management Azure