<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0"><channel><title>Pulumi Blog: Sean Gilespie</title><link>https://www.pulumi.com/blog/authors/sean-gillespie/</link><description>Pulumi blog posts: Sean Gilespie.</description><language>en-us</language><pubDate>Wed, 15 May 2019 00:00:00 +0000</pubDate><item><title>Pulumi and Docker: Development to Production</title><link>https://www.pulumi.com/blog/pulumi-and-docker-development-to-production/</link><pubDate>Wed, 15 May 2019 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/pulumi-and-docker-development-to-production/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/pulumi-and-docker-development-to-production/index.png" /&gt;
&lt;p&gt;Here at Pulumi, we&amp;rsquo;re big fans of Docker: at this point there is little
doubt that Docker has completely revolutionized the way that we think
about deploying software. However, even in 2019, it&amp;rsquo;s quite difficult to
get Docker containers to production. &lt;code&gt;docker run&lt;/code&gt; is great, and we all
love it, but unfortunately it&amp;rsquo;s quite a big leap from &lt;code&gt;docker run&lt;/code&gt; to
running your container in a production-ready environment.&lt;/p&gt;
&lt;p&gt;We recently wrote a blog post about
&lt;a href="https://www.pulumi.com/blog/get-started-with-docker-on-aws-fargate-using-pulumi/"&gt;using AWS Fargate to run your docker containers with our open source packages&lt;/a&gt;.
In this blog post we&amp;rsquo;re going to focus on another interesting aspect of
Pulumi: being able to re-use your infrastructure code for both
development and production!&lt;/p&gt;
&lt;h2 id="its-all-code-composing-docker-containers"&gt;It&amp;rsquo;s All Code: Composing Docker Containers&lt;/h2&gt;
&lt;p&gt;In addition to the number of cloud and infrastructure providers that
Pulumi supports, Pulumi also supports
&lt;a href="https://www.pulumi.com/registry/packages/docker/api-docs/"&gt;defining Docker resources&lt;/a&gt;
in code. Let&amp;rsquo;s look at this code snippet of Pulumi TypeScript code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// This program encodes a complete application: a container running Redis Commander,
// and a container running Redis. Redis Commander connects directly with Redis.
//
// In order for the two containers to communicate directly, they must be placed in the
// same network. Before creating the containers themselves, we first create the network
// that will contain both of them.
const network = new docker.Network(&amp;quot;net&amp;quot;);
// Also before creating a container, we must first obtain a &amp;quot;RemoteImage&amp;quot;, which is a reference to an external image
// that is downloaded to the local machine. In this case, we're referring to an image on Docker Hub.
const redisImage = new docker.RemoteImage(&amp;quot;redis-image&amp;quot;, {
name: &amp;quot;redis:latest&amp;quot;,
keepLocally: true, // don't delete the image from the local machine when deleting this resource.
});
// We can create a container using a reference to the name of the image we just downloaded and a reference to the name
// of the network that this container should use.
const redisContainer = new docker.Container(&amp;quot;redis&amp;quot;, {
image: redisImage.name,
networksAdvanced: [{ name: network.name }],
restart: &amp;quot;on-failure&amp;quot;,
});
// We do the same thing for the Redis Commander container.
const redisCommanderImage = new docker.RemoteImage(&amp;quot;redis-commander-image&amp;quot;, {
name: &amp;quot;rediscommander/redis-commander:latest&amp;quot;,
keepLocally: true,
});
const redisCommanderContainer = new docker.Container(&amp;quot;redis-commander&amp;quot;, {
image: redisCommanderImage.name,
restart: &amp;quot;on-failure&amp;quot;,
networksAdvanced: [{ name: network.name }],
envs: [
// Pulumi resources have &amp;quot;output&amp;quot; properties, which are properties that are set upon successful completion of
// the resource operation. These &amp;quot;outputs&amp;quot; are like promises - they can't be used directly but instead must be
// manipulated through use of the `apply` function.
//
// Here, we are using the name of the Redis commander to build an environment variable `REDIS_HOST` that points
// to the network identity of the Redis container we just created.
redisContainer.name.apply(name =&amp;gt; `REDIS_HOST=${name}`),
],
// Finally, we expose some ports. Redis Commander listens on port 8081, so we'll map that to external
// port 3000 for easy consumption on the user machine.
ports: [{
internal: 8081,
external: 3000,
}]
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here we are looking at a complete Pulumi program that does a &lt;em&gt;bunch&lt;/em&gt; of
things with Docker:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;We create a Docker network named &lt;code&gt;net&lt;/code&gt;, which we&amp;rsquo;ll use to connect
two containers together&lt;/li&gt;
&lt;li&gt;We pull the &lt;code&gt;redis:latest&lt;/code&gt; image from Docker Hub and create a
container using it, named &lt;code&gt;redis&lt;/code&gt;, which we attach to the network we
just created&lt;/li&gt;
&lt;li&gt;We pull the &lt;code&gt;rediscommander/redis-commander:latest&lt;/code&gt; image from
Docker Hub and also create a container using it, named
&lt;code&gt;redis-commander&lt;/code&gt;, which likewise is attached to the network and
exposes some ports on the host machine.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is fairly nontrivial, but we&amp;rsquo;ve done it in code right here. Using
code we&amp;rsquo;ve replicated many of the features offered by tools like
&lt;code&gt;docker-compose&lt;/code&gt;, but without writing a single line of YAML. Running
&lt;code&gt;pulumi up&lt;/code&gt; with this code results in a working instance of Redis
Commander listening on port 3000 on your machine. Nice and simple!&lt;/p&gt;
&lt;h2 id="moving-to-production"&gt;Moving to Production&lt;/h2&gt;
&lt;p&gt;Orchestrating Docker containers on your local machine while developing
is great, but when it comes time to pushing containers to production,
you can&amp;rsquo;t rely on Docker alone anymore. There are a number of excellent
container orchestrators out there but there few are as successful as
Kubernetes. The way that you launch production workloads in Kubernetes
is significantly different than how you would do it using &lt;code&gt;docker run&lt;/code&gt;
on your own, so it&amp;rsquo;s often the case that you&amp;rsquo;d need to write another
series of YAML documents to get your application into production.&lt;/p&gt;
&lt;p&gt;With Pulumi, we&amp;rsquo;re just writing code. Since we&amp;rsquo;re just writing code, we
can do exactly what we would do if we were writing application code:
&lt;strong&gt;abstract!&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Since we&amp;#39;re using a general-purpose programming language, we can now use that language to provide multiple
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// implementations of the same abstraction. In this case, we define an abstract &amp;#34;Redis&amp;#34; component whose only property is
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// that it has some network identity (host) that consumers can connect to and talk to a Redis connection.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;abstract&lt;/span&gt; &lt;span class="kr"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;Redis&lt;/span&gt; &lt;span class="kr"&gt;extends&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;ComponentResource&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="kr"&gt;public&lt;/span&gt; &lt;span class="kr"&gt;abstract&lt;/span&gt; &lt;span class="kr"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;host&lt;/span&gt;: &lt;span class="kt"&gt;pulumi.Output&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;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;public&lt;/span&gt; &lt;span class="kr"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;: &lt;span class="kt"&gt;RedisArgs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;opts?&lt;/span&gt;: &lt;span class="kt"&gt;pulumi.ComponentResourceOptions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Redis&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="c1"&gt;// Since we are using TypeScript and RedisArgs is the union of argument types for each resource. Since args.type
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// has type &amp;#34;amazon&amp;#34; | &amp;#34;docker&amp;#34; | &amp;#34;kubernetes&amp;#34;, the compiler assists us in making sure that we don&amp;#39;t
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// accidentally mix up argument types.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kr"&gt;type&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="k"&gt;case&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;amazon&amp;#34;&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; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;AmazonRedis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;opts&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="k"&gt;case&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;docker&amp;#34;&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; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;DockerRedis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;opts&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="k"&gt;case&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;kubernetes&amp;#34;&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; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;KubernetesRedis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;opts&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;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&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ty&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;: &lt;span class="kt"&gt;RedisArgs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;opts?&lt;/span&gt;: &lt;span class="kt"&gt;pulumi.ComponentResourceOptions&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="kr"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ty&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;opts&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;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&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;RedisArgs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;DockerRedisArgs&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;KubernetesRedisArgs&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;AmazonRedisArgs&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;We&amp;rsquo;ve departed a bit from our previous example, but we&amp;rsquo;re still writing
code. In particular, what we&amp;rsquo;re doing here is defining a new,
&lt;em&gt;&lt;strong&gt;abstract&lt;/strong&gt;&lt;/em&gt;, Redis component that takes the Redis container from the
previous example and abstracts it away a little bit. This class we&amp;rsquo;ve
created still represents Redis, but completely abstracts away where and
how the Redis instance is running. In this case, it can run in any one
of three different configurations:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Redis backed by AWS ElastiCache (&amp;ldquo;amazon&amp;rdquo;)&lt;/li&gt;
&lt;li&gt;Redis running as a Docker container on your machine (&amp;ldquo;docker&amp;rdquo;)&lt;/li&gt;
&lt;li&gt;Redis running as a Deployment on a Kubernetes cluster (&amp;ldquo;kubernetes&amp;rdquo;)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now, you can use this Redis component completely in the abstract, like
this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&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;redis&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;redis&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="kr"&gt;type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;docker&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;network&lt;/span&gt;: &lt;span class="kt"&gt;network&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;We&amp;rsquo;re requesting a &amp;ldquo;docker&amp;rdquo; container, but we could just as easily
switch this out for &amp;ldquo;amazon&amp;rdquo; and &amp;ldquo;kubernetes&amp;rdquo;, and suddenly our Redis
workload is transparently deployed in different ways, all without
disrupting our development environment!&lt;/p&gt;
&lt;h2 id="pulumi-infrastructure-as-software"&gt;Pulumi: Infrastructure as Software&lt;/h2&gt;
&lt;p&gt;We often say on this blog that Pulumi is &amp;ldquo;infrastructure as code&amp;rdquo;, and
that sentence is definitely true, but I prefer calling it
&amp;ldquo;&lt;a href="https://www.pulumi.com/what-is/what-is-infrastructure-as-software/"&gt;infrastructure as software&lt;/a&gt;&amp;rdquo;
instead. The distinction is subtle, but in
my mind Pulumi brings to the realm of infrastructure the variety of
tools we already use for software engineering:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Abstraction, encapsulation, and code reuse for infrastructure and
applications&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/blog/testing-your-infrastructure-as-code-with-pulumi/"&gt;Testing&lt;/a&gt;,
both unit and integration&lt;/li&gt;
&lt;li&gt;IDEs and tools for detecting errors extremely early in a developer&amp;rsquo;s
inner loop, instead of at deployment time&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Pulumi is open source, free to use, and works today with
&lt;a href="https://www.pulumi.com/registry/"&gt;a variety of clouds&lt;/a&gt; and bring a little more
software and less code into your infrastructure! If you&amp;rsquo;d like to see
more about this particular code demo,
&lt;a href="https://www.youtube.com/watch?v=EbsE4p3uCu0"&gt;check out my DockerCon EU 2018 talk&lt;/a&gt;
where I dive into this in detail. The code for this post and the talk are in
&lt;a href="https://github.com/swgillespie/dockercon18"&gt;this repository&lt;/a&gt;.&lt;/p&gt;</description><author>Sean Gilespie</author><category>containers</category><category>kubernetes</category><category>docker</category></item><item><title>Programming the Cloud with Python</title><link>https://www.pulumi.com/blog/programming-the-cloud-with-python/</link><pubDate>Thu, 04 Apr 2019 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/programming-the-cloud-with-python/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/programming-the-cloud-with-python/index.png" /&gt;
&lt;p&gt;Across the industry, the popularity of Python is exploding. Amongst our
own customers at Pulumi, who automate their infrastructure using Python,
we&amp;rsquo;ve seen the same. Stack Overflow wrote about the astounding growth
of Python:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The term &amp;ldquo;fastest-growing&amp;rdquo; can be &lt;a href="https://xkcd.com/1102/"&gt;hard to define
precisely&lt;/a&gt;, but we make the case that &lt;strong&gt;Python
has a solid claim to being the fastest-growing major programming
language&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&amp;ndash; &lt;a href="https://stackoverflow.blog/2017/09/06/incredible-growth-python/"&gt;David Robinson, Stack Overflow&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Since Python is not a new language, what could be driving this incredible adoption curve?&lt;/p&gt;
&lt;p&gt;Python is, and always has been, particularly amenable to the automation
of previously-manual tasks. So much so, in fact, that books have been
written on how to &lt;a href="https://automatetheboringstuff.com/"&gt;automate common tasks with Python&lt;/a&gt;. In recent years, Python&amp;rsquo;s
penchant for task automation have led to its use at the foundation of
tools now ubiquitous in the DevOps space: tools like
&lt;a href="https://www.ansible.com/"&gt;Ansible&lt;/a&gt;,
&lt;a href="https://www.saltstack.com/"&gt;SaltStack&lt;/a&gt;, and
&lt;a href="https://www.openstack.org/"&gt;OpenStack&lt;/a&gt; are all authored primarily in
Python. It would not be a stretch to claim that Python is the language
of automation.&lt;/p&gt;
&lt;p&gt;At &lt;a href="https://pulumi.com"&gt;Pulumi&lt;/a&gt; we are passionate about automating cloud infrastructure.
However, we see a major open opportunity to leverage our most powerful,
fundamental tool - the programming language - to automate our
infrastructure tasks. We love the idea of &amp;ldquo;infrastructure of code&amp;rdquo;, but
we struggle with the industry&amp;rsquo;s definition of &amp;ldquo;code&amp;rdquo;; it&amp;rsquo;s hardly code
at all, often consisting of YAML documents, DSLs, or other,
domain-specific solutions to the task at hand. Since Python is such an
incredible tool for task automation and since its use is rapidly
pervading the industry, wouldn&amp;rsquo;t it make sense to use code, to use
Python, to automate tasks as critical as the provisioning of our cloud
infrastructure and delivery of our applications?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Delivery is not a detail, it is our job. Now is the time to apply our
core skills to our own work. Now is the time to &lt;em&gt;engineer&lt;/em&gt; our
delivery. We divide our work between ourselves and computers: humans
for decisions, and automation for tasks.&lt;/p&gt;
&lt;p&gt; &amp;ndash; &lt;a href="https://github.com/sdd-manifesto/manifesto"&gt;The Software Defined Delivery Manifesto&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="that-sounds-great-but-what-is-thispulumi-thing"&gt;That sounds great, but what is this &amp;ldquo;Pulumi&amp;rdquo; thing?&lt;/h2&gt;
&lt;p&gt;Pulumi is an infrastructure as code tool for provisioning cloud
infrastructure and deploying applications. The key difference between
Pulumi and other tools in this space (such as Ansible, Terraform, and
AWS CloudFormation) is that Pulumi aggressively reclaims the word
&amp;ldquo;code&amp;rdquo;: users of Pulumi write programs in &lt;em&gt;general purpose programming languages&lt;/em&gt;
that, when run, deploy and run applications in cloud
environments, while still retaining all the known benefits of
infrastructure as code that our industry has grown accustomed to
(repeatability, resilience to failure, history and auditing, and so
on).&lt;/p&gt;
&lt;p&gt;Pulumi is a rebellion against YAML and domain-specific
non-Turing-complete languages. We firmly believe that your
infrastructure isn&amp;rsquo;t just code: &lt;em&gt;your infrastructure is software.&lt;/em&gt; By
applying the same engineering discipline to your infrastructure code
that you apply to your application code, we can iterate quickly and with
confidence, leaning on things such as automated tests, code analysis
tools, and a common language. Pulumi does not generate YAML; it instead
brings the full API surface area of your cloud environment into Python,
powered by an infrastructure as code engine.&lt;/p&gt;
&lt;p&gt;It is hard to overstate how liberating it is to write infrastructure as
code with a full general-purpose programming language at your disposal.
Below is a code snippet of a Pulumi program, written in Python, that
deploys a static website to S3:&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;import&lt;/span&gt; &lt;span class="nn"&gt;mimetypes&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&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;pulumi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;export&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FileAsset&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;pulumi_aws&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;s3&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;web_bucket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;s3-website-bucket&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;website&lt;/span&gt;&lt;span class="o"&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;index_document&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;index.html&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&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;content_dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;www&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;listdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content_dir&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;filepath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content_dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;file&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;mime_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mimetypes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;guess_type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filepath&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;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BucketObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&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;bucket&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;web_bucket&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;source&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;FileAsset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filepath&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;content_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;mime_type&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;There are only 18 lines of Python code here, but this program does a
ton!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;First, we create an AWS S3 Bucket that we&amp;rsquo;ll use to host our
website from, setting the index document to
be &amp;ldquo;index.html&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;Next, we iterate over all files in the &amp;ldquo;www&amp;rdquo; directory (using the
standard Python for loop!&lt;/li&gt;
&lt;li&gt;Finally, for every file in the &amp;ldquo;www&amp;rdquo; directory, we guess its MIME
type using the Python standard library and then create an S3
BucketObject inside the website bucket, which uploads the file to
S3.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is a simple example, but it&amp;rsquo;s hard to overstate how awesome it is to be able to reach into
Python&amp;rsquo;s deep standard library whenever we need to. In this example we&amp;rsquo;re using both the “os” and
“mimetypes” packages in the Python standard library: the first to list the files in a particular
directory and the second to guess a particular file&amp;rsquo;s MIME type based on its extension and contents,
which we eventually pass directly to S3.&lt;/p&gt;
&lt;p&gt;Remember, this code isn&amp;rsquo;t performing imperative commands — like, say, your cloud provider&amp;rsquo;s Python
SDK or Boto would — and instead creates a declarative resource graph that the Pulumi engine understands
how to act upon. This works for the first deployment, but more importantly, for all subsequent
incremental updates too. If we were to change the contents of one of the files on disk, Pulumi would
recognize that one of the files has changed and re-upload it, without changing the bucket or any of
the other already existing bucket objects!&lt;/p&gt;
&lt;h2 id="where-can-i-learn-more"&gt;Where can I learn more?&lt;/h2&gt;
&lt;p&gt;Don&amp;rsquo;t take our word for it, though! We&amp;rsquo;d love for you to check it out and see for yourself how
great it is to reclaim the “code” in “infrastructure as code”.&lt;/p&gt;
&lt;p&gt;If you want to know more about Pulumi and the things it can do for you, check out the &lt;a href="https://www.pulumi.com/docs/get-started/"&gt;Getting Started&lt;/a&gt; page and &lt;a href="https://www.pulumi.com/docs/"&gt;Documentation&lt;/a&gt; for more information.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;d like to try the above example out for yourself, we&amp;rsquo;ve put the &lt;a href="https://github.com/pulumi/examples/tree/master/aws-py-s3-folder"&gt;full code on GitHub&lt;/a&gt;. There are also &lt;a href="https://github.com/pulumi/examples"&gt;dozens of other Python examples&lt;/a&gt; across AWS, Azure, GCP, Kubernetes and more you can explore.&lt;/p&gt;
&lt;p&gt;Python is the language of automation today and for the future. Pulumi is the infrastructure as
code automation tool of the future. Using them both together is an incredible way to automate a
crucial job while staying entirely within a language you already know and love!&lt;/p&gt;</description><author>Sean Gilespie</author><category>serverless</category><category>aws</category><category>python</category></item><item><title>How to deploy Jenkins to Kubernetes with Pulumi</title><link>https://www.pulumi.com/blog/how-to-deploy-jenkins-to-kubernetes-with-pulumi/</link><pubDate>Wed, 27 Jun 2018 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/how-to-deploy-jenkins-to-kubernetes-with-pulumi/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/how-to-deploy-jenkins-to-kubernetes-with-pulumi/index.png" /&gt;
&lt;p&gt;In this blog post, we&amp;rsquo;ll see how to run
&lt;a href="https://github.com/pulumi/examples/tree/master/kubernetes-ts-jenkins"&gt;Jenkins on Kubernetes with Pulumi&lt;/a&gt;.
We abstract away the complexity of the configuration into a reusable
component to enable it to be reused by team mates. Our example is based
on adapting a Helm template.&lt;/p&gt;
&lt;h2 id="reusing-the-jenkins-component"&gt;Reusing the Jenkins component&lt;/h2&gt;
&lt;p&gt;Once the component is created, it can be reused with just a few lines of
implementation code.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&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="kr"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;pulumi&lt;/span&gt; &lt;span class="kr"&gt;from&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;@pulumi/pulumi&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="kr"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="kr"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;jenkins&lt;/span&gt; &lt;span class="kr"&gt;from&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;./jenkins&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;config&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;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;jenkins&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="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;instance&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;jenkins&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Instance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;jenkins&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;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;jenkins&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;credentials&lt;/span&gt;&lt;span class="o"&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;username&lt;/span&gt;: &lt;span class="kt"&gt;config.require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;username&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;password&lt;/span&gt;: &lt;span class="kt"&gt;config.require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;password&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="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;resources&lt;/span&gt;&lt;span class="o"&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;memory&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;512Mi&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;cpu&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;100m&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="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;We could take the component code and prepare a fully reusable NPM
package, but as this is just an example, we&amp;rsquo;ve simply maintained the
code as an included class.&lt;/p&gt;
&lt;h2 id="running-the-app"&gt;Running the App&lt;/h2&gt;
&lt;p&gt;Follow the steps in
&lt;a href="https://www.pulumi.com/docs/install/"&gt;Pulumi Installation and Setup&lt;/a&gt; and
&lt;a href="https://www.pulumi.com/docs/iac/get-started/kubernetes/"&gt;Configuring Pulumi Kubernetes&lt;/a&gt;
to get setup with Pulumi and Kubernetes.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: The code in this repo assumes you are deploying to a cluster
that supports the &lt;code&gt;LoadBalancer&lt;/code&gt; service type. This includes most
cloud providers as well as &lt;a href="https://docs.docker.com/docker-for-mac/kubernetes/"&gt;Docker for Mac Edge w/ Kubernetes&lt;/a&gt;. If
not (for example if you are targeting &lt;code&gt;minikube&lt;/code&gt; or your own custom
Kubernetes cluster), replace &lt;code&gt;type: &amp;quot;LoadBalancer&amp;quot;&lt;/code&gt; with
&lt;code&gt;type: &amp;quot;ClusterIP&amp;quot;&lt;/code&gt; in &lt;code&gt;jenkins.ts&lt;/code&gt;. See the Kubernetes &lt;a href="https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services---service-types"&gt;Services docs&lt;/a&gt;
for more details.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Clone the repo and navigate to the Jenkins example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git clone https://github.com/pulumi/examples.git
$ cd kubernetes-ts-jenkins
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Install dependencies:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ npm install
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Create a new stack:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ pulumi stack init
Enter a stack name: kubernetes-ts-jenkins-dev
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Create configuration keys for the root username and password for the
Jenkins instance we are about to create:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ pulumi config set jenkins:username &amp;lt;your desired username&amp;gt;
$ pulumi config set jenkins:password &amp;lt;your desired password&amp;gt; --secret
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Preview the deployment of the application:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ pulumi preview
Previewing update of stack 'kubernetes-ts-jenkins-dev'
Type Name Status Info
* global global unchanged
Previewing changes:
Type Name Status Info
* global global no change
+ pulumi:pulumi:Stack kubernetes-ts-jenkins-kubernetes-ts-jenkins-dev create
+ └─ jenkins:jenkins:Instance jenkins create
+ ├─ kubernetes:core:v1:Secret jenkins-secret create
+ ├─ kubernetes:core:v1:PersistentVolumeClaim jenkins-pvc create
+ ├─ kubernetes:core:v1:Service jenkins-service create
+ └─ kubernetes:extensions:v1beta1:Deployment jenkins-deploy create
info: 6 changes previewed:
+ 6 resources to create
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Perform the deployment:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ pulumi update --skip-preview
Updating stack 'kubernetes-ts-jenkins-dev'
Type Name Status Info
* global global unchanged
Performing changes:
Type Name Status Info
* global global unchanged
+ pulumi:pulumi:Stack kubernetes-ts-jenkins-kubernetes-ts-jenkins-dev created
+ └─ jenkins:jenkins:Instance jenkins created
+ ├─ kubernetes:core:v1:Secret jenkins-secret created
+ ├─ kubernetes:core:v1:PersistentVolumeClaim jenkins-pvc created
+ ├─ kubernetes:core:v1:Service jenkins-service created
+ └─ kubernetes:extensions:v1beta1:Deployment jenkins-deploy created
info: 6 changes performed:
+ 6 resources created
Update duration: 2m30.397621136s
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The deployment is complete! Use &lt;code&gt;kubectl&lt;/code&gt; to see the Service that we
just deployed:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
jenkins LoadBalancer 10.43.241.251 35.230.56.127 80:30638/TCP,443:30204/TCP 3m
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Jenkins instance we just deployed is reachable through port 80 of
the external IP address. You can now visit
&lt;code&gt;http://35.230.56.127/jenkins/login&lt;/code&gt; in a Web browser to begin the
first-install flow for your new Jenkins instance. You can use the
username and password that you saved in your Pulumi config to log in to
your new Jenkins instance.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: If you are deploying to a cluster that does not support
&lt;code&gt;type: &amp;quot;LoadBalancer&amp;quot;&lt;/code&gt;, and deployed the example using
&lt;code&gt;type: &amp;quot;ClusterIP&amp;quot;&lt;/code&gt; instead, run
&lt;code&gt;kubectl port-forward svc/jenkins 8080:80&lt;/code&gt; to forward the cluster port
to the local machine and access the service via &lt;code&gt;localhost:8080&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When you&amp;rsquo;re ready to be done with Jenkins, you can destroy the
instance:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ pulumi destroy
Do you want to perform this destroy? yes
Destroying stack 'kubernetes-ts-jenkins-dev'
Performing changes:
Type Name Status Info
- pulumi:pulumi:Stack kubernetes-ts-jenkins-kubernetes-ts-jenkins-dev deleted
- └─ jenkins:jenkins:Instance jenkins deleted
- ├─ kubernetes:extensions:v1beta1:Deployment jenkins-deploy deleted
- ├─ kubernetes:core:v1:Service jenkins-service deleted
- ├─ kubernetes:core:v1:PersistentVolumeClaim jenkins-pvc deleted
- └─ kubernetes:core:v1:Secret jenkins-secret deleted
info: 6 changes performed:
- 6 resources deleted
Update duration: 18.202009282s
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="next-steps"&gt;Next Steps&lt;/h2&gt;
&lt;p&gt;This example showed just a little of the potential of reusing components
and code, instead of copy and pasting config, to improve productivity
and comprehension for building cloud stacks.&lt;/p&gt;
&lt;p&gt;Find out more:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Get the &lt;a href="https://github.com/pulumi/examples/tree/master/kubernetes-ts-jenkins"&gt;example code on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Read the docs on &lt;a href="https://www.pulumi.com/registry/packages/kubernetes/api-docs/"&gt;Kubernetes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;See the tutorial on &lt;a href="https://www.pulumi.com/docs/iac/guides/building-extending/components/build-a-component/"&gt;building components&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description><author>Sean Gilespie</author><category>kubernetes</category></item></channel></rss>