{"id":15156359,"url":"https://github.com/mtumilowicz/terraform-basics-modules-workshop","last_synced_at":"2026-03-09T11:33:33.114Z","repository":{"id":110879562,"uuid":"416869688","full_name":"mtumilowicz/terraform-basics-modules-workshop","owner":"mtumilowicz","description":"Introduction to terraform basics.","archived":false,"fork":false,"pushed_at":"2025-05-05T22:46:37.000Z","size":141,"stargazers_count":1,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-05-05T23:33:26.125Z","etag":null,"topics":["aws","devops","infrastructure-as-code","terraform","terraform-aws","terraform-live","terraform-managed","terraform-modules","terraform-project","terraform-providers","terraform-state"],"latest_commit_sha":null,"homepage":"","language":"HCL","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mtumilowicz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-10-13T19:17:46.000Z","updated_at":"2025-05-05T22:46:41.000Z","dependencies_parsed_at":"2024-10-10T07:40:50.752Z","dependency_job_id":"0b4215ef-112c-4b8d-8cd0-28f4f69d2783","html_url":"https://github.com/mtumilowicz/terraform-basics-modules-workshop","commit_stats":{"total_commits":126,"total_committers":1,"mean_commits":126.0,"dds":0.0,"last_synced_commit":"a039c4d9c0548753b9a611c39850f3012d02fc5c"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/mtumilowicz/terraform-basics-modules-workshop","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mtumilowicz%2Fterraform-basics-modules-workshop","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mtumilowicz%2Fterraform-basics-modules-workshop/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mtumilowicz%2Fterraform-basics-modules-workshop/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mtumilowicz%2Fterraform-basics-modules-workshop/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mtumilowicz","download_url":"https://codeload.github.com/mtumilowicz/terraform-basics-modules-workshop/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mtumilowicz%2Fterraform-basics-modules-workshop/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30292479,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-09T11:12:22.024Z","status":"ssl_error","status_checked_at":"2026-03-09T11:10:54.577Z","response_time":61,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aws","devops","infrastructure-as-code","terraform","terraform-aws","terraform-live","terraform-managed","terraform-modules","terraform-project","terraform-providers","terraform-state"],"created_at":"2024-09-26T19:20:32.990Z","updated_at":"2026-03-09T11:33:33.090Z","avatar_url":"https://github.com/mtumilowicz.png","language":"HCL","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)\n\n# terraform-basics-modules-workshop\n* references\n    * https://discuss.hashicorp.com/t/terraform-0-14-the-dependency-lock-file/15696\n    * https://medium.com/@business_99069/terraform-count-vs-for-each-b7ada2c0b186\n    * https://hub.docker.com/r/danjellz/http-server\n    * https://discuss.hashicorp.com/t/validate-list-object-variables/18291/2\n    * https://github.com/morethancertified/mtc-terraform\n    * https://github.com/edgar-anascimento/terraform-localstack-setup\n    * [[#122​] Terraform i AWS - odtwarzalna infrastruktura w 10 minut - Maciej Rostański](https://www.youtube.com/watch?v=87wIafVYK9I)\n    * [When Terraform alone isn't enough - Marcin Żbik](https://www.youtube.com/watch?v=nR1U9sdcR3k)\n    * [Version-Controlled Infrastructure with GitHub \u0026 Terraform with Seth Vargo](https://www.youtube.com/watch?v=2TWqi7dLSro)\n    * [[#128​] Infrastructure as a Code - AWS + Terraform + Ansible - Daniel Kossakowski](https://www.youtube.com/watch?v=BSHpZcy-BAo)\n    * [DevOps Crash Course (Docker, Terraform, and Github Actions)](https://www.youtube.com/watch?v=OXE2a8dqIAI)\n    * [Terraform Course - Automate your AWS cloud infrastructure](https://www.youtube.com/watch?v=SLB_c_ayRMo)\n    * [Terraform for AWS - Beginner to Expert 2021 (0.12)](https://www.udemy.com/course/terraform-fast-track)\n    * [Learn DevOps: Infrastructure Automation With Terraform](https://www.udemy.com/course/learn-devops-infrastructure-automation-with-terraform)\n    * [More than Certified in Terraform](https://www.udemy.com/course/terraform-certified/)\n    * [Terraform in Action](https://www.manning.com/books/terraform-in-action)\n    * https://www.packer.io/intro\n    * https://www.terraform.io/docs\n    * https://acloudguru.com/hands-on-labs/exploring-terraform-state-functionality\n    * https://www.andreagrandi.it/2017/08/25/getting-latest-ubuntu-ami-with-terraform/\n    * https://learn.hashicorp.com/tutorials/terraform\n    * https://pilotcoresystems.com/insights/what-are-terraform-workspaces\n    * https://medium.com/@diogok/terraform-workspaces-and-locals-for-environment-separation-a5b88dd516f5\n    * https://shanidgafur.github.io/blog/terraform-workspaces-for-multi-region-deployment\n\n## preface\n* goals of this workshop\n    * introduction to infrastructure as a code\n    * introduction to terraform\n        * provider, resources, data, variables, outputs\n        * standard functions, meta-arguments and expressions\n        * modules\n    * introduction to terraform version manager: https://github.com/tfutils/tfenv\n* plan for the workshop\n    * fill the scaffolds and follow the hints in directories:\n        1. pt1_basics\n        1. pt2_modules\n    * note that `docker provider` differs for unix and windows os:\n        ```\n        provider \"docker\" {\n          // host = \"unix:///var/run/docker.sock\" // macos\n          // host = \"npipe:////.//pipe//docker_engine\" // windows\n        }\n        ```\n        you should uncomment appropriate one\n\n\n## infrastructure as a code\n* is the process of managing and provisioning infrastructure through definition files\n* what is infrastructure?\n    * anything that could be controlled through an API\n    * usually: cloud-based infrastructure\n* infrastructure provisioning vs configuration management\n    * inherently different problems\n    * provisioning = deploying infrastructure\n        * Terraform favors immutable infrastructure\n        * immutable infrastructure = infrastructure as a disposable commodity\n    * configuration management = application delivery on virtual machines (VMs)\n        * CM tools favor mutable infrastructure\n        * mutable infrastructure = updates on existing servers\n* terraform vs packer vs ainsible\n    * terraform\n        * automates provisioning of the infrastructure\n        * makes your infrastructure auditable\n            * keep your infrastructure change history in git\n        * cloud agnostic\n            * integrates with different clouds through providers (plugins)\n        * is a state management tool + CRUD operations\n            * anything that is CRUD can be managed by terraform\n            * uses the same APIs as automation script\n                * difference: not only deployment but also infrastructure management\n            * understands dependencies between resources\n            * can detect and correct configuration drift\n                * drift means real-world state of infrastructure =/= state defined in configuration\n                * cannot detect drift of resources that are not managed by terraform\n        * is a simple state management engine\n    * packer\n        * example: build AWS AMIs based on templates\n            * Amazon Machine Image (AMI) provides the information required to launch an instance\n        * instead of installing the software after booting up an instance, you create an AMI\n        with all needed software from a machine image\n            * machine image = pre-configured operating system + software\n        * speed up boot times of instances\n        * common approach when running horizontally scaled apps\n    * ainsible\n        * install software after the infrastructure is provisioned\n        * has a focus on automating the installation and configuration of software\n        * example: security updates\n\n## terraform structure\n* terraform is separated into 3 separate parts\n    * core\n        * parsing configuration files\n        * resource state management\n        * construction of the Resource Graph (DAG)\n        * plan execution\n        * communication with plugins over RPC\n        * contains language interpreter, the CLI and how to interact with providers\n            * no code to interact with the API of the cloud providers\n                * that code is in providers, which be installed separately by invoking `terraform init`\n    * plugins (providers and provisioners)\n        * implementations for a specific service, such as AWS, or provisioner, such as bash\n        * separate process communicating with terraform binary over an RPC interface\n        * providers\n            * maps terraform Resources into cloud Services\n            * handles authentication\n        * provisioners\n            * executes commands/scripts on the designated Resource after creation, or on destruction\n    * upstream\n       * terraform does not create resources - it makes the cloud api to create it\n       * api: aws, google cloud, github, etc\n\n## project structure\n* `.terraform`\n    * binary of the providers (initialized during `terraform init`)\n* `terraform.lock.hcl`\n    * problem: providers and modules can be published and updated independently from Terraform itself\n        * Terraform must determine which versions of those dependencies are potentially compatible with the\n        current configuration\n    * provider dependency lockfile\n    * created when `terraform init`\n    * tracks versions of providers and modules\n    * should be committed to git\n    * re-runs of terraform will use the same provider/module versions\n        * example: terraform is ran by other members or using automation\n* `*.tf` files\n    * configuration files\n    * terraform concatenates all `.tf` files together (the context is a module - explained in the module section)\n* `*.tfvars` files\n    * values assignments to variables\n* `terraform.tfstate`\n    * is the state file used to keep track of the resources\n    * used to perform diffs during the plan and detect configuration drift\n    * example\n        ```\n        {\n          \"version\": 4,\n          \"terraform_version\": \"1.0.5\",\n          \"serial\": 10, // monotonically increasing with every apply and destroy\n          \"lineage\": \"d7fe6d32-593e-60c6-52f2-dff37b956408\", // unique ID assigned to a state when it is created\n          \"outputs\": {}, // outputs from last apply\n          \"resources\": []\n        }\n        ```\n        * \"lineage\" and \"serial\" matters only during validation when `terraform state push`\n            * pushing the state to the currently configured backend\n    * what happens when removed?\n        * it is not recreate automatically\n        * use `terraform import` to manually recreate it\n    * it’s important not to edit or delete (terraform will lose track of the resources)\n* `terraform.tfstate.backup`\n    * in case to recover to the last deployed state\n* module directories\n    * module is a collection of `.tf` files kept together in a directory\n    * nested directories are treated as completely separate modules\n        * are not automatically included in the configuration\n    * root module = main directory\n    * terraform treats the entire module as a single document\n        * separating various blocks into different files is purely for the convenience of readers\n            * no effect on the module's behavior\n\n## module\n* powerful way to reuse code\n* are self-contained packages of code\n* allow you to create reusable components by grouping related resources together\n* https://registry.terraform.io/namespaces/terraform-aws-modules\n* root module - the directory where you run terraform apply\n* you may have one or more child modules\n* convention: three configuration files per module\n    * `main.tf` - entry point\n    * `outputs.tf` - all output variables\n    * `variables.tf` - all input variables\n    * additional: `versions.tf`, `providers.tf`, and `README.md` in the root module\n\n## language\n* providers\n    * interact with cloud providers\n    * each provider defines a set of resources\n    * example: AWS provider - S3, EC2, etc\n* resources\n    * describe infrastructure objects\n    * example: ec2, vpc, database\n        * https://registry.terraform.io/providers/hashicorp/aws/latest/docs\n    * have inputs and outputs\n        * inputs are called arguments\n        * outputs are called attributes\n        * arguments are passed through the resource and are also available as attributes\n        * computed attributes = available after the creation\n            * example: AWS `arn:partition:service:region:account-id:resource-type:resource-id`\n    * implement the resource schema interface\n        * definitions of CRUD functions hooks\n        * Terraform invokes these hooks when certain conditions are met\n            * example\n                * `Create()` is called during resource creation\n                * `Read()` during plan generation\n* variables\n    * three types\n        * input\n        * output\n            * pass values between modules\n            * print values to the CLI\n        * local\n            * like temporary variables\n            * used for calculations, concatenations, conditionals\n            * example\n                ```\n                locals {\n                  name_suffix = \"${var.resource_tags[\"project\"]}-${var.resource_tags[\"environment\"]}\"\n                }\n                 module \"vpc\" {\n                   source  = \"terraform-aws-modules/vpc/aws\"\n                   version = \"2.66.0\"\n\n                   name = \"vpc-${local.name_suffix}\" // instead of \"vpc-${var.resource_tags[\"project\"]}-${var.resource_tags[\"environment\"]}\"\n                   ...\n                 }\n                ```\n    * variables should be validated\n        * example - usually internal ports are fixed\n            ```\n            variable \"internal_port\" {\n              type    = number\n              default = 8080\n\n              validation {\n                condition     = var.internal_port == 8080\n                error_message = \"The internal port must be 8080.\"\n              }\n            }\n            ```\n    * declare variables in `.tfvars`\n        * terraform automatically loads variable definitions if\n            * named exactly `terraform.tfvars`\n            * names ending in `.auto.tfvars`\n        * other way to load variables: `terraform apply --var-file prod.tfvars`\n* datasources\n    * fetch data from outside of the terraform\n    * example\n        ```\n        data \"aws_ami\" \"ubuntu\" {\n            most_recent = true\n\n            filter {\n                name   = \"name\"\n                values = [\"ubuntu/images/hvm-ssd/ubuntu-xenial-16.04-amd64-server-*\"]\n            }\n\n            filter {\n                name   = \"virtualization-type\"\n                values = [\"hvm\"]\n            }\n\n            owners = [\"099720109477\"] # Canonical\n        }\n\n        resource \"aws_instance\" \"web\" {\n            ami           = \"${data.aws_ami.ubuntu.id}\"\n            instance_type = \"t2.micro\"\n\n            tags {\n                Name = \"HelloUbuntu\"\n            }\n        }\n        ```\n* provisioners VM\n    * are an anti-pattern, and they may even be deprecated in a newer version of Terraform\n        * example\n            * sometimes resources are marked \"created\" and it takes a few more seconds before they are truly ready\n                * don't: insert delays with the local-exec provisioner\n                * do: `resource \"time_sleep\"` and `depends_on = [time_sleep.wait_30_seconds]`\n    * resource provisioners are essentially backdoors to the Terraform runtime\n    * provisioners can execute arbitrary code on either a local or remote machine as part of resource\n    creation or destruction\n    * used for various tasks, such as bootstrapping, copying files\n    * call external scripts, there is an implicit dependency on the OS interpreter\n    * should be used only as a method of last resort\n    * types\n        * local-provisioner (execute something locally after spinning up a VM)\n        * remote-provisioner (execute something remote on the VM)\n\n## standard operations\n* `terraform init`\n    * determines which plugins are necessary (based on configuration files)\n    * install plugins if needed\n        * providers resides in `.terraform/providers/`\n        * if any versions that meets the constraint are installed -\u003e chooses newest one\n        * otherwise -\u003e downloads and installs the newest acceptable from the Terraform Registry\n        * otherwise -\u003e initialization fails\n    * writes a lock file\n* `terraform plan`\n    * what Terraform intends to do\n    * algorithm\n        1. refresh state\n        1. read configuration\n        1. read state\n        1. resource in state?\n            * YES -\u003e `Read()`\n                1. has changes?\n                    * Yes -\u003e is destroy plan?\n                        * Yes -\u003e `Delete()`\n                        * No -\u003e `Update()`\n                    * No -\u003e `No-op`\n            * NO - `Create()`\n        1. output plan\n    * advice: always run plan before deploying\n    * digression\n        * if an attribute is marked as an ForceNew - the resource is destroyed and recreated\n           ```\n           \"ami\": {\n           \tType:     schema.TypeString,\n           \tRequired: true,\n           \tForceNew: true,\n           }\n           ```\n        * most resources have regular in-place updates\n* `terraform apply`\n    * executes the actions proposed in a Terraform plan\n    * is shortcut for: `terraform plan -out file; terraform apply file; rm file`\n    * useful flag: `-auto-approve`\n* `terraform destroy`\n    * destroy all remote objects managed by configuration\n* `terraform show`\n    * human-readable output from a state\n* `terraform validate`\n    * checks if configuration is syntactically valid regardless of any provided variables or existing state\n* `terraform fmt`\n    * rewrite files to a canonical format and style\n* workspaces\n    * `terraform workspace new / delete workspaceName`\n    * `terraform workspace list`\n    * `terraform workspace select workspaceName`\n    * `terraform workspace show`\n\n## standard functions, meta-arguments and expression\n* https://www.terraform.io/docs/language/functions/index.html\n    * `join(separator, list)`\n        * `join(\", \", [\"foo\", \"bar\", \"baz\"])` -\u003e `foo, bar, baz`\n    * `alltrue(list)`\n        * `alltrue([\"true\", true])` -\u003e `true`\n    * `length(any)`\n        * `length(\"hello\")` -\u003e `1`\n        * `length({\"a\" = \"b\"})` -\u003e `1`\n        * `length([\"a\", \"b\"])` -\u003e `2`\n    * `lookup(map, key, default)`\n        * `lookup({a=\"ay\", b=\"bee\"}, \"c\", \"what?\")` -\u003e `what?`\n    * `templatefile(path, vars)`\n        * `templatefile(\"${path.module}/backends.tpl\", { port = 8080, ip_addrs = [\"10.0.0.1\", \"10.0.0.2\"] })`\n    * expanding function arguments: `...`\n        * expanded list into separate arguments\n        * `min([55, 2453, 2]...)`\n* meta-arguments\n    * providers\n        * specifies which provider configurations will be available inside the module\n    * `for_each` and `count`\n        * sometimes you want to manage several similar objects (like a fixed pool of compute instances) without\n        writing a separate block for each one\n        * count\n            * accepts a number and creates that many instances\n            * `count.index` - (starting with 0) corresponding to current instance\n            * is sensible for any changes in list order\n                * terraform will force replacement of all resources of which the index in the list has changed\n            * example\n                ```\n                resource \"aws_instance\" \"server\" {\n                  count = 4 # create four similar EC2 instances\n\n                  ami           = \"ami-a1b2c3d4\"\n                  instance_type = \"t2.micro\"\n\n                  tags = {\n                    Name = \"Server ${count.index}\"\n                  }\n                }\n                ```\n        * `for_each`\n            * accepts a map or a set of strings, and creates an instance for each item\n            * `each.key`, `each.value`\n            * example\n                ```\n                resource \"aws_iam_user\" \"the-accounts\" {\n                  for_each = toset( [\"Todd\", \"James\", \"Alice\", \"Dottie\"] )\n                  name     = each.key\n                }\n                ```\n    * `depends_on`\n        * handle hidden resource or module dependencies\n        * used when relies on some other resource's but doesn't access any of that resource's data\n        * should be used only as a last resort\n        * example\n            * software running in this EC2 instance needs access to the S3 API in order to boot properly\n                * `aws_instance depends_on aws_iam_role_policy`\n* expressions\n    * for\n        * `[for o in var.list : o.id]`\n    * splat\n        * more concise way to express a common operation performed with a `for`\n        * `[for o in var.list : o.id]` -\u003e `var.list[*].id`\n        * does not work for maps\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmtumilowicz%2Fterraform-basics-modules-workshop","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmtumilowicz%2Fterraform-basics-modules-workshop","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmtumilowicz%2Fterraform-basics-modules-workshop/lists"}