<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0"><channel><title>Pulumi Blog: Development environment</title><link>https://www.pulumi.com/blog/tag/development-environment/</link><description>Pulumi blog posts: Development environment.</description><language>en-us</language><pubDate>Tue, 26 Mar 2024 17:19:00 +0100</pubDate><item><title>Using Pulumi Inside Node.js Monorepos</title><link>https://www.pulumi.com/blog/nx-monorepo/</link><pubDate>Tue, 26 Mar 2024 17:19:00 +0100</pubDate><guid>https://www.pulumi.com/blog/nx-monorepo/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/nx-monorepo/index.png" /&gt;
&lt;p&gt;One of Pulumi&amp;rsquo;s core goals is to provide cloud engineers with access to the very best software engineering tooling available. Using traditional programming languages like Node.js, Python, Go, .NET and Java means the latest and greatest software engineering tools from each of these ecosystems is available to bring to bear on managing cloud infrastructure, natively integrated with your existing development environments.&lt;/p&gt;
&lt;p&gt;In the Node.js ecosystem, we&amp;rsquo;ve seen an explosion of great tooling over the last couple of years around support for monorepos - larger repositories built out of many smaller projects, and sharing code and dependencies smartly across all the various projects. We&amp;rsquo;ve seen many of our Pulumi Node.js users adopting these tools and repo structures, including tools like &lt;a href="https://yarnpkg.com/features/workspaces"&gt;Yarn Workspaces&lt;/a&gt;, &lt;a href="https://pnpm.io/"&gt;pnpm&lt;/a&gt;, &lt;a href="https://turbo.build/"&gt;Turborepo&lt;/a&gt;, and especially &lt;a href="https://nx.dev"&gt;Nx&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While it has always been possible to apply these tools to Pulumi Node.js projects in TypeScript or JavaScript just like any other Node.js project, we&amp;rsquo;ve recently made &lt;a href="https://github.com/pulumi/pulumi/issues/15436"&gt;a&lt;/a&gt; &lt;a href="https://github.com/pulumi/pulumi/issues/2661"&gt;number&lt;/a&gt; &lt;a href="https://github.com/pulumi/pulumi/issues/7168"&gt;of&lt;/a&gt; &lt;a href="https://github.com/pulumi/pulumi/issues/3013"&gt;enhancements&lt;/a&gt; &lt;a href="https://github.com/pulumi/pulumi/issues/15455"&gt;and&lt;/a&gt; &lt;a href="https://github.com/pulumi/examples/issues/1605"&gt;fixes&lt;/a&gt; to make sure that Pulumi works truly seamlessly with these tools.&lt;/p&gt;
&lt;p&gt;In this post, we&amp;rsquo;ll show how you can build a seamless development workflow by integrating Pulumi code level abstractions, such as &lt;a href="https://www.pulumi.com/docs/concepts/resources/components/"&gt;Component Resources&lt;/a&gt;, with a monorepo-based build system like &lt;a href="https://nx.dev"&gt;Nx&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Component resources let us create reusable components that manage logical groupings of resources. With modern monorepo tooling, and our recent improvements to make Pulumi aware of monorepo setups, we can colocate these reusable components, Pulumi infrastructure programs, and application code all in one monorepo, and have Nx manage the build and deploy-time dependencies for us.&lt;/p&gt;
&lt;p&gt;We will walk through an example project that deploys a website built with &lt;a href="https://astro.build"&gt;Astro&lt;/a&gt; to AWS S3. The complete code can be found at &lt;a href="https://github.com/pulumi/examples/tree/master/nx-monorepo"&gt;pulumi/examples/nx-monorepo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Our example monorepo has the following structure:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/pulumi/examples/tree/master/nx-monorepo/website"&gt;website&lt;/a&gt;: A website built with &lt;a href="https://astro.build"&gt;Astro&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/pulumi/examples/blob/master/nx-monorepo/components/s3folder/index.ts"&gt;components/s3folder&lt;/a&gt;: A component resource that manages a S3 bucket and its access policies.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/pulumi/examples/blob/master/nx-monorepo/components/website-deploy/index.ts"&gt;components/website-deploy&lt;/a&gt;: A component resource resource that manages files in a S3 bucket&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/pulumi/examples/blob/master/nx-monorepo/infra/index.ts"&gt;infra&lt;/a&gt;: A Pulumi program that uses the &lt;code&gt;s3folder&lt;/code&gt; and &lt;code&gt;website-deploy&lt;/code&gt; component resources to deploy the generated &lt;code&gt;website&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By using &lt;a href="https://docs.npmjs.com/cli/v10/using-npm/workspaces"&gt;npm workspaces&lt;/a&gt; we can have multiple npm packages managed from a singular top-level package. Npm will take care of installing the dependencies for all our packages and enables packages within the monorepo to reference each other. In the &lt;a href="https://github.com/pulumi/examples/blob/master/nx-monorepo/package.json"&gt;package.json&lt;/a&gt; at the root of the monorepo we set up the workspaces matching our folder structure. &lt;a href="https://classic.yarnpkg.com/lang/en/docs/workspaces/"&gt;Yarn workspaces&lt;/a&gt; work similarly and are fully supported by Pulumi.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// package.json
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="err"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;workspaces&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;components/*&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;infra&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;website&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="typescript"&gt;TypeScript&lt;/h2&gt;
&lt;p&gt;Pulumi has builtin TypeScript support and compiles your code on the fly without manual build-step, however this is currently limited to TypeScript 3.8. We are working on providing more choice here, but in the mean time Nx makes it easy to add a build-step to compile code using any version of TypeScript. For this example we are using the latest and greatest, TypeScript 5.4.&lt;/p&gt;
&lt;div class="note note-info"&gt;
&lt;div class="icon-and-line"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--fill" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.21047dcd83825f0caafb78a6fd28628a694219e6b6824f6b3e24ee3147bac331.svg#p-info-fill"/&gt;&lt;/svg&gt;
&lt;div class="line"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="content"&gt;As of &lt;a href="https://www.npmjs.com/package/@pulumi/pulumi"&gt;v3.113.0 of the @pulumi/pulumi NPM package&lt;/a&gt; any version of TypeScript is supported natively. To select the version to use, add it as a &lt;a href="https://www.pulumi.com/docs/languages-sdks/javascript/#typescript-versions"&gt;dependency to your package.json&lt;/a&gt;.&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="declaring-dependencies"&gt;Declaring Dependencies&lt;/h2&gt;
&lt;p&gt;If we were to manually build and deploy the code in our monorepo, we would have to run the following steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Run &lt;code&gt;astro build&lt;/code&gt; to generate the HTML output that we want to deploy.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;npm run build&lt;/code&gt; for &lt;code&gt;s3folder&lt;/code&gt; and &lt;code&gt;website-deploy&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;npm run build&lt;/code&gt; for &lt;code&gt;infra&lt;/code&gt; afterwards, since this imports &lt;code&gt;s3folder&lt;/code&gt; and &lt;code&gt;website-deploy&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;pulumi up&lt;/code&gt; to deploy our website.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Instead of running these steps manually, we will leverage Nx&amp;rsquo;s task running mechanism, which can be made aware of the dependencies between the packages in the monorepo. This ensures we don&amp;rsquo;t accidentally forget a step. On top of that, Nx provides caching, so we also avoid re-running unnecessary tasks on subsequent runs.&lt;/p&gt;
&lt;p&gt;Because we are using npm workspaces, Nx can understand the dependencies declared in the &lt;code&gt;package.json&lt;/code&gt; for each of the packages in our monorepo. For example in &lt;a href="https://github.com/pulumi/examples/blob/master/nx-monorepo/infra/package.json"&gt;infra/package.json&lt;/a&gt; we declare that we depend on &lt;code&gt;s3folder&lt;/code&gt;, &lt;code&gt;website&lt;/code&gt; and &lt;code&gt;website-deploy&lt;/code&gt;.
We also let Nx know that the &lt;code&gt;deploy&lt;/code&gt; target in the &lt;code&gt;infra&lt;/code&gt; package depends on the build step, and the HTML generation step of the &lt;code&gt;website&lt;/code&gt; package:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// infra/package.json
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;infra&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;dependencies&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;@pulumi/pulumi&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;latest&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;s3folder&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;*&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;website-deploy&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;*&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;website&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;*&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;scripts&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;build&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;tsc&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;deploy&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;pulumi up --stack dev&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;nx&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;targets&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;deploy&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;cache&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;dependsOn&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;build&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;website:generate&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In &lt;a href="https://github.com/pulumi/examples/blob/master/nx-monorepo/nx.json"&gt;nx.json&lt;/a&gt; we let Nx know that each package&amp;rsquo;s build-step depends on its dependencies&amp;rsquo; build-steps. With that Nx now knows that in order build &lt;code&gt;infra&lt;/code&gt;, it first needs to build its dependencies.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// nx.json
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;extends&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;nx/presets/npm.json&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;$schema&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;./node_modules/nx/schemas/nx-schema.json&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;targetDefaults&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;build&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;cache&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;dependsOn&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;^build&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The full dependency graph, as understood by Nx, can be visualized by running &lt;code&gt;npx nx deploy infra --graph&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/nx-monorepo/dependency-graph.png" alt="Dependency graph of our monorepo example"&gt;&lt;/p&gt;
&lt;h2 id="walkthrough"&gt;Walkthrough&lt;/h2&gt;
&lt;p&gt;Now that we have taught Nx all about the dependencies in our monorepo, we can run &lt;code&gt;npx nx deploy infra&lt;/code&gt; and Nx will run all the required steps in the correct order, using parallelism where possible.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt; ✔ 4/4 dependent project tasks succeeded [0 read from cache]
Hint: you can run the command with --verbose to see the full dependent project outputs
————————————————————————————————————————————————————————————————————————————————
&amp;gt; nx run infra:build
&amp;gt; infra@1.0.0 build
&amp;gt; tsc
&amp;gt; nx run infra:deploy
&amp;gt; infra@1.0.0 deploy
&amp;gt; pulumi up --stack dev
The stack &amp;#39;dev&amp;#39; does not exist.
If you would like to create this stack now, please press &amp;lt;ENTER&amp;gt;, otherwise press ^C:
Created stack &amp;#39;dev&amp;#39;
Previewing update (dev)
View in Browser (Ctrl+O): https://app.pulumi.com/julienp/nx-monorepo/dev/previews/fc7630fd-7dc4-4c7e-baa0-3d6e014fc90a
Type Name Plan
+ pulumi:pulumi:Stack nx-monorepo-dev create
+ ├─ pulumi:examples:WebsiteDeploy my-website create
+ │ └─ aws:s3:BucketObject index.html create
+ └─ pulumi:examples:S3Folder my-folder create
+ ├─ aws:s3:Bucket my-folder create
+ ├─ aws:s3:BucketPublicAccessBlock public-access-block create
+ └─ aws:s3:BucketPolicy bucketPolicy create
Outputs:
websiteUrl: output&amp;lt;string&amp;gt;
Resources:
+ 7 to create
Do you want to perform this update? yes
Updating (dev)
...
NX Successfully ran target deploy for project infra and 4 tasks it depends on (27s)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The output tells us that Nx found the 4 dependent tasks for the &lt;code&gt;deploy&lt;/code&gt; task of the &lt;code&gt;infra&lt;/code&gt; package and ran them successfully.&lt;/p&gt;
&lt;p&gt;If we now run &lt;code&gt;npx nx deploy infra&lt;/code&gt; again, we can see Nx&amp;rsquo;s caching mechanism in action. Nx notices that there are no code changes to the &lt;code&gt;infra&lt;/code&gt; package, and that none of its dependencies have changed either, so it just replays the output from the previous run.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt; ✔ 3/3 dependent project tasks succeeded [3 read from cache]
Hint: you can run the command with --verbose to see the full dependent project outputs
————————————————————————————————————————————————————————————————————————————————
&amp;gt;nx run infra:build [existing outputs match the cache, left as is]
&amp;gt; infra@1.0.0 build
&amp;gt; tsc
&amp;gt; nx run infra:deploy [existing outputs match the cache, left as is]
&amp;gt; infra@1.0.0 deploy
&amp;gt; pulumi up --stack dev
Previewing update (dev)
...
NX Successfully ran target deploy for project infra and 4 tasks it depends on (29ms)
Nx read the output from the cache instead of running the command for 5 out of 5 tasks.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now let&amp;rsquo;s create a new page in our website by adding a markdown file in the &lt;code&gt;src/pages&lt;/code&gt; folder.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Hello, World!&amp;#34;&lt;/span&gt; &amp;gt; website/src/pages/hello.md
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When we run &lt;code&gt;npx nx deploy infra&lt;/code&gt; again, Nx notices that there is a change to the website and reruns the HTML generation step. Since one of the dependencies of &lt;code&gt;infra&lt;/code&gt; has now changed, the stack is re-deployed.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt; ✔ 2/2 dependent project tasks succeeded [2 read from cache]
Hint: you can run the command with --verbose to see the full dependent project outputs
————————————————————————————————————————————————————————————————————————————————
&amp;gt; nx run infra:build
&amp;gt; infra@1.0.0 build
&amp;gt; tsc
&amp;gt; nx run infra:deploy
&amp;gt; infra@1.0.0 deploy
&amp;gt; pulumi up --stack dev
Previewing update (dev)
View in Browser (Ctrl+O): https://app.pulumi.com/v-julien-pulumi-corp/nx-monorepo/dev/previews/8d9db825-77e1-4d1a-8f9b-8279481e7e40
Type Name Plan
pulumi:pulumi:Stack nx-monorepo-dev
└─ pulumi:examples:WebsiteDeploy my-website
+ └─ aws:s3:BucketObject hello/index.html create
Resources:
+ 1 to create
8 unchanged
Do you want to perform this update? yes
Updating (dev)
...
NX Successfully ran target deploy for project infra and 4 tasks it depends on (19s)
Nx read the output from the cache instead of running the command for 2 out of 5 tasks.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We can see that Nx used the cached results for 2 of our tasks, &lt;code&gt;s3folder&lt;/code&gt; and &lt;code&gt;website-deploy&lt;/code&gt; didn&amp;rsquo;t change, so Nx skips rebuilding them. Nx also ran the other 3 tasks to generate the website&amp;rsquo;s HTML, building the infra package and finally deploying the infra package.&lt;/p&gt;
&lt;div class="rounded-lg bg-violet-50 p-6 my-8"&gt;
&lt;p class="heading-4 m-0 mb-3 flex items-center gap-1.5"&gt;Ship infrastructure from your monorepo&lt;/p&gt;
&lt;div class="body-base m-0 text-gray-950"&gt;Colocate reusable Pulumi component resources, infrastructure programs, and application code in one monorepo, then build and deploy them together with Nx. Manage every stack in Pulumi Cloud.&lt;/div&gt;
&lt;a href="https://app.pulumi.com/signup" data-track="blog-body-cta" class="btn btn-primary mt-4"&gt;
Get started
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--regular size-4" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.21047dcd83825f0caafb78a6fd28628a694219e6b6824f6b3e24ee3147bac331.svg#p-arrow-right-regular"/&gt;&lt;/svg&gt;
&lt;/a&gt;
&lt;/div&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this post we&amp;rsquo;ve shown how we can combine Pulumi&amp;rsquo;s code level abstractions with a build system to create a seamless developer workflow. By using a monorepo we can colocate our reusable components with the Pulumi programs that use the components, as well as our application code. Tools like Nx allow us to intelligently manage the dependencies between the packages in the monorepo, ensuring we are always deploying the correct version of the code.&lt;/p&gt;
&lt;p&gt;Pulumi provides you with access to the latest and greatest software engineering tools (like Nx), and allows you to bring them to bear on managing cloud infrastructure, natively integrated with your existing development environments.&lt;/p&gt;</description><author>Julien Poissonnier</author><category>development-environment</category><category>monorepo</category><category>nx</category></item><item><title>Organizational Patterns: A Developer Portal</title><link>https://www.pulumi.com/blog/organizational-patterns-developer-portal/</link><pubDate>Thu, 30 Dec 2021 11:00:39 -0600</pubDate><guid>https://www.pulumi.com/blog/organizational-patterns-developer-portal/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/organizational-patterns-developer-portal/index.png" /&gt;
&lt;p&gt;Using Pulumi is more than just writing code and components. In addition to common software development practices, there are also a number of success patterns related to how your company or team builds and deploys Pulumi programs to successfully build, deploy, and manage your infrastructure and applications. In this continuation of a series, I will explore one of these patterns - using the Pulumi &lt;a href="https://www.pulumi.com/docs/using-pulumi/automation-api/"&gt;Automation API&lt;/a&gt; to create a developer portal.&lt;/p&gt;
&lt;p&gt;It is becoming more and more common to consider building out centralized web-based &amp;ldquo;portals&amp;rdquo; for developers (and other team members) to provision the infrastructure that their services and applications require. In many ways, the pattern of a developer portal takes portions of both the &lt;a href="https://www.pulumi.com/blog/organizational-patterns-infra-repo/"&gt;Single Infra Repo&lt;/a&gt; and &lt;a href="https://www.pulumi.com/blog/organizational-patterns-automation-team/"&gt;Automation Team&lt;/a&gt; patterns covered in previous posts. The difference is that the developer portal is a single, centralized web application that can be used by multiple teams and organizations to provision infrastructure and applications, rather than writing the Pulumi programs themselves.&lt;/p&gt;
&lt;p&gt;Depending upon the needs of the various teams, the developer portal could include options to deploy virtual machines into the cloud of their choice (or the organization&amp;rsquo;s standard cloud; perhaps the choice isn&amp;rsquo;t&amp;hellip;a choice!), to provision cloud resources such as virtual networks, security groups, database instances, or even deployments to a kubernetes cluster.&lt;/p&gt;
&lt;p&gt;Generally speaking, the developer portal is created and maintained by a central platform team. This is the team who knows the success patterns/standards that are employed by the organization, and can implement these patterns in the developer portal. The platform team is also responsible for maintaining the infrastructure that the developer portal requires.&lt;/p&gt;
&lt;p&gt;One of the great advantages of providing a single portal for provisioning these resources is that all the &amp;ldquo;other stuff&amp;rdquo; that is often required (besides the resources from the hyperscaler) can be handled by the developer portal. For example, if the portal is used to provision a virtual machine, the code behind it can register the virtual machine with the company&amp;rsquo;s infrastructure management system.&lt;/p&gt;
&lt;p&gt;A great example of what is possible in a portal can be seen with &lt;a href="https://github.com/komalali/"&gt;Komal Ali&amp;rsquo;s&lt;/a&gt; example, the &lt;a href="https://github.com/komalali/self-service-platyform"&gt;Self Service Infrastructure Platyform&lt;/a&gt;. This is example code only, but it shows some of the capabilities of a developer portal.&lt;/p&gt;
&lt;p&gt;&lt;img src="platyform.png" alt="Screeshot of the platyform"&gt;&lt;/p&gt;
&lt;p&gt;In the example, the web portal is created using a combination of Python, Flask and Jinja templates (along with the Pulumi Automation API) to provide push-button access to deploy cloud resources according to the standards and patterns of the organization. The code snippets below illustrate some of the concepts (this code is not meant to be run, but rather to illustrate the concepts - the full example code can be found at &lt;a href="https://github.com/komalali/self-service-platyform"&gt;github.com/komalali/self-service-platyform&lt;/a&gt;).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;flask&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Blueprint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;current_app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url_for&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;render_template&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;pulumi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;pulumi_aws&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nn"&gt;aws&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;pulumi.automation&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nn"&gt;auto&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;bp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Blueprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;virtual_machines&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="vm"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url_prefix&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;/vms&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;instance_types&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;c5.xlarge&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;p2.xlarge&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;p3.2xlarge&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In the initial snippet above, we are setting up what we need for the Flask application, but the key items to make note of are including the &lt;code&gt;pulumi_aws&lt;/code&gt; and &lt;code&gt;pulumi.automation&lt;/code&gt; packages, which will be used for the cloud specific resources and automation.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_pulumi_program&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keydata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;instance_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ami&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ec2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_ami&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;most_recent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;owners&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;amazon&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;filters&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetAmiFilterArgs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;*amzn2-ami-minimal-hvm*&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;])])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;group&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ec2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SecurityGroup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;web-secgrp&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Enable SSH access&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ingress&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ec2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SecurityGroupIngressArgs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;protocol&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;tcp&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;from_port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;to_port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;cidr_blocks&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;0.0.0.0/0&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Continuing on, we define the Pulumi program, and set up some of the standard settings that we consider our defaults and that are not selectable by the user.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ec2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Instance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;dlami-server&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;instance_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;instance_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;vpc_security_group_ids&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;group&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;key_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;keypair&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ami&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ami&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;pulumi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;export&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;public_dns&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;public_dns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This final snippet is what creates the actual instance, and it exports the public DNS of the instance so that it can be accessed by the user and presented in the portal.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This pattern has been implemented and deployed at many larger enterprises, where the platform team has the resources to dedicate to managing the portal as an actual product. This is a key part to remember - the developer portal is a product whose consumers are the developers and other teams in the organization, and it needs to be managed as such!&lt;/p&gt;
&lt;p&gt;Don&amp;rsquo;t forget to check out the previous two posts in this series, &lt;a href="https://www.pulumi.com/blog/organizational-patterns-infra-repo/"&gt;Organizational Patterns - A Single Infra Repo&lt;/a&gt; and &lt;a href="https://www.pulumi.com/blog/organizational-patterns-automation-team/"&gt;Organizational Patterns - An Automation Team&amp;quot;&lt;/a&gt;.&lt;/p&gt;</description><author>Matty Stratton</author><category>development-environment</category><category>automation-api</category></item><item><title>Organizational Patterns: An Automation Team</title><link>https://www.pulumi.com/blog/organizational-patterns-automation-team/</link><pubDate>Wed, 22 Dec 2021 11:49:08 -0600</pubDate><guid>https://www.pulumi.com/blog/organizational-patterns-automation-team/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/organizational-patterns-automation-team/index.png" /&gt;
&lt;p&gt;Using Pulumi is more than just writing code and components. In addition to common software development practices, there are also a number of success patterns related to how your company or team builds and deploys Pulumi programs to successfully build, deploy, and manage your infrastructure and applications. In this continuation of a series, I will explore one of these patterns - a specialized automation team.&lt;/p&gt;
&lt;p&gt;I want to approach this pattern with a bit of caution - there are patterns and anti-patterns related to having a single central team focused on automation.&lt;/p&gt;
&lt;p&gt;The anti-pattern is to have an &amp;ldquo;automation team&amp;rdquo; within your organization who is tasked with creating all infrastructure as code for the entire organization. This is a common pattern, but it is generally rife with issues.&lt;/p&gt;
&lt;p&gt;Understanding how to build and deploy a service or application requires a certain amount of domain knowledge of that service. If you have a single set of people across your entire company who need to write Pulumi programs for each and every application or service, you are now expecting that small group to not only be experts in Pulumi, but also every bit of infrastructure and software applications (both third party and created internally) across your organization.&lt;/p&gt;
&lt;p&gt;A more successful pattern is to have the automation team act as enablers and providers for the other groups within the company. This is a team of subject matter experts in using Pulumi, and not only do they have the knowledge to build and deploy infrastructure, but they are familiar with various patterns and good practices for how to build and deploy infrastructure.&lt;/p&gt;
&lt;p&gt;There are different mechanisms for how this automation team can enable others. One way is to embed them temporarily within a product team to work alongside them to build their automation. Then, when the product team is done, the automation team member can go and help another squad.&lt;/p&gt;
&lt;p&gt;Depending upon the size and skills of the company and this group, they may also be responsible for creating training materials for the other groups. These are usually based upon existing Pulumi training materials, but customized for the specific needs and culture of the company.&lt;/p&gt;
&lt;h2 id="reusable-components"&gt;Reusable components&lt;/h2&gt;
&lt;p&gt;This central automation team also often provides reusable components that might be shared across multiple development teams. This helps the individual teams to not have to &amp;ldquo;reinvent the wheel&amp;rdquo; and to bring in these components for their own particular needs.&lt;/p&gt;
&lt;p&gt;As a simple example, a component could be created (and published as a library to be consumed by product teams) that defines a Kubernetes deployment.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;deploy&lt;/span&gt; &lt;span class="nx"&gt;from&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;@mycorp/deploy&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;kuard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;deploy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Deployment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;kuard&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;gcr.io/kuard-project/kuard:latest&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;replicas&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;What&amp;rsquo;s happened here in our (incomplete!) example is that the published package only exposes the parts that the team needs to change; the rest is provided by the automation team.&lt;/p&gt;
&lt;p&gt;The application team don’t need to duplicate values (such as ports) because the abstractions cater for them. The application team also didn’t need to apply any metadata, health checks, and environment variables because it can be inferred through convention, increasing velocity across the organization. When values are provided by the application team, they override convention and they can still iterate and experiment, providing feedback to the automation team.&lt;/p&gt;
&lt;h2 id="final-tips"&gt;Final tips&lt;/h2&gt;
&lt;p&gt;One of the more important recommendations for this pattern is to avoid trying to create a &amp;ldquo;mandate&amp;rdquo; for all teams for adoption. The automation team provides capabilities, such as templated CI/CD pipelines, reusable components, and training materials, but it is still up to the individual teams to decide how to use them.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This is a pattern that works well at a larger organization, where it would be beyond the scope of a single group to be able to wrap their understanding around hundreds of services. However, it is a pattern that can be applied to smaller organizations as well!&lt;/p&gt;
&lt;p&gt;Watch for the next post in this series, where we will dig into some other patterns! Or revisit the first post, &lt;a href="https://www.pulumi.com/blog/organizational-patterns-infra-repo/"&gt;Organizational Patterns - A Single Infra Repo&lt;/a&gt;.&lt;/p&gt;</description><author>Matty Stratton</author><category>development-environment</category></item><item><title>Organizational Patterns: A Single Infra Repo</title><link>https://www.pulumi.com/blog/organizational-patterns-infra-repo/</link><pubDate>Fri, 17 Dec 2021 05:46:04 -0600</pubDate><guid>https://www.pulumi.com/blog/organizational-patterns-infra-repo/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/organizational-patterns-infra-repo/index.png" /&gt;
&lt;p&gt;Using Pulumi is more than just writing code and components. In addition to common software development practices, there are also a number of success patterns related to how your company or team builds and deploys Pulumi programs to successfully build, deploy, and manage your infrastructure and applications. In this first post of a series, I will explore one of these patterns - the centralized platform infrastructure repository.&lt;/p&gt;
&lt;p&gt;An emergent organizational pattern these days is that of a centralized &amp;ldquo;platform&amp;rdquo; team, which has various product and service teams (or squads) as internal customers. In this approach, the platform team takes responsibility for the tooling and infrastructure - if it&amp;rsquo;s not directly product related, it usually falls under the responsibility of the platform team. The platform team provides functionality and platforms to be consumed by the product teams.&lt;/p&gt;
&lt;p&gt;For many of the examples I&amp;rsquo;ll be using to illustrate this pattern, I refer to a conversation I had recently with Jacob Foard, who is the Tech Lead for the Platform Team at &lt;a href="https://greenparksports.com/"&gt;GreenPark Sports&lt;/a&gt;. This pattern is used at GreenPark Sports, and he was very clear about the benefits of the pattern.&lt;/p&gt;
&lt;p&gt;One of the key concepts to keep in mind is that when providing a platform, it is made up of more than just the compute and other resources provided by AWS, GCP, Azure, or even your own Kubernetes implementations. The platform also includes the infrastructure that is shared between the various teams, such as monitoring and observability tooling, version control/pipeline services, as well as secret and key management.&lt;/p&gt;
&lt;p&gt;In this pattern, your main infrastructure repository is made up of directories for each product/service that your teams use, in addition to directories for each higher level shared service. Each of these directories is itself a Pulumi program. So it would look something like this:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;├── bluth-apps
│   ├── apps
│   │   ├── apps.go
│   │   ├── bananastand.go
│   │   ├── suddenvalley.go
│   ├── main.go
│   ├── Pulumi.dev.yaml
│   └── Pulumi.prod.yaml
├── datadog
│   ├── main.go
│   └── Pulumi.prod.yaml
├── github
│   ├── main.go
│   └── Pulumi.prod.yaml
├── pkg
│   ├── datadog
│   ├── pagerduty
│   └── vault
└── .etc
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In the above (fictional, but inspired by the GreenPark Sports pattern) example, the Bluth Company has two main services that are used in all of its environments (&amp;ldquo;Banana Stand&amp;rdquo; and &amp;ldquo;Sudden Valley&amp;rdquo;). The main &lt;code&gt;apps.go&lt;/code&gt; file is the entry point that simply calls functions from each of the various apps to &amp;ldquo;set up&amp;rdquo; those apps, as well as the common infrastructure that an environment might require (networks, storage, etc). Note that the way you structure your code is up to you, and likely will vary depending upon the runtime for your particular Pulumi program, but this is the general idea.&lt;/p&gt;
&lt;p&gt;Similarly, the &lt;code&gt;github&lt;/code&gt; and &lt;code&gt;datadog&lt;/code&gt; directories are Pulumi programs that are responsible for the &amp;ldquo;core&amp;rdquo; infrastructure for those services (perhaps creating roles, etc). The &lt;code&gt;pkg&lt;/code&gt; directory is a directory that contains packages that are used by the other programs to implement that infrastructure. Again, the &lt;code&gt;pkg&lt;/code&gt; convention is used by Go, but other runtimes will have a similar approach.&lt;/p&gt;
&lt;h2 id="examples"&gt;Examples&lt;/h2&gt;
&lt;p&gt;These examples are not complete runnable code, but used to illustrate the pattern. While these examples are using Go, they are written in a way that is compatible with any language that supports the Pulumi language.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;main.go&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;github.com/bluthcompany/infra/bluth-apps/apps&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;github.com/bluthcompany/infra/pkg/datadog&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;github.com/bluthcompany/infra/pkg/github&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;github.com/pulumi/pulumi/sdk/go/pulumi&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// Create the apps.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;apps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetupApps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bananastand&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;suddenvalley&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// Create the infrastructure.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;datadog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateInfrastructure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;github&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateInfrastructure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;apps.go&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;apps&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;github.com/pulumi/pulumi/sdk/go/pulumi&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;SetupApps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;setupBananaStand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;setupSuddenValley&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;bananastand.go&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;apps&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// imports, etc&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;setupBananaStand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// Create the banana stand.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="setting-up-a-new-service-in-the-platform-repository"&gt;Setting up a new service in the platform repository&lt;/h2&gt;
&lt;p&gt;If a service/product team has a new service they want infrastructure for, they simply add a new &lt;code&gt;myapp.go&lt;/code&gt; file to the &lt;code&gt;apps&lt;/code&gt; directory for their service, and add it to the &lt;code&gt;apps.go&lt;/code&gt; file to make sure it is called. This is then submitted as a pull request for the platform team to review.&lt;/p&gt;
&lt;p&gt;One important part of this pattern is that the platform team does not want to be a &amp;ldquo;blocker&amp;rdquo; for the product and service teams. It&amp;rsquo;s key to make sure that you have more than one person able to review and merge these pull requests, and to add sufficient testing into your CI/CD pipeline for this infrastructure repository.&lt;/p&gt;
&lt;h2 id="variations-on-this-pattern"&gt;Variations on this pattern&lt;/h2&gt;
&lt;p&gt;In the fictional Bluth example, there is one Pulumi program that is used regardless of environment, and the different configurations are handled by the use of stacks. However, there are situations where you might have complex enough differences between your environments where the amount of conditionals you require in your code to handle this would make for very challenging maintenance and understanding of the code! This is the case with GreenPark Sports, so in their implementation, instead of a single &lt;code&gt;bluth-apps&lt;/code&gt; directory at the root of the repo, you would instead have &lt;code&gt;bluth-prod&lt;/code&gt;, &lt;code&gt;bluth-dev&lt;/code&gt;, etc.&lt;/p&gt;
&lt;p&gt;This approach does generate duplication of code, and it can provide challenges at scale, but it is up to you and your teams to determine the tradeoffs of the branching/conditional logic vs separate programs.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This pattern works well depending upon the makeup of your teams and services. It is a pattern that facilitates collaboration between teams and focuses on having a central platform team that enables product teams, rather than getting in their way.&lt;/p&gt;
&lt;p&gt;Watch for the next posts in this series, where we will dig into some other patterns as well!&lt;/p&gt;</description><author>Matty Stratton</author><category>development-environment</category></item><item><title>Building a Development Environment for Cloud Engineering</title><link>https://www.pulumi.com/blog/configuring-your-dev-environment/</link><pubDate>Wed, 03 Feb 2021 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/configuring-your-dev-environment/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/configuring-your-dev-environment/index.png" /&gt;
&lt;p&gt;Starting can be daunting. Before you take your first step, there&amp;rsquo;s a lot to consider, but you can prepare your development environment ahead of time to make your first steps in cloud engineering smooth and productive. In this article, we&amp;rsquo;ll cover how to set up your development environment to work across cloud providers, multiple languages, and different operating systems.&lt;/p&gt;
&lt;h2 id="building-your-toolbox"&gt;Building your toolbox&lt;/h2&gt;
&lt;p&gt;You might have heard of the French culinary term &amp;ldquo;mise-en-place,&amp;rdquo; which means laying out all the ingredients and cookware before starting to cook. That&amp;rsquo;s what we&amp;rsquo;re going to do here; layout all the accounts, authorizations, and software that you need to be a successful cloud engineer. We are going to need the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A package manager:&lt;/strong&gt; Every operating system has a package manager for installing software. Unlike binary installers, a package manager lets you manage all software packages, including updates. Package managers can help resolve dependencies, saving you from frustration.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cloud provider accounts:&lt;/strong&gt; You can choose to set up one or multiple accounts. The important thing is how to configure credentials in your development environment,&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Programming languages:&lt;/strong&gt; You can choose one or many, but they all have different versions and dependencies.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Code editor:&lt;/strong&gt; This is personal preference but make sure that it can perform code completion, error checking, and use enums. These features can be the difference between hitting &lt;code&gt;Tab&lt;/code&gt; and searching through online documentation for a function.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pulumi:&lt;/strong&gt; You can install Pulumi with a package manager and configure&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="decisions"&gt;Decisions&lt;/h2&gt;
&lt;p&gt;Before proceeding, you need to answer three questions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Which operating system to use for building cloud resources: macOS, Windows, or Linux?&lt;/li&gt;
&lt;li&gt;Which cloud provider are you using? This guide covers AWS, Azure, and Google Cloud.&lt;/li&gt;
&lt;li&gt;Which programming language will you use? Pulumi supports Node.js (JavaScript and Typescript), Python 3.7 or higher, Golang, and .NET (C#, F#, and VB).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once you&amp;rsquo;ve made these choices, you can follow this guide in a choose-your-own-adventure style.&lt;/p&gt;
&lt;h2 id="package-manager"&gt;Package manager&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s start with the package manager. We&amp;rsquo;ll use it to install and manage all the software we need, including cloud provider CLIs, programming languages, editors, and Pulumi. Choose your operating system below.&lt;/p&gt;
&lt;div&gt;
&lt;pulumi-chooser type="os" options="macos,windows,linux" mode=""&gt;
&lt;div&gt;
&lt;pulumi-choosable type="os" values="macos" mode=""&gt;&lt;p&gt;&lt;a href="https://docs.brew.sh/Installation"&gt;Homebrew&lt;/a&gt; is the most popular package manager for macOS. The Command Line Tools (CLT) for XCode is required to install and build Homebrew. Install the XCode Tools first, then install Homebrew from the command line.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ xcode-select --install
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ /bin/bash -c &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you are uncomfortable with downloading and running an online shell script (with good reason), Homebrew provides an &lt;a href="https://docs.brew.sh/Installation#alternative-installs"&gt;alternate installation method&lt;/a&gt;.&lt;/p&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="os" values="windows" mode=""&gt;&lt;p&gt;&lt;a href="https://chocolatey.org/"&gt;Chocolatey&lt;/a&gt; is a popular package manager for Windows. It should be installed using an &lt;a href="https://www.howtogeek.com/194041/how-to-open-the-command-prompt-as-administrator-in-windows-10/"&gt;administrative shell&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Make sure that &lt;a href="https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies?view=powershell-7.1"&gt;&lt;code&gt;Get-ExecutionPolicy&lt;/code&gt;&lt;/a&gt; is not restricted.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cmd" data-lang="cmd"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; Get-ExecutionPolicy
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If the command returns &lt;code&gt;Restricted&lt;/code&gt;, we can use &lt;code&gt;Bypass&lt;/code&gt; to install Chocolatey with the following command:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;&amp;gt; Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString(&amp;#39;https://chocolatey.org/install.ps1&amp;#39;))
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To check if it&amp;rsquo;s installed type:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cmd" data-lang="cmd"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; choco
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="os" values="linux" mode=""&gt;&lt;p&gt;Linux distributions include a package manager, &lt;a href="https://wiki.debian.org/Apt"&gt;apt&lt;/a&gt; for Debian based distributions or &lt;a href="https://www.redhat.com/sysadmin/how-manage-packages"&gt;yum&lt;/a&gt; for Red Hat-based Linux systems. However, they are primarily used for application and system management.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://docs.brew.sh/Homebrew-on-Linux"&gt;Homebrew&lt;/a&gt; is a popular package manager for utilities, Software Development Kits, and programming tools. Install Homebrew from the command line.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ /bin/bash -c &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To add Homebrew to your &lt;code&gt;PATH&lt;/code&gt; and your bash shell profile script (&lt;code&gt;~/.profile&lt;/code&gt; on Debian or &lt;code&gt;~/.bash_profile&lt;/code&gt; on Red Hat), follow the &lt;code&gt;Next steps&lt;/code&gt; instructions to install and configure brew. To check if it&amp;rsquo;s installed, install a package;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ brew install hello
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;/pulumi-chooser&gt;
&lt;/div&gt;
&lt;h2 id="setting-up-a-cloud-account"&gt;Setting up a cloud account&lt;/h2&gt;
&lt;p&gt;The first task is signing up for an account. Once you have that out of the way, the next steps are installing the CLI and configuring your credentials.&lt;/p&gt;
&lt;h3 id="macos"&gt;macOS&lt;/h3&gt;
&lt;div&gt;
&lt;pulumi-chooser type="cloud" options="aws,azure,gcp" mode=""&gt;
&lt;div&gt;
&lt;pulumi-choosable type="cloud" values="aws" mode=""&gt;&lt;p&gt;We&amp;rsquo;ll use brew to install AWS CLI version 2 and verify if it&amp;rsquo;s installed by checking the version.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ brew update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; brew install awscli
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ aws --version
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The next step is to create and download your AWS access keys and configure your environment to make them available to both the AWS CLI. To create your access keys, follow these directions for &lt;a href="https://docs.aws.amazon.com/general/latest/gr/aws-sec-cred-types.html#access-keys-and-secret-access-keys"&gt;programmatic access&lt;/a&gt;.&lt;/p&gt;
&lt;div class="note note-info"&gt;
&lt;div class="icon-and-line"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--fill" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.21047dcd83825f0caafb78a6fd28628a694219e6b6824f6b3e24ee3147bac331.svg#p-info-fill"/&gt;&lt;/svg&gt;
&lt;div class="line"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="content"&gt;Pulumi uses the AWS SDK to authenticate requests. Your AWS access keys are never sent to pulumi.com.&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;To configure the AWS CLI with your credentials, use &lt;code&gt;aws configure&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ aws configure
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;AWS Access Key ID &lt;span class="o"&gt;[&lt;/span&gt;None&lt;span class="o"&gt;]&lt;/span&gt;: &amp;lt;YOUR_ACCESS_KEY_ID&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;AWS Secret Access Key &lt;span class="o"&gt;[&lt;/span&gt;None&lt;span class="o"&gt;]&lt;/span&gt;: &amp;lt;YOUR_SECRET_ACCESS_KEY&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Default region name &lt;span class="o"&gt;[&lt;/span&gt;None&lt;span class="o"&gt;]&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Default output format &lt;span class="o"&gt;[&lt;/span&gt;None&lt;span class="o"&gt;]&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This creates a &lt;code&gt;~/.aws/credentials&lt;/code&gt; file used by the AWS CLI to authenticate requests.&lt;/p&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="cloud" values="azure" mode=""&gt;&lt;p&gt;We&amp;rsquo;ll use brew to install Azure CLI and check if it&amp;rsquo;s installed.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ brew update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; brew install azure-cli
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ az --version
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;To log into Azure, run the &lt;span class="sb"&gt;`&lt;/span&gt;login&lt;span class="sb"&gt;`&lt;/span&gt; command, which opens a browser to log into &lt;span class="o"&gt;[&lt;/span&gt;Azure&lt;span class="o"&gt;](&lt;/span&gt;https://login.microsoftonline.com/common/oauth2/authorize&lt;span class="o"&gt;)&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sb"&gt;```&lt;/span&gt;bash
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ az login
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;The default web browser has been opened at https://login.microsoftonline.com/common/oauth2/authorize. Please &lt;span class="k"&gt;continue&lt;/span&gt; the login in the web browser. If no web browser is available or &lt;span class="k"&gt;if&lt;/span&gt; the web browser fails to open, use device code flow with &lt;span class="sb"&gt;`&lt;/span&gt;az login --use-device-code&lt;span class="sb"&gt;`&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;You have logged in. Now &lt;span class="nb"&gt;let&lt;/span&gt; us find all the subscriptions to which you have access...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The Azure client is authenticated and ready to use.&lt;/p&gt;
&lt;div class="note note-info"&gt;
&lt;div class="icon-and-line"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--fill" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.21047dcd83825f0caafb78a6fd28628a694219e6b6824f6b3e24ee3147bac331.svg#p-info-fill"/&gt;&lt;/svg&gt;
&lt;div class="line"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="content"&gt;Pulumi uses the Azure SDK to authenticate requests. Your AWS access keys are never sent to pulumi.com.&lt;/div&gt;
&lt;/div&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="cloud" values="gcp" mode=""&gt;&lt;p&gt;We&amp;rsquo;ll use brew to install the Google Cloud SDK and CLI.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ brew update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; brew install --cask google-cloud-sdk
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Update &lt;span class="k"&gt;done&lt;/span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;==&lt;/span&gt;&amp;gt; Source &lt;span class="o"&gt;[&lt;/span&gt;/usr/local/Caskroom/google-cloud-sdk/latest/google-cloud-sdk/completion.bash.inc&lt;span class="o"&gt;]&lt;/span&gt; in your profile to &lt;span class="nb"&gt;enable&lt;/span&gt; shell &lt;span class="nb"&gt;command&lt;/span&gt; completion &lt;span class="k"&gt;for&lt;/span&gt; gcloud.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;==&lt;/span&gt;&amp;gt; Source &lt;span class="o"&gt;[&lt;/span&gt;/usr/local/Caskroom/google-cloud-sdk/latest/google-cloud-sdk/path.bash.inc&lt;span class="o"&gt;]&lt;/span&gt; in your profile to add the Google Cloud SDK &lt;span class="nb"&gt;command&lt;/span&gt; line tools to your &lt;span class="nv"&gt;$PATH&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Add the gcloud SDK to $PATH in you ~/.bash_profile&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;source&lt;/span&gt; /usr/local/Caskroom/google-cloud-sdk/latest/google-cloud-sdk/completion.bash.inc
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;source&lt;/span&gt; /usr/local/Caskroom/google-cloud-sdk/latest/google-cloud-sdk/path.bash.inc
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Open a new shell or source &lt;code&gt;~/.profile&lt;/code&gt; for Debian or &lt;code&gt;~/.bash_profile&lt;/code&gt; for Red Hat and check to see if it&amp;rsquo;s installed and pathed.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ &lt;span class="nb"&gt;source&lt;/span&gt; ~/.bash_profile
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ gcloud version
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Google Cloud SDK 325.0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;bq 2.0.64
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;core 2021.01.22
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gsutil 4.58
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Authenticate using the gcloud CLI.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gcloud init
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="note note-info"&gt;
&lt;div class="icon-and-line"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--fill" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.21047dcd83825f0caafb78a6fd28628a694219e6b6824f6b3e24ee3147bac331.svg#p-info-fill"/&gt;&lt;/svg&gt;
&lt;div class="line"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="content"&gt;Pulumi uses the Google Cloud SDK to authenticate requests. Your AWS access keys are never sent to pulumi.com.&lt;/div&gt;
&lt;/div&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;/pulumi-chooser&gt;
&lt;/div&gt;
&lt;h3 id="windows"&gt;Windows&lt;/h3&gt;
&lt;div&gt;
&lt;pulumi-chooser type="cloud" options="aws,azure,gcp" mode=""&gt;
&lt;div&gt;
&lt;pulumi-choosable type="cloud" values="aws" mode=""&gt;&lt;p&gt;We&amp;rsquo;ll use chocolatey to install AWS CLI version 2 and check if it&amp;rsquo;s installed. Open a &lt;code&gt;cmd&lt;/code&gt; Command Prompt as Administrator:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cmd" data-lang="cmd"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; choco install awscli
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; aws --version
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The install adds the AWS CLI client to the &lt;code&gt;$PATH&lt;/code&gt;, so either open a new &lt;code&gt;cmd&lt;/code&gt; window or use the &lt;code&gt;refreshenv&lt;/code&gt; command to update the window&amp;rsquo;s environment variables and use the AWS CLI.&lt;/p&gt;
&lt;p&gt;The next step is to create and download your AWS access keys and configure your environment to make them available to both the AWS CLI. To create your access keys, follow these directions for &lt;a href="https://docs.aws.amazon.com/general/latest/gr/aws-sec-cred-types.html#access-keys-and-secret-access-keys"&gt;programmatic access&lt;/a&gt;.&lt;/p&gt;
&lt;div class="note note-info"&gt;
&lt;div class="icon-and-line"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--fill" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.21047dcd83825f0caafb78a6fd28628a694219e6b6824f6b3e24ee3147bac331.svg#p-info-fill"/&gt;&lt;/svg&gt;
&lt;div class="line"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="content"&gt;Pulumi uses the AWS SDK to authenticate requests. Your AWS access keys are never sent to pulumi.com.&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;To configure the AWS CLI with your credentials, use &lt;code&gt;aws configure&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cmd" data-lang="cmd"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; aws configure
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;AWS Access Key ID [None]: &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;YOUR_ACCESS_KEY_ID&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;AWS Secret Access Key [None]: &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;YOUR_SECRET_ACCESS_KEY&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Default region name [None]:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Default output format [None]:
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This will create the &lt;code&gt;~/.aws/credentials&lt;/code&gt; file used by the AWS CLI to authenticate requests.&lt;/p&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="cloud" values="azure" mode=""&gt;&lt;p&gt;We&amp;rsquo;ll use chocolatey to install Azure CLI and check if it&amp;rsquo;s installed. Open a &lt;code&gt;cmd&lt;/code&gt; Command Prompt as Administrator:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cmd" data-lang="cmd"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; choco install azure-cli
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The Azure CLI client was added to the path, so either open a new &lt;code&gt;cmd&lt;/code&gt; window or use the &lt;code&gt;refreshenv&lt;/code&gt; command to update the window&amp;rsquo;s environment variables. To log into Azure, run the &lt;code&gt;login&lt;/code&gt; command, which opens a browser to log into &lt;a href="https://login.microsoftonline.com/common/oauth2/authorize"&gt;Azure&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cmd" data-lang="cmd"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; refreshenv
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; az login
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The Azure client will open a browser window and prompt you to sign-in to your account. Once signed-in, the Azure CLI is authenticated and ready to use.&lt;/p&gt;
&lt;div class="note note-info"&gt;
&lt;div class="icon-and-line"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--fill" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.21047dcd83825f0caafb78a6fd28628a694219e6b6824f6b3e24ee3147bac331.svg#p-info-fill"/&gt;&lt;/svg&gt;
&lt;div class="line"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="content"&gt;Pulumi uses the Azure SDK to authenticate requests. Your AWS access keys are never sent to pulumi.com.&lt;/div&gt;
&lt;/div&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="cloud" values="gcp" mode=""&gt;&lt;p&gt;We&amp;rsquo;ll use chocolatey to install the Google Cloud SDK and CLI.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cmd" data-lang="cmd"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; choco install gcloudsdk --ignore-checksums
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;gcloud&lt;/code&gt; CLI was added to the path, so either open a new &lt;code&gt;cmd&lt;/code&gt; window or use the &lt;code&gt;refreshenv&lt;/code&gt; command to update the window&amp;rsquo;s environment variables. Check to see if &lt;code&gt;gcloud&lt;/code&gt; CLI is installed and pathed correctly.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cmd" data-lang="cmd"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; refreshenv
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; gcloud version
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Google Cloud SDK 325.0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;bq 2.0.64
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;core 2021.01.22
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gsutil 4.58
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Authenticate using the gcloud CLI&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cmd" data-lang="cmd"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; gcloud init
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Welcome! This command will take you through the configuration of gcloud.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Your current configuration has been set to: [default]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;You can skip diagnostics next time by using the following flag:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; gcloud init --skip-diagnostics
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Network diagnostic detects and fixes local network connection issues.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Checking network connection...done.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Reachability Check passed.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Network diagnostic passed (1/1 checks passed).
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;You must log in to continue. Would you like to log in (Y/n)? Y
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Your browser has been opened to visit:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; https://accounts.google.com/o/oauth2/...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A browser window will open to authenticate your client.&lt;/p&gt;
&lt;div class="note note-info"&gt;
&lt;div class="icon-and-line"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--fill" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.21047dcd83825f0caafb78a6fd28628a694219e6b6824f6b3e24ee3147bac331.svg#p-info-fill"/&gt;&lt;/svg&gt;
&lt;div class="line"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="content"&gt;Pulumi uses the Google Cloud SDK to authenticate requests. Your AWS access keys are never sent to pulumi.com.&lt;/div&gt;
&lt;/div&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;/pulumi-chooser&gt;
&lt;/div&gt;
&lt;h3 id="linux"&gt;Linux&lt;/h3&gt;
&lt;div&gt;
&lt;pulumi-chooser type="cloud" options="aws,azure,gcp" mode=""&gt;
&lt;div&gt;
&lt;pulumi-choosable type="cloud" values="aws" mode=""&gt;&lt;p&gt;We&amp;rsquo;ll use brew to install AWS CLI version 2 and check if it&amp;rsquo;s installed.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ brew update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; brew install awscli
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ aws --version
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The next step is to create and download your AWS access keys and configure your environment to make them available to both the AWS CLI. To create your access keys, follow these directions for &lt;a href="https://docs.aws.amazon.com/general/latest/gr/aws-sec-cred-types.html#access-keys-and-secret-access-keys"&gt;programmatic access&lt;/a&gt;.&lt;/p&gt;
&lt;div class="note note-info"&gt;
&lt;div class="icon-and-line"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--fill" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.21047dcd83825f0caafb78a6fd28628a694219e6b6824f6b3e24ee3147bac331.svg#p-info-fill"/&gt;&lt;/svg&gt;
&lt;div class="line"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="content"&gt;Pulumi uses the AWS SDK to authenticate requests. Your AWS access keys are never sent to pulumi.com.&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;To configure the AWS CLI with your credentials, use &lt;code&gt;aws configure&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ aws configure
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;AWS Access Key ID &lt;span class="o"&gt;[&lt;/span&gt;None&lt;span class="o"&gt;]&lt;/span&gt;: &amp;lt;YOUR_ACCESS_KEY_ID&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;AWS Secret Access Key &lt;span class="o"&gt;[&lt;/span&gt;None&lt;span class="o"&gt;]&lt;/span&gt;: &amp;lt;YOUR_SECRET_ACCESS_KEY&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Default region name &lt;span class="o"&gt;[&lt;/span&gt;None&lt;span class="o"&gt;]&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Default output format &lt;span class="o"&gt;[&lt;/span&gt;None&lt;span class="o"&gt;]&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This will create the &lt;code&gt;~/.aws/credentials&lt;/code&gt; file used by the AWS CLI to authenticate requests.&lt;/p&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="cloud" values="azure" mode=""&gt;&lt;p&gt;We&amp;rsquo;ll use brew to install Azure CLI and check if it&amp;rsquo;s installed.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ brew update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; brew install azure-cli
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ az --version
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;To log into Azure, run the &lt;span class="sb"&gt;`&lt;/span&gt;login&lt;span class="sb"&gt;`&lt;/span&gt; command, which opens a browser to log into &lt;span class="o"&gt;[&lt;/span&gt;Azure&lt;span class="o"&gt;](&lt;/span&gt;https://login.microsoftonline.com/common/oauth2/authorize&lt;span class="o"&gt;)&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sb"&gt;```&lt;/span&gt;bash
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ az login
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;The default web browser has been opened at https://login.microsoftonline.com/common/oauth2/authorize. Please &lt;span class="k"&gt;continue&lt;/span&gt; the login in the web browser. If no web browser is available or &lt;span class="k"&gt;if&lt;/span&gt; the web browser fails to open, use device code flow with &lt;span class="sb"&gt;`&lt;/span&gt;az login --use-device-code&lt;span class="sb"&gt;`&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;You have logged in. Now &lt;span class="nb"&gt;let&lt;/span&gt; us find all the subscriptions to which you have access...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The Azure client is authenticated and ready to use.&lt;/p&gt;
&lt;div class="note note-info"&gt;
&lt;div class="icon-and-line"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--fill" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.21047dcd83825f0caafb78a6fd28628a694219e6b6824f6b3e24ee3147bac331.svg#p-info-fill"/&gt;&lt;/svg&gt;
&lt;div class="line"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="content"&gt;Pulumi uses the Azure SDK to authenticate requests. Your AWS access keys are never sent to pulumi.com.&lt;/div&gt;
&lt;/div&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="cloud" values="gcp" mode=""&gt;&lt;p&gt;We&amp;rsquo;ll use brew to install the Google Cloud SDK and CLI.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ brew update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; brew install --cask google-cloud-sdk
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Update &lt;span class="k"&gt;done&lt;/span&gt;!
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;==&lt;/span&gt;&amp;gt; Source &lt;span class="o"&gt;[&lt;/span&gt;/usr/local/Caskroom/google-cloud-sdk/latest/google-cloud-sdk/completion.bash.inc&lt;span class="o"&gt;]&lt;/span&gt; in your profile to &lt;span class="nb"&gt;enable&lt;/span&gt; shell &lt;span class="nb"&gt;command&lt;/span&gt; completion &lt;span class="k"&gt;for&lt;/span&gt; gcloud.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;==&lt;/span&gt;&amp;gt; Source &lt;span class="o"&gt;[&lt;/span&gt;/usr/local/Caskroom/google-cloud-sdk/latest/google-cloud-sdk/path.bash.inc&lt;span class="o"&gt;]&lt;/span&gt; in your profile to add the Google Cloud SDK &lt;span class="nb"&gt;command&lt;/span&gt; line tools to your &lt;span class="nv"&gt;$PATH&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Add the gcloud SDK to $PATH to your &lt;code&gt;~/.bash_profile&lt;/code&gt; or &lt;code&gt;~/.profile&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;source&lt;/span&gt; /usr/local/Caskroom/google-cloud-sdk/latest/google-cloud-sdk/completion.bash.inc
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;source&lt;/span&gt; /usr/local/Caskroom/google-cloud-sdk/latest/google-cloud-sdk/path.bash.inc
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Open a new shell or source &lt;code&gt;~/.profile&lt;/code&gt; for Debian or &lt;code&gt;~/.bash_profile&lt;/code&gt; for Red Hat and check to see if it&amp;rsquo;s installed and pathed.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ &lt;span class="nb"&gt;source&lt;/span&gt; ~/.bash_profile
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ gcloud version
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Google Cloud SDK 325.0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;bq 2.0.64
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;core 2021.01.22
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gsutil 4.58
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Authenticate using the gcloud CLI&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gcloud init
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="note note-info"&gt;
&lt;div class="icon-and-line"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--fill" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.21047dcd83825f0caafb78a6fd28628a694219e6b6824f6b3e24ee3147bac331.svg#p-info-fill"/&gt;&lt;/svg&gt;
&lt;div class="line"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="content"&gt;Pulumi uses the Google Cloud SDK to authenticate requests. Your AWS access keys are never sent to pulumi.com.&lt;/div&gt;
&lt;/div&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;/pulumi-chooser&gt;
&lt;/div&gt;
&lt;h2 id="choose-a-programming-language"&gt;Choose a Programming Language&lt;/h2&gt;
&lt;p&gt;Pulumi supports Node.js (JavaScript and Typescript), Python 3, Golang, and .NET Core (C#, VB, and F#) languages.&lt;/p&gt;
&lt;h3 id="nodejs"&gt;Node.js&lt;/h3&gt;
&lt;div&gt;
&lt;pulumi-chooser type="os" options="macos,windows,linux" mode=""&gt;
&lt;div&gt;
&lt;pulumi-choosable type="os" values="macos" mode=""&gt;&lt;p&gt;Use brew to install Node.js for JavaScript and Typescript.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ brew install node
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="os" values="windows" mode=""&gt;&lt;p&gt;Use chocolatey to install Node.js for JavaScript and Typescript.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cmd" data-lang="cmd"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; choco install nodejs
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="os" values="linux" mode=""&gt;&lt;p&gt;Use brew to install Node.js for JavaScript and Typescript.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ brew install node
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;/pulumi-chooser&gt;
&lt;/div&gt;
&lt;h3 id="python"&gt;Python&lt;/h3&gt;
&lt;div&gt;
&lt;pulumi-chooser type="os" options="macos,windows,linux" mode=""&gt;
&lt;div&gt;
&lt;pulumi-choosable type="os" values="macos" mode=""&gt;&lt;p&gt;MacOS includes Python; however, versions shipped before December 2019 have Python 2.7 installed, which is deprecated. Pulumi requires Python 3.7 or higher. Use brew to install Python, which installs it at &lt;code&gt;/usr/bin/local/python3&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ brew install python
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In macOS versions with Python 2 installed, calling &lt;code&gt;python&lt;/code&gt; uses the 2.7 binary. To ensure that you will always use Python 3, you can add an alias to your &lt;code&gt;.bash_profile&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;python&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/local/bin/python3
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It is a best practice to create a virtual environment and activate it for a Python project. Pulumi creates a new &lt;code&gt;venv&lt;/code&gt; environment when you start a new Project with &lt;code&gt;pulumi new&lt;/code&gt;.&lt;/p&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="os" values="windows" mode=""&gt;&lt;p&gt;You can install Python in several ways, including typing &amp;lsquo;python` in the command prompt, which brings up the Microsoft Store application. In this article, we&amp;rsquo;ll continue using chocolatey to install Python 3.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cmd" data-lang="cmd"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; choco install python --pre
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It is a best practice to create a virtual environment and activate it for a Python project. Pulumi creates a new &lt;code&gt;venv&lt;/code&gt; environment when you start a new Project with &lt;code&gt;pulumi new&lt;/code&gt;.&lt;/p&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="os" values="linux" mode=""&gt;&lt;p&gt;Use brew to install Python3.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ brew install python
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Use &lt;code&gt;python3&lt;/code&gt; to call Python, but you can add an alias to your &lt;code&gt;.bash_profile&lt;/code&gt; or &lt;code&gt;.profile&lt;/code&gt; to use just &lt;code&gt;python&lt;/code&gt; to run scripts.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;alias&lt;/span&gt; &lt;span class="nv"&gt;python&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/local/bin/python3
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It is a best practice to create a virtual environment and activate it for a Python project. Pulumi creates a new &lt;code&gt;venv&lt;/code&gt; environment when you start a new Project with &lt;code&gt;pulumi new&lt;/code&gt;.&lt;/p&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;/pulumi-chooser&gt;
&lt;/div&gt;
&lt;h3 id="golang"&gt;Golang&lt;/h3&gt;
&lt;div&gt;
&lt;pulumi-chooser type="os" options="macos,windows,linux" mode=""&gt;
&lt;div&gt;
&lt;pulumi-choosable type="os" values="macos" mode=""&gt;&lt;p&gt;Use brew to install golang.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ brew install golang
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It is a best practice to create a local programming environment and set &lt;code&gt;GOPATH&lt;/code&gt; as an environment variable, although it is not required for golang versions after 1.8. Pulumi creates a new local environment and &lt;code&gt;go.mod&lt;/code&gt; to work with modules each time you start a new Project with &lt;code&gt;pulumi new&lt;/code&gt;.&lt;/p&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="os" values="windows" mode=""&gt;&lt;p&gt;Use chocolatey to install golang.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cmd" data-lang="cmd"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; choco install golang
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It is a best practice to create a local programming environment and set &lt;code&gt;GOPATH&lt;/code&gt; as an environment variable, although it is not required for golang versions after 1.16. Pulumi creates a new local environment and &lt;code&gt;go.mod&lt;/code&gt; to work with modules each time you start a new Project with &lt;code&gt;pulumi new&lt;/code&gt;.&lt;/p&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="os" values="linux" mode=""&gt;&lt;p&gt;Use brew to install golang.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ brew install golang
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It is a best practice to create a local programming environment and set &lt;code&gt;GOPATH&lt;/code&gt; as an environment variable, although it is not required for golang versions after 1.8. Pulumi creates a new local environment and &lt;code&gt;go.mod&lt;/code&gt; to work with modules each time you start a new Project with &lt;code&gt;pulumi new&lt;/code&gt;.&lt;/p&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;/pulumi-chooser&gt;
&lt;/div&gt;
&lt;h3 id="net"&gt;.NET&lt;/h3&gt;
&lt;div&gt;
&lt;pulumi-chooser type="os" options="macos,windows,linux" mode=""&gt;
&lt;div&gt;
&lt;pulumi-choosable type="os" values="macos" mode=""&gt;&lt;p&gt;Install .NET with brew, Pulumi requires .NET Core 3.1 or higher.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ brew install dotnet
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="os" values="windows" mode=""&gt;&lt;p&gt;Install .NET with chocolatey. Pulumi requires .NET Core 3.1 or higher.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cmd" data-lang="cmd"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; choco install dotnet-sdk
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="os" values="linux" mode=""&gt;&lt;p&gt;Install .NET with brew, Pulumi requires .NET Core 3.1 or higher.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ brew install dotnet
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;/pulumi-chooser&gt;
&lt;/div&gt;
&lt;h2 id="get-a-code-editor"&gt;Get a code editor&lt;/h2&gt;
&lt;p&gt;While knowing how to use vim or similar text editors is a worthwhile skill, you should use a modern code editor. Here&amp;rsquo;s a non-exhaustive list why you should use a code editor.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Quickly navigating to a type&lt;/li&gt;
&lt;li&gt;Autocompletion when you can&amp;rsquo;t remember the names of all members by heart&lt;/li&gt;
&lt;li&gt;Automatic code generation&lt;/li&gt;
&lt;li&gt;Refactoring&lt;/li&gt;
&lt;li&gt;Organise imports&lt;/li&gt;
&lt;li&gt;Warnings as you type.&lt;/li&gt;
&lt;li&gt;Hovering over something to see the docs&lt;/li&gt;
&lt;li&gt;Keeping a view of files, errors/warnings/console/unit-tests and source code on the screen&lt;/li&gt;
&lt;li&gt;Running unit tests from the same window&lt;/li&gt;
&lt;li&gt;Integrated debugging&lt;/li&gt;
&lt;li&gt;Integrated source control&lt;/li&gt;
&lt;li&gt;Navigating to where a compile-time error or run-time exception occurred directly from the error details.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can use an IDE (Integrated Development Environment) such as &lt;a href="https://visualstudio.microsoft.com/"&gt;Microsoft Visual Studio&lt;/a&gt;, &lt;a href="https://developer.apple.com/xcode/"&gt;Xcode&lt;/a&gt;, or any one of &lt;a href="https://www.jetbrains.com/products/#type=ide"&gt;JetBrains&amp;rsquo; language-specific IDEs&lt;/a&gt;. Alternatively, you can use a lightweight solution with many of the features of an IDE. Popular code editors include &lt;a href="https://code.visualstudio.com/"&gt;Visual Studio Code&lt;/a&gt;, &lt;a href="https://www.sublimetext.com/"&gt;Sublime Text&lt;/a&gt;, and &lt;a href="https://atom.io/"&gt;Atom&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can install some editors with brew.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ brew install --cask visual-studio-code
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ brew install --cask sublime-text
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ brew install --cask atom
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ brew install --cask pycharm-ce
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ brew install --cask goland
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="install-pulumi"&gt;Install Pulumi&lt;/h2&gt;
&lt;div&gt;
&lt;pulumi-chooser type="os" options="macos,windows,linux" mode=""&gt;
&lt;div&gt;
&lt;pulumi-choosable type="os" values="macos" mode=""&gt;&lt;p&gt;macOS Ventura (13) or later is required.&lt;/p&gt;
&lt;h3 id="homebrew"&gt;Homebrew&lt;/h3&gt;
&lt;p&gt;You can install Pulumi through the &lt;a href="https://brew.sh/"&gt;Homebrew package manager&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ brew install pulumi/tap/pulumi
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This will install the &lt;code&gt;pulumi&lt;/code&gt; CLI to the usual place (often &lt;code&gt;/usr/local/bin/pulumi&lt;/code&gt;) and add it to your path.&lt;/p&gt;
&lt;p&gt;Subsequent updates can be installed in the usual way:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ brew upgrade pulumi
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="os" values="linux" mode=""&gt;&lt;h3 id="installation-script"&gt;Installation Script&lt;/h3&gt;
&lt;p&gt;To install, run our installation script:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ curl -fsSL https://get.pulumi.com &lt;span class="p"&gt;|&lt;/span&gt; sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This will install the &lt;code&gt;pulumi&lt;/code&gt; CLI to &lt;code&gt;~/.pulumi/bin&lt;/code&gt; and add it to your path. When it can&amp;rsquo;t automatically add &lt;code&gt;pulumi&lt;/code&gt; to your path, you will be prompted to add it manually.
See &lt;a href="https://stackoverflow.com/questions/14637979/how-to-permanently-set-path-on-linux-unix"&gt;How to permanently set $PATH on Unix&lt;/a&gt; for guidance.&lt;/p&gt;
&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="os" values="windows" mode=""&gt;&lt;p&gt;Windows 8 and 10 are supported.&lt;/p&gt;
&lt;h3 id="chocolatey"&gt;Chocolatey&lt;/h3&gt;
&lt;p&gt;You can install Pulumi using elevated permissions through the &lt;a href="https://chocolatey.org"&gt;Chocolatey package manager&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-powershell" data-lang="powershell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;choco&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="n"&gt;pulumi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This will install the &lt;code&gt;pulumi&lt;/code&gt; CLI to the usual place (often &lt;code&gt;$($env:ChocolateyInstall)\lib\pulumi&lt;/code&gt;) and generate the &lt;a href="https://docs.chocolatey.org/en-us/features/shim"&gt;shims&lt;/a&gt; (usually &lt;code&gt;$($env:ChocolateyInstall)\bin&lt;/code&gt;) to add Pulumi your path.&lt;/p&gt;
&lt;p&gt;Subsequent updates can be installed in the usual way:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-powershell" data-lang="powershell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;choco&lt;/span&gt; &lt;span class="n"&gt;upgrade&lt;/span&gt; &lt;span class="n"&gt;pulumi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;/pulumi-chooser&gt;
&lt;/div&gt;
&lt;h2 id="verifying-your-installation"&gt;Verifying your Installation&lt;/h2&gt;
&lt;p&gt;After installing Pulumi, verify everything is in working order by running the &lt;code&gt;pulumi&lt;/code&gt; CLI:&lt;/p&gt;
&lt;div&gt;
&lt;pulumi-chooser type="os" options="macos,windows,linux" mode=""&gt;
&lt;div&gt;
&lt;pulumi-choosable type="os" values="macos" mode=""&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi version
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;v3.255.0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="os" values="linux" mode=""&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi version
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;v3.255.0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="os" values="windows" mode=""&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;gt; pulumi version
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;v3.255.0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;/pulumi-chooser&gt;
&lt;/div&gt;
&lt;h2 id="next-steps"&gt;Next steps&lt;/h2&gt;
&lt;p&gt;Congratulations! You have a fully configured environment, and you&amp;rsquo;re ready to jump into cloud engineering. You can maintain your development environment using the package manager to add or update your toolset. Your code editor provides a modern development platform that takes advantage of all the advances in software engineering. Your coding experience will be more productive and less frustrating.&lt;/p&gt;
&lt;p&gt;What are the next steps? Begin with Pulumi&amp;rsquo;s &lt;a href="https://www.pulumi.com/docs/get-started/"&gt;Getting Started&lt;/a&gt;. You can skip the configuration sections and jump straight into your &lt;a href="https://www.pulumi.com/docs/iac/get-started/aws/"&gt;first project&lt;/a&gt;. Once you&amp;rsquo;re done with your first project, try out example projects on &lt;a href="https://github.com/pulumi/examples"&gt;Github&lt;/a&gt;. You can start with simple projects using the &lt;code&gt;pulumi&lt;/code&gt; CLI, such as deploying a web server on AWS with python.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi new https://github.com/pulumi/examples/tree/master/aws-py-webserver
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This command will download the project from Github, create a virtual environment and activate it, and download all the python package dependencies. You&amp;rsquo;re ready to go and deploy with &lt;code&gt;pulumi up&lt;/code&gt;. Want more? How about deploying Kubernetes on Azure with python?&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi new https://github.com/pulumi/examples/tree/master/azure-py-aks
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can use the examples as a starting point for building your cloud infrastructure and add resources documented on Pulumi&amp;rsquo;s &lt;a href="https://www.pulumi.com/registry/"&gt;Registry&lt;/a&gt; and &lt;a href="https://www.pulumi.com/docs/iac/guides/"&gt;Guides&lt;/a&gt;.&lt;/p&gt;</description><author>Sophia Parafina</author><category>development-environment</category><category>cloud-engineering</category></item><item><title>Build a Pulumi VS Code Devcontainer Environment</title><link>https://www.pulumi.com/blog/vscode-devcontainers/</link><pubDate>Tue, 14 Jul 2020 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/vscode-devcontainers/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/vscode-devcontainers/index.png" /&gt;
&lt;p&gt;One of the major advantages of using containers for development is reducing the need to install software and associated dependencies. Developers can start writing code without configuring a development environment that emulates production. The Visual Studio Code Remote - Containers extension lets you develop inside a container. If you want to use Pulumi’s infrastructure as code engine without installing the Pulumi CLI, this blog post is for you!&lt;/p&gt;
&lt;h2 id="pre-requisites"&gt;Pre-requisites&lt;/h2&gt;
&lt;p&gt;To set up your development environment, you’ll need Visual Studio Code, &lt;a href="https://www.docker.com/products/docker-desktop"&gt;Docker Desktop&lt;/a&gt;, and the &lt;a href="https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers"&gt;Remote - Containers extension&lt;/a&gt;.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Check to see if Docker is running:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ docker --version
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Docker version 19.03.8, build afacb8b
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Check to see if the &lt;strong&gt;Remote - Containers&lt;/strong&gt; is installed:&lt;/p&gt;
&lt;p&gt;&lt;img src="remote-status-bar.png" alt="Remote status"&gt;&lt;/p&gt;
&lt;p&gt;Click on the green icon in the Remote Status Bar to display the commands:&lt;/p&gt;
&lt;p&gt;&lt;img src="remote-containers-commands.png" alt="Remote container commands"&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="building-the-pulumi-container"&gt;Building the Pulumi container&lt;/h2&gt;
&lt;p&gt;Now we can start!&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create a directory for your project.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ mkdir my_devcontainer
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ &lt;span class="nb"&gt;cd&lt;/span&gt; my_devcontainer
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Open the directory in VS Code.&lt;/p&gt;
&lt;p&gt;&lt;img src="open_devcontainer_dir.png" alt="Open directory"&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Next, we’ll create the devcontainer configuration files. Click on the Remote Status button and select &lt;strong&gt;Add Development Container Configuration Files &amp;hellip;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="add_devcontainer_config_files.png" alt="A configuration files"&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Select the latest version for &lt;strong&gt;Alpine&lt;/strong&gt;. We’ll replace the Dockerfile with the Pulumi Dockerfile.&lt;/p&gt;
&lt;p&gt;&lt;img src="select_config_file.png" alt="Select config file"&gt;&lt;/p&gt;
&lt;p&gt;VS Code will display a popup asking to build the container. Dismiss the popup, we will replace the Dockerfile with the Pulumi Dockerfile.&lt;/p&gt;
&lt;p&gt;&lt;img src="build_container_popup.png" alt="Popup"&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In your project directory, you’ll see a &lt;em&gt;.devcontainer&lt;/em&gt; directory with a Dockerfile that builds the container and a &lt;em&gt;devcontainer.json&lt;/em&gt; for configuring the container environment.&lt;/p&gt;
&lt;h2 id="dockerfile"&gt;Dockerfile&lt;/h2&gt;
&lt;p&gt;For this example, we’ll use the standard Pulumi Dockerfile, which includes the SDK for all the supported languages. Download the &lt;a href="https://raw.githubusercontent.com/pulumi/pulumi/master/.devcontainer/Dockerfile"&gt;Dockerfile&lt;/a&gt; and save it to the .devcontainer directory.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ &lt;span class="nb"&gt;cd&lt;/span&gt; .devcontainer
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ curl &lt;span class="s2"&gt;&amp;#34;https://raw.githubusercontent.com/pulumi/pulumi/master/.devcontainer/Dockerfile&amp;#34;&lt;/span&gt; -o Dockerfile
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="container-configuration"&gt;Container configuration&lt;/h2&gt;
&lt;p&gt;Next, we&amp;rsquo;ll clean up the &lt;code&gt;.devcontainer/devcontainer.json&lt;/code&gt; file and set up the necessary credentials.&lt;/p&gt;
&lt;p&gt;First edit &lt;code&gt;devcontainer.json&lt;/code&gt; as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Replace the &amp;ldquo;name&amp;rdquo; field with &lt;code&gt;Pulumi&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Remove the &amp;ldquo;args&amp;rdquo; line&lt;/li&gt;
&lt;li&gt;Replace the &amp;ldquo;remoteUser&amp;rdquo; value with &lt;code&gt;user&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Regardless of your cloud provider, you will have to provide your credentials to deploy resources. If you want to save your project to Github or another repository, you don’t want your credentials stored in the repository. There are several ways to do this securely. Using AWS as an example, you can export them inside the container, e.g.,&lt;/p&gt;
&lt;p&gt;Linux/macOS:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;AKIAI44QH8DHBEXAMPLE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Windows:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cmd" data-lang="cmd"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="nv"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;AKIAI44QH8DHBEXAMPLE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="nv"&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The disadvantage of this method is that you will have to set these environment variables every time you start the devcontainer.&lt;/p&gt;
&lt;h3 id="use-local-environment-variables"&gt;Use local environment variables&lt;/h3&gt;
&lt;p&gt;One alternative is to set the environment variables on your local machine and pass them to the container through the &lt;em&gt;devcontainer.json&lt;/em&gt; file. This method requires that you have VS Code in your path and launch it from the shell.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Use CTRL+SHIFT+P or CMD+SHIFT+P to bring up the command palette and type &lt;em&gt;Shell Command: Install ‘code’ command in PATH&lt;/em&gt;. You can set your credentials as environmental variables and launch the VS Code from the shell&lt;/p&gt;
&lt;p&gt;&lt;img src="install-code-in-path.png" alt="Install code"&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ &lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;AKIAI44QH8DHBEXAMPLE
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ &lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ code .
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Next, set your provider credentials on your machine and add the following to &lt;em&gt;devcontainer.json&lt;/em&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;&amp;#34;containerEnv&amp;#34;&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;AWS_ACCESS_KEY_ID&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;${localEnv:AWS_ACCESS_KEY_ID}&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;AWS_SECRET_ACCESS_KEY&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;${localEnv:AWS_SECRET_ACCESS_KEY}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="use-an-env-file"&gt;Use an .env file&lt;/h3&gt;
&lt;p&gt;Another alternative is to use a devcontainer.env file, which contains your credentials.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create a file with your credentials.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;AWS_ACCESS_KEY_ID=AKIAI44QH8DHBEXAMPLE
AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Then add it to the &lt;em&gt;devcontainer.json&lt;/em&gt; file.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;&amp;#34;runArgs&amp;#34;&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;--env-file&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;devcontainer.env&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To prevent it from exposing your credentials on a public repository, add the file to &lt;em&gt;.gitignore&lt;/em&gt; or similar for you repository, e.g.,&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; devcontainer.json &amp;gt; .gitignore
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;There are many more &lt;a href="https://code.visualstudio.com/docs/remote/containers-advanced"&gt;configuration options available&lt;/a&gt;, including mounts and remote configurations.&lt;/p&gt;
&lt;h2 id="try-it-out"&gt;Try it out&lt;/h2&gt;
&lt;p&gt;Again, use the command palette to start the container. Use the &lt;strong&gt;Open Folder in Container&amp;hellip;&lt;/strong&gt; command, and select the project folder. If you’ve already got the folder open locally, you could also use the &lt;strong&gt;Reopen in Container&lt;/strong&gt; command.&lt;/p&gt;
&lt;p&gt;Check to see if your credentials are set. Open a terminal in VS Code if it isn’t already open.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ user@973a612c1555:/workspaces/my_devcontainer# env &lt;span class="p"&gt;|&lt;/span&gt; grep AWS
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;AKIAI44QH8DHBEXAMPLE
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now we ready to use Pulumi in our VS Code development environment! Let’s try it out by creating an S3 bucket. First, we’ll make a directory for our project and use &lt;code&gt;pulumi new&lt;/code&gt; to create a default project.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ mkdir my_project
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ &lt;span class="nb"&gt;cd&lt;/span&gt; my_project
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi new aws-typescript
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Follow the prompts, then run &lt;code&gt;pulumi up&lt;/code&gt; to deploy.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi up
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Previewing update &lt;span class="o"&gt;(&lt;/span&gt;dev&lt;span class="o"&gt;)&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Type Name Plan
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; + pulumi:pulumi:Stack my_project-dev create
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; + └─ aws:s3:Bucket my-bucket create
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Resources:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; + &lt;span class="m"&gt;2&lt;/span&gt; to create
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Do you want to perform this update? yes
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Updating &lt;span class="o"&gt;(&lt;/span&gt;dev&lt;span class="o"&gt;)&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Type Name Status
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; + pulumi:pulumi:Stack my_project-dev created
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; + └─ aws:s3:Bucket my-bucket created
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Outputs:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; bucketName: &lt;span class="s2"&gt;&amp;#34;my-bucket-cbdec06&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Resources:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; + &lt;span class="m"&gt;2&lt;/span&gt; created
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Duration: 31s
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Permalink: https://app.pulumi.com/spara/my_project/dev/updates/1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can CMD + click on the link to open a browser and display the status of your project on the Pulumi Service.&lt;/p&gt;
&lt;p&gt;&lt;img src="pulumi-console.png" alt="Pulumi Service"&gt;&lt;/p&gt;
&lt;h2 id="build-a-pulumi-examples-devcontainer"&gt;Build a Pulumi examples devcontainer&lt;/h2&gt;
&lt;p&gt;Pulumi has a repository of examples, and we can create a devcontainer from the repository so you can try them out.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Clone the repository, then follow the steps above to create and configure the Pulumi container image.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ git clone https://github.com/pulumi/examples.git
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create the configuration files, add the Pulumi Docker file, and add your credentials.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Let’s deploy a Kubernetes cluster! With &lt;code&gt;pulumi stack init&lt;/code&gt;, we can create a stack, but we will need to install the project dependencies and set configuration variables such as the region.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ &lt;span class="nb"&gt;cd&lt;/span&gt; aws-ts-eks
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi stack init
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ npm install
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi config &lt;span class="nb"&gt;set&lt;/span&gt; aws:region us-west-2
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi up
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Here’s the kubeconfig file&amp;rsquo;s output, which you can use with kubectl to manage the cluster.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Outputs:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; kubeconfig: &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; apiVersion : &lt;span class="s2"&gt;&amp;#34;v1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; clusters : &lt;span class="o"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;[&lt;/span&gt;0&lt;span class="o"&gt;]&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; cluster: &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; certificate-authority-data: &lt;span class="s2"&gt;&amp;#34;LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRJd01EY3hNVEl5TXpZMU9Wb1hEVE13TURjd09USXlNelkxT1Zvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTHFvCk9wTDBiQWo2TFFMNlh2anRsMFZ6TUN5WTJmYlo4cXEvNGd3bkJxcVI2RFV6Q1RwbkJmOHJVRjVrUXhBQXRUNysKTTFZblp5VEFBYndOZ3NIL3lObk5sMnFCQmRSQ0JZTVVlN1I2MVBxcGdabFZpN0JaNHRlek9DalRqeGV0SXlaMwoxRW9TdTNBYnhzTmh6dDVBTjVYZklnZlBuM3B2eEtwYTA1MEg3aWhFaUptSEl3M0Z5TVovUHpxY2JHczh3RHVCCk1jYjNzOHMwZDBIVExsb2dCL2svOVBLbGVpZDgyWFkxMEdBN0YxeFM2cFdZODkwQ1BwNXpWZ0pRWGhuRGR2S1gKVlFValdCTDZQYU14U0lBZEZQM1BZYk1FdXk5Vyt0c2lqc2VydThVNTVpUDlWSUdMdTZzdEdycTNuQUhtUk40UQpqeXRCRWd4RjN1R0dtZ0dMOStFQ0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFEcUtyVGVnZmhWbElNUklQNjFVZEtvaGtnS3MKblUyZjUvTHBzU3ozbmliUCt3Y2VpNktYL3RSNjAzTHhFMlVXUTlmR0ZycTBCMTlJR1JaK0VVQjl2Vy9JdWowTApVK2UwUUtWc01qd2dMWm4rS3IyN0VQNUNGay8vZEVCRUZqa01PMmNlTFFRaFcvUXFzSFhJb2ZjZ0UvZnJ3YzErCmQwdGROWmxJa3JRdzJwYnVhcVI0VmRlWlpVSitqbW8rdEo1SlZ5a2Rwa29JYml1ZEZ6Q0N5YVB1LzhJc09CTUsKcWtvTFpNazdBMzh5SWxDK2RCTnJwdkQvRTF5U1lhcXlDaE5CdVBkd1VqcWZaWmJmaWR5N050emd2VjMvUWFtWgpuZUJJcWs0c1AzSWU0TUN0QmV4bU9iSWowdVBLTnVCQ01UTStxSVI2UWdnYXdEbWxXcXE4V0ZiUlNJMD0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; server : &lt;span class="s2"&gt;&amp;#34;https://3FE47B904E57AF9E16E0B7F00C7EEABA.yl4.us-west-2.eks.amazonaws.com&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; name : &lt;span class="s2"&gt;&amp;#34;kubernetes&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; contexts : &lt;span class="o"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;[&lt;/span&gt;0&lt;span class="o"&gt;]&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; context: &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; cluster: &lt;span class="s2"&gt;&amp;#34;kubernetes&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; user : &lt;span class="s2"&gt;&amp;#34;aws&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; name : &lt;span class="s2"&gt;&amp;#34;aws&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; current-context: &lt;span class="s2"&gt;&amp;#34;aws&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; kind : &lt;span class="s2"&gt;&amp;#34;Config&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; users : &lt;span class="o"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;[&lt;/span&gt;0&lt;span class="o"&gt;]&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; name: &lt;span class="s2"&gt;&amp;#34;aws&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; user: &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; exec: &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; apiVersion: &lt;span class="s2"&gt;&amp;#34;client.authentication.k8s.io/v1alpha1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; args : &lt;span class="o"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;[&lt;/span&gt;0&lt;span class="o"&gt;]&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;eks&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;[&lt;/span&gt;1&lt;span class="o"&gt;]&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;get-token&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;[&lt;/span&gt;2&lt;span class="o"&gt;]&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;--cluster-name&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;[&lt;/span&gt;3&lt;span class="o"&gt;]&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;cluster-eksCluster-367b66b&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;command&lt;/span&gt; : &lt;span class="s2"&gt;&amp;#34;aws&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can now try out any of our infrastructure as code examples with this devcontainer.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;As you can see, we’ve built our development with VS Code and Docker. Using a Pulumi devcontainer lets you build and deploy infrastructure without installing Pulumi or any associated dependencies on your computer. Moreover, you can share your development environment by creating a repository. Give it a try and let us know what you’re building on &lt;a href="https://pulumi.slack.com"&gt;Slack&lt;/a&gt; or &lt;a href="https://twitter.com/pulumicorp"&gt;Twitter&lt;/a&gt;.&lt;/p&gt;</description><author>Sophia Parafina</author><category>development-environment</category><category>containers</category><category>docker</category></item></channel></rss>