Hey <@U039K8MS5HV>! I'd love to help you understan...
# getting-started
g
Hey @stocky-butcher-62635! I'd love to help you understand Pulumi a bit. Want to hop into this thread, and we'll see if we can help you get sorted out? 🧵 I'm also happy to hop onto a Zoom call to go over how Pulumi works if that would help.
So I think a quick overview of what to expect would be helpful here:
You can think of
stacks
as
environments
. I really like this diagram from the docs as a way to explain all the various terms in a visual way: https://www.pulumi.com/images/docs/pulumi-programming-model-diagram.svg
👍 1
When you created a directory on your local machine, you created a project. The program is the
.cs
file (or
.py
or
.ts
... depends on your programming language). The stack's config is defined by the
Pulumi-<stack>.yaml
file, while the project config is the
Pulumi.yaml
file.
You write one program that abstracts the overall infrastructure. The stack config acts a bit like a store of environment variables that you call from your program. So, when I run the program and tell it to call from the dev stack, it uses the configuration from that stack. When I run the program and instead point it to staging, then it uses the configuration from the staging stack.
Regarding tearing down a stack versus tearing down a project: If you run
pulumi destroy
, it tears down the infrastructure (both the resources and the state) in the current context--the stack you have been working on. It doesn't delete the stack's configuration from Pulumi. To remove that stack's configuration from Pulumi, you use
pulumi stack rm
. Be careful as you'll have to rebuild the config from scratch if you do that!
To completely remove the project from Pulumi, you have to remove all the stacks. When you run
pulumi stack rm
on all of the stacks, you've wiped all of the configurations, and the project is no longer needed as it doesn't mean much without a stack to attach to it. You still have the project on your local machine (or in a codebase somewhere), though, and can kick it back off by initializing a new stack and adding configurations.
The program itself is a declaration of the desired state of the infrastructure. You aren't running commands in order (e.g., initialize this piece of infra, run configuration, then initialize this other piece of infra...), but rather telling Pulumi that you want these pieces of infra with these configs ready to go, and Pulumi then communicates with the cloud providers to get you those pieces as you want them.
s
My initial instinct was to make 1 project with a stack for each environment --
production
,
test
, and maybe feature branches. I think you call this monolithic? The alternative seemed to be to make a project and stacks for every git repository that contains something that gets deployed. But, for example, this would make a web app difficult to configure when it depends on other apps (e.g., HTTP APIs) that are deployed in other stacks of other projects. Is there a way to manage this configuration?
g
So I personally think of projects and stacks as following the logic of the system and keeping anything that's connected in one project because they often need to be on the same stack for testing or other purposes. So the API infra and the web app infra would be in the same project in your example when I build it. I do define the infra as classes or functions in different files if possible and then import them to the main file just for readability, but that's a Python style. You don't have to if your language of choice doesn't typically do that. If you have the option of doing things this way (your first instinct), I'd do it as I find it saves a lot of heartache in the long run. Some folks keep a sort of control repo that has all of their infra definitions in one place, separate from the application code. I find that to be less than ideal for the same reason I prefer docs to live in the same repo and be treated as code: It's far too easy to update one without considering updating the other. This pattern is often seen with teams that are more separated, though. In the case where you're talking about, the best way to handle that is to export anything that's required to configure something else (e.g., the address for the API) so that it can be used across stacks. We call those things stack references. I'm not the best at C#, to be honest, but we do have some code snippets that might help in the docs here: https://www.pulumi.com/docs/intro/concepts/stack/#stackreferences. You can use stack references across stacks and across projects.
Our learning references that go beyond the basic tutorials are currently in TypeScript and Python (I'm working on getting them in other languages!), but would it help to see a full project? I've built a couple demo ones and would be happy to walk you through them: • https://github.com/nimbinatus/circleci-pulumi-samplehttps://github.com/nimbinatus/stand-back-talk The last one probably is the cleanest for me to show you. If you poke around, you'll find I've got the app itself in its own directory, and then the infra in another. In the infra, there's a
Pulumi.yaml
file, which got generated by the
pulumi new python
command, and a
Pulumi.dev.yaml
file, which got generated in that same command because I defined a first stack of
dev
. The
Pulumi.dev.yaml
file got populated by me running the following command:
pulumi config set <key> <value>
for each one of those pairs. I could alternatively have run
pulumi config set-all
, but I'd recommend doing the standard command one by one first until you're comfortable.