Tool and how-to guide to use Pulumi OSS IaC (Infrastructure as Code) to create multiple Google Cloud sandbox projects with previously created resources for training courses, workshops, interactive demos, etc.
Learn more about Pulumi IaC: www.pulumi.com
Contact maintainer:
- Marcos Manuel Ortega: info@indavelopers.com
- Consultant, architect and trainer
- Google Cloud Authorized Trainer
- Google Developer Expert in Google Cloud
- LinkedIn: Marcos Manuel Ortega
- Made with ❤️ from Almería, Spain
You want to run a GCP workshop, training course, sandbox, hackathon... and you need to create several individual projects for each participant.
Each participant needs a GCP project with some IAM roles assigned to them, APIs enabled, a billing account assigned, etc., and maybe some resources already created, as VM instances, GKE clusters, DBs, GCS buckets, etc.
Since last time, you don't want to have to setup again everything up for each participant manually, then again next time, maybe forgetting to setup something and trying to fix errors live...
You'd prefer to have a template and setting it all up automatically, and just reuse it every time new environments are needed or new attendees join, and even collaborate sharing project templates with other event organizers.
Sometimes you just want environments to for a single lab exercise, sometimes you're running an event/workshop/course composed of multiple labs.
Here, events are represented by Pulumi projects, and labs by Pulumi Stacks.
Recommended dir structure:
events: Holds all events and labs, independent from basesrcevents/example-generic_events: Miscellaneous, single labs.events/example-course: Example course or event composed of multiple labs, each with ownexample-lab0stack, folder andlab-project_infra.pyGCP resources file.
src: Pulumi Python code and example/base config files:src/example-Pulumi.yaml: Base Pulumi project config file.src/example-Pulumi.stack_name.yaml: Base Pulumi stack config file.src/example-lab-project_infra.py: Example Pulumi Python resource definition file.
You can use this structure, using them as example files and adding your new event dirs, or a custom one.
- Stacks config YAML files are created by default next to the project's
Pulumi.yamlfile, instead of the current dir. - In each
Pulumi.yaml, use relative paths to navigate up from the event directory to the repository root'ssrcdirectory. For example, if your project is 2 levels deep (events/example-course/), use../../src/__main__.pyand../../src/venv. - Also, in each stack YAML file, use the correct relative path to the lab
lab-project_infra.pyfile as evaluated from the main script (e.g.,../events/example-course/example-lab0/lab-project_infra.pyas seen fromsrc/__main__.py).
As we're creating the GCP projects and enabling the GCP APIs or services in the same Pulumi script, you need to explicitly declare the GCP API/service each resource depends on. If not declared, APIs and resources would be created at the same time, and thus resource creation would fail as the API hasn't been enabled yet.
Something similar happens with GCP project creation: if the GCP project is not declared for each resource - even eg. for subnets, where the network is declared as an attribute, Pulumi would take your local Cloud SDK config GCP project, instead of the projects created by this script. Therefore, you need to explicitly include the GCP project using the project var from gcp_projects the loop is iterating over.
- Clone repo and open dir:
git clone https://github.com/Indavelopers/gcp-training-projects.git,cd gcp-training-projects - Install Pulumi CLI: Pulumi: Getting started,
curl -fsSL https://get.pulumi.com/ | sh- You can login to Pulumi Cloud or manage stack state locally with Pulumi IaC OSS:
- State file in
$HOME/.pulumi:pulumi login --local(alias forpulumi login file://~) - State file in another location:
pulumi login file://path/to/pulumi-config-dir
- State file in
- Don't create a new Pulumi project in
src, as will rewrite__main__.pyfile. CheckPulumi CLI usagesection for more.
- You can login to Pulumi Cloud or manage stack state locally with Pulumi IaC OSS:
- You can setup the Pulumi passphrase so you don't have to input it every time:
export PULUMI_CONFIG_PASSPHRASE=passphrase && echo $PULUMI_CONFIG_PASSPHRASE - Setup GCP authn Application Default Credentials (ADC) for Pulumi CLI:
gcloud auth application-default login- You need a working local Cloud SDK installation or use GCP Cloud Shell.
- Check first previous instructions about using Pulumi projects and stacks in section Creating events and lab exercises.
- Create a event/lab dir and work in it:
cd events,mkdir example-course1 && mkdir example-course1/example-lab1,cd example-course1/example-lab1
- Create a event/lab dir and work in it:
- For each new event dir, you need to create a new Pulumi project inside. For a new lab, you just need to create a new Pulumi stack.
- Creating a new project and stacks register them in your Pulumi state, and sets a new encryption salt for that stack.
- Create a new Pulumi
Python GCPproject:pulumi new - Create a new Pulumi stack. You can use the lab name for the stack name:
pulumi stack init STACK_NAME - Copy the
src/Pulumi.yamlcontent into thePulumi.yamlproject config file, and modify paths tosrc/__main__.pyandsrc/venvaccordingly. - Copy the
src/example-Pulumi.stack_name-yamlcontent into thePulumi.STACK_NAME.yamlstack config file:encryptionsalt: Don't overwrite, unique to that stack.infra_script: Resources script to import, relative path fromsrc/__main__.py.- File can have any name,
lab-project_infrais just a convention.
- File can have any name,
emails: List of attendees' emails. You can add an environment for the trainer putting his email first.apis: List of GCP APIs/services to enable.roles: List of roles to be assigned to attendes in their projects.organization_id: GCP organization ID, billing account IDbilling_account_id: GCP billing account ID.folder_name: GCP folder name.project_prefix: GCP project prefix, e.g. GCP project ID would bePROJECT_PREFIX-00-HASH_SUFFIX.PROJECT_PREFIX: Can reflect e.g. the lab or workshop name, so can be the same as Pulumi stack name.- GCP project IDs must be 6-30 chars with lowercase letters, digits, hyphens. Should start with a letter, no underscores, and trailing hyphens are prohibited, therefore this applies to project prefix as well.
00-99: Project/attendee index, following emails list.HASH_SUFFIX: Unique hash created using stack config fields and random data.- For clarity, you can use
STACK_NAME_infra, but it's not enforced - e.g. this how-to guide examples uselab-project_infra.
event_unique_id: Unique event ID, modify if you want to repeat the event using the same stack name when users.- As GCP project IDs should be globally unique, a unique
HASH_SUFFIXfor each user is computed. - This hash is computed using the stack config and random data, as stated before.
- When you delete the GCP project (e.g. with
pulumi down), it enters a pending delete state for 30 days, during which you can manually restore a project, but you can't usepulumi upto recreate them again. - When running the same lab again, you might copy and create a new stack with a different name and/or config, but sometimes you might just modify the email list and try to deploy again.
- If any email is used again (e.g. same trainer or repeating attende), it would generate the same project ID again, and would error out when creating the GCP project.
- Therefore, if the same lab is to be repeated, you can modify this unique event ID so that a different hash is created.
- As GCP project IDs should be globally unique, a unique
- As we're creating a GCP folder and multiple projects, Pulumi config
gcp:projectis not used, so it can be skipped (Pulumi throwns a warning).
Then voilá, check and deploy environments with pulumi preview and pulumi up (see Pulumi CLI usage section).
- Pulumi automatically creates and uses a Python virtual env when running e.g.
pulumi upfor the first time, without user creating or activating it.- When writing your
lab-project_infra.pyfiles, you can select this virtual env for your IDE.
- When writing your
src/Pulumi.yamlrefers to thissrc/venvvirtual environment.- It automatically installs Python packages from
src/requirements.txt. - You can point your IDE's Python interpreter or virtual environment to this
src/venvdir.
Check src/requirements.txt:
- Pulumi for Python v3
- Pulumi provider: Google Cloud (GCP) Classic v7
You can add your Python modules here, or point to another venv dir in your stack config YAML file.
BEWARE::
- When creating a new Pulumi project, it rewrites any
Pulumi.yamland__main__.pyin that dir. - Creating a new Stack rewrites any
Pulumi.STACK_NAME.yaml. - Therefore, it's recommended to first create projects and stacks, then overwriting the YAML with content from
src.
Manage Pulumi projects:
- Create a new Pulumi Python GCP project using the
GCP Pythontemplate:pulumi new - Any
pulumicommand will run linked to the nearest Pulumi projectPulumi.yamlfile found in the same dir, or parent dirs.
Manage Pulumi stacks:
- Create a new stack and select it:
pulumi stack init STACK_NAME - Get stack resources state:
pulumi stack - List stacks:
pulumi stack ls - List all stacks, including other projects:
pulumi stack ls -aQ - Select a different stack:
pulumi stack select STACK_NAME - Remove a stack:
pulumi stack rm STACK_NAME
Deploy GCP resources:
- Check plan of resources to create, modify or delete:
pulumi preview - Deploy resources:
pulumi up - Check created resources state:
pulumi stack - Destroy resources:
pulumi down
GNU GPLv3
Tested at the time of last commit:
- None.
If you find any issues, please open a GitHub issue before, (optionally) open a PR to fix it, or contact the maintainer directly any way.
Just open an issue, submit a pull request, or generally contact the author by any mean.
See to-dos in to-dos.md.