<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Panda Code Tech blog]]></title><description><![CDATA[Panda Code Tech blog]]></description><link>https://techblog.pandacode.fr</link><generator>RSS for Node</generator><lastBuildDate>Mon, 27 Apr 2026 12:40:13 GMT</lastBuildDate><atom:link href="https://techblog.pandacode.fr/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Symfony/Bref/Pulumi : ajout d'un nom de domaine et d'une tâche planifiée]]></title><description><![CDATA[Préambule
Cette article est le deuxième d'une série sur le déploiement d'un projet Symfony sur AWS Lambda avec l'outil d'IaC Pulumi. Dans le premier article, nous avons mis en place le nécessaire pour avoir notre API accessible via une url fournie pa...]]></description><link>https://techblog.pandacode.fr/symfonybrefpulumi-ajout-dun-nom-de-domaine-et-dune-tache-planifiee</link><guid isPermaLink="true">https://techblog.pandacode.fr/symfonybrefpulumi-ajout-dun-nom-de-domaine-et-dune-tache-planifiee</guid><category><![CDATA[Pulumi]]></category><category><![CDATA[AWS]]></category><category><![CDATA[Symfony]]></category><category><![CDATA[bref php]]></category><dc:creator><![CDATA[Sébastien Porati]]></dc:creator><pubDate>Wed, 01 Mar 2023 20:10:38 GMT</pubDate><content:encoded><![CDATA[<h2 id="heading-preambule">Préambule</h2>
<p>Cette article est le deuxième d'une série sur le déploiement d'un projet Symfony sur AWS Lambda avec l'outil d'IaC Pulumi. Dans le <a target="_blank" href="https://techblog.pandacode.fr/deployer-un-projet-symfony-sur-aws-lambda-avec-pulumi-et-bref">premier article</a>, nous avons mis en place le nécessaire pour avoir notre API accessible via une url fournie par AWS ressemblant à ça : <code>https://0nz9kqsta9.execute-api.eu-west-3.amazonaws.com</code></p>
<p>Dans ce deuxième article, nous allons voir comment utiliser un nom de domaine plus <em>friendly</em> pour notre API et comment mettre en place une tâche planifiée (<em>aka cron</em>): 2 choses essentielles dans tout projet ;)</p>
<p>Comme pour le premier article, le code est disponible sur le <a target="_blank" href="https://github.com/popofr13/blog-articles/tree/main/2023-02-pulumi-php-bref-2">repository Github</a>, et j'ai fait en sorte qu'il y ait une <a target="_blank" href="https://github.com/popofr13/blog-articles/pull/2/files">PR contenant seulement les modifications liées</a> à ce deuxième article.</p>
<h2 id="heading-la-partie-infrastructure-le-sous-domaine-personnalise">La partie "Infrastructure" : le sous-domaine personnalisé</h2>
<p>J'ai acheté le nom de domaine <code>my-projects.tech</code> spécialement pour écrire cet article : nous allons faire en sorte que le sous-domaine <code>api.my-projects.tech</code> soit utilisé pour notre API.</p>
<h3 id="heading-le-certificat-ssl-aws-certificate-managerhttpsawsamazoncomcertificate-managernc1hls">Le certificat SSL (<a target="_blank" href="https://aws.amazon.com/certificate-manager/?nc1=h_ls">AWS Certificate Manager</a>)</h3>
<p>Avant de pouvoir plugger notre domaine sur notre <em>API Gateway</em>, nous avons besoin d'un certificat <em>SSL</em> que nous obtiendrons en utilisant un service AWS : celui-ci sera ensuite facilement utilisable avec les autres services.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// src/acm/index.ts</span>
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> aws <span class="hljs-keyword">from</span> <span class="hljs-string">"@pulumi/aws"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> sslCertificateApi = <span class="hljs-keyword">new</span> aws.acm.Certificate(<span class="hljs-string">"api"</span>,
    {
        domainName: <span class="hljs-string">"api.my-projects.tech"</span>,
        validationMethod: <span class="hljs-string">"DNS"</span>,
    }
);
</code></pre>
<h3 id="heading-le-dns-amazon-route53httpsawsamazoncomroute53nc1hls">Le DNS (<a target="_blank" href="https://aws.amazon.com/route53/?nc1=h_ls">Amazon Route53</a>)</h3>
<p>Nous voyons que la méthode de validation du certificat choisie est DNS. Nous allons donc utiliser le service Route53 pour gérer les enregistrements DNS nécessaires à cette validation.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// src/route53/index.ts</span>
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> aws <span class="hljs-keyword">from</span> <span class="hljs-string">"@pulumi/aws"</span>;
<span class="hljs-keyword">import</span> {sslCertificateApi} <span class="hljs-keyword">from</span> <span class="hljs-string">"../acm"</span>;
<span class="hljs-keyword">import</span> {apiDomainName} <span class="hljs-keyword">from</span> <span class="hljs-string">"../api-gateway"</span>;

<span class="hljs-comment">// La liste des serveurs de nom de domaines</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> mainDelegationSet = <span class="hljs-keyword">new</span> aws.route53.DelegationSet(<span class="hljs-string">"main"</span>, {}, {});

<span class="hljs-comment">// Création de la Zone principale (domaine)</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> zone = <span class="hljs-keyword">new</span> aws.route53.Zone(<span class="hljs-string">"my-projects"</span>, {
    delegationSetId: mainDelegationSet.id,
    name: <span class="hljs-string">"my-projects.tech"</span>,
});

<span class="hljs-comment">// L'enregistrement DNS permettant la validation du certificat SSL</span>
<span class="hljs-keyword">const</span> apiAcmValidation = <span class="hljs-keyword">new</span> aws.route53.Record(<span class="hljs-string">"api.acm"</span>,
    {
        zoneId: zone.zoneId,
        name: sslCertificateApi.domainValidationOptions[<span class="hljs-number">0</span>].resourceRecordName,
        <span class="hljs-keyword">type</span>: sslCertificateApi.domainValidationOptions[<span class="hljs-number">0</span>].resourceRecordType,
        records: [sslCertificateApi.domainValidationOptions[<span class="hljs-number">0</span>].resourceRecordValue],
        ttl: <span class="hljs-number">10</span> * <span class="hljs-number">60</span>,
    }
);

<span class="hljs-comment">// Lance la validation du certificat SSL</span>
<span class="hljs-keyword">new</span> aws.acm.CertificateValidation(
    <span class="hljs-string">'api'</span>,
    {
        certificateArn: sslCertificateApi.arn,
        validationRecordFqdns: [apiAcmValidation.fqdn],
    }
);
</code></pre>
<blockquote>
<p><strong>Note :</strong> si vous n'avez pas acheté votre nom de domain chez AWS (ce qui est mon cas =&gt; chez Gandi), il faudra modifier les serveurs de noms pour définir ceux d'AWS. Pour connaître la liste, il faudra préalablement faire un <code>pulumi up</code> pour créer la zone et récupérer la liste (DelegationSet dans le code).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1677667355133/de55571f-85b0-473b-9e09-41eb1140a1a0.jpeg" alt class="image--center mx-auto" /></p>
</blockquote>
<h3 id="heading-modification-de-notre-api-gateway">Modification de notre API Gateway</h3>
<p>Il nous restera une petite modification à faire dans <em>Route53</em>, mais nous avons d'abord besoin de modifier notre <em>API Gateway</em> pour prendre en compte notre sous-domaine et le mapper à notre <em>stage</em>.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// src/api-gateway/index.ts</span>
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> aws <span class="hljs-keyword">from</span> <span class="hljs-string">"@pulumi/aws"</span>;
<span class="hljs-keyword">import</span> {sslCertificateApi} <span class="hljs-keyword">from</span> <span class="hljs-string">"../acm"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> apiApi = <span class="hljs-keyword">new</span> aws.apigatewayv2.Api(<span class="hljs-string">"api"</span>, {
    protocolType: <span class="hljs-string">"HTTP"</span>,
});

<span class="hljs-keyword">const</span> apiStage = <span class="hljs-keyword">new</span> aws.apigatewayv2.Stage(<span class="hljs-string">"api.default"</span>, {
    apiId: apiApi.id,
    autoDeploy: <span class="hljs-literal">true</span>,
    name: <span class="hljs-string">"$default"</span>
});

<span class="hljs-comment">// Ajout de notre sous-domaine personnalisé et utilisant de notre certificat SSL</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> apiDomainName = <span class="hljs-keyword">new</span> aws.apigatewayv2.DomainName(<span class="hljs-string">"api"</span>, {
    domainName: <span class="hljs-string">'api.my-projects.tech'</span>,
    domainNameConfiguration: {
        certificateArn: sslCertificateApi.arn,
        endpointType: <span class="hljs-string">"REGIONAL"</span>,
        securityPolicy: <span class="hljs-string">"TLS_1_2"</span>,
    },
});

<span class="hljs-comment">// Mapping de notre sous-domaine avec le stage de notre APIG</span>
<span class="hljs-keyword">new</span> aws.apigatewayv2.ApiMapping(<span class="hljs-string">"api.api"</span>, {
    apiId: apiApi.id,
    domainName: apiDomainName.id,
    stage: apiStage.id
});
</code></pre>
<p>Il ne manque plus qu'à créer l'enregistrement DNS pour que le sous-domaine <code>api.my-projects.tech</code> pointe bien vers notre <em>API Gateway</em>.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// src/route53/index.ts</span>
<span class="hljs-comment">// ...</span>

<span class="hljs-comment">// Création de l'enregistrement DNS qui utilise les informations du nom de domaine défini dans API Gateway (aws.apigatewayv2.DomainName).</span>
<span class="hljs-keyword">new</span> aws.route53.Record(<span class="hljs-string">'api.apig'</span>, {
    zoneId: zone.zoneId,
    name: <span class="hljs-string">'api.my-projects.tech'</span>,
    <span class="hljs-keyword">type</span>: <span class="hljs-string">"A"</span>,
    aliases: [{
        evaluateTargetHealth: <span class="hljs-literal">true</span>,
        name: apiDomainName.domainNameConfiguration.targetDomainName,
        zoneId: apiDomainName.domainNameConfiguration.hostedZoneId
    }],
});
</code></pre>
<p>Il n'y a plus qu'à <code>pulumi up</code> et notre API sera accessible via notre sous-domaine personnalisé.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1677668068686/f82449e6-9a11-4c2e-8b03-ce78a3f27341.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-la-partie-code-la-tache-planifiee">La partie "code" : la tâche planifiée</h2>
<p>Cette partie est très simple car gérée par <em>Serverless framework</em> (<a target="_blank" href="https://www.serverless.com/framework/docs/providers/aws/events/schedule">doc Schedule</a>) et <em>Bref</em> (<a target="_blank" href="https://bref.sh/docs/web-apps/cron.html">doc Cron</a>). Il suffit de modifier le fichier <code>serverless.yml</code> pour configurer l'exécution de notre cron.</p>
<pre><code class="lang-yaml"><span class="hljs-string">//</span> <span class="hljs-string">serverless.yml</span>

    <span class="hljs-attr">cron1:</span>
        <span class="hljs-attr">handler:</span> <span class="hljs-string">bin/console</span>
        <span class="hljs-attr">layers:</span>
            <span class="hljs-bullet">-</span> <span class="hljs-string">${bref:layer.php-82}</span>
            <span class="hljs-bullet">-</span> <span class="hljs-string">${bref:layer.console}</span>
        <span class="hljs-attr">events:</span>
            <span class="hljs-bullet">-</span> <span class="hljs-attr">schedule:</span>
                  <span class="hljs-attr">enabled:</span> <span class="hljs-literal">true</span>
                  <span class="hljs-attr">rate:</span> <span class="hljs-string">cron(*/15</span> <span class="hljs-string">*</span> <span class="hljs-string">*</span> <span class="hljs-string">*</span> <span class="hljs-string">?</span> <span class="hljs-string">*)</span> <span class="hljs-comment"># l'expression de planification (https://docs.aws.amazon.com/AmazonCloudWatch/latest/events/ScheduledEvents.html)</span>
                  <span class="hljs-attr">input:</span> <span class="hljs-string">'"app:cron1 arg1 --option1=foo"'</span> <span class="hljs-comment"># la commande Symfony</span>
</code></pre>
<p>Voici un petit extrait des dernières invocations que l'on peut trouver sur la Console Web sur la page de détails de la fonction Lambda (<em>pour les plus observateurs, la planification n'a pas toujours été toutes les 15 minutes ^^</em>).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1677668710315/88500789-9537-476d-bb91-352e7490e719.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-cest-fini-pour-aujourdhui">C'est fini pour aujourd'hui !</h2>
<p>Dans le prochain article, nous verrons comment ajouter un serveur SQL (mais <em>serverless</em> quand même ^^) à notre infrastructure et comment faire en sorte que nos <em>Lambda</em> en <em>Symfony</em> y accèdent.</p>
<p>N'hésitez pas à commenter ce post, ou me laisser un message sur Twitter/Linkedin pour toutes remarques de tout type (erreur, avis, envie, question, ...) : j'essaierai d'en tenir compte et d'y répondre rapidement.</p>
]]></content:encoded></item><item><title><![CDATA[Déployer un projet Symfony sur AWS Lambda avec Pulumi et Bref]]></title><description><![CDATA[Préambule
Je me lance dans une petite série d'articles concernant le déploiement d'une application Symfony sur AWS Lambda en gérant la partie infrastructure (tout ou presque ce qui n'est pas Lambda) via l'outil d'IaC Pulumi.
Le contenu sera assez (co...]]></description><link>https://techblog.pandacode.fr/deployer-un-projet-symfony-sur-aws-lambda-avec-pulumi-et-bref</link><guid isPermaLink="true">https://techblog.pandacode.fr/deployer-un-projet-symfony-sur-aws-lambda-avec-pulumi-et-bref</guid><category><![CDATA[Pulumi]]></category><category><![CDATA[bref php]]></category><category><![CDATA[Symfony]]></category><category><![CDATA[AWS]]></category><category><![CDATA[aws lambda]]></category><dc:creator><![CDATA[Sébastien Porati]]></dc:creator><pubDate>Wed, 15 Feb 2023 16:27:13 GMT</pubDate><content:encoded><![CDATA[<h2 id="heading-preambule">Préambule</h2>
<p>Je me lance dans une petite série d'articles concernant le déploiement d'une application <em>Symfony</em> sur <em>AWS Lambda</em> en gérant la partie infrastructure (tout ou presque ce qui n'est pas <em>Lambda</em>) via l'outil d'<em>IaC</em> <em>Pulumi</em>.</p>
<p>Le contenu sera assez (con)centré sur le code utile pour arriver au résultat. Il n'y aura pas de longue explication de théorie ou de concept. J'essaierai cependant de fournir un maximum de liens pour vous aider à appréhender ou creuser les sujets.</p>
<p>Le contenu des articles ne sera pas des tutoriels pas à pas mais je fournirai un <a target="_blank" href="https://github.com/popofr13/blog-articles"><em>repository Github</em></a> comprenant le code fonctionnel pour chaque article afin de permettre de bien comprendre comment fonctionnent ensemble tous les extraits de code.</p>
<h2 id="heading-quelques-outilsconceptsservices-avant-de-commencer">Quelques outils/concepts/services avant de commencer</h2>
<p>Il y a pas mal d'outils/concepts ou services évoqués dans cet article. Si vous êtes arrivés ici, c'est que vous en connaissez au moins un, mais je vais essayer de définir rapidement les autres et donner quelques liens utiles.</p>
<p><a target="_blank" href="https://aws.amazon.com/?nc2=h_lg">Amazon Web Services</a> (AWS) et <a target="_blank" href="https://aws.amazon.com/lambda/?nc1=h_ls">Lambda</a> : Le <em>CLOUD</em> d'Amazon. Des centaines (pour de vrai, plus de 500) de services dont le service <em>AWS Lambda</em> qui permet d'exécuter du code "sans serveur".</p>
<p><a target="_blank" href="https://www.serverless.com/">Serverless Framework</a> et <em>serverless</em> : avec une majuscule (au moins dans cet article), c'est un framework qui permet de déployer des applications sur le service <em>AWS Lambda</em>. Avec une minuscule, c'est le concept d'avoir du code exécuté sans (gérer soi-même les) serveurs.</p>
<p><a target="_blank" href="https://www.pulumi.com/">Pulumi</a> : c'est un outil d'<em>Infrastructure As Code (IAC)</em>. A la différence d'autres outils comme <em>Terraform</em>/<em>AWS CloudFormation</em>, il n'impose pas d'apprendre un <em>DSL</em> mais permet d'utiliser un langage de programmation comme le <em>Typescript</em> dans le cas de cet article. Le tutoriel pour AWS, <a target="_blank" href="https://www.pulumi.com/docs/get-started/aws/">c'est par là</a>.</p>
<p><a target="_blank" href="https://symfony.com/">Symfony</a> : un framework <em>PHP</em>.</p>
<p><a target="_blank" href="https://bref.sh/">Bref</a> : un (même plusieurs en fait) <em>package Composer</em> qui permet de faire tourner du <em>PHP</em> sur <em>AWS Lambda</em>.</p>
<h2 id="heading-notre-mvp-minimum-viable-project">Notre MVP (minimum viable "Project")</h2>
<p>Le <em>MVP</em> de notre project sera une simple API (<code>/api/ok</code>) écrite en <em>PHP</em> avec le framework <em>Symfony</em> qui tournera sur <em>AWS Lambda</em>.</p>
<p>Dans les articles suivants, on ajoutera des fonctionnalités supplémentaires étape par étape :</p>
<ul>
<li><p>utilisation d'un nom de domaine personnalisé</p>
</li>
<li><p>ajout d'une tâche planifiée <em>CRON</em></p>
</li>
<li><p>ajout d'un serveur de base de données (<em>Aurora Serverless of course</em>)</p>
</li>
<li><p>utilisation de file de messages (<em>SQS</em>)</p>
</li>
<li><p>déploiement via <em>Github Actions</em></p>
</li>
</ul>
<h2 id="heading-la-partie-infrastructure">La partie "Infrastructure"</h2>
<p>Pour pouvoir déployer et exécuter notre code <em>PHP</em> sur <em>AWS Lamba</em> via un appel HTTP, nous allons avoir besoin de créer quelques ressources sur quelques services différents de la plate-forme AWS.</p>
<h3 id="heading-la-base-reseau-le-vpc-amazon-virtual-private-cloudhttpsdocsawsamazoncomvpclatestuserguidewhat-is-amazon-vpchtml">La "base" réseau : le VPC (<a target="_blank" href="https://docs.aws.amazon.com/vpc/latest/userguide/what-is-amazon-vpc.html">Amazon Virtual Private Cloud</a> )</h3>
<p>Lorsque vous créez un compte AWS, vous avez un VPC créé par défaut, mais nous allons en créer un tout nouveau avec sous-réseau "isolé" dans lequel on ajoutera plus tard notre base de données et avec une passerelle (<em>NAT Gateway)</em> pour que notre code <em>PHP</em> puisse accéder à l'internet (pour appeler d'autres APIs).</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// src/vpc/index.ts</span>
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> awsx <span class="hljs-keyword">from</span> <span class="hljs-string">"@pulumi/awsx"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> vpc = <span class="hljs-keyword">new</span> awsx.ec2.Vpc(<span class="hljs-string">"vpc"</span>, {
    natGateways: {
        strategy: <span class="hljs-string">"None"</span>, <span class="hljs-comment">// Change to "Single" if you want your Lambda to be able to access the internet</span>
    },
    subnetSpecs: [
        { <span class="hljs-keyword">type</span>: <span class="hljs-string">"Public"</span> },
        { <span class="hljs-keyword">type</span>: <span class="hljs-string">"Private"</span> },
        { <span class="hljs-keyword">type</span>: <span class="hljs-string">"Isolated"</span>, name: <span class="hljs-string">"databases"</span> } <span class="hljs-comment">// =&gt; pour plus tard</span>
    ],
});
</code></pre>
<h3 id="heading-api-gatewayhttpsawsamazoncomapi-gatewaync1hls"><a target="_blank" href="https://aws.amazon.com/api-gateway/?nc1=h_ls">API Gateway</a></h3>
<p>Nous allons ensuite créer une API sur le service <em>API Gateway</em> pour nous permettre d'avoir une URL pour appeler le code <em>PHP</em>. Nous utiliserons la <em>V2</em> qui a moins de fonctionnalités mais qui est aussi moins coûteuse.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// src/api-gateway/index.ts</span>
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> aws <span class="hljs-keyword">from</span> <span class="hljs-string">"@pulumi/aws"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> apiApi = <span class="hljs-keyword">new</span> aws.apigatewayv2.Api(<span class="hljs-string">"api"</span>, {
    protocolType: <span class="hljs-string">"HTTP"</span>,
});

<span class="hljs-keyword">new</span> aws.apigatewayv2.Stage(<span class="hljs-string">"api.default"</span>, {
    apiId: apiApi.id,
    autoDeploy: <span class="hljs-literal">true</span>,
    name: <span class="hljs-string">"$default"</span>
});
</code></pre>
<h3 id="heading-les-droits-iamhttpsawsamazoncomiamnc1hls-in-hell">Les droits (<a target="_blank" href="https://aws.amazon.com/iam/?nc1=h_ls">I.AM</a> in hell ?^^)</h3>
<p>Je pars du postulat que la personne ou l'outil qui déploie l'infra via <em>Pulumi</em> ou le code via <em>Serverless Framework</em> a tous les droits. Cependant, une fois l'infra et le code déployé, il faut définir des droits qui seront utilisés lors de l'exécution.</p>
<p>Nous allons créer un rôle que nous attribuerons à nos fonctions sur <em>AWS Lambda</em>. On donnera à ce rôle les droits nécessaires à l'accès au réseau (<em>VPC</em>), l'accès à la base de données (dans un futur article) et celui de lire ou envoyer des messages via le service <em>SQS</em>.</p>
<p>Dans ce premier article, on va se limiter à la partie réseau/VPC. On va attribuer au rôle une <em>Managed Policy</em> (c'est-à-dire qu'elle est fournie par <em>AWS</em>).</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// src/iam/index.ts</span>
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> aws <span class="hljs-keyword">from</span> <span class="hljs-string">"@pulumi/aws"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> lambdaRole = <span class="hljs-keyword">new</span> aws.iam.Role(<span class="hljs-string">"lambda"</span>, {
    assumeRolePolicy: aws.iam.assumeRolePolicyForPrincipal(aws.iam.Principals.LambdaPrincipal),
}); 

<span class="hljs-keyword">new</span> aws.iam.RolePolicyAttachment(<span class="hljs-string">"RoleLambdaPoliciesVpcAccessExecution"</span>, {
    role: lambdaRole,
    policyArn: aws.iam.ManagedPolicies.AWSLambdaVPCAccessExecutionRole,
});
</code></pre>
<h3 id="heading-transition-vers-le-projet-php-aws-systems-managerhttpsawsamazoncomsystems-managernc1hls">Transition vers le projet PHP (<a target="_blank" href="https://aws.amazon.com/systems-manager/?nc1=h_ls"><em>AWS Systems Manager</em></a>)</h3>
<p>Nous avons désormais toutes les ressources "Infra" nécessaires pour faire tourner notre projet <em>PHP</em> dans le <em>Cloud</em>. Il va cependant falloir fournir à <em>Serverless</em> de quoi se "brancher" dessus.<br />Nous allons utiliser le service <em>AWS Systems Manager</em> qui va nous permettre de stocker des données que <em>Serverless</em> viendra lire au moment du déploiement. Ces données seront :</p>
<ul>
<li><p>l'id de l'API (<em>Gateway</em>)</p>
</li>
<li><p>l'id (l'<a target="_blank" href="https://docs.aws.amazon.com/fr_fr/general/latest/gr/aws-arns-and-namespaces.html">ARN</a> pour être plus exacte) du rôle <em>IAM</em></p>
</li>
<li><p>l'id du <em>Security Group</em> par défaut du <em>VPC</em></p>
</li>
<li><p>les ids des sous-réseaux privés du <em>VPC</em></p>
</li>
</ul>
<pre><code class="lang-typescript"><span class="hljs-comment">// src/ssm/index.ts</span>
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> aws <span class="hljs-keyword">from</span> <span class="hljs-string">"@pulumi/aws"</span>;
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> pulumi <span class="hljs-keyword">from</span> <span class="hljs-string">"@pulumi/pulumi"</span>;

<span class="hljs-keyword">import</span> {apiApi} <span class="hljs-keyword">from</span> <span class="hljs-string">"../api-gateway"</span>;
<span class="hljs-keyword">import</span> {vpc} <span class="hljs-keyword">from</span> <span class="hljs-string">"../vpc"</span>;
<span class="hljs-keyword">import</span> {lambdaRole} <span class="hljs-keyword">from</span> <span class="hljs-string">"../iam"</span>;

<span class="hljs-keyword">const</span> config = <span class="hljs-keyword">new</span> pulumi.Config();

<span class="hljs-keyword">new</span> aws.ssm.Parameter(<span class="hljs-string">"apigateway.api.id"</span>, {
    <span class="hljs-keyword">type</span>: <span class="hljs-string">"String"</span>,
    name: <span class="hljs-string">"/my-project/api-gateway/http_api_id"</span>,
    value: apiApi.id,
});

<span class="hljs-keyword">new</span> aws.ssm.Parameter(<span class="hljs-string">"lambda.role"</span>, {
    <span class="hljs-keyword">type</span>: <span class="hljs-string">"String"</span>,
    name: <span class="hljs-string">"/my-project/lambda/role-arn"</span>,
    value: lambdaRole.arn,
});

<span class="hljs-keyword">new</span> aws.ssm.Parameter(<span class="hljs-string">"lambda.securityGroup"</span>, {
    <span class="hljs-keyword">type</span>: <span class="hljs-string">"String"</span>,
    name: <span class="hljs-string">"/my-project/lambda/security_group-id"</span>,
    value: vpc.vpc.defaultSecurityGroupId,
});

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> ssmVpcPrivateSubnetIds = <span class="hljs-keyword">new</span> aws.ssm.Parameter(<span class="hljs-string">"vpc.subnet.ids"</span>, {
    <span class="hljs-keyword">type</span>: <span class="hljs-string">"StringList"</span>,
    name: <span class="hljs-string">"/my-project/vpc/private_subnet_ids"</span>,
    value: pulumi.concat(vpc.privateSubnetIds),
});
</code></pre>
<p>Nous allons aussi utiliser ce système pour définir les nombreuses variables d'environnement que l'on peut avoir besoin de définir dans notre projet <em>Symfony</em>. Pour notre MVP, cela se limitera à la variable <code>APP_SECRET</code>.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// src/ssm/index.ts</span>
<span class="hljs-comment">// ...</span>

<span class="hljs-keyword">const</span> symfonyEnvVars = config.requireObject&lt;<span class="hljs-built_in">string</span>[]&gt;(<span class="hljs-string">"symfony"</span>);

<span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> key <span class="hljs-keyword">in</span> symfonyEnvVars) {
    <span class="hljs-keyword">new</span> aws.ssm.Parameter(<span class="hljs-string">`symfony.env.vars-<span class="hljs-subst">${key}</span>`</span>, {
        <span class="hljs-keyword">type</span>: <span class="hljs-string">"String"</span>,
        name: <span class="hljs-string">`/my-project/symfony/envvars/<span class="hljs-subst">${key}</span>`</span>,
        value: symfonyEnvVars[key],
    });
}
</code></pre>
<p>Le fichier README du repository indique comment ajouter de nouvelles variables.</p>
<pre><code class="lang-markdown">Add a Symfony env vars : 

<span class="hljs-code">```bash
pulumi config set --path 'symfony["APP_BASE_URL"]' https://localhost:5173
pulumi config set --path 'symfony["APP_SECRET"]' somesecret --secret
```</span>
</code></pre>
<h3 id="heading-lets-create">Let's create</h3>
<p>Si on exécute la commande <code>pulumi up</code>, on peut voir l'ensemble des ressources qui vont être créées :</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1676041888281/68ebe112-df87-487f-a5f3-2fc220a11431.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-la-partie-code-php-symfony">La partie "code" : PHP / Symfony</h2>
<h3 id="heading-brefhttpsbrefsh"><a target="_blank" href="https://bref.sh/">Bref</a></h3>
<p>Cette deuxième partie du projet va être plus simple grâce à <em>Bref</em> qui permet de faire tourner du code <em>PHP</em> et fournit un package spécialement adapté pour <em>Symfony</em> (<a target="_blank" href="https://bref.sh/docs/frameworks/symfony.html">cf documentation pour l'installation</a>). <em>Bref</em> utilise <em>Serverless Framework</em> pour le déploiement des fonctions <em>Lambda</em> sur la plate-forme AWS.</p>
<p>Nous allons modifier le fichier <code>serverless.yml</code> pour utiliser les informations que nous avons stockées dans <em>AWS Systems Manager</em> (<em>SSM</em>).</p>
<pre><code class="lang-yaml"><span class="hljs-comment"># serverless.yml</span>
<span class="hljs-attr">service:</span> <span class="hljs-string">pulumi-php-bref-1</span>

<span class="hljs-attr">provider:</span>
    <span class="hljs-attr">name:</span> <span class="hljs-string">aws</span>
    <span class="hljs-attr">region:</span> <span class="hljs-string">${opt:region,</span> <span class="hljs-string">"eu-west-3"</span><span class="hljs-string">}</span>
    <span class="hljs-attr">stage:</span> <span class="hljs-string">prod</span>
    <span class="hljs-attr">runtime:</span> <span class="hljs-string">provided.al2</span>

    <span class="hljs-attr">role:</span> <span class="hljs-string">${ssm:/my-project/lambda/role-arn}</span> <span class="hljs-comment"># Notre role IAM</span>
    <span class="hljs-attr">vpc:</span>
        <span class="hljs-attr">securityGroupIds:</span>
            <span class="hljs-bullet">-</span> <span class="hljs-string">${ssm:/my-project/lambda/security_group-id}</span>
        <span class="hljs-attr">subnetIds:</span> <span class="hljs-string">${ssm:/my-project/vpc/private_subnet_ids}</span>

    <span class="hljs-attr">httpApi:</span>
        <span class="hljs-attr">id:</span> <span class="hljs-string">${ssm:/my-project/api-gateway/http_api_id}</span>

    <span class="hljs-attr">environment:</span>
        <span class="hljs-attr">APP_ENV:</span> <span class="hljs-string">prod</span>
        <span class="hljs-comment"># Notre variable d'environnement définie dans le projet Infra</span>
        <span class="hljs-attr">APP_SECRET:</span> <span class="hljs-string">${ssm:/my-project/symfony/envvars/APP_SECRET}</span>
<span class="hljs-comment">#...</span>
</code></pre>
<p>Il ne reste plus qu'à déployer en utilisant les instructions contenues dans le README du projet.</p>
<pre><code class="lang-markdown">Deploy

<span class="hljs-code">```bash
bin/console cache:clear --env=prod
bin/console cache:warmup --env=prod
serverless deploy --stage prod
```</span>
</code></pre>
<p>Et voilà, nous avons l'URL de notre API :</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1676042660328/d926d327-d0b1-45f8-ae27-58ab41044572.jpeg" alt class="image--center mx-auto" /></p>
<p>Et (normalement) ça marche ! ;)</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1676042776200/8727d186-6d22-4887-85a6-476d81e15f2f.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-this-is-only-the-beginning">This is only the beginning ?!</h2>
<p>Nous avons mise en place notre MVP : mais ce n'est que le début ! <a target="_blank" href="https://github.com/popofr13/blog-articles/tree/main/2023-02-pulumi-php-bref-1">Le code complet est disponible dans le repository Github</a>.</p>
<p>Dans le prochain article, nous verrons comment utiliser un nom de domaine personnalisé pour notre API en utilisant le service <a target="_blank" href="https://aws.amazon.com/route53/?nc1=h_ls">AWS Route 53.</a></p>
<p>N'hésitez pas à commenter ce post, ou me laisser un message sur Twitter/Linkedin pour toutes remarques de tout type (erreur, avis, envie, question, ...) : j'essaierai d'en tenir compte et d'y répondre rapidement.</p>
]]></content:encoded></item></channel></rss>