Jekyll2023-10-02T16:52:50+00:00https://damienaicheh.github.io/feed.xmlDamien AichehMobile, Xamarin, Azure DevOps, Tutorials, Quick Tips and moreDamien AichehAdd Azure Managed Grafana to monitor your Azure Container Apps with Terraform2023-05-11T06:00:00+00:002023-05-11T06:00:00+00:00https://damienaicheh.github.io/terraform/azure/azure-container-apps/2023/05/11/azure-container-apps-grafana-terraform-en<p>In this tutorial you will deploy Azure Managed Grafana to monitor your Azure Container Apps defined in the <strong><a href="/terraform/azure/azure-container-apps/2023/05/09/azure-container-apps-use-secrets-terraform-en.html">previous tutorial</a></strong>. The source code is available in this <strong><a href="https://github.com/damienaicheh/fruits-on-azure-container-apps">Github</a></strong> repository.</p>
<p>This tutorial is part of a <strong><a href="/terraform/azure/azure-container-apps/2023/05/01/azure-container-apps-terraform-series-en.html">full series</a></strong> of tutorials on using Azure Container Apps with Terraform.</p>
<h2 id="configure-your-azure-subscription">Configure your Azure subscription</h2>
<p>Before you can deploy Azure Managed Grafana, you need to configure your Azure subscription to use it. To do that, you need to register the <code class="language-plaintext highlighter-rouge">Microsoft.Dashboard</code> resource provider.</p>
<p>To register the <code class="language-plaintext highlighter-rouge">Microsoft.Dashboard</code> resource provider, you can use the Azure CLI:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Register</span>
az provider register <span class="nt">--namespace</span> <span class="s1">'Microsoft.Dashboard'</span>
<span class="c"># Check the registration status</span>
az provider show <span class="nt">-n</span> Microsoft.Dashboard
</code></pre></div></div>
<h2 id="deploy-azure-managed-grafana">Deploy Azure Managed Grafana</h2>
<p>Deploying Azure Managed Grafana is pretty straightforward. You just need to add the following resource to your Terraform definition:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">resource</span> <span class="dl">"</span><span class="s2">azurerm_dashboard_grafana</span><span class="dl">"</span> <span class="dl">"</span><span class="s2">this</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="nx">format</span><span class="p">(</span><span class="dl">"</span><span class="s2">amg-%s</span><span class="dl">"</span><span class="p">,</span> <span class="nx">local</span><span class="p">.</span><span class="nx">resource_suffix_kebabcase</span><span class="p">)</span>
<span class="nx">resource_group_name</span> <span class="o">=</span> <span class="nx">azurerm_resource_group</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">name</span>
<span class="nx">location</span> <span class="o">=</span> <span class="nx">azurerm_resource_group</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">location</span>
<span class="nx">api_key_enabled</span> <span class="o">=</span> <span class="kc">false</span>
<span class="nx">deterministic_outbound_ip_enabled</span> <span class="o">=</span> <span class="kc">false</span>
<span class="nx">public_network_access_enabled</span> <span class="o">=</span> <span class="kc">true</span>
<span class="nx">identity</span> <span class="p">{</span>
<span class="nx">type</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">SystemAssigned</span><span class="dl">"</span>
<span class="p">}</span>
<span class="nx">tags</span> <span class="o">=</span> <span class="nx">local</span><span class="p">.</span><span class="nx">tags</span>
<span class="p">}</span>
</code></pre></div></div>
<h2 id="configure-azure-managed-grafana">Configure Azure Managed Grafana</h2>
<p>To be able to access the Azure Managed Grafana instance, you need to manage identities. In fact, you need to give the <code class="language-plaintext highlighter-rouge">Grafana Viewer</code>, <code class="language-plaintext highlighter-rouge">Grafana Editor</code> and <code class="language-plaintext highlighter-rouge">Monitoring Reader</code> role to the Azure Managed Grafana instance.</p>
<p>To do that, create a new file called <code class="language-plaintext highlighter-rouge">roles.tf</code> and add:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">resource</span> <span class="dl">"</span><span class="s2">azurerm_role_assignment</span><span class="dl">"</span> <span class="dl">"</span><span class="s2">grafana_viewer</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">scope</span> <span class="o">=</span> <span class="nx">azurerm_resource_group</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">id</span>
<span class="nx">role_definition_name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">Grafana Viewer</span><span class="dl">"</span>
<span class="nx">principal_id</span> <span class="o">=</span> <span class="nx">azurerm_dashboard_grafana</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">identity</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">principal_id</span>
<span class="p">}</span>
<span class="nx">resource</span> <span class="dl">"</span><span class="s2">azurerm_role_assignment</span><span class="dl">"</span> <span class="dl">"</span><span class="s2">grafana_editor</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">scope</span> <span class="o">=</span> <span class="nx">azurerm_resource_group</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">id</span>
<span class="nx">role_definition_name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">Grafana Editor</span><span class="dl">"</span>
<span class="nx">principal_id</span> <span class="o">=</span> <span class="nx">azurerm_dashboard_grafana</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">identity</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">principal_id</span>
<span class="p">}</span>
<span class="nx">resource</span> <span class="dl">"</span><span class="s2">azurerm_role_assignment</span><span class="dl">"</span> <span class="dl">"</span><span class="s2">monitor_reader</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">scope</span> <span class="o">=</span> <span class="nx">azurerm_resource_group</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">id</span>
<span class="nx">role_definition_name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">Monitoring Reader</span><span class="dl">"</span>
<span class="nx">principal_id</span> <span class="o">=</span> <span class="nx">azurerm_dashboard_grafana</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">identity</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">principal_id</span>
<span class="p">}</span>
</code></pre></div></div>
<p>And for each users you want to give access and ability to configure the Azure Managed Grafana, you also need to give the <code class="language-plaintext highlighter-rouge">Grafana Viewer</code>, <code class="language-plaintext highlighter-rouge">Grafana Editor</code> and <code class="language-plaintext highlighter-rouge">Monitoring Reader</code> role.</p>
<p>In your <code class="language-plaintext highlighter-rouge">locals.tf</code> file, declare a list of user identities:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">users_identities</span> <span class="o">=</span> <span class="p">[</span><span class="dl">"</span><span class="s2">USE-YOUR-OWN-IDENTITY-HERE</span><span class="dl">"</span><span class="p">]</span>
</code></pre></div></div>
<p>Then go back to the <code class="language-plaintext highlighter-rouge">roles.tf</code> file and add the following resource:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">resource</span> <span class="dl">"</span><span class="s2">azurerm_role_assignment</span><span class="dl">"</span> <span class="dl">"</span><span class="s2">users_grafana_viewer</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">for_each</span> <span class="o">=</span> <span class="nx">toset</span><span class="p">(</span><span class="nx">local</span><span class="p">.</span><span class="nx">users_identities</span><span class="p">)</span>
<span class="nx">scope</span> <span class="o">=</span> <span class="nx">azurerm_resource_group</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">id</span>
<span class="nx">role_definition_name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">Grafana Viewer</span><span class="dl">"</span>
<span class="nx">principal_id</span> <span class="o">=</span> <span class="nx">each</span><span class="p">.</span><span class="nx">key</span>
<span class="p">}</span>
<span class="nx">resource</span> <span class="dl">"</span><span class="s2">azurerm_role_assignment</span><span class="dl">"</span> <span class="dl">"</span><span class="s2">users_grafana_editor</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">for_each</span> <span class="o">=</span> <span class="nx">toset</span><span class="p">(</span><span class="nx">local</span><span class="p">.</span><span class="nx">users_identities</span><span class="p">)</span>
<span class="nx">scope</span> <span class="o">=</span> <span class="nx">azurerm_resource_group</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">id</span>
<span class="nx">role_definition_name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">Grafana Editor</span><span class="dl">"</span>
<span class="nx">principal_id</span> <span class="o">=</span> <span class="nx">each</span><span class="p">.</span><span class="nx">key</span>
<span class="p">}</span>
<span class="nx">resource</span> <span class="dl">"</span><span class="s2">azurerm_role_assignment</span><span class="dl">"</span> <span class="dl">"</span><span class="s2">users_monitor_reader</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">for_each</span> <span class="o">=</span> <span class="nx">toset</span><span class="p">(</span><span class="nx">local</span><span class="p">.</span><span class="nx">users_identities</span><span class="p">)</span>
<span class="nx">scope</span> <span class="o">=</span> <span class="nx">azurerm_resource_group</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">id</span>
<span class="nx">role_definition_name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">Monitoring Reader</span><span class="dl">"</span>
<span class="nx">principal_id</span> <span class="o">=</span> <span class="nx">each</span><span class="p">.</span><span class="nx">key</span>
<span class="p">}</span>
</code></pre></div></div>
<h2 id="run-terraform">Run Terraform</h2>
<p>It’s now time to deploy the Azure Managed Grafana. Just run Terraform plan command and apply it:</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>terraform plan <span class="nt">--out</span><span class="o">=</span>plan.out
</code></pre></div></div>
<p>Then:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>terraform apply plan.out
</code></pre></div></div>
<h2 id="access-and-configure-azure-managed-grafana">Access and configure Azure Managed Grafana</h2>
<p>Go to the Azure portal and into the Azure Managed Grafana instance with one of the users you gave access to. Then let’s configure it by adding these two dashboard:</p>
<ul>
<li><a href="https://grafana.com/grafana/dashboards/16591-azure-container-apps-aggregate-view/">Azure Container Apps Aggregate View</a></li>
<li><a href="https://grafana.com/grafana/dashboards/16592-azure-container-apps-container-app-view/">Azure Container Apps Container App View</a></li>
</ul>
<p>To do that, in the left panel click on <code class="language-plaintext highlighter-rouge">Dashboard</code> and then <code class="language-plaintext highlighter-rouge">import</code>. Copy paste the url and click on <code class="language-plaintext highlighter-rouge">Load</code>. Then select Azure Monitor and click on <code class="language-plaintext highlighter-rouge">Import</code>.</p>
<p><img src="https://damienaicheh.github.io/assets/posts/2023-05-11-import-grafana-dashboard.png" alt="Import dashboard" /></p>
<p>Repeated the operation for the second dashboard.</p>
<p>Now, if you navigate to the first dashboard you will see the list of your containers apps:
<img src="https://damienaicheh.github.io/assets/posts/2023-05-11-grafana-dashboard-1.png" alt="Dashboard 1" /></p>
<p>And if you click on one, you will be redirect to the second dashboard to see the details of the container app:
<img src="https://damienaicheh.github.io/assets/posts/2023-05-11-grafana-dashboard-2.png" alt="Dashboard 2" /></p>
<h2 id="final-touch">Final touch</h2>
<p>The Azure Managed Grafana instance is deployed and configured. You can now start to monitor your Azure Container Apps. You will find the complete source code in this <strong><a href="https://github.com/damienaicheh/fruits-on-azure-container-apps">Github</a></strong> repository.</p>Damien AichehMonitor your environmentsAjoutez Azure Managed Grafana pour monitorer votre Azure Container Apps avec Terraform2023-05-11T06:00:00+00:002023-05-11T06:00:00+00:00https://damienaicheh.github.io/terraform/azure/azure-container-apps/2023/05/11/azure-container-apps-grafana-terraform-fr<p>Dans ce tutoriel, vous allez déployer Azure Managed Grafana pour monitorer vos Azure Container Apps définies dans le <strong><a href="/terraform/azure/azure-container-apps/2023/05/09/azure-container-apps-use-secrets-terraform-fr.html">tutoriel précédent</a></strong>. Le code source est disponible dans ce répertoire <strong><a href="https://github.com/damienaicheh/fruits-on-azure-container-apps">Github</a></strong>.</p>
<p>Ce tutoriel fait partie d’une <strong><a href="/terraform/azure/azure-container-apps/2023/05/01/azure-container-apps-terraform-series-fr.html">série complète</a></strong> de tutoriel sur l’utilisation d’Azure Container Apps avec Terraform.</p>
<h2 id="configurez-votre-souscription-azure">Configurez votre souscription Azure</h2>
<p>Avant de pouvoir déployer Azure Managed Grafana, vous devez configurer votre souscription Azure pour l’utiliser. Pour ce faire, vous devez enregistrer le provider de ressources <code class="language-plaintext highlighter-rouge">Microsoft.Dashboard</code>.</p>
<p>Pour enregistrer le provider de ressources <code class="language-plaintext highlighter-rouge">Microsoft.Dashboard</code>, vous pouvez utiliser l’Azure CLI:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Register</span>
az provider register <span class="nt">--namespace</span> <span class="s1">'Microsoft.Dashboard'</span>
<span class="c"># Check the registration status</span>
az provider show <span class="nt">-n</span> Microsoft.Dashboard
</code></pre></div></div>
<h2 id="déployer-azure-managed-grafana">Déployer Azure Managed Grafana</h2>
<p>Le déploiement d’Azure Managed Grafana est assez simple. Il vous suffit d’ajouter la ressource suivante à votre définition Terraform :</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">resource</span> <span class="dl">"</span><span class="s2">azurerm_dashboard_grafana</span><span class="dl">"</span> <span class="dl">"</span><span class="s2">this</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="nx">format</span><span class="p">(</span><span class="dl">"</span><span class="s2">amg-%s</span><span class="dl">"</span><span class="p">,</span> <span class="nx">local</span><span class="p">.</span><span class="nx">resource_suffix_kebabcase</span><span class="p">)</span>
<span class="nx">resource_group_name</span> <span class="o">=</span> <span class="nx">azurerm_resource_group</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">name</span>
<span class="nx">location</span> <span class="o">=</span> <span class="nx">azurerm_resource_group</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">location</span>
<span class="nx">api_key_enabled</span> <span class="o">=</span> <span class="kc">false</span>
<span class="nx">deterministic_outbound_ip_enabled</span> <span class="o">=</span> <span class="kc">false</span>
<span class="nx">public_network_access_enabled</span> <span class="o">=</span> <span class="kc">true</span>
<span class="nx">identity</span> <span class="p">{</span>
<span class="nx">type</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">SystemAssigned</span><span class="dl">"</span>
<span class="p">}</span>
<span class="nx">tags</span> <span class="o">=</span> <span class="nx">local</span><span class="p">.</span><span class="nx">tags</span>
<span class="p">}</span>
</code></pre></div></div>
<h2 id="configurer-azure-managed-grafana">Configurer Azure Managed Grafana</h2>
<p>Pour pouvoir accéder à l’instance Azure Managed Grafana, vous devez gérer les identités. En effet, vous devez donner le rôle <code class="language-plaintext highlighter-rouge">Grafana Viewer</code>, <code class="language-plaintext highlighter-rouge">Grafana Editor</code> et <code class="language-plaintext highlighter-rouge">Monitoring Reader</code> à l’instance Azure Managed Grafana.</p>
<p>Pour ce faire, créez un nouveau fichier appelé <code class="language-plaintext highlighter-rouge">roles.tf</code> et ajoutez :</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">resource</span> <span class="dl">"</span><span class="s2">azurerm_role_assignment</span><span class="dl">"</span> <span class="dl">"</span><span class="s2">grafana_viewer</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">scope</span> <span class="o">=</span> <span class="nx">azurerm_resource_group</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">id</span>
<span class="nx">role_definition_name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">Grafana Viewer</span><span class="dl">"</span>
<span class="nx">principal_id</span> <span class="o">=</span> <span class="nx">azurerm_dashboard_grafana</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">identity</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">principal_id</span>
<span class="p">}</span>
<span class="nx">resource</span> <span class="dl">"</span><span class="s2">azurerm_role_assignment</span><span class="dl">"</span> <span class="dl">"</span><span class="s2">grafana_editor</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">scope</span> <span class="o">=</span> <span class="nx">azurerm_resource_group</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">id</span>
<span class="nx">role_definition_name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">Grafana Editor</span><span class="dl">"</span>
<span class="nx">principal_id</span> <span class="o">=</span> <span class="nx">azurerm_dashboard_grafana</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">identity</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">principal_id</span>
<span class="p">}</span>
<span class="nx">resource</span> <span class="dl">"</span><span class="s2">azurerm_role_assignment</span><span class="dl">"</span> <span class="dl">"</span><span class="s2">monitor_reader</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">scope</span> <span class="o">=</span> <span class="nx">azurerm_resource_group</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">id</span>
<span class="nx">role_definition_name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">Monitoring Reader</span><span class="dl">"</span>
<span class="nx">principal_id</span> <span class="o">=</span> <span class="nx">azurerm_dashboard_grafana</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">identity</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">principal_id</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Et pour chaque utilisateur auquel vous souhaitez accorder l’accès et la possibilité de configurer Azure Managed Grafana, vous devez également attribuer les rôles <code class="language-plaintext highlighter-rouge">Grafana Viewer</code>, <code class="language-plaintext highlighter-rouge">Grafana Editor</code> et <code class="language-plaintext highlighter-rouge">Monitoring Reader</code>.</p>
<p>Dans votre fichier <code class="language-plaintext highlighter-rouge">locals.tf</code>, déclarez une liste d’identités d’utilisateur :</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">users_identities</span> <span class="o">=</span> <span class="p">[</span><span class="dl">"</span><span class="s2">USE-YOUR-OWN-IDENTITY-HERE</span><span class="dl">"</span><span class="p">]</span>
</code></pre></div></div>
<p>Revenez ensuite au fichier <code class="language-plaintext highlighter-rouge">roles.tf</code> et ajoutez la ressource suivante :</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">resource</span> <span class="dl">"</span><span class="s2">azurerm_role_assignment</span><span class="dl">"</span> <span class="dl">"</span><span class="s2">users_grafana_viewer</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">for_each</span> <span class="o">=</span> <span class="nx">toset</span><span class="p">(</span><span class="nx">local</span><span class="p">.</span><span class="nx">users_identities</span><span class="p">)</span>
<span class="nx">scope</span> <span class="o">=</span> <span class="nx">azurerm_resource_group</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">id</span>
<span class="nx">role_definition_name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">Grafana Viewer</span><span class="dl">"</span>
<span class="nx">principal_id</span> <span class="o">=</span> <span class="nx">each</span><span class="p">.</span><span class="nx">key</span>
<span class="p">}</span>
<span class="nx">resource</span> <span class="dl">"</span><span class="s2">azurerm_role_assignment</span><span class="dl">"</span> <span class="dl">"</span><span class="s2">users_grafana_editor</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">for_each</span> <span class="o">=</span> <span class="nx">toset</span><span class="p">(</span><span class="nx">local</span><span class="p">.</span><span class="nx">users_identities</span><span class="p">)</span>
<span class="nx">scope</span> <span class="o">=</span> <span class="nx">azurerm_resource_group</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">id</span>
<span class="nx">role_definition_name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">Grafana Editor</span><span class="dl">"</span>
<span class="nx">principal_id</span> <span class="o">=</span> <span class="nx">each</span><span class="p">.</span><span class="nx">key</span>
<span class="p">}</span>
<span class="nx">resource</span> <span class="dl">"</span><span class="s2">azurerm_role_assignment</span><span class="dl">"</span> <span class="dl">"</span><span class="s2">users_monitor_reader</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">for_each</span> <span class="o">=</span> <span class="nx">toset</span><span class="p">(</span><span class="nx">local</span><span class="p">.</span><span class="nx">users_identities</span><span class="p">)</span>
<span class="nx">scope</span> <span class="o">=</span> <span class="nx">azurerm_resource_group</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">id</span>
<span class="nx">role_definition_name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">Monitoring Reader</span><span class="dl">"</span>
<span class="nx">principal_id</span> <span class="o">=</span> <span class="nx">each</span><span class="p">.</span><span class="nx">key</span>
<span class="p">}</span>
</code></pre></div></div>
<h2 id="lancer-terraform">Lancer Terraform</h2>
<p>Il est maintenant temps de déployer Azure Managed Grafana. Exécutez simplement la commande Terraform <code class="language-plaintext highlighter-rouge">plan</code> et appliquez-la :</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>terraform plan <span class="nt">--out</span><span class="o">=</span>plan.out
</code></pre></div></div>
<p>Puis:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>terraform apply plan.out
</code></pre></div></div>
<h2 id="accéder-et-configurer-azure-managed-grafana">Accéder et configurer Azure Managed Grafana</h2>
<p>Accédez au portail Azure puis à l’instance Azure Managed Grafana avec l’un des utilisateurs auxquels vous avez donné accès. Ensuite, configurez-le en ajoutant ces deux tableaux de bord :</p>
<ul>
<li><a href="https://grafana.com/grafana/dashboards/16591-azure-container-apps-aggregate-view/">Azure Container Apps Aggregate View</a></li>
<li><a href="https://grafana.com/grafana/dashboards/16592-azure-container-apps-container-app-view/">Azure Container Apps Container App View</a></li>
</ul>
<p>Pour ce faire, dans le panneau de gauche, cliquez sur <code class="language-plaintext highlighter-rouge">Dashboard</code>, puis sur <code class="language-plaintext highlighter-rouge">import</code>. Copiez-collez l’URL et cliquez sur <code class="language-plaintext highlighter-rouge">Load</code>. Sélectionnez ensuite Azure Monitor et cliquez sur <code class="language-plaintext highlighter-rouge">Import</code>.</p>
<p><img src="https://damienaicheh.github.io/assets/posts/2023-05-11-import-grafana-dashboard.png" alt="Import dashboard" /></p>
<p>Répéter l’opération pour le deuxième tableau de bord.</p>
<p>Maintenant, si vous accédez au premier tableau de bord, vous verrez la liste de vos container apps :
<img src="https://damienaicheh.github.io/assets/posts/2023-05-11-grafana-dashboard-1.png" alt="Dashboard 1" /></p>
<p>Et si vous cliquez sur l’un d’entre eux, vous serez redirigé vers le deuxième tableau de bord pour voir les détails de votre container App :
<img src="https://damienaicheh.github.io/assets/posts/2023-05-11-grafana-dashboard-2.png" alt="Dashboard 2" /></p>
<h2 id="touche-finale">Touche finale</h2>
<p>L’instance Azure Managed Grafana est déployée et configurée. Vous pouvez maintenant commencer à monitorer votre Azure Container Apps. Vous trouverez le code source complet dans ce répertoire <strong><a href="https://github.com/damienaicheh/fruits-on-azure-container-apps">Github</a></strong>.</p>Damien AichehMonitor your environmentsDefine secrets and environment variables in Azure Container Apps using Terraform2023-05-09T06:00:00+00:002023-05-09T06:00:00+00:00https://damienaicheh.github.io/terraform/azure/azure-container-apps/2023/05/09/azure-container-apps-use-secrets-terraform-en<p>In this tutorial you will finalize the terraform definition you did in the <strong><a href="/terraform/azure/azure-container-apps/2023/05/07/azure-container-apps-define-containers-terraform-en.html">previous tutorial</a></strong> for your frontend and backend containers using Terraform. The source code is available in this <strong><a href="https://github.com/damienaicheh/fruits-on-azure-container-apps">Github</a></strong> repository.</p>
<p>This tutorial is part of a <strong><a href="/terraform/azure/azure-container-apps/2023/05/01/azure-container-apps-terraform-series-en.html">full series</a></strong> of tutorials on using Azure Container Apps with Terraform.</p>
<h2 id="use-secrets">Use secrets</h2>
<p>In the two containers app you need specify password to access the Azure Container Registry to retrieve the Docker images. To do that, you need to define the <code class="language-plaintext highlighter-rouge">password_secret_name</code> attribute of the <code class="language-plaintext highlighter-rouge">registry</code> block inside the <code class="language-plaintext highlighter-rouge">azurerm_container_app</code> resource.</p>
<p>So inside your <code class="language-plaintext highlighter-rouge">container-api.tf</code> <strong>and</strong> <code class="language-plaintext highlighter-rouge">container-web.tf</code> files, you need to declare a secret to store the admin password of the Azure Container Registry just before the <code class="language-plaintext highlighter-rouge">registry</code> block:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">secret</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">container-registry-password</span><span class="dl">"</span>
<span class="nx">value</span> <span class="o">=</span> <span class="nx">azurerm_container_registry</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">admin_password</span>
<span class="p">}</span>
</code></pre></div></div>
<p>As you can see the secret is defined with the name <code class="language-plaintext highlighter-rouge">container-registry-password</code>. Now you can use this name as a reference to consume it in the <code class="language-plaintext highlighter-rouge">registry</code> block.</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">registry</span> <span class="p">{</span>
<span class="nx">server</span> <span class="o">=</span> <span class="nx">azurerm_container_registry</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">login_server</span>
<span class="nx">username</span> <span class="o">=</span> <span class="nx">azurerm_container_registry</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">admin_username</span>
<span class="nx">password_secret_name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">container-registry-password</span><span class="dl">"</span>
<span class="p">}</span>
</code></pre></div></div>
<h2 id="define-environment-varibles">Define environment varibles</h2>
<p>In the backend container you need to define the <code class="language-plaintext highlighter-rouge">MONGODB_URI</code> environment variable to connect to the Azure Cosmos Db database. To do that, you need to define an <code class="language-plaintext highlighter-rouge">env</code> attribute in the <code class="language-plaintext highlighter-rouge">container</code> attribute of your <code class="language-plaintext highlighter-rouge">azurerm_container_app</code> resource.</p>
<p>Remember that you don’t want to expose the connection string in clear text, you will use a secret to store it and reference it inside the environment variable.</p>
<p>So inside your <code class="language-plaintext highlighter-rouge">container-api.tf</code> file, you will add a secret:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">secret</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">mongodb-connection-string</span><span class="dl">"</span>
<span class="nx">value</span> <span class="o">=</span> <span class="nx">azurerm_cosmosdb_account</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">connection_strings</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="p">}</span>
</code></pre></div></div>
<p>and the <code class="language-plaintext highlighter-rouge">env</code> attribute to your container <code class="language-plaintext highlighter-rouge">container</code> block:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">env</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">MONGODB_URI</span><span class="dl">"</span>
<span class="nx">secret_name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">mongodb-connection-string</span><span class="dl">"</span>
<span class="p">}</span>
</code></pre></div></div>
<p>In the frontend container you need to define the <code class="language-plaintext highlighter-rouge">API</code> environment variable to connect to the backend container, so just reference the fqdn of the backend container. In the <code class="language-plaintext highlighter-rouge">container-web.tf</code> file, you will have this code in your your <code class="language-plaintext highlighter-rouge">container</code> block:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">env</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">API</span><span class="dl">"</span>
<span class="nx">value</span> <span class="o">=</span> <span class="nx">format</span><span class="p">(</span><span class="dl">"</span><span class="s2">https://%s</span><span class="dl">"</span><span class="p">,</span> <span class="nx">azurerm_container_app</span><span class="p">.</span><span class="nx">api</span><span class="p">.</span><span class="nx">latest_revision_fqdn</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>
<h2 id="recap">Recap</h2>
<p>So your <code class="language-plaintext highlighter-rouge">container-api.tf</code> file should look like this:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">resource</span> <span class="dl">"</span><span class="s2">azurerm_container_app</span><span class="dl">"</span> <span class="dl">"</span><span class="s2">api</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="nx">format</span><span class="p">(</span><span class="dl">"</span><span class="s2">ca-api-%s</span><span class="dl">"</span><span class="p">,</span> <span class="nx">local</span><span class="p">.</span><span class="nx">resource_suffix_kebabcase</span><span class="p">)</span>
<span class="nx">container_app_environment_id</span> <span class="o">=</span> <span class="nx">azurerm_container_app_environment</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">id</span>
<span class="nx">resource_group_name</span> <span class="o">=</span> <span class="nx">azurerm_resource_group</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">name</span>
<span class="nx">revision_mode</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">Single</span><span class="dl">"</span>
<span class="nx">lifecycle</span> <span class="p">{</span>
<span class="nx">ignore_changes</span> <span class="o">=</span> <span class="p">[</span>
<span class="nx">template</span><span class="p">.</span><span class="mi">0</span><span class="p">.</span><span class="nx">container</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">image</span>
<span class="p">]</span>
<span class="p">}</span>
<span class="nx">secret</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">container-registry-password</span><span class="dl">"</span>
<span class="nx">value</span> <span class="o">=</span> <span class="nx">azurerm_container_registry</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">admin_password</span>
<span class="p">}</span>
<span class="nx">secret</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">mongodb-connection-string</span><span class="dl">"</span>
<span class="nx">value</span> <span class="o">=</span> <span class="nx">azurerm_cosmosdb_account</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">connection_strings</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="p">}</span>
<span class="nx">registry</span> <span class="p">{</span>
<span class="nx">server</span> <span class="o">=</span> <span class="nx">azurerm_container_registry</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">login_server</span>
<span class="nx">username</span> <span class="o">=</span> <span class="nx">azurerm_container_registry</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">admin_username</span>
<span class="nx">password_secret_name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">container-registry-password</span><span class="dl">"</span>
<span class="p">}</span>
<span class="nx">ingress</span> <span class="p">{</span>
<span class="nx">external_enabled</span> <span class="o">=</span> <span class="kc">true</span>
<span class="nx">target_port</span> <span class="o">=</span> <span class="mi">3000</span>
<span class="nx">traffic_weight</span> <span class="p">{</span>
<span class="nx">percentage</span> <span class="o">=</span> <span class="mi">100</span>
<span class="nx">latest_revision</span> <span class="o">=</span> <span class="kc">true</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nx">template</span> <span class="p">{</span>
<span class="nx">container</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="nx">format</span><span class="p">(</span><span class="dl">"</span><span class="s2">ca-api</span><span class="dl">"</span><span class="p">)</span>
<span class="nx">image</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">crdevwefrt01.azurecr.io/fruits-backend:1.0.0</span><span class="dl">"</span>
<span class="nx">cpu</span> <span class="o">=</span> <span class="mf">0.25</span>
<span class="nx">memory</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">0.5Gi</span><span class="dl">"</span>
<span class="nx">env</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">MONGODB_URI</span><span class="dl">"</span>
<span class="nx">secret_name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">mongodb-connection-string</span><span class="dl">"</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nx">min_replicas</span> <span class="o">=</span> <span class="mi">0</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>And your <code class="language-plaintext highlighter-rouge">container-web.tf</code> file should look like this:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">resource</span> <span class="dl">"</span><span class="s2">azurerm_container_app</span><span class="dl">"</span> <span class="dl">"</span><span class="s2">web</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="nx">format</span><span class="p">(</span><span class="dl">"</span><span class="s2">ca-web-%s</span><span class="dl">"</span><span class="p">,</span> <span class="nx">local</span><span class="p">.</span><span class="nx">resource_suffix_kebabcase</span><span class="p">)</span>
<span class="nx">container_app_environment_id</span> <span class="o">=</span> <span class="nx">azurerm_container_app_environment</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">id</span>
<span class="nx">resource_group_name</span> <span class="o">=</span> <span class="nx">azurerm_resource_group</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">name</span>
<span class="nx">revision_mode</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">Single</span><span class="dl">"</span>
<span class="nx">secret</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">container-registry-password</span><span class="dl">"</span>
<span class="nx">value</span> <span class="o">=</span> <span class="nx">azurerm_container_registry</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">admin_password</span>
<span class="p">}</span>
<span class="nx">registry</span> <span class="p">{</span>
<span class="nx">server</span> <span class="o">=</span> <span class="nx">azurerm_container_registry</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">login_server</span>
<span class="nx">username</span> <span class="o">=</span> <span class="nx">azurerm_container_registry</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">admin_username</span>
<span class="nx">password_secret_name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">container-registry-password</span><span class="dl">"</span>
<span class="p">}</span>
<span class="nx">lifecycle</span> <span class="p">{</span>
<span class="nx">ignore_changes</span> <span class="o">=</span> <span class="p">[</span>
<span class="nx">template</span><span class="p">.</span><span class="mi">0</span><span class="p">.</span><span class="nx">container</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">image</span>
<span class="p">]</span>
<span class="p">}</span>
<span class="nx">ingress</span> <span class="p">{</span>
<span class="nx">external_enabled</span> <span class="o">=</span> <span class="kc">true</span>
<span class="nx">target_port</span> <span class="o">=</span> <span class="mi">8080</span>
<span class="nx">traffic_weight</span> <span class="p">{</span>
<span class="nx">percentage</span> <span class="o">=</span> <span class="mi">100</span>
<span class="nx">latest_revision</span> <span class="o">=</span> <span class="kc">true</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nx">template</span> <span class="p">{</span>
<span class="nx">container</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="nx">format</span><span class="p">(</span><span class="dl">"</span><span class="s2">ca-web</span><span class="dl">"</span><span class="p">)</span>
<span class="nx">image</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">crdevwefrt01.azurecr.io/fruits-frontend:1.0.0</span><span class="dl">"</span>
<span class="nx">cpu</span> <span class="o">=</span> <span class="mf">0.25</span>
<span class="nx">memory</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">0.5Gi</span><span class="dl">"</span>
<span class="nx">env</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">API</span><span class="dl">"</span>
<span class="nx">value</span> <span class="o">=</span> <span class="nx">format</span><span class="p">(</span><span class="dl">"</span><span class="s2">https://%s</span><span class="dl">"</span><span class="p">,</span> <span class="nx">azurerm_container_app</span><span class="p">.</span><span class="nx">api</span><span class="p">.</span><span class="nx">latest_revision_fqdn</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nx">min_replicas</span> <span class="o">=</span> <span class="mi">0</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<h2 id="run-terraform">Run Terraform</h2>
<p>It’s now time to deploy the Container Apps and the Cosmos Db you defined in the <strong><a href="/terraform/azure/azure-container-apps/2023/05/07/azure-container-apps-define-containers-terraform-en.html">previous tutorial</a></strong>. Just run Terraform <code class="language-plaintext highlighter-rouge">plan</code> command and apply it:</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>terraform plan <span class="nt">--out</span><span class="o">=</span>plan.out
</code></pre></div></div>
<p>Then:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>terraform apply plan.out
</code></pre></div></div>
<h2 id="test-the-application">Test the application</h2>
<p>To test the application, go to the <strong><a href="https://portal.azure.com">Azure portal</a></strong>, in your resource group, find the frontend container and in the <code class="language-plaintext highlighter-rouge">Overview</code> tab click on the <code class="language-plaintext highlighter-rouge">Application url</code> link.</p>
<p><img src="https://damienaicheh.github.io/assets/posts/2023-05-09-web-container-url.png" alt="Web Container Url" /></p>
<p>This will take a few seconds to appear because, remember you set the number of replicat for the container apps to 0.</p>
<p>If everithing is ok, you will see the application:</p>
<p><img src="https://damienaicheh.github.io/assets/posts/2023-05-09-web-overview.png" alt="Web Container Url" /></p>
<p>Rate the fruits and then go to your Cosmos Db database, and inside the <code class="language-plaintext highlighter-rouge">Data Explorer</code> tab you will see <code class="language-plaintext highlighter-rouge">ratingdb</code>. Navigate to it and you will see a collection of <code class="language-plaintext highlighter-rouge">ratings</code>.</p>
<h2 id="final-touch">Final touch</h2>
<p>Congratulation! You have your Container Apps and your Azure Cosmos Db running. The application is now up and running. You will find the complete source code in this <strong><a href="https://github.com/damienaicheh/fruits-on-azure-container-apps">Github</a></strong> repository.</p>
<h2 id="whats-next">What’s next?</h2>
<p>In the next <strong><a href="/terraform/azure/azure-container-apps/2023/05/11/azure-container-apps-grafana-terraform-en.html">tutorial</a></strong> of this series we will focus on adding Grafana to monitor your environment.</p>Damien AichehSecure your credentialsDéfinir les secrets et les variables d’environnement dans Azure Container Apps avec Terraform2023-05-09T06:00:00+00:002023-05-09T06:00:00+00:00https://damienaicheh.github.io/terraform/azure/azure-container-apps/2023/05/09/azure-container-apps-use-secrets-terraform-fr<p>Dans ce tutoriel, vous finaliserez la définition terraform que vous avez effectuée dans le <strong><a href="/terraform/azure/azure-container-apps/2023/05/07/azure-container-apps-define-containers-terraform-fr.html">tutoriel précédent</a>* * pour vos conteneurs frontend et backend utilisant Terraform. Le code source est disponible dans ce répetoire **<a href="https://github.com/damienaicheh/fruits-on-azure-container-apps">Github</a></strong>.</p>
<p>Ce tutoriel fait partie d’une <strong><a href="/terraform/azure/azure-container-apps/2023/05/01/azure-container-apps-terraform-series-fr.html">série complète</a></strong> de tutoriels sur l’utilisation d’Azure Container Apps avec Terraform.</p>
<h2 id="utiliser-des-secrets">Utiliser des secrets</h2>
<p>Dans les deux conteneurs apps, vous devez spécifier un mot de passe pour accéder au Azure Container Registry afin de récupérer les images Docker. Pour ce faire, vous devez définir l’attribut <code class="language-plaintext highlighter-rouge">password_secret_name</code> du bloc <code class="language-plaintext highlighter-rouge">registry</code> dans la ressource <code class="language-plaintext highlighter-rouge">azurerm_container_app</code>.</p>
<p>Ainsi, dans vos fichiers <code class="language-plaintext highlighter-rouge">container-api.tf</code> <strong>et</strong> <code class="language-plaintext highlighter-rouge">container-web.tf</code>, vous devez déclarer un secret pour stocker le mot de passe administrateur d’Azure Container Registry juste avant le bloc <code class="language-plaintext highlighter-rouge">registry</code> :</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">secret</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">container-registry-password</span><span class="dl">"</span>
<span class="nx">value</span> <span class="o">=</span> <span class="nx">azurerm_container_registry</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">admin_password</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Comme vous pouvez le voir, le secret est défini avec le nom <code class="language-plaintext highlighter-rouge">container-registry-password</code>. Vous pouvez maintenant utiliser ce nom comme référence pour le consommer dans le bloc <code class="language-plaintext highlighter-rouge">registry</code>.</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">registry</span> <span class="p">{</span>
<span class="nx">server</span> <span class="o">=</span> <span class="nx">azurerm_container_registry</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">login_server</span>
<span class="nx">username</span> <span class="o">=</span> <span class="nx">azurerm_container_registry</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">admin_username</span>
<span class="nx">password_secret_name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">container-registry-password</span><span class="dl">"</span>
<span class="p">}</span>
</code></pre></div></div>
<h2 id="définir-les-variables-denvironnement">Définir les variables d’environnement</h2>
<p>Dans le conteneur backend, vous devez définir la variable d’environnement <code class="language-plaintext highlighter-rouge">MONGODB_URI</code> pour vous connecter à la base de données Azure Cosmos Db. Pour ce faire, vous devez définir un attribut <code class="language-plaintext highlighter-rouge">env</code> dans l’attribut <code class="language-plaintext highlighter-rouge">container</code> de votre ressource <code class="language-plaintext highlighter-rouge">azurerm_container_app</code>.</p>
<p>N’oubliez pas que vous ne voulez pas exposer la connection string en clair, vous utiliserez un secret pour la stocker et la référencer dans la variable d’environnement.</p>
<p>Ainsi, dans votre fichier <code class="language-plaintext highlighter-rouge">container-api.tf</code>, vous ajouterez un secret :</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">secret</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">mongodb-connection-string</span><span class="dl">"</span>
<span class="nx">value</span> <span class="o">=</span> <span class="nx">azurerm_cosmosdb_account</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">connection_strings</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="p">}</span>
</code></pre></div></div>
<p>et l’attribut <code class="language-plaintext highlighter-rouge">env</code> au bloc <code class="language-plaintext highlighter-rouge">container</code> de votre conteneur :</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">env</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">MONGODB_URI</span><span class="dl">"</span>
<span class="nx">secret_name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">mongodb-connection-string</span><span class="dl">"</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Dans le conteneur frontend, vous devez définir la variable d’environnement <code class="language-plaintext highlighter-rouge">API</code> pour vous connecter au conteneur backend, il vous suffit donc de référencer le FQDN du conteneur backend. Dans le fichier <code class="language-plaintext highlighter-rouge">container-web.tf</code>, vous aurez ce code dans votre bloc <code class="language-plaintext highlighter-rouge">container</code> :</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">env</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">API</span><span class="dl">"</span>
<span class="nx">value</span> <span class="o">=</span> <span class="nx">format</span><span class="p">(</span><span class="dl">"</span><span class="s2">https://%s</span><span class="dl">"</span><span class="p">,</span> <span class="nx">azurerm_container_app</span><span class="p">.</span><span class="nx">api</span><span class="p">.</span><span class="nx">latest_revision_fqdn</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>
<h2 id="résumer">Résumer</h2>
<p>Ainsi, votre fichier <code class="language-plaintext highlighter-rouge">container-api.tf</code> devrait ressembler à ceci :</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">resource</span> <span class="dl">"</span><span class="s2">azurerm_container_app</span><span class="dl">"</span> <span class="dl">"</span><span class="s2">api</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="nx">format</span><span class="p">(</span><span class="dl">"</span><span class="s2">ca-api-%s</span><span class="dl">"</span><span class="p">,</span> <span class="nx">local</span><span class="p">.</span><span class="nx">resource_suffix_kebabcase</span><span class="p">)</span>
<span class="nx">container_app_environment_id</span> <span class="o">=</span> <span class="nx">azurerm_container_app_environment</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">id</span>
<span class="nx">resource_group_name</span> <span class="o">=</span> <span class="nx">azurerm_resource_group</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">name</span>
<span class="nx">revision_mode</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">Single</span><span class="dl">"</span>
<span class="nx">lifecycle</span> <span class="p">{</span>
<span class="nx">ignore_changes</span> <span class="o">=</span> <span class="p">[</span>
<span class="nx">template</span><span class="p">.</span><span class="mi">0</span><span class="p">.</span><span class="nx">container</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">image</span>
<span class="p">]</span>
<span class="p">}</span>
<span class="nx">secret</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">container-registry-password</span><span class="dl">"</span>
<span class="nx">value</span> <span class="o">=</span> <span class="nx">azurerm_container_registry</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">admin_password</span>
<span class="p">}</span>
<span class="nx">secret</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">mongodb-connection-string</span><span class="dl">"</span>
<span class="nx">value</span> <span class="o">=</span> <span class="nx">azurerm_cosmosdb_account</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">connection_strings</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="p">}</span>
<span class="nx">registry</span> <span class="p">{</span>
<span class="nx">server</span> <span class="o">=</span> <span class="nx">azurerm_container_registry</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">login_server</span>
<span class="nx">username</span> <span class="o">=</span> <span class="nx">azurerm_container_registry</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">admin_username</span>
<span class="nx">password_secret_name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">container-registry-password</span><span class="dl">"</span>
<span class="p">}</span>
<span class="nx">ingress</span> <span class="p">{</span>
<span class="nx">external_enabled</span> <span class="o">=</span> <span class="kc">true</span>
<span class="nx">target_port</span> <span class="o">=</span> <span class="mi">3000</span>
<span class="nx">traffic_weight</span> <span class="p">{</span>
<span class="nx">percentage</span> <span class="o">=</span> <span class="mi">100</span>
<span class="nx">latest_revision</span> <span class="o">=</span> <span class="kc">true</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nx">template</span> <span class="p">{</span>
<span class="nx">container</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="nx">format</span><span class="p">(</span><span class="dl">"</span><span class="s2">ca-api</span><span class="dl">"</span><span class="p">)</span>
<span class="nx">image</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">crdevwefrt01.azurecr.io/fruits-backend:1.0.0</span><span class="dl">"</span>
<span class="nx">cpu</span> <span class="o">=</span> <span class="mf">0.25</span>
<span class="nx">memory</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">0.5Gi</span><span class="dl">"</span>
<span class="nx">env</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">MONGODB_URI</span><span class="dl">"</span>
<span class="nx">secret_name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">mongodb-connection-string</span><span class="dl">"</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nx">min_replicas</span> <span class="o">=</span> <span class="mi">0</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Et votre fichier <code class="language-plaintext highlighter-rouge">container-web.tf</code> devrait ressembler à ceci :</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">resource</span> <span class="dl">"</span><span class="s2">azurerm_container_app</span><span class="dl">"</span> <span class="dl">"</span><span class="s2">web</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="nx">format</span><span class="p">(</span><span class="dl">"</span><span class="s2">ca-web-%s</span><span class="dl">"</span><span class="p">,</span> <span class="nx">local</span><span class="p">.</span><span class="nx">resource_suffix_kebabcase</span><span class="p">)</span>
<span class="nx">container_app_environment_id</span> <span class="o">=</span> <span class="nx">azurerm_container_app_environment</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">id</span>
<span class="nx">resource_group_name</span> <span class="o">=</span> <span class="nx">azurerm_resource_group</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">name</span>
<span class="nx">revision_mode</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">Single</span><span class="dl">"</span>
<span class="nx">secret</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">container-registry-password</span><span class="dl">"</span>
<span class="nx">value</span> <span class="o">=</span> <span class="nx">azurerm_container_registry</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">admin_password</span>
<span class="p">}</span>
<span class="nx">registry</span> <span class="p">{</span>
<span class="nx">server</span> <span class="o">=</span> <span class="nx">azurerm_container_registry</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">login_server</span>
<span class="nx">username</span> <span class="o">=</span> <span class="nx">azurerm_container_registry</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">admin_username</span>
<span class="nx">password_secret_name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">container-registry-password</span><span class="dl">"</span>
<span class="p">}</span>
<span class="nx">lifecycle</span> <span class="p">{</span>
<span class="nx">ignore_changes</span> <span class="o">=</span> <span class="p">[</span>
<span class="nx">template</span><span class="p">.</span><span class="mi">0</span><span class="p">.</span><span class="nx">container</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">image</span>
<span class="p">]</span>
<span class="p">}</span>
<span class="nx">ingress</span> <span class="p">{</span>
<span class="nx">external_enabled</span> <span class="o">=</span> <span class="kc">true</span>
<span class="nx">target_port</span> <span class="o">=</span> <span class="mi">8080</span>
<span class="nx">traffic_weight</span> <span class="p">{</span>
<span class="nx">percentage</span> <span class="o">=</span> <span class="mi">100</span>
<span class="nx">latest_revision</span> <span class="o">=</span> <span class="kc">true</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nx">template</span> <span class="p">{</span>
<span class="nx">container</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="nx">format</span><span class="p">(</span><span class="dl">"</span><span class="s2">ca-web</span><span class="dl">"</span><span class="p">)</span>
<span class="nx">image</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">crdevwefrt01.azurecr.io/fruits-frontend:1.0.0</span><span class="dl">"</span>
<span class="nx">cpu</span> <span class="o">=</span> <span class="mf">0.25</span>
<span class="nx">memory</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">0.5Gi</span><span class="dl">"</span>
<span class="nx">env</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">API</span><span class="dl">"</span>
<span class="nx">value</span> <span class="o">=</span> <span class="nx">format</span><span class="p">(</span><span class="dl">"</span><span class="s2">https://%s</span><span class="dl">"</span><span class="p">,</span> <span class="nx">azurerm_container_app</span><span class="p">.</span><span class="nx">api</span><span class="p">.</span><span class="nx">latest_revision_fqdn</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nx">min_replicas</span> <span class="o">=</span> <span class="mi">0</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<h2 id="lancer-terraform">Lancer Terraform</h2>
<p>Il est maintenant temps de déployer les Container Apps et la base Cosmos Db que vous avez définies dans le <strong><a href="/terraform/azure/azure-container-apps/2023/05/07/azure-container-apps-define-containers-terraform-fr.html">tutoriel précédent</a></strong>. Exécutez simplement la commande Terraform <code class="language-plaintext highlighter-rouge">plan</code> et appliquez-la :</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>terraform plan <span class="nt">--out</span><span class="o">=</span>plan.out
</code></pre></div></div>
<p>Enfin:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>terraform apply plan.out
</code></pre></div></div>
<h2 id="testez-lapplication">Testez l’application</h2>
<p>Pour tester l’application, rendez-vous sur le <strong><a href="https://portal.azure.com">portail Azure</a></strong>, dans votre groupe de ressources, recherchez le conteneur frontend et dans l’onglet <code class="language-plaintext highlighter-rouge">Overview</code> cliquez sur le lien <code class="language-plaintext highlighter-rouge">Application url</code>.</p>
<p><img src="https://damienaicheh.github.io/assets/posts/2023-05-09-web-container-url.png" alt="Web Container Url" /></p>
<p>Cela prendra quelques secondes pour apparaître car, rappelez-vous que vous avez défini le nombre de réplicas pour les container apps à 0.</p>
<p>Si tout est ok, vous verrez l’application :</p>
<p><img src="https://damienaicheh.github.io/assets/posts/2023-05-09-web-overview.png" alt="Web Container Url" /></p>
<p>Évaluez les fruits, puis accédez à votre base de données Cosmos Db, et dans l’onglet <code class="language-plaintext highlighter-rouge">Data Explorer</code>, vous verrez la base de donnée <code class="language-plaintext highlighter-rouge">ratingdb</code>. Ouvrez là et vous verrez une collection de <code class="language-plaintext highlighter-rouge">ratings</code>.</p>
<h2 id="touche-finale">Touche finale</h2>
<p>Félicitations ! Vos conteneur Apps et votre Azure Cosmos Db sont en cours d’exécution. L’application est maintenant opérationnelle. Vous trouverez le code source complet dans ce répertoire <strong><a href="https://github.com/damienaicheh/fruits-on-azure-container-apps">Github</a></strong>.</p>
<h2 id="et-après">Et après?</h2>
<p>Dans le prochain <strong><a href="/terraform/azure/azure-container-apps/2023/05/11/azure-container-apps-grafana-terraform-fr.html">tutoriel</a></strong> de cette série, nous nous concentrerons sur l’ajout de Grafana pour monitorer votre environnement.</p>Damien AichehSécurisez vos identifiantsDefine your containers inside your Azure Container Apps environment using Terraform2023-05-07T06:00:00+00:002023-05-07T06:00:00+00:00https://damienaicheh.github.io/terraform/azure/azure-container-apps/2023/05/07/azure-container-apps-define-containers-terraform-en<p>In this tutorial you will start to define your frontend and backend containers to the Azure Container Apps environment and the Azure Cosmos Db associated using Terraform. This will be done in the ressource group made in the <strong><a href="/terraform/azure/azure-container-apps/2023/05/05/azure-container-apps-environment-terraform-en.html">previous tutorial</a></strong>.</p>
<p>This tutorial is part of a <strong><a href="/terraform/azure/azure-container-apps/2023/05/01/azure-container-apps-terraform-series-en.html">full series</a></strong> of tutorials on using Azure Container Apps with Terraform.</p>
<h2 id="deploy-the-azure-cosmos-db">Deploy the Azure Cosmos Db</h2>
<p>To store the result of the API calls you will use an Azure Cosmos Db database and define a mongo database named <code class="language-plaintext highlighter-rouge">ratingsdb</code>.</p>
<p>To achieve this, let’s create a file called <code class="language-plaintext highlighter-rouge">cosmos-db.tf</code> and add this code:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">resource</span> <span class="dl">"</span><span class="s2">azurerm_cosmosdb_account</span><span class="dl">"</span> <span class="dl">"</span><span class="s2">this</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="nx">format</span><span class="p">(</span><span class="dl">"</span><span class="s2">cosmos-%s</span><span class="dl">"</span><span class="p">,</span> <span class="nx">local</span><span class="p">.</span><span class="nx">resource_suffix_kebabcase</span><span class="p">)</span>
<span class="nx">location</span> <span class="o">=</span> <span class="nx">azurerm_resource_group</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">location</span>
<span class="nx">resource_group_name</span> <span class="o">=</span> <span class="nx">azurerm_resource_group</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">name</span>
<span class="nx">offer_type</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">Standard</span><span class="dl">"</span>
<span class="nx">kind</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">MongoDB</span><span class="dl">"</span>
<span class="nx">capabilities</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">mongoEnableDocLevelTTL</span><span class="dl">"</span>
<span class="p">}</span>
<span class="nx">capabilities</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">MongoDBv3.4</span><span class="dl">"</span>
<span class="p">}</span>
<span class="nx">capabilities</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">EnableMongo</span><span class="dl">"</span>
<span class="p">}</span>
<span class="nx">capabilities</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">EnableServerless</span><span class="dl">"</span>
<span class="p">}</span>
<span class="nx">consistency_policy</span> <span class="p">{</span>
<span class="nx">consistency_level</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">Session</span><span class="dl">"</span>
<span class="nx">max_interval_in_seconds</span> <span class="o">=</span> <span class="mi">5</span>
<span class="nx">max_staleness_prefix</span> <span class="o">=</span> <span class="mi">100</span>
<span class="p">}</span>
<span class="nx">geo_location</span> <span class="p">{</span>
<span class="nx">location</span> <span class="o">=</span> <span class="nx">azurerm_resource_group</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">location</span>
<span class="nx">failover_priority</span> <span class="o">=</span> <span class="mi">0</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nx">resource</span> <span class="dl">"</span><span class="s2">azurerm_cosmosdb_mongo_database</span><span class="dl">"</span> <span class="dl">"</span><span class="s2">this</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">ratingsdb</span><span class="dl">"</span>
<span class="nx">resource_group_name</span> <span class="o">=</span> <span class="nx">azurerm_cosmosdb_account</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">resource_group_name</span>
<span class="nx">account_name</span> <span class="o">=</span> <span class="nx">azurerm_cosmosdb_account</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">name</span>
<span class="p">}</span>
</code></pre></div></div>
<p>To continue in the spirit of serverless services like Azure Container Apps, as you can see the Azure Cosmos Db is enabled with the <code class="language-plaintext highlighter-rouge">serverless</code> mode.</p>
<h2 id="define-the-backend-container">Define the backend container</h2>
<p>In the previous tutorial you created the Azure Container Apps environment. Now you will define the backend container to it.</p>
<p>First, create a file called <code class="language-plaintext highlighter-rouge">container-api.tf</code> and add this code:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">resource</span> <span class="dl">"</span><span class="s2">azurerm_container_app</span><span class="dl">"</span> <span class="dl">"</span><span class="s2">api</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="nx">format</span><span class="p">(</span><span class="dl">"</span><span class="s2">ca-api-%s</span><span class="dl">"</span><span class="p">,</span> <span class="nx">local</span><span class="p">.</span><span class="nx">resource_suffix_kebabcase</span><span class="p">)</span>
<span class="nx">container_app_environment_id</span> <span class="o">=</span> <span class="nx">azurerm_container_app_environment</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">id</span>
<span class="nx">resource_group_name</span> <span class="o">=</span> <span class="nx">azurerm_resource_group</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">name</span>
<span class="nx">revision_mode</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">Single</span><span class="dl">"</span>
<span class="nx">lifecycle</span> <span class="p">{</span>
<span class="nx">ignore_changes</span> <span class="o">=</span> <span class="p">[</span>
<span class="nx">template</span><span class="p">.</span><span class="mi">0</span><span class="p">.</span><span class="nx">container</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">image</span>
<span class="p">]</span>
<span class="p">}</span>
<span class="nx">registry</span> <span class="p">{</span>
<span class="nx">server</span> <span class="o">=</span> <span class="nx">azurerm_container_registry</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">login_server</span>
<span class="nx">username</span> <span class="o">=</span> <span class="nx">azurerm_container_registry</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">admin_username</span>
<span class="p">}</span>
<span class="nx">ingress</span> <span class="p">{</span>
<span class="nx">external_enabled</span> <span class="o">=</span> <span class="kc">true</span>
<span class="nx">target_port</span> <span class="o">=</span> <span class="mi">3000</span>
<span class="nx">traffic_weight</span> <span class="p">{</span>
<span class="nx">percentage</span> <span class="o">=</span> <span class="mi">100</span>
<span class="nx">latest_revision</span> <span class="o">=</span> <span class="kc">true</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nx">template</span> <span class="p">{</span>
<span class="nx">container</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="nx">format</span><span class="p">(</span><span class="dl">"</span><span class="s2">ca-api</span><span class="dl">"</span><span class="p">)</span>
<span class="nx">image</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">crdevwefrt01.azurecr.io/fruits-backend:1.0.0</span><span class="dl">"</span>
<span class="nx">cpu</span> <span class="o">=</span> <span class="mf">0.25</span>
<span class="nx">memory</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">0.5Gi</span><span class="dl">"</span>
<span class="p">}</span>
<span class="nx">min_replicas</span> <span class="o">=</span> <span class="mi">0</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<blockquote>
<p>Make sure to change the <code class="language-plaintext highlighter-rouge">image</code> attribute to your own image registry.</p>
</blockquote>
<p>If you look at the Dockerfile inside the <a href="https://github.com/damienaicheh/fruits-ratings-api">GitHub repository</a>, you will see that the port <code class="language-plaintext highlighter-rouge">3000</code> is exposed. So you need to define it to <code class="language-plaintext highlighter-rouge">3000</code> in the <code class="language-plaintext highlighter-rouge">target_port</code> attribute of the <code class="language-plaintext highlighter-rouge">ingress</code> block.</p>
<p>The image attribute of the container is ignore using the <code class="language-plaintext highlighter-rouge">lifecycle</code> block so that it can be managed by your CI/CD pipeline.</p>
<p>By default you can see that the <code class="language-plaintext highlighter-rouge">min_replicas</code> is set to <code class="language-plaintext highlighter-rouge">0</code>. This means that the container will not be started until the first request is received. This is a great way to save money and resources.</p>
<p>To retreive the Docker image from the Azure Container Registry you need to define the <code class="language-plaintext highlighter-rouge">registry</code> attribute and link it to the registry you created in the previous tutorial.</p>
<p>The password will be provided using secrets in the next tutorial.</p>
<h2 id="define-the-frontend-container">Define the frontend container</h2>
<p>After the backend container, it’s time to define the frontend container. For that, create a file called <code class="language-plaintext highlighter-rouge">container-web.tf</code> and add this code:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">resource</span> <span class="dl">"</span><span class="s2">azurerm_container_app</span><span class="dl">"</span> <span class="dl">"</span><span class="s2">web</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="nx">format</span><span class="p">(</span><span class="dl">"</span><span class="s2">ca-web-%s</span><span class="dl">"</span><span class="p">,</span> <span class="nx">local</span><span class="p">.</span><span class="nx">resource_suffix_kebabcase</span><span class="p">)</span>
<span class="nx">container_app_environment_id</span> <span class="o">=</span> <span class="nx">azurerm_container_app_environment</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">id</span>
<span class="nx">resource_group_name</span> <span class="o">=</span> <span class="nx">azurerm_resource_group</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">name</span>
<span class="nx">revision_mode</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">Single</span><span class="dl">"</span>
<span class="nx">registry</span> <span class="p">{</span>
<span class="nx">server</span> <span class="o">=</span> <span class="nx">azurerm_container_registry</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">login_server</span>
<span class="nx">username</span> <span class="o">=</span> <span class="nx">azurerm_container_registry</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">admin_username</span>
<span class="p">}</span>
<span class="nx">lifecycle</span> <span class="p">{</span>
<span class="nx">ignore_changes</span> <span class="o">=</span> <span class="p">[</span>
<span class="nx">template</span><span class="p">.</span><span class="mi">0</span><span class="p">.</span><span class="nx">container</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">image</span>
<span class="p">]</span>
<span class="p">}</span>
<span class="nx">ingress</span> <span class="p">{</span>
<span class="nx">external_enabled</span> <span class="o">=</span> <span class="kc">true</span>
<span class="nx">target_port</span> <span class="o">=</span> <span class="mi">8080</span>
<span class="nx">traffic_weight</span> <span class="p">{</span>
<span class="nx">percentage</span> <span class="o">=</span> <span class="mi">100</span>
<span class="nx">latest_revision</span> <span class="o">=</span> <span class="kc">true</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nx">template</span> <span class="p">{</span>
<span class="nx">container</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="nx">format</span><span class="p">(</span><span class="dl">"</span><span class="s2">ca-web</span><span class="dl">"</span><span class="p">)</span>
<span class="nx">image</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">crdevwefrt01.azurecr.io/fruits-frontend:1.0.0</span><span class="dl">"</span>
<span class="nx">cpu</span> <span class="o">=</span> <span class="mf">0.25</span>
<span class="nx">memory</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">0.5Gi</span><span class="dl">"</span>
<span class="p">}</span>
<span class="nx">min_replicas</span> <span class="o">=</span> <span class="mi">0</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<blockquote>
<p>Remember to change the <code class="language-plaintext highlighter-rouge">image</code> attribute to your own image registry.</p>
</blockquote>
<p>Like the backend container, the frontend container is linked to the Azure Container Registry and the image attribute is ignored. The <code class="language-plaintext highlighter-rouge">target_port</code> is set to <code class="language-plaintext highlighter-rouge">8080</code> as defined in the Dockerfile, see the <strong><a href="https://github.com/damienaicheh/fruits-ratings-web">GitHub repository</a></strong>.</p>
<h2 id="final-touch">Final touch</h2>
<p>You have your Container Apps and Cosmos Db serverless for MongoDb defined. You will find the complete source code in this <strong><a href="https://github.com/damienaicheh/fruits-on-azure-container-apps">Github</a></strong> repository.</p>
<h2 id="whats-next">What’s next?</h2>
<p>In the next <strong><a href="/terraform/azure/azure-container-apps/2023/05/09/azure-container-apps-use-secrets-terraform-en.html">tutorial</a></strong> of this series we will focus on deploying the Azure Container Apps and declare secrets and environment variables for the containers.</p>Damien AichehContainers in the cloudDéfinissez vos conteneurs dans votre environnement Azure Container Apps avec Terraform2023-05-07T06:00:00+00:002023-05-07T06:00:00+00:00https://damienaicheh.github.io/terraform/azure/azure-container-apps/2023/05/07/azure-container-apps-define-containers-terraform-fr<p>Dans ce tutoriel, vous commencerez à définir vos conteneurs frontend et backend dans l’environnement Azure Container Apps et l’Azure Cosmos Db associés avec Terraform. Cela se fera dans le groupe de ressources créé dans le <strong><a href="/terraform/azure/azure-container-apps/2023/05/05/azure-container-apps-environment-terraform-fr.html">tutoriel précédent</a></strong>.</p>
<p>Ce tutoriel fait partie d’une <strong><a href="/terraform/azure/azure-container-apps/2023/05/01/azure-container-apps-terraform-series-fr.html">série complète</a></strong> de tutoriels sur l’utilisation d’Azure Container Apps avec Terraform.</p>
<h2 id="déployer-la-base-de-données-azure-cosmos">Déployer la base de données Azure Cosmos</h2>
<p>Pour stocker le résultat des appels d’API, vous utiliserez une base de données Azure Cosmos Db et définirez une base de données mongo nommée <code class="language-plaintext highlighter-rouge">ratingsdb</code>.</p>
<p>Pour ce faire, créons un fichier appelé <code class="language-plaintext highlighter-rouge">cosmos-db.tf</code> et ajoutons ce code :</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">resource</span> <span class="dl">"</span><span class="s2">azurerm_cosmosdb_account</span><span class="dl">"</span> <span class="dl">"</span><span class="s2">this</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="nx">format</span><span class="p">(</span><span class="dl">"</span><span class="s2">cosmos-%s</span><span class="dl">"</span><span class="p">,</span> <span class="nx">local</span><span class="p">.</span><span class="nx">resource_suffix_kebabcase</span><span class="p">)</span>
<span class="nx">location</span> <span class="o">=</span> <span class="nx">azurerm_resource_group</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">location</span>
<span class="nx">resource_group_name</span> <span class="o">=</span> <span class="nx">azurerm_resource_group</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">name</span>
<span class="nx">offer_type</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">Standard</span><span class="dl">"</span>
<span class="nx">kind</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">MongoDB</span><span class="dl">"</span>
<span class="nx">capabilities</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">mongoEnableDocLevelTTL</span><span class="dl">"</span>
<span class="p">}</span>
<span class="nx">capabilities</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">MongoDBv3.4</span><span class="dl">"</span>
<span class="p">}</span>
<span class="nx">capabilities</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">EnableMongo</span><span class="dl">"</span>
<span class="p">}</span>
<span class="nx">capabilities</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">EnableServerless</span><span class="dl">"</span>
<span class="p">}</span>
<span class="nx">consistency_policy</span> <span class="p">{</span>
<span class="nx">consistency_level</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">Session</span><span class="dl">"</span>
<span class="nx">max_interval_in_seconds</span> <span class="o">=</span> <span class="mi">5</span>
<span class="nx">max_staleness_prefix</span> <span class="o">=</span> <span class="mi">100</span>
<span class="p">}</span>
<span class="nx">geo_location</span> <span class="p">{</span>
<span class="nx">location</span> <span class="o">=</span> <span class="nx">azurerm_resource_group</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">location</span>
<span class="nx">failover_priority</span> <span class="o">=</span> <span class="mi">0</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nx">resource</span> <span class="dl">"</span><span class="s2">azurerm_cosmosdb_mongo_database</span><span class="dl">"</span> <span class="dl">"</span><span class="s2">this</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">ratingsdb</span><span class="dl">"</span>
<span class="nx">resource_group_name</span> <span class="o">=</span> <span class="nx">azurerm_cosmosdb_account</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">resource_group_name</span>
<span class="nx">account_name</span> <span class="o">=</span> <span class="nx">azurerm_cosmosdb_account</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">name</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Pour continuer dans l’esprit du serverless comme Azure Container Apps, comme vous pouvez le constater, Azure Cosmos Db est activé avec le mode <code class="language-plaintext highlighter-rouge">serverless</code> .</p>
<h2 id="définir-le-conteneur-pour-le-backend">Définir le conteneur pour le backend</h2>
<p>Dans le tutoriel précédent, vous avez créé l’environnement Azure Container Apps. Vous allez maintenant lui définir le conteneur pour le backend.</p>
<p>Tout d’abord, créez un fichier appelé <code class="language-plaintext highlighter-rouge">container-api.tf</code> et ajoutez ce code :</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">resource</span> <span class="dl">"</span><span class="s2">azurerm_container_app</span><span class="dl">"</span> <span class="dl">"</span><span class="s2">api</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="nx">format</span><span class="p">(</span><span class="dl">"</span><span class="s2">ca-api-%s</span><span class="dl">"</span><span class="p">,</span> <span class="nx">local</span><span class="p">.</span><span class="nx">resource_suffix_kebabcase</span><span class="p">)</span>
<span class="nx">container_app_environment_id</span> <span class="o">=</span> <span class="nx">azurerm_container_app_environment</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">id</span>
<span class="nx">resource_group_name</span> <span class="o">=</span> <span class="nx">azurerm_resource_group</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">name</span>
<span class="nx">revision_mode</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">Single</span><span class="dl">"</span>
<span class="nx">lifecycle</span> <span class="p">{</span>
<span class="nx">ignore_changes</span> <span class="o">=</span> <span class="p">[</span>
<span class="nx">template</span><span class="p">.</span><span class="mi">0</span><span class="p">.</span><span class="nx">container</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">image</span>
<span class="p">]</span>
<span class="p">}</span>
<span class="nx">registry</span> <span class="p">{</span>
<span class="nx">server</span> <span class="o">=</span> <span class="nx">azurerm_container_registry</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">login_server</span>
<span class="nx">username</span> <span class="o">=</span> <span class="nx">azurerm_container_registry</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">admin_username</span>
<span class="p">}</span>
<span class="nx">ingress</span> <span class="p">{</span>
<span class="nx">external_enabled</span> <span class="o">=</span> <span class="kc">true</span>
<span class="nx">target_port</span> <span class="o">=</span> <span class="mi">3000</span>
<span class="nx">traffic_weight</span> <span class="p">{</span>
<span class="nx">percentage</span> <span class="o">=</span> <span class="mi">100</span>
<span class="nx">latest_revision</span> <span class="o">=</span> <span class="kc">true</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nx">template</span> <span class="p">{</span>
<span class="nx">container</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="nx">format</span><span class="p">(</span><span class="dl">"</span><span class="s2">ca-api</span><span class="dl">"</span><span class="p">)</span>
<span class="nx">image</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">crdevwefrt01.azurecr.io/fruits-backend:1.0.0</span><span class="dl">"</span>
<span class="nx">cpu</span> <span class="o">=</span> <span class="mf">0.25</span>
<span class="nx">memory</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">0.5Gi</span><span class="dl">"</span>
<span class="p">}</span>
<span class="nx">min_replicas</span> <span class="o">=</span> <span class="mi">0</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<blockquote>
<p>Assurez-vous de remplacer l’attribut <code class="language-plaintext highlighter-rouge">image</code> par celui de votre propre image registry.</p>
</blockquote>
<p>Si vous regardez le Dockerfile à l’intérieur du <a href="https://github.com/damienaicheh/fruits-ratings-api">répetoire GitHub</a>, vous verrez que le port <code class="language-plaintext highlighter-rouge">3000</code> est exposé. Vous devez donc le définir sur <code class="language-plaintext highlighter-rouge">3000</code> l’attribut <code class="language-plaintext highlighter-rouge">target_port</code> du bloc <code class="language-plaintext highlighter-rouge">ingress</code>.</p>
<p>L’attribut image du conteneur est ignoré à l’aide du bloc <code class="language-plaintext highlighter-rouge">lifecycle</code> afin qu’il puisse être géré par votre pipeline CI/CD.</p>
<p>Par défaut, vous pouvez voir que <code class="language-plaintext highlighter-rouge">min_replicas</code> est défini sur <code class="language-plaintext highlighter-rouge">0</code>. Cela signifie que le conteneur ne sera pas démarré tant que la première requête n’aura pas été reçue. C’est un excellent moyen d’économiser de l’argent et des ressources.</p>
<p>Pour récupérer l’image Docker à partir d’un Azure Container Registry, vous devez définir l’attribut <code class="language-plaintext highlighter-rouge">registry</code> et le lier au registre que vous avez créé dans le tutoriel précédent.</p>
<p>Le mot de passe sera fourni à l’aide de secrets dans le prochain tutoriel.</p>
<h2 id="définir-le-conteneur-frontend">Définir le conteneur frontend</h2>
<p>Après le conteneur backend, c’est le moment de définir le conteneur frontend. Pour cela, créez un fichier nommé <code class="language-plaintext highlighter-rouge">container-web.tf</code> et ajoutez ce code :</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">resource</span> <span class="dl">"</span><span class="s2">azurerm_container_app</span><span class="dl">"</span> <span class="dl">"</span><span class="s2">web</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="nx">format</span><span class="p">(</span><span class="dl">"</span><span class="s2">ca-web-%s</span><span class="dl">"</span><span class="p">,</span> <span class="nx">local</span><span class="p">.</span><span class="nx">resource_suffix_kebabcase</span><span class="p">)</span>
<span class="nx">container_app_environment_id</span> <span class="o">=</span> <span class="nx">azurerm_container_app_environment</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">id</span>
<span class="nx">resource_group_name</span> <span class="o">=</span> <span class="nx">azurerm_resource_group</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">name</span>
<span class="nx">revision_mode</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">Single</span><span class="dl">"</span>
<span class="nx">registry</span> <span class="p">{</span>
<span class="nx">server</span> <span class="o">=</span> <span class="nx">azurerm_container_registry</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">login_server</span>
<span class="nx">username</span> <span class="o">=</span> <span class="nx">azurerm_container_registry</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">admin_username</span>
<span class="p">}</span>
<span class="nx">lifecycle</span> <span class="p">{</span>
<span class="nx">ignore_changes</span> <span class="o">=</span> <span class="p">[</span>
<span class="nx">template</span><span class="p">.</span><span class="mi">0</span><span class="p">.</span><span class="nx">container</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">image</span>
<span class="p">]</span>
<span class="p">}</span>
<span class="nx">ingress</span> <span class="p">{</span>
<span class="nx">external_enabled</span> <span class="o">=</span> <span class="kc">true</span>
<span class="nx">target_port</span> <span class="o">=</span> <span class="mi">8080</span>
<span class="nx">traffic_weight</span> <span class="p">{</span>
<span class="nx">percentage</span> <span class="o">=</span> <span class="mi">100</span>
<span class="nx">latest_revision</span> <span class="o">=</span> <span class="kc">true</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nx">template</span> <span class="p">{</span>
<span class="nx">container</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="nx">format</span><span class="p">(</span><span class="dl">"</span><span class="s2">ca-web</span><span class="dl">"</span><span class="p">)</span>
<span class="nx">image</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">crdevwefrt01.azurecr.io/fruits-frontend:1.0.0</span><span class="dl">"</span>
<span class="nx">cpu</span> <span class="o">=</span> <span class="mf">0.25</span>
<span class="nx">memory</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">0.5Gi</span><span class="dl">"</span>
<span class="p">}</span>
<span class="nx">min_replicas</span> <span class="o">=</span> <span class="mi">0</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<blockquote>
<p>N’oubliez pas de remplacer l’attribut <code class="language-plaintext highlighter-rouge">image</code> par votre propre image registry.</p>
</blockquote>
<p>Comme le conteneur backend, le conteneur frontend est lié à Azure Container Registry et l’attribut image est ignoré. Le <code class="language-plaintext highlighter-rouge">target_port</code> est défini sur <code class="language-plaintext highlighter-rouge">8080</code> comme défini dans le Dockerfile, voir le <strong><a href="https://github.com/damienaicheh/fruits-ratings-web">répertoire GitHub</a></strong>.</p>
<h2 id="touche-finale">Touche finale</h2>
<p>Vous avez défini vos applications de conteneur et Cosmos Db sans serveur pour MongoDb. Vous trouverez le code source complet dans ce dépôt <strong><a href="https://github.com/damienaicheh/fruits-on-azure-container-apps">Github</a></strong>.</p>
<h2 id="et-après">Et après?</h2>
<p>Dans le <strong><a href="/terraform/azure/azure-container-apps/2023/05/09/azure-container-apps-use-secrets-terraform-fr.html">tutoriel</a></strong> suivant de cette série, nous nous concentrerons sur le déploiement des Azure Container Apps et déclarerons des secrets et des variables d’environnement pour les conteneurs.</p>Damien AichehConteneurs dans le cloudCreate an Azure Container Apps environment using Terraform2023-05-05T06:00:00+00:002023-05-05T06:00:00+00:00https://damienaicheh.github.io/terraform/azure/azure-container-apps/2023/05/05/azure-container-apps-environment-terraform-en<p>In this tutorial we will setup the Azure Container Apps environment using Terraform and link it with a Log Analytics workspace. This will be done in the same resource group that we created in the <strong><a href="/terraform/azure/azure-container-apps/2023/05/03/azure-container-apps-prepare-docker-images-en.html">previous tutorial</a></strong>.</p>
<p>This tutorial is part of a <strong><a href="/terraform/azure/azure-container-apps/2023/05/01/azure-container-apps-terraform-series-en.html">full series</a></strong> of tutorials on using Azure Container Apps with Terraform.</p>
<h2 id="attach-a-log-analytics-workspace">Attach a Log Analytics workspace</h2>
<p>Before creating the Azure Container Apps environment we will create a Log Analytics workspace. This will allow us to monitor the environment with Grafana. You will discover this in a future tutorial of this series.</p>
<p>For that, create a file called <code class="language-plaintext highlighter-rouge">log_analytics.tf</code> and add this code:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">resource</span> <span class="dl">"</span><span class="s2">azurerm_log_analytics_workspace</span><span class="dl">"</span> <span class="dl">"</span><span class="s2">this</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="nx">format</span><span class="p">(</span><span class="dl">"</span><span class="s2">log-%s</span><span class="dl">"</span><span class="p">,</span> <span class="nx">local</span><span class="p">.</span><span class="nx">resource_suffix_kebabcase</span><span class="p">)</span>
<span class="nx">location</span> <span class="o">=</span> <span class="nx">azurerm_resource_group</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">location</span>
<span class="nx">resource_group_name</span> <span class="o">=</span> <span class="nx">azurerm_resource_group</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">name</span>
<span class="nx">sku</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">PerGB2018</span><span class="dl">"</span>
<span class="nx">retention_in_days</span> <span class="o">=</span> <span class="mi">30</span>
<span class="p">}</span>
</code></pre></div></div>
<p>We will use only 30 days of logs retentions but feel free to adjust this value and the associated sku to your needs.</p>
<h2 id="create-the-azure-container-apps-environment">Create the Azure Container Apps environment</h2>
<p>Next step is to create the Azure Container Apps environment. To do that, create a file called <code class="language-plaintext highlighter-rouge">ca-env.tf</code> and add this code:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">resource</span> <span class="dl">"</span><span class="s2">azurerm_container_app_environment</span><span class="dl">"</span> <span class="dl">"</span><span class="s2">this</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="nx">format</span><span class="p">(</span><span class="dl">"</span><span class="s2">cae-%s</span><span class="dl">"</span><span class="p">,</span> <span class="nx">local</span><span class="p">.</span><span class="nx">resource_suffix_kebabcase</span><span class="p">)</span>
<span class="nx">location</span> <span class="o">=</span> <span class="nx">azurerm_resource_group</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">location</span>
<span class="nx">resource_group_name</span> <span class="o">=</span> <span class="nx">azurerm_resource_group</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">name</span>
<span class="nx">log_analytics_workspace_id</span> <span class="o">=</span> <span class="nx">azurerm_log_analytics_workspace</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">id</span>
<span class="p">}</span>
</code></pre></div></div>
<p>As you can see, you use the <code class="language-plaintext highlighter-rouge">azurerm_container_app_environment</code> resource to create the environment. Then you reference the <code class="language-plaintext highlighter-rouge">azurerm_log_analytics_workspace</code> to retrieve the Log Analytics workspace that you created in the previous step.</p>
<h2 id="run-terraform">Run Terraform</h2>
<p>Let’s run Terraform <code class="language-plaintext highlighter-rouge">plan</code> command and apply it:</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>terraform plan <span class="nt">--out</span><span class="o">=</span>plan.out
</code></pre></div></div>
<p>Then:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>terraform apply plan.out
</code></pre></div></div>
<h2 id="final-touch">Final touch</h2>
<p>You have your Azure Container Apps environment and the Log Analytics workspace deployed. You will find the complete source code in this <strong><a href="https://github.com/damienaicheh/fruits-on-azure-container-apps">Github</a></strong> repository.</p>
<h2 id="whats-next">What’s next?</h2>
<p>In the next <strong><a href="/terraform/azure/azure-container-apps/2023/05/07/azure-container-apps-define-containers-terraform-en.html">tutorial</a></strong> of this series we will focus on deploying the Azure Container Apps and link them with the Azure Container Registry.</p>Damien AichehOne environment for your containersCréer un environnement Azure Container Apps avec Terraform2023-05-05T06:00:00+00:002023-05-05T06:00:00+00:00https://damienaicheh.github.io/terraform/azure/azure-container-apps/2023/05/05/azure-container-apps-environment-terraform-fr<p>Dans ce tutoriel, nous allons configurer l’environnement Azure Container Apps à l’aide de Terraform et le lier à un Log Analytics workspace. Cela se fera dans le même groupe de ressources que nous avons créé dans le <strong><a href="/terraform/azure/azure-container-apps/2023/05/03/azure-container-apps-prepare-docker-images-fr.html">tutoriel précédent</a></strong> .</p>
<p>Ce tutoriel fait partie d’une <strong><a href="/terraform/azure/azure-container-apps/2023/05/01/azure-container-apps-terraform-series-fr.html">série complète</a></strong> de tutoriels sur l’utilisation d’Azure Container Apps avec Terraform.</p>
<h2 id="attacher-un-log-analytics-workspace">Attacher un Log Analytics workspace</h2>
<p>Avant de créer l’environnement Azure Container Apps, nous allons créer un Log Analytics workspace. Cela nous permettra de monitorer l’environnement avec Grafana. Vous découvrirez cela dans un futur tutoriel de cette série.</p>
<p>Pour cela, créez un fichier appelé <code class="language-plaintext highlighter-rouge">log_analytics.tf</code> et ajoutez ce code :</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">resource</span> <span class="dl">"</span><span class="s2">azurerm_log_analytics_workspace</span><span class="dl">"</span> <span class="dl">"</span><span class="s2">this</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="nx">format</span><span class="p">(</span><span class="dl">"</span><span class="s2">log-%s</span><span class="dl">"</span><span class="p">,</span> <span class="nx">local</span><span class="p">.</span><span class="nx">resource_suffix_kebabcase</span><span class="p">)</span>
<span class="nx">location</span> <span class="o">=</span> <span class="nx">azurerm_resource_group</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">location</span>
<span class="nx">resource_group_name</span> <span class="o">=</span> <span class="nx">azurerm_resource_group</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">name</span>
<span class="nx">sku</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">PerGB2018</span><span class="dl">"</span>
<span class="nx">retention_in_days</span> <span class="o">=</span> <span class="mi">30</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Nous n’utiliserons que 30 jours de rétention des journaux, mais n’hésitez pas à ajuster cette valeur et le sku associé à vos besoins.</p>
<h2 id="créer-lenvironnement-azure-container-apps">Créer l’environnement Azure Container Apps</h2>
<p>L’étape suivante consiste à créer l’environnement Azure Container Apps. Pour ce faire, créez un fichier appelé <code class="language-plaintext highlighter-rouge">ca-env.tf</code> et ajoutez ce code :</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">resource</span> <span class="dl">"</span><span class="s2">azurerm_container_app_environment</span><span class="dl">"</span> <span class="dl">"</span><span class="s2">this</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="nx">format</span><span class="p">(</span><span class="dl">"</span><span class="s2">cae-%s</span><span class="dl">"</span><span class="p">,</span> <span class="nx">local</span><span class="p">.</span><span class="nx">resource_suffix_kebabcase</span><span class="p">)</span>
<span class="nx">location</span> <span class="o">=</span> <span class="nx">azurerm_resource_group</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">location</span>
<span class="nx">resource_group_name</span> <span class="o">=</span> <span class="nx">azurerm_resource_group</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">name</span>
<span class="nx">log_analytics_workspace_id</span> <span class="o">=</span> <span class="nx">azurerm_log_analytics_workspace</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">id</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Comme vous pouvez le voir, vous utilisez la ressource <code class="language-plaintext highlighter-rouge">azurerm_container_app_environment</code> pour créer l’environnement. Ensuite, vous référencez <code class="language-plaintext highlighter-rouge">azurerm_log_analytics_workspace</code> pour récupérer Log Analytics workspace que vous avez créé à l’étape précédente.</p>
<h2 id="exécuter-terraform">Exécuter Terraform</h2>
<p>Exécutons la commande Terraform <code class="language-plaintext highlighter-rouge">plan</code> et appliquons-la :</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>terraform plan <span class="nt">--out</span><span class="o">=</span>plan.out
</code></pre></div></div>
<p>Puis:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>terraform apply plan.out
</code></pre></div></div>
<h2 id="touche-finale">Touche finale</h2>
<p>Votre environnement Azure Container Apps et le Log Analytics workspace sont déployés. Vous trouverez le code source complet dans ce répertoire <strong><a href="https://github.com/damienaicheh/fruits-on-azure-container-apps">Github</a></strong>.</p>
<h2 id="et-après">Et après?</h2>
<p>Dans le <strong><a href="/terraform/azure/azure-container-apps/2023/05/07/azure-container-apps-define-containers-terraform-en.html">tutoriel</a></strong> suivant de cette série, nous nous concentrerons sur le déploiement des Azure Container Apps et les associerons à Azure Container Registry.</p>Damien AichehUn environnement pour vos conteneursPrepare your Azure Container Registry for your Azure Container Apps using Terraform2023-05-03T06:00:00+00:002023-05-03T06:00:00+00:00https://damienaicheh.github.io/terraform/azure/azure-container-apps/2023/05/03/azure-container-apps-prepare-docker-images-en<p>In this tutorial you will setup the <a href="https://azure.microsoft.com/en-us/services/container-registry/">Azure Container Registry</a> to store the Docker images. You will also create the Docker images that you will use in the Azure Container Apps environment.</p>
<p>This tutorial is part of a <strong><a href="/terraform/azure/azure-container-apps/2023/05/01/azure-container-apps-terraform-series-en.html">full series</a></strong> of tutorials on using Azure Container Apps with Terraform.</p>
<h2 id="project-structure">Project structure</h2>
<p>Let’s create a dedicated Terraform project called for instance <code class="language-plaintext highlighter-rouge">fruits-on-azure-container-apps</code> with this structure inside:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>| - fruits-on-azure-container-apps
| - .gitignore
</code></pre></div></div>
<p>The <code class="language-plaintext highlighter-rouge">.gitignore</code> will contains all terraform files that we want to ignore. It will look like this:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.terraform
*.tfstate
**/*.lock.*
**/*.tfplan
terraform.tfplan
terraform.tfstate.backup
plan.out
</code></pre></div></div>
<h2 id="initialize-terraform">Initialize terraform</h2>
<p>To be able to use Terraform with Azure, you need to install the <strong><a href="https://docs.microsoft.com/en-us/cli/azure/install-azure-cli">Azure CLI</a></strong> and login to your Azure account. You can also use a Service Principal Name (SPN) to authenticate, all details can be found in the official <a href="https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/guides/service_principal_client_secret#configuring-the-service-principal-in-terraform">documentation</a>.</p>
<p>To be able to store the Terraform state in Azure, you need to create a Azure Storage Account and a container to store the state.</p>
<p>Then, log in to your subscription and create a resource group dedicated to the Terraform States, for instance <code class="language-plaintext highlighter-rouge">rg-dev-terraform-states</code>:</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Connect to Azure</span>
az login
<span class="c"># Select the subscription</span>
az account <span class="nb">set</span> <span class="nt">--subscription</span> <your-subscription-id>
<span class="c"># Create the resource group with the location of your choice</span>
az group create <span class="nt">--name</span> rg-dev-terraform-states <span class="nt">--location</span> westeurope
</code></pre></div></div>
<p>And then run the following commands to create an Azure Storage Account and the container to store the Terraform state. Make sure to define <strong>your own Storage Account name</strong> which must be unique:</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Create the storage account</span>
az storage account create <span class="nt">-n</span> <your-storage-account-name> <span class="se">\</span>
<span class="nt">-g</span> rg-dev-terraform-states <span class="se">\</span>
<span class="nt">-l</span> westeurope <span class="se">\</span>
<span class="nt">--sku</span> Standard_LRS
</code></pre></div></div>
<p>Based on the command line below, to create the container called <code class="language-plaintext highlighter-rouge">tfstates</code> for the terraform states files you need to get one of the access key of your Storage Account. You can get it in the Azure Portal in the <code class="language-plaintext highlighter-rouge">Access Keys</code> section of your Storage Account:</p>
<p><img src="https://damienaicheh.github.io/assets/posts/2023-05-03-storage-account-key.png" alt="Storage account access keys" /></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Then create the tfstates container inside it</span>
az storage container create <span class="nt">-n</span> tfstates <span class="se">\</span>
<span class="nt">--account-name</span> <your-storage-account-name> <span class="se">\</span>
<span class="nt">--account-key</span> <your-storage-account-key>
</code></pre></div></div>
<p>Let’s create a <code class="language-plaintext highlighter-rouge">provider.tf</code> file and declare the <code class="language-plaintext highlighter-rouge">azurerm</code> provider in it:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">provider</span> <span class="dl">"</span><span class="s2">azurerm</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">features</span> <span class="p">{</span>
<span class="nx">log_analytics_workspace</span> <span class="p">{</span>
<span class="nx">permanently_delete_on_destroy</span> <span class="o">=</span> <span class="kc">true</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nx">skip_provider_registration</span> <span class="o">=</span> <span class="kc">false</span>
<span class="p">}</span>
<span class="nx">terraform</span> <span class="p">{</span>
<span class="nx">required_providers</span> <span class="p">{</span>
<span class="nx">azurerm</span> <span class="o">=</span> <span class="p">{</span>
<span class="nx">source</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">hashicorp/azurerm</span><span class="dl">"</span>
<span class="nx">version</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">~> 3.51.0</span><span class="dl">"</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nx">required_version</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">>=1.4.5</span><span class="dl">"</span>
<span class="nx">backend</span> <span class="dl">"</span><span class="s2">azurerm</span><span class="dl">"</span> <span class="p">{}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Now we can run the following command to initialize Terraform:</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>terraform init <span class="se">\</span>
<span class="nt">-reconfigure</span> <span class="se">\</span>
<span class="nt">-input</span><span class="o">=</span><span class="nb">false</span> <span class="se">\</span>
<span class="nt">-backend-config</span><span class="o">=</span><span class="s2">"resource_group_name=rg-dev-terraform-states"</span> <span class="se">\</span>
<span class="nt">-backend-config</span><span class="o">=</span><span class="s2">"storage_account_name=<your-storage-account-name>"</span> <span class="se">\</span>
<span class="nt">-backend-config</span><span class="o">=</span><span class="s2">"container_name=tfstates"</span> <span class="se">\</span>
<span class="nt">-backend-config</span><span class="o">=</span><span class="s2">"key=fruits.aca.terraform.tfstate"</span>
</code></pre></div></div>
<p>If everything is ok you should see this kind of message in your terminal:</p>
<p><img src="https://damienaicheh.github.io/assets/posts/2023-05-03-terraform-init.png" alt="Terraform init" /></p>
<h2 id="define-naming-conventions">Define naming conventions</h2>
<p>You will use the official <strong><a href="https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/resource-naming">naming convention</a></strong> for the ressources that you will create on Azure. All the abbreviations can be found in the <a href="https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/resource-abbreviations">documentation</a>.</p>
<p>Let’s define this naming convention:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"><!--If the resource prefix has a dash: --></span>
<span class="nt"><service-prefix></span>-<span class="nt"><environment></span>-<span class="nt"><region></span>-<span class="nt"><application-name></span>-<span class="nt"><instance></span>
<span class="c"><!--If the resource does not autorize any special caracters: --></span>
<span class="nt"><service-prefix><environment><region><application-name><instance></span>
</code></pre></div></div>
<p>So let’s create a <code class="language-plaintext highlighter-rouge">variables.tf</code> file and define all of these values as variables:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">variable</span> <span class="dl">"</span><span class="s2">environment</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">description</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">The environment deployed</span><span class="dl">"</span>
<span class="nx">type</span> <span class="o">=</span> <span class="nx">string</span>
<span class="k">default</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">dev</span><span class="dl">"</span>
<span class="nx">validation</span> <span class="p">{</span>
<span class="nx">condition</span> <span class="o">=</span> <span class="nx">can</span><span class="p">(</span><span class="nx">regex</span><span class="p">(</span><span class="dl">"</span><span class="s2">(dev|stag|prod)</span><span class="dl">"</span><span class="p">,</span> <span class="kd">var</span><span class="p">.</span><span class="nx">environment</span><span class="p">))</span>
<span class="nx">error_message</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">The environment value must be valid.</span><span class="dl">"</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nx">variable</span> <span class="dl">"</span><span class="s2">region</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">description</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">Azure deployment region</span><span class="dl">"</span>
<span class="nx">type</span> <span class="o">=</span> <span class="nx">string</span>
<span class="k">default</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">we</span><span class="dl">"</span>
<span class="p">}</span>
<span class="nx">variable</span> <span class="dl">"</span><span class="s2">application</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">description</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">The name of the application</span><span class="dl">"</span>
<span class="nx">type</span> <span class="o">=</span> <span class="nx">string</span>
<span class="k">default</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">frt</span><span class="dl">"</span>
<span class="p">}</span>
<span class="nx">variable</span> <span class="dl">"</span><span class="s2">location</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">description</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">Azure deployment location</span><span class="dl">"</span>
<span class="nx">type</span> <span class="o">=</span> <span class="nx">string</span>
<span class="k">default</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">westeurope</span><span class="dl">"</span>
<span class="p">}</span>
<span class="nx">variable</span> <span class="dl">"</span><span class="s2">resource_group_name_suffix</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">type</span> <span class="o">=</span> <span class="nx">string</span>
<span class="k">default</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">01</span><span class="dl">"</span>
<span class="nx">description</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">The resource group name suffix</span><span class="dl">"</span>
<span class="nx">validation</span> <span class="p">{</span>
<span class="nx">condition</span> <span class="o">=</span> <span class="nx">can</span><span class="p">(</span><span class="nx">regex</span><span class="p">(</span><span class="dl">"</span><span class="s2">[0-9]{2}</span><span class="dl">"</span><span class="p">,</span> <span class="kd">var</span><span class="p">.</span><span class="nx">resource_group_name_suffix</span><span class="p">))</span>
<span class="nx">error_message</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">The resource group name suffix value is not a valid number.</span><span class="dl">"</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nx">variable</span> <span class="dl">"</span><span class="s2">repository</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">description</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">The repository name</span><span class="dl">"</span>
<span class="nx">type</span> <span class="o">=</span> <span class="nx">string</span>
<span class="k">default</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">fruits-on-azure-container-apps</span><span class="dl">"</span>
<span class="p">}</span>
<span class="nx">variable</span> <span class="dl">"</span><span class="s2">creator</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">description</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">The name of the project's creator</span><span class="dl">"</span>
<span class="nx">type</span> <span class="o">=</span> <span class="nx">string</span>
<span class="k">default</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">terraform</span><span class="dl">"</span>
<span class="p">}</span>
<span class="nx">variable</span> <span class="dl">"</span><span class="s2">tags</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">type</span> <span class="o">=</span> <span class="nx">map</span><span class="p">(</span><span class="nx">any</span><span class="p">)</span>
<span class="nx">description</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">The custom tags for all resources</span><span class="dl">"</span>
<span class="k">default</span> <span class="o">=</span> <span class="p">{}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Let’s define a resource suffix and the tags for your resources inside a <code class="language-plaintext highlighter-rouge">locals.tf</code> file:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">locals</span> <span class="p">{</span>
<span class="nx">resource_lowercase_array</span> <span class="o">=</span> <span class="p">[</span><span class="nx">lower</span><span class="p">(</span><span class="kd">var</span><span class="p">.</span><span class="nx">environment</span><span class="p">),</span> <span class="nx">lower</span><span class="p">(</span><span class="kd">var</span><span class="p">.</span><span class="nx">region</span><span class="p">),</span> <span class="nx">lower</span><span class="p">(</span><span class="kd">var</span><span class="p">.</span><span class="nx">application</span><span class="p">),</span> <span class="kd">var</span><span class="p">.</span><span class="nx">resource_group_name_suffix</span><span class="p">]</span>
<span class="nx">resource_suffix_kebabcase</span> <span class="o">=</span> <span class="nx">join</span><span class="p">(</span><span class="dl">"</span><span class="s2">-</span><span class="dl">"</span><span class="p">,</span> <span class="nx">local</span><span class="p">.</span><span class="nx">resource_lowercase_array</span><span class="p">)</span>
<span class="nx">resource_suffix_lowercase</span> <span class="o">=</span> <span class="nx">join</span><span class="p">(</span><span class="dl">""</span><span class="p">,</span> <span class="nx">local</span><span class="p">.</span><span class="nx">resource_lowercase_array</span><span class="p">)</span>
<span class="nx">tags</span> <span class="o">=</span> <span class="nx">merge</span><span class="p">(</span>
<span class="kd">var</span><span class="p">.</span><span class="nx">tags</span><span class="p">,</span>
<span class="nx">tomap</span><span class="p">(</span>
<span class="p">{</span>
<span class="dl">"</span><span class="s2">Creator</span><span class="dl">"</span> <span class="o">=</span> <span class="kd">var</span><span class="p">.</span><span class="nx">creator</span><span class="p">,</span>
<span class="dl">"</span><span class="s2">Environment</span><span class="dl">"</span> <span class="o">=</span> <span class="kd">var</span><span class="p">.</span><span class="nx">environment</span><span class="p">,</span>
<span class="dl">"</span><span class="s2">Region</span><span class="dl">"</span> <span class="o">=</span> <span class="kd">var</span><span class="p">.</span><span class="nx">region</span><span class="p">,</span>
<span class="dl">"</span><span class="s2">Repository</span><span class="dl">"</span> <span class="o">=</span> <span class="kd">var</span><span class="p">.</span><span class="nx">repository</span><span class="p">,</span>
<span class="dl">"</span><span class="s2">Application</span><span class="dl">"</span> <span class="o">=</span> <span class="kd">var</span><span class="p">.</span><span class="nx">application</span><span class="p">,</span>
<span class="p">}</span>
<span class="p">)</span>
<span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>
<p>This will be used to define the suffix of all the resources that we will create.</p>
<h2 id="create-a-resource-group">Create a resource group</h2>
<p>First thing you need to do is to create a resource group to store all the resources that we will create. To do that, create a file called <code class="language-plaintext highlighter-rouge">rg.tf</code> and add this code:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">resource</span> <span class="dl">"</span><span class="s2">azurerm_resource_group</span><span class="dl">"</span> <span class="dl">"</span><span class="s2">this</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="nx">format</span><span class="p">(</span><span class="dl">"</span><span class="s2">rg-%s</span><span class="dl">"</span><span class="p">,</span> <span class="nx">local</span><span class="p">.</span><span class="nx">resource_suffix_kebabcase</span><span class="p">)</span>
<span class="nx">location</span> <span class="o">=</span> <span class="kd">var</span><span class="p">.</span><span class="nx">location</span>
<span class="nx">tags</span> <span class="o">=</span> <span class="nx">local</span><span class="p">.</span><span class="nx">tags</span>
<span class="p">}</span>
</code></pre></div></div>
<h2 id="create-the-docker-image-registry">Create the docker image registry</h2>
<p>To store the Docker images you have 2 options:</p>
<ul>
<li>Use the <strong><a href="https://azure.microsoft.com/en-us/services/container-registry/">Azure Container Registry</a></strong> service</li>
<li>Use <strong><a href="https://hub.docker.com/">Docker Hub</a></strong> directly</li>
</ul>
<p>In this tutorial we will use the Azure Container Registry service. To do that, create a file called <code class="language-plaintext highlighter-rouge">acr.tf</code> and add this code:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">resource</span> <span class="dl">"</span><span class="s2">azurerm_container_registry</span><span class="dl">"</span> <span class="dl">"</span><span class="s2">this</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="nx">format</span><span class="p">(</span><span class="dl">"</span><span class="s2">cr%s</span><span class="dl">"</span><span class="p">,</span> <span class="nx">local</span><span class="p">.</span><span class="nx">resource_suffix_lowercase</span><span class="p">)</span>
<span class="nx">resource_group_name</span> <span class="o">=</span> <span class="nx">azurerm_resource_group</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">name</span>
<span class="nx">location</span> <span class="o">=</span> <span class="nx">azurerm_resource_group</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">location</span>
<span class="nx">sku</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">Basic</span><span class="dl">"</span>
<span class="nx">admin_enabled</span> <span class="o">=</span> <span class="kc">true</span>
<span class="p">}</span>
</code></pre></div></div>
<p>As you can see you need to enable the admin mode to be able to use the credentials in the Azure Container Apps. You can also specify the SKU that you want to use. In this tutorial we will use the <code class="language-plaintext highlighter-rouge">Basic</code> SKU.</p>
<h2 id="run-terraform">Run Terraform</h2>
<p>Let’s run Terraform <code class="language-plaintext highlighter-rouge">plan</code> command and apply it:</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>terraform plan <span class="nt">--out</span><span class="o">=</span>plan.out
</code></pre></div></div>
<p>Then:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>terraform apply plan.out
</code></pre></div></div>
<h2 id="create-the-docker-images">Create the docker images</h2>
<p>Now that we have our registry we can create our docker images. You have 2 images to build, one for the frontend and one for the backend API.</p>
<h3 id="the-frontend-image">The frontend image</h3>
<p>Let’s clone the <a href="https://github.com/damienaicheh/fruits-ratings-web">repository</a> that contains the frontend application and run the <code class="language-plaintext highlighter-rouge">docker build</code> command in it:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker build <span class="nt">-t</span> <your-container-registry-name>.azurecr.io/fruits-frontend:1.0.0 <span class="nb">.</span>
</code></pre></div></div>
<p>You can of course specify the name and tag for the image of your choice. In this tutorial we will use the following name and tag: <code class="language-plaintext highlighter-rouge"><your-container-registry-name>.azurecr.io/fruits-frontend:1.0.0</code>.</p>
<h3 id="the-backend-image">The backend image</h3>
<p>Let’s clone the <a href="https://github.com/damienaicheh/fruits-ratings-api">repository</a> that contains the backend API and run the <code class="language-plaintext highlighter-rouge">docker build</code> command:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker build <span class="nt">-t</span> <your-container-registry-name>.azurecr.io/fruits-backend:1.0.0 <span class="nb">.</span>
</code></pre></div></div>
<p>The name and tag for this image will be <code class="language-plaintext highlighter-rouge"><your-container-registry-name>.azurecr.io/fruits-backend:1.0.0</code>.</p>
<h3 id="push-the-images-to-the-registry">Push the images to the registry</h3>
<p>Now that we have our images we can push them into the registry. Connect to Azure Container Registry:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Connect to the registry</span>
az acr login <span class="nt">--name</span> <your-container-registry-name>
</code></pre></div></div>
<p>Make sure you have the <code class="language-plaintext highlighter-rouge"><your-container-registry-name>.azurecr.io/</code> prefix to be able to push your Docker images.</p>
<p>Push the images:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Push the frontend image</span>
docker push crdevwefrt01.azurecr.io/fruits-frontend:1.0.0
<span class="c"># Push the backend image</span>
docker push crdevwefrt01.azurecr.io/fruits-backend:1.0.0
</code></pre></div></div>
<h2 id="check-images-locally-with-docker">Check images locally with Docker</h2>
<p>This part is optional but it can be useful to check that the images are correctly build before deploying them to Azure Container Apps. To do that you will need to run a mongodb container locally.</p>
<p>First, create a Docker local network called <code class="language-plaintext highlighter-rouge">fruits-network</code>:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker network create fruits-network
</code></pre></div></div>
<p>This will allow the frontend, backend and mongodb containers to communicate together.</p>
<p>Instanciate the mongodb container, choose the username and passwords you want, you will need them to connect to the database from the backend image:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker run <span class="nt">--name</span> mongodb <span class="se">\</span>
<span class="nt">--network</span><span class="o">=</span>fruits-network <span class="se">\</span>
<span class="nt">-e</span> <span class="nv">MONGODB_USERNAME</span><span class="o">=</span>ratingsuser <span class="se">\</span>
<span class="nt">-e</span> <span class="nv">MONGODB_PASSWORD</span><span class="o">=</span>ratingspassword <span class="se">\</span>
<span class="nt">-e</span> <span class="nv">MONGODB_DATABASE</span><span class="o">=</span>ratingsdb <span class="se">\</span>
<span class="nt">-e</span> <span class="nv">MONGODB_ROOT_USER</span><span class="o">=</span>root <span class="se">\</span>
<span class="nt">-e</span> <span class="nv">MONGODB_ROOT_PASSWORD</span><span class="o">=</span>ratingspassword <span class="se">\</span>
<span class="nt">-it</span> bitnami/mongodb:latest
</code></pre></div></div>
<p>As you can see above the container is running inside the <code class="language-plaintext highlighter-rouge">fruits-network</code> network.</p>
<p>Next, run the backend image and pass the <code class="language-plaintext highlighter-rouge">MONGODB_URI</code> environment variable. The <code class="language-plaintext highlighter-rouge">MONGODB_URI</code> must be in this format <code class="language-plaintext highlighter-rouge">mongodb://[username]:[password]@[endpoint]:27017/ratingsdb</code></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker run <span class="nt">--name</span> api <span class="se">\</span>
<span class="nt">--network</span><span class="o">=</span>fruits-network <span class="se">\</span>
<span class="nt">-p</span> 3000:3000 <span class="se">\</span>
<span class="nt">-e</span> <span class="nv">MONGODB_URI</span><span class="o">=</span>mongodb://ratingsuser:ratingspassword@mongodb:27017/ratingsdb <span class="se">\</span>
<span class="nt">-it</span> <span class="nt">--rm</span> <your-container-registry-name>.azurecr.io/fruits-backend:1.0.0
</code></pre></div></div>
<p>If you go to <code class="language-plaintext highlighter-rouge">http://localhost:3000/api/items</code> you should see the list of fruits in the database.</p>
<p>Finally, run the frontend image and pass the <code class="language-plaintext highlighter-rouge">API</code> environment variable:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker run <span class="nt">--name</span> web <span class="se">\</span>
<span class="nt">--network</span><span class="o">=</span>fruits-network <span class="se">\</span>
<span class="nt">-p</span> 8080:8080 <span class="se">\</span>
<span class="nt">-e</span> <span class="nv">API</span><span class="o">=</span>http://api:3000 <span class="se">\</span>
<span class="nt">-it</span> <span class="nt">--rm</span> <your-container-registry-name>.azurecr.io/fruits-frontend:1.0.0
</code></pre></div></div>
<p>If everything is ok you should be able to access the application at <code class="language-plaintext highlighter-rouge">http://localhost:8080</code> and see something like this:</p>
<p><img src="https://damienaicheh.github.io/assets/posts/2023-05-03-web-result.png" alt="Front web" /></p>
<p>You can vote for your favorite fruit and see the results in the leaderboard.</p>
<h2 id="final-touch">Final touch</h2>
<p>You have your Azure Container Registry and your Docker images ready to be used in the Azure Container Apps environment. You will find the complete source code in this <strong><a href="https://github.com/damienaicheh/fruits-on-azure-container-apps">Github</a></strong> repository.</p>
<h2 id="whats-next">What’s next?</h2>
<p>In the next <strong><a href="/terraform/azure/azure-container-apps/2023/05/05/azure-container-apps-environment-terraform-en.html">tutorial</a></strong> of this series we will focus on creating the Azure Container Apps environment.</p>Damien AichehStore your Docker ImagesPréparez votre Azure Container Registry pour votre Azure Container Apps avec Terraform2023-05-03T06:00:00+00:002023-05-03T06:00:00+00:00https://damienaicheh.github.io/terraform/azure/azure-container-apps/2023/05/03/azure-container-apps-prepare-docker-images-fr<p>Dans ce tutoriel, vous allez configurer un <a href="https://azure.microsoft.com/en-us/services/container-registry/">Azure Container Registry</a> pour stocker les images Docker. Vous créerez également les images Docker que vous utiliserez dans l’environnement Azure Container Apps.</p>
<p>Ce tutoriel fait partie d’une <strong><a href="/terraform/azure/azure-container-apps/2023/05/01/azure-container-apps-terraform-series-fr.html">série complète</a></strong> de tutoriels sur l’utilisation d’Azure Container Apps avec Terraform.</p>
<h2 id="structuration-du-projet">Structuration du projet</h2>
<p>Créons un projet Terraform dédié appelé par exemple <code class="language-plaintext highlighter-rouge">fruits-on-azure-container-apps</code> avec cette structure à l’intérieur :</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>| - fruits-on-azure-container-apps
| - .gitignore
</code></pre></div></div>
<p>Le <code class="language-plaintext highlighter-rouge">.gitignore</code> contiendra tous les fichiers terraform que nous voulons ignorer. Il ressemblera à ceci:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.terraform
*.tfstate
**/*.lock.*
**/*.tfplan
terraform.tfplan
terraform.tfstate.backup
plan.out
</code></pre></div></div>
<h2 id="initialiser-terraform">Initialiser terraform</h2>
<p>Pour pouvoir utiliser Terraform avec Azure, vous devez installer <strong><a href="https://docs.microsoft.com/en-us/cli/azure/install-azure-cli">Azure CLI</a></strong> et vous connecter à votre compte Azure. Vous pouvez également utiliser un Service Principal Name (SPN) pour vous authentifier, tous les détails peuvent être trouvés dans la <a href="https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/guides/service_principal_client_secret#configuring-the-service-principal-in-terraform">documentation</a> officielle.</p>
<p>Pour pouvoir stocker le state de Terraform dans Azure, vous devez créer un Azure Storage Account et un container.</p>
<p>Ensuite, connectez-vous à votre abonnement et créez un groupe de ressources dédié aux states Terraform, par exemple <code class="language-plaintext highlighter-rouge">rg-dev-terraform-states</code> :</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Connect to Azure</span>
az login
<span class="c"># Select the subscription</span>
az account <span class="nb">set</span> <span class="nt">--subscription</span> <your-subscription-id>
<span class="c"># Create the resource group with the location of your choice</span>
az group create <span class="nt">--name</span> rg-dev-terraform-states <span class="nt">--location</span> westeurope
</code></pre></div></div>
<p>Ensuite, exécutez les commandes suivantes pour créer un Azure Storage Account et le container pour stocker le state de Terraform. Assurez-vous de définir <strong>votre propre nom de stockage account</strong> qui doit être unique :</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Create the storage account</span>
az storage account create <span class="nt">-n</span> <your-storage-account-name> <span class="se">\</span>
<span class="nt">-g</span> rg-dev-terraform-states <span class="se">\</span>
<span class="nt">-l</span> westeurope <span class="se">\</span>
<span class="nt">--sku</span> Standard_LRS
</code></pre></div></div>
<p>Sur la base de la ligne de commande ci-dessous, pour créer le container appelé <code class="language-plaintext highlighter-rouge">tfstates</code> pour les fichiers de states terraform, vous devez récupérer l’une des clés d’accès de votre Storage Account. Vous pouvez l’obtenir dans le portail Azure dans la section <code class="language-plaintext highlighter-rouge">Access Keys</code> de votre Storage Account :</p>
<p><img src="https://damienaicheh.github.io/assets/posts/2023-05-03-storage-account-key.png" alt="Storage account access keys" /></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Then create the tfstates container inside it</span>
az storage container create <span class="nt">-n</span> tfstates <span class="se">\</span>
<span class="nt">--account-name</span> <your-storage-account-name> <span class="se">\</span>
<span class="nt">--account-key</span> <your-storage-account-key>
</code></pre></div></div>
<p>Créons un fichier <code class="language-plaintext highlighter-rouge">provider.tf</code> et déclarons-y le provider <code class="language-plaintext highlighter-rouge">azurerm</code> :</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">provider</span> <span class="dl">"</span><span class="s2">azurerm</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">features</span> <span class="p">{</span>
<span class="nx">log_analytics_workspace</span> <span class="p">{</span>
<span class="nx">permanently_delete_on_destroy</span> <span class="o">=</span> <span class="kc">true</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nx">skip_provider_registration</span> <span class="o">=</span> <span class="kc">false</span>
<span class="p">}</span>
<span class="nx">terraform</span> <span class="p">{</span>
<span class="nx">required_providers</span> <span class="p">{</span>
<span class="nx">azurerm</span> <span class="o">=</span> <span class="p">{</span>
<span class="nx">source</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">hashicorp/azurerm</span><span class="dl">"</span>
<span class="nx">version</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">~> 3.51.0</span><span class="dl">"</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nx">required_version</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">>=1.4.5</span><span class="dl">"</span>
<span class="nx">backend</span> <span class="dl">"</span><span class="s2">azurerm</span><span class="dl">"</span> <span class="p">{}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Nous pouvons maintenant exécuter la commande suivante pour initialiser Terraform :</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>terraform init <span class="se">\</span>
<span class="nt">-reconfigure</span> <span class="se">\</span>
<span class="nt">-input</span><span class="o">=</span><span class="nb">false</span> <span class="se">\</span>
<span class="nt">-backend-config</span><span class="o">=</span><span class="s2">"resource_group_name=rg-dev-terraform-states"</span> <span class="se">\</span>
<span class="nt">-backend-config</span><span class="o">=</span><span class="s2">"storage_account_name=<your-storage-account-name>"</span> <span class="se">\</span>
<span class="nt">-backend-config</span><span class="o">=</span><span class="s2">"container_name=tfstates"</span> <span class="se">\</span>
<span class="nt">-backend-config</span><span class="o">=</span><span class="s2">"key=fruits.aca.terraform.tfstate"</span>
</code></pre></div></div>
<p>Si tout va bien vous devriez voir ce genre de message dans votre terminal :</p>
<p><img src="https://damienaicheh.github.io/assets/posts/2023-05-03-terraform-init.png" alt="Terraform init" /></p>
<h2 id="définir-les-conventions-de-nommage">Définir les conventions de nommage</h2>
<p>Vous utiliserez la <strong><a href="https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/resource-naming">convention de nommage</a></strong> officielle pour les ressources que vous créerez sur Azure. Toutes les abréviations se trouvent dans la <a href="https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/resource-abbreviations">documentation</a>.</p>
<p>Définissons cette convention de nommage :</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"><!--If the resource prefix has a dash: --></span>
<span class="nt"><service-prefix></span>-<span class="nt"><environment></span>-<span class="nt"><region></span>-<span class="nt"><application-name></span>-<span class="nt"><instance></span>
<span class="c"><!--If the resource does not autorize any special caracters: --></span>
<span class="nt"><service-prefix><environment><region><application-name><instance></span>
</code></pre></div></div>
<p>Créons donc un fichier <code class="language-plaintext highlighter-rouge">variables.tf</code> et définissons toutes ces valeurs en tant que variables :</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">variable</span> <span class="dl">"</span><span class="s2">environment</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">description</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">The environment deployed</span><span class="dl">"</span>
<span class="nx">type</span> <span class="o">=</span> <span class="nx">string</span>
<span class="k">default</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">dev</span><span class="dl">"</span>
<span class="nx">validation</span> <span class="p">{</span>
<span class="nx">condition</span> <span class="o">=</span> <span class="nx">can</span><span class="p">(</span><span class="nx">regex</span><span class="p">(</span><span class="dl">"</span><span class="s2">(dev|stag|prod)</span><span class="dl">"</span><span class="p">,</span> <span class="kd">var</span><span class="p">.</span><span class="nx">environment</span><span class="p">))</span>
<span class="nx">error_message</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">The environment value must be valid.</span><span class="dl">"</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nx">variable</span> <span class="dl">"</span><span class="s2">region</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">description</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">Azure deployment region</span><span class="dl">"</span>
<span class="nx">type</span> <span class="o">=</span> <span class="nx">string</span>
<span class="k">default</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">we</span><span class="dl">"</span>
<span class="p">}</span>
<span class="nx">variable</span> <span class="dl">"</span><span class="s2">application</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">description</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">The name of the application</span><span class="dl">"</span>
<span class="nx">type</span> <span class="o">=</span> <span class="nx">string</span>
<span class="k">default</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">frt</span><span class="dl">"</span>
<span class="p">}</span>
<span class="nx">variable</span> <span class="dl">"</span><span class="s2">location</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">description</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">Azure deployment location</span><span class="dl">"</span>
<span class="nx">type</span> <span class="o">=</span> <span class="nx">string</span>
<span class="k">default</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">westeurope</span><span class="dl">"</span>
<span class="p">}</span>
<span class="nx">variable</span> <span class="dl">"</span><span class="s2">resource_group_name_suffix</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">type</span> <span class="o">=</span> <span class="nx">string</span>
<span class="k">default</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">01</span><span class="dl">"</span>
<span class="nx">description</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">The resource group name suffix</span><span class="dl">"</span>
<span class="nx">validation</span> <span class="p">{</span>
<span class="nx">condition</span> <span class="o">=</span> <span class="nx">can</span><span class="p">(</span><span class="nx">regex</span><span class="p">(</span><span class="dl">"</span><span class="s2">[0-9]{2}</span><span class="dl">"</span><span class="p">,</span> <span class="kd">var</span><span class="p">.</span><span class="nx">resource_group_name_suffix</span><span class="p">))</span>
<span class="nx">error_message</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">The resource group name suffix value is not a valid number.</span><span class="dl">"</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nx">variable</span> <span class="dl">"</span><span class="s2">repository</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">description</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">The repository name</span><span class="dl">"</span>
<span class="nx">type</span> <span class="o">=</span> <span class="nx">string</span>
<span class="k">default</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">fruits-on-azure-container-apps</span><span class="dl">"</span>
<span class="p">}</span>
<span class="nx">variable</span> <span class="dl">"</span><span class="s2">creator</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">description</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">The name of the project's creator</span><span class="dl">"</span>
<span class="nx">type</span> <span class="o">=</span> <span class="nx">string</span>
<span class="k">default</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">terraform</span><span class="dl">"</span>
<span class="p">}</span>
<span class="nx">variable</span> <span class="dl">"</span><span class="s2">tags</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">type</span> <span class="o">=</span> <span class="nx">map</span><span class="p">(</span><span class="nx">any</span><span class="p">)</span>
<span class="nx">description</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">The custom tags for all resources</span><span class="dl">"</span>
<span class="k">default</span> <span class="o">=</span> <span class="p">{}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Définissons un suffixe de ressource et les tags pour vos ressources dans un fichier <code class="language-plaintext highlighter-rouge">locals.tf</code> :</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">locals</span> <span class="p">{</span>
<span class="nx">resource_lowercase_array</span> <span class="o">=</span> <span class="p">[</span><span class="nx">lower</span><span class="p">(</span><span class="kd">var</span><span class="p">.</span><span class="nx">environment</span><span class="p">),</span> <span class="nx">lower</span><span class="p">(</span><span class="kd">var</span><span class="p">.</span><span class="nx">region</span><span class="p">),</span> <span class="nx">lower</span><span class="p">(</span><span class="kd">var</span><span class="p">.</span><span class="nx">application</span><span class="p">),</span> <span class="kd">var</span><span class="p">.</span><span class="nx">resource_group_name_suffix</span><span class="p">]</span>
<span class="nx">resource_suffix_kebabcase</span> <span class="o">=</span> <span class="nx">join</span><span class="p">(</span><span class="dl">"</span><span class="s2">-</span><span class="dl">"</span><span class="p">,</span> <span class="nx">local</span><span class="p">.</span><span class="nx">resource_lowercase_array</span><span class="p">)</span>
<span class="nx">resource_suffix_lowercase</span> <span class="o">=</span> <span class="nx">join</span><span class="p">(</span><span class="dl">""</span><span class="p">,</span> <span class="nx">local</span><span class="p">.</span><span class="nx">resource_lowercase_array</span><span class="p">)</span>
<span class="nx">tags</span> <span class="o">=</span> <span class="nx">merge</span><span class="p">(</span>
<span class="kd">var</span><span class="p">.</span><span class="nx">tags</span><span class="p">,</span>
<span class="nx">tomap</span><span class="p">(</span>
<span class="p">{</span>
<span class="dl">"</span><span class="s2">Creator</span><span class="dl">"</span> <span class="o">=</span> <span class="kd">var</span><span class="p">.</span><span class="nx">creator</span><span class="p">,</span>
<span class="dl">"</span><span class="s2">Environment</span><span class="dl">"</span> <span class="o">=</span> <span class="kd">var</span><span class="p">.</span><span class="nx">environment</span><span class="p">,</span>
<span class="dl">"</span><span class="s2">Region</span><span class="dl">"</span> <span class="o">=</span> <span class="kd">var</span><span class="p">.</span><span class="nx">region</span><span class="p">,</span>
<span class="dl">"</span><span class="s2">Repository</span><span class="dl">"</span> <span class="o">=</span> <span class="kd">var</span><span class="p">.</span><span class="nx">repository</span><span class="p">,</span>
<span class="dl">"</span><span class="s2">Application</span><span class="dl">"</span> <span class="o">=</span> <span class="kd">var</span><span class="p">.</span><span class="nx">application</span><span class="p">,</span>
<span class="p">}</span>
<span class="p">)</span>
<span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Cela servira à définir le suffixe de toutes les ressources que nous allons créer.</p>
<h2 id="créer-un-groupe-de-ressources">Créer un groupe de ressources</h2>
<p>La première chose que vous devez faire est de créer un groupe de ressources pour stocker toutes les ressources que nous allons créer. Pour ce faire, créez un fichier appelé <code class="language-plaintext highlighter-rouge">rg.tf</code> et ajoutez ce code :</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">resource</span> <span class="dl">"</span><span class="s2">azurerm_resource_group</span><span class="dl">"</span> <span class="dl">"</span><span class="s2">this</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="nx">format</span><span class="p">(</span><span class="dl">"</span><span class="s2">rg-%s</span><span class="dl">"</span><span class="p">,</span> <span class="nx">local</span><span class="p">.</span><span class="nx">resource_suffix_kebabcase</span><span class="p">)</span>
<span class="nx">location</span> <span class="o">=</span> <span class="kd">var</span><span class="p">.</span><span class="nx">location</span>
<span class="nx">tags</span> <span class="o">=</span> <span class="nx">local</span><span class="p">.</span><span class="nx">tags</span>
<span class="p">}</span>
</code></pre></div></div>
<h2 id="créer-le-registre-dimages-docker">Créer le registre d’images Docker</h2>
<p>Pour stocker les images Docker vous avez 2 options :</p>
<ul>
<li>Utilisez le service <strong><a href="https://azure.microsoft.com/en-us/services/container-registry/">Azure Container Registry</a></strong></li>
<li>Utilisez <strong><a href="https://hub.docker.com/">Docker Hub</a></strong> directement</li>
</ul>
<p>Dans ce tutoriel, nous utiliserons le service Azure Container Registry. Pour ce faire, créez un fichier appelé <code class="language-plaintext highlighter-rouge">acr.tf</code> et ajoutez ce code :</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">resource</span> <span class="dl">"</span><span class="s2">azurerm_container_registry</span><span class="dl">"</span> <span class="dl">"</span><span class="s2">this</span><span class="dl">"</span> <span class="p">{</span>
<span class="nx">name</span> <span class="o">=</span> <span class="nx">format</span><span class="p">(</span><span class="dl">"</span><span class="s2">cr%s</span><span class="dl">"</span><span class="p">,</span> <span class="nx">local</span><span class="p">.</span><span class="nx">resource_suffix_lowercase</span><span class="p">)</span>
<span class="nx">resource_group_name</span> <span class="o">=</span> <span class="nx">azurerm_resource_group</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">name</span>
<span class="nx">location</span> <span class="o">=</span> <span class="nx">azurerm_resource_group</span><span class="p">.</span><span class="k">this</span><span class="p">.</span><span class="nx">location</span>
<span class="nx">sku</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">Basic</span><span class="dl">"</span>
<span class="nx">admin_enabled</span> <span class="o">=</span> <span class="kc">true</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Comme vous pouvez le constater, vous devez activer le mode administrateur pour pouvoir utiliser les informations d’identification dans Azure Container Apps. Vous pouvez également spécifier le SKU que vous souhaitez utiliser. Dans ce tutoriel, nous utiliserons le SKU <code class="language-plaintext highlighter-rouge">Basic</code>.</p>
<h2 id="lancez-terraform">Lancez Terraform</h2>
<p>Exécutons la commande <code class="language-plaintext highlighter-rouge">plan</code> de Terraform et appliquons-la :</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>terraform plan <span class="nt">--out</span><span class="o">=</span>plan.out
</code></pre></div></div>
<p>Then:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>terraform apply plan.out
</code></pre></div></div>
<h2 id="créer-les-images-docker">Créer les images Docker</h2>
<p>Maintenant que nous avons notre registre, nous pouvons créer nos images Docker. Vous avez 2 images à construire, une pour le frontend et une pour l’API backend.</p>
<h3 id="limage-frontend">L’image frontend</h3>
<p>Clonons le <a href="https://github.com/damienaicheh/fruits-ratings-web">repository</a> qui contient l’application frontend et exécutons la commande <code class="language-plaintext highlighter-rouge">docker build</code> dedans :</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker build <span class="nt">-t</span> <your-container-registry-name>.azurecr.io/fruits-frontend:1.0.0 <span class="nb">.</span>
</code></pre></div></div>
<p>Vous pouvez bien sûr préciser le nom et le tag de l’image de votre choix. Dans ce tutorial, nous utiliserons le nom et le tag suivants : <code class="language-plaintext highlighter-rouge"><your-container-registry-name>.azurecr.io/fruits-frontend:1.0.0</code>.</p>
<h3 id="limage-backend">L’image backend</h3>
<p>Clonons le <a href="https://github.com/damienaicheh/fruits-ratings-api">repository</a> qui contient l’API backend et exécutons la commande <code class="language-plaintext highlighter-rouge">docker build</code> :</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker build <span class="nt">-t</span> <your-container-registry-name>.azurecr.io/fruits-backend:1.0.0 <span class="nb">.</span>
</code></pre></div></div>
<p>Le nom et le tag de cette image seront <code class="language-plaintext highlighter-rouge"><your-container-registry-name>.azurecr.io/fruits-backend:1.0.0</code>.</p>
<h3 id="poussez-les-images-vers-le-registre">Poussez les images vers le registre</h3>
<p>Maintenant que nous avons nos images, nous pouvons les pousser dans le registre.
Connectez-vous à Azure Container Registry :</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Connect to the registry</span>
az acr login <span class="nt">--name</span> <your-container-registry-name>
</code></pre></div></div>
<p>Assurez-vous d’avoir le préfixe <code class="language-plaintext highlighter-rouge"><your-container-registry-name>.azurecr.io/</code> pour pouvoir pousser vos images Docker.</p>
<p>Poussez les images :</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Push the frontend image</span>
docker push crdevwefrt01.azurecr.io/fruits-frontend:1.0.0
<span class="c"># Push the backend image</span>
docker push crdevwefrt01.azurecr.io/fruits-backend:1.0.0
</code></pre></div></div>
<h2 id="vérifier-les-images-localement-avec-docker">Vérifier les images localement avec Docker</h2>
<p>Cette partie est facultative mais elle peut être utile pour vérifier que les images sont correctement construites avant de les déployer sur Azure Container Apps. Pour ce faire, vous devrez exécuter un conteneur mongodb localement.</p>
<p>Tout d’abord, créez un réseau local à Docker appelé <code class="language-plaintext highlighter-rouge">fruits-network</code> :</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker network create fruits-network
</code></pre></div></div>
<p>Cela permettra aux conteneurs frontend, backend et mongodb de communiquer ensemble.</p>
<p>Instanciez le conteneur mongodb, choisissez le nom d’utilisateur et les mots de passe que vous souhaitez, vous en aurez besoin pour vous connecter à la base de données depuis l’image backend :</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker run <span class="nt">--name</span> mongodb <span class="se">\</span>
<span class="nt">--network</span><span class="o">=</span>fruits-network <span class="se">\</span>
<span class="nt">-e</span> <span class="nv">MONGODB_USERNAME</span><span class="o">=</span>ratingsuser <span class="se">\</span>
<span class="nt">-e</span> <span class="nv">MONGODB_PASSWORD</span><span class="o">=</span>ratingspassword <span class="se">\</span>
<span class="nt">-e</span> <span class="nv">MONGODB_DATABASE</span><span class="o">=</span>ratingsdb <span class="se">\</span>
<span class="nt">-e</span> <span class="nv">MONGODB_ROOT_USER</span><span class="o">=</span>root <span class="se">\</span>
<span class="nt">-e</span> <span class="nv">MONGODB_ROOT_PASSWORD</span><span class="o">=</span>ratingspassword <span class="se">\</span>
<span class="nt">-it</span> bitnami/mongodb:latest
</code></pre></div></div>
<p>Comme vous pouvez le voir ci-dessus, le conteneur s’exécute à l’intérieur du réseau <code class="language-plaintext highlighter-rouge">fruits-network</code>.</p>
<p>Ensuite, exécutez l’image backend et transmettez la variable d’environnement <code class="language-plaintext highlighter-rouge">MONGODB_URI</code>. Le <code class="language-plaintext highlighter-rouge">MONGODB_URI</code> doit être au format <code class="language-plaintext highlighter-rouge">mongodb://[username]:[password]@[endpoint]:27017/ratingsdb</code></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker run <span class="nt">--name</span> api <span class="se">\</span>
<span class="nt">--network</span><span class="o">=</span>fruits-network <span class="se">\</span>
<span class="nt">-p</span> 3000:3000 <span class="se">\</span>
<span class="nt">-e</span> <span class="nv">MONGODB_URI</span><span class="o">=</span>mongodb://ratingsuser:ratingspassword@mongodb:27017/ratingsdb <span class="se">\</span>
<span class="nt">-it</span> <span class="nt">--rm</span> <your-container-registry-name>.azurecr.io/fruits-backend:1.0.0
</code></pre></div></div>
<p>Si vous allez sur <code class="language-plaintext highlighter-rouge">http://localhost:3000/api/items</code> vous devriez voir la liste des fruits dans la base de données.</p>
<p>Enfin, exécutez l’image frontale et passez la variable d’environnement <code class="language-plaintext highlighter-rouge">API</code> :</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker run <span class="nt">--name</span> web <span class="se">\</span>
<span class="nt">--network</span><span class="o">=</span>fruits-network <span class="se">\</span>
<span class="nt">-p</span> 8080:8080 <span class="se">\</span>
<span class="nt">-e</span> <span class="nv">API</span><span class="o">=</span>http://api:3000 <span class="se">\</span>
<span class="nt">-it</span> <span class="nt">--rm</span> <your-container-registry-name>.azurecr.io/fruits-frontend:1.0.0
</code></pre></div></div>
<p>Si tout va bien, vous devriez pouvoir accéder à l’application sur <code class="language-plaintext highlighter-rouge">http://localhost:8080</code> et voir quelque chose comme ceci :</p>
<p><img src="https://damienaicheh.github.io/assets/posts/2023-05-03-web-result.png" alt="Front web" /></p>
<p>Vous pouvez voter pour votre fruit préféré et voir les résultats dans le classement.</p>
<h2 id="touche-finale">Touche finale</h2>
<p>Votre Azure Container Registry et vos images Docker sont prêts à être utilisés dans l’environnement Azure Container Apps. Vous trouverez le code source complet dans ce répertoire <strong><a href="https://github.com/damienaicheh/fruits-on-azure-container-apps">Github</a></strong>.</p>
<h2 id="et-après-">Et après ?</h2>
<p>Dans le <strong><a href="/terraform/azure/azure-container-apps/2023/05/05/azure-container-apps-environment-terraform-fr.html">tutoriel</a></strong> suivant de cette série, nous nous concentrerons sur la création de l’environnement Azure Container Apps.</p>Damien AichehStore your Docker Images