1 00:00:06,610 --> 00:00:08,030 - Okay, now that we understand 2 00:00:08,030 --> 00:00:09,710 a little bit about using 3 00:00:09,710 --> 00:00:11,550 the configuration language, 4 00:00:11,550 --> 00:00:13,450 it's important to understand 5 00:00:13,450 --> 00:00:15,240 how we can encapsulate 6 00:00:15,240 --> 00:00:18,060 and reuse our code in Terraform. 7 00:00:18,060 --> 00:00:20,170 Just like in any other software project, 8 00:00:20,170 --> 00:00:22,800 it's important that your code 9 00:00:23,690 --> 00:00:24,640 doesn't repeat itself, 10 00:00:24,640 --> 00:00:27,220 so it's DRY, don't repeat yourself, 11 00:00:27,220 --> 00:00:29,540 and that it's modular 12 00:00:29,540 --> 00:00:32,170 so that the pieces can be reused. 13 00:00:32,170 --> 00:00:35,423 So, in Terraform what is a module? 14 00:00:36,750 --> 00:00:38,800 All Terraform code is in a module. 15 00:00:38,800 --> 00:00:40,720 The parts, the configurations 16 00:00:40,720 --> 00:00:42,440 that we looked at before 17 00:00:42,440 --> 00:00:44,693 were a single module called the root module. 18 00:00:45,630 --> 00:00:47,560 A root module is always required 19 00:00:47,560 --> 00:00:50,210 to plan or apply Terraform. 20 00:00:50,210 --> 00:00:52,670 But in addition to the root module, 21 00:00:52,670 --> 00:00:54,910 there can be other modules. 22 00:00:54,910 --> 00:00:56,030 Okay. 23 00:00:56,030 --> 00:00:57,680 And what comprises a module 24 00:00:57,680 --> 00:01:00,960 is simply a directory 25 00:01:00,960 --> 00:01:03,400 that contains Terraform code. 26 00:01:03,400 --> 00:01:06,530 So remember when I talked about evaluating 27 00:01:06,530 --> 00:01:07,910 the Terraform configuration 28 00:01:07,910 --> 00:01:09,610 and how it doesn't recurse, 29 00:01:09,610 --> 00:01:12,420 well, if you have subdirectories in your Terraform, 30 00:01:12,420 --> 00:01:13,740 then those are considered modules 31 00:01:13,740 --> 00:01:16,720 and you have to specifically tell Terraform 32 00:01:16,720 --> 00:01:18,210 to use those. 33 00:01:18,210 --> 00:01:19,910 Now, since it's a directory structure 34 00:01:19,910 --> 00:01:20,820 it can be nested, 35 00:01:20,820 --> 00:01:22,760 so you can have modules within modules, 36 00:01:22,760 --> 00:01:25,620 and sometimes that's a good idea 37 00:01:25,620 --> 00:01:27,003 and sometimes it's not. 38 00:01:27,960 --> 00:01:30,600 So, when should you use a module 39 00:01:30,600 --> 00:01:34,160 versus just putting config 40 00:01:34,160 --> 00:01:35,730 into the root module? 41 00:01:35,730 --> 00:01:37,490 Well, the first thing to look for 42 00:01:37,490 --> 00:01:39,660 is if somebody else has already written it. 43 00:01:39,660 --> 00:01:43,683 So, just like in other software development disciplines, 44 00:01:44,890 --> 00:01:48,847 there are standard libraries in Terraform, 45 00:01:48,847 --> 00:01:52,190 and HashiCorp maintains a public registry 46 00:01:52,190 --> 00:01:54,410 of Terraform modules 47 00:01:54,410 --> 00:01:56,270 that other people have written. 48 00:01:56,270 --> 00:01:57,910 Some of these are very high quality 49 00:01:57,910 --> 00:01:59,260 written by HashiCorp, 50 00:01:59,260 --> 00:02:02,600 aome of these are lower quality 51 00:02:02,600 --> 00:02:04,590 written by individual contributors 52 00:02:04,590 --> 00:02:06,040 in the community. 53 00:02:06,040 --> 00:02:07,840 So it's up to you to sort of determine 54 00:02:07,840 --> 00:02:10,300 whether or not the modules in the registry 55 00:02:10,300 --> 00:02:14,480 meet your requirements for that. 56 00:02:14,480 --> 00:02:16,120 They did have a registry 57 00:02:16,120 --> 00:02:21,120 at terraform.io/registry, I believe. 58 00:02:21,230 --> 00:02:22,690 Okay, so the Terraform registry 59 00:02:22,690 --> 00:02:25,030 is just a searchable interface 60 00:02:25,030 --> 00:02:27,390 and you can look for modules 61 00:02:27,390 --> 00:02:30,010 relating to anything that you're interested in, 62 00:02:30,010 --> 00:02:31,640 things like VPC. 63 00:02:31,640 --> 00:02:33,460 Now, as I mentioned, 64 00:02:33,460 --> 00:02:35,390 there's a vast difference in quality 65 00:02:35,390 --> 00:02:37,310 with these modules, so it's a good idea, 66 00:02:37,310 --> 00:02:39,703 if you can, to select the verified modules, 67 00:02:40,670 --> 00:02:44,540 and these will essentially filter 68 00:02:44,540 --> 00:02:45,810 the module list by ones 69 00:02:45,810 --> 00:02:47,297 that have been vetted by HashiCorp, 70 00:02:47,297 --> 00:02:50,490 and in most cases actually developed by HashiCorp. 71 00:02:50,490 --> 00:02:54,700 So VPC, the AWS VPC module 72 00:02:54,700 --> 00:02:57,710 is a very powerful and popular module. 73 00:02:57,710 --> 00:02:58,810 I use this all the time. 74 00:02:58,810 --> 00:03:01,310 It's extremely complex to set up 75 00:03:01,310 --> 00:03:03,550 a VPC with all the options in AWS, 76 00:03:03,550 --> 00:03:05,350 and so this module does a good job 77 00:03:05,350 --> 00:03:06,920 of encapsulating that. 78 00:03:06,920 --> 00:03:08,570 Okay, so if somebody has already written 79 00:03:08,570 --> 00:03:10,380 a module for you, great, use that. 80 00:03:10,380 --> 00:03:13,360 Otherwise, when should you use a module? 81 00:03:13,360 --> 00:03:16,150 Well, some good rules of thumb 82 00:03:16,150 --> 00:03:20,760 are any code that is frequently used. 83 00:03:20,760 --> 00:03:24,590 So things like setting up AWS accounts, 84 00:03:24,590 --> 00:03:26,090 areas where you need to enforce 85 00:03:26,090 --> 00:03:27,890 organizational standards, 86 00:03:27,890 --> 00:03:29,270 any time you find yourself cutting 87 00:03:29,270 --> 00:03:31,629 and pasting big blocks of code, 88 00:03:31,629 --> 00:03:34,410 you're more than likely 89 00:03:34,410 --> 00:03:35,920 to probably encapsulate that 90 00:03:35,920 --> 00:03:38,180 into a module that can be reused. 91 00:03:38,180 --> 00:03:40,840 Another common case is 92 00:03:40,840 --> 00:03:43,160 to add a level of abstraction. 93 00:03:43,160 --> 00:03:45,440 So one thing I'll mention about Terraform 94 00:03:45,440 --> 00:03:47,540 that beginners often miss 95 00:03:48,960 --> 00:03:51,180 is that Terraform is a very low level tool. 96 00:03:51,180 --> 00:03:55,650 So Terraform maps right on to the provider API. 97 00:03:55,650 --> 00:03:58,400 So, you're interacting almost directly 98 00:03:58,400 --> 00:04:01,910 with the resources exposed by the AWS API 99 00:04:01,910 --> 00:04:04,810 or the Google API, and sometimes 100 00:04:04,810 --> 00:04:06,150 that's a level of granularity 101 00:04:06,150 --> 00:04:08,023 that you just don't need or want. 102 00:04:08,930 --> 00:04:11,640 So a good example is things 103 00:04:11,640 --> 00:04:13,550 that are separate resources in Terraform 104 00:04:13,550 --> 00:04:16,000 but are logically one thing. 105 00:04:16,000 --> 00:04:20,480 Azure does this where the virtual machine, 106 00:04:20,480 --> 00:04:23,420 the NIC and the disk are all separate resources. 107 00:04:23,420 --> 00:04:25,660 And there is not really a case 108 00:04:25,660 --> 00:04:26,520 where you don't want to bring 109 00:04:26,520 --> 00:04:27,930 all those things up at the same time, 110 00:04:27,930 --> 00:04:29,620 and so using a module there 111 00:04:30,550 --> 00:04:32,240 to encapsulate those sorts of things, 112 00:04:32,240 --> 00:04:34,210 that just all go together, 113 00:04:34,210 --> 00:04:35,080 is a good way to do it. 114 00:04:35,080 --> 00:04:37,010 Kubernetes is another place 115 00:04:37,010 --> 00:04:38,080 where this is really common. 116 00:04:38,080 --> 00:04:39,970 So you create an EKS cluster 117 00:04:39,970 --> 00:04:42,480 but you also want to create worker nodes. 118 00:04:42,480 --> 00:04:45,620 That's in our minds, 119 00:04:45,620 --> 00:04:46,730 it seems like one thing, 120 00:04:46,730 --> 00:04:48,280 but from an API level it's not, 121 00:04:48,280 --> 00:04:51,940 so that's a common place to add abstraction. 122 00:04:51,940 --> 00:04:53,450 DNS providers is another one. 123 00:04:53,450 --> 00:04:55,610 So you may be using Route 53 124 00:04:56,720 --> 00:04:58,420 and another DNS provider, 125 00:04:58,420 --> 00:05:01,120 and you can make the interface of those things 126 00:05:01,120 --> 00:05:03,140 look the same to your internal code 127 00:05:03,140 --> 00:05:04,070 by using a module 128 00:05:04,070 --> 00:05:06,300 and implementing the same interface. 129 00:05:06,300 --> 00:05:09,660 Occasionally, the providers are, 130 00:05:09,660 --> 00:05:11,730 the Terraform providers are not up-to-date 131 00:05:11,730 --> 00:05:14,090 with the latest API and there may be a resource 132 00:05:14,090 --> 00:05:18,060 that is not exposed to the Terraform provider. 133 00:05:18,060 --> 00:05:21,450 And so in that case you can create a module to sort of 134 00:05:21,450 --> 00:05:23,623 implement that functionality yourself. 135 00:05:24,660 --> 00:05:25,990 An example that comes to mind 136 00:05:25,990 --> 00:05:28,053 is in the API Gateway. 137 00:05:28,940 --> 00:05:32,170 It does not support WebSockets APIs 138 00:05:32,170 --> 00:05:33,980 in the Terraform provider. 139 00:05:33,980 --> 00:05:35,350 They're fully supported 140 00:05:35,350 --> 00:05:36,590 by the Gateway itself, 141 00:05:36,590 --> 00:05:38,880 but that support has not yet made it 142 00:05:38,880 --> 00:05:40,760 to the Terraform provider. 143 00:05:40,760 --> 00:05:44,450 And so people have created modules 144 00:05:44,450 --> 00:05:46,290 that sort of wrap that functionality. 145 00:05:46,290 --> 00:05:47,980 Now that we know what a module is 146 00:05:47,980 --> 00:05:49,450 and when we should use one, 147 00:05:49,450 --> 00:05:50,750 how do we create a module? 148 00:05:51,980 --> 00:05:54,290 Well, it's a really simple process. 149 00:05:54,290 --> 00:05:55,740 Simply create a directory 150 00:05:55,740 --> 00:05:57,290 and put some Terraform in it. 151 00:05:57,290 --> 00:05:59,070 That's really all there is to it. 152 00:05:59,070 --> 00:06:02,830 That being said, there are a bunch of conventions 153 00:06:02,830 --> 00:06:04,520 to go around creating modules, 154 00:06:04,520 --> 00:06:06,580 one of which is the naming convention. 155 00:06:06,580 --> 00:06:10,850 Now, if you're planning to publish your modules, 156 00:06:10,850 --> 00:06:13,810 either to a private Terraform registry 157 00:06:13,810 --> 00:06:16,220 or to the public Terraform registry, 158 00:06:16,220 --> 00:06:18,950 you have to follow this naming convention. 159 00:06:18,950 --> 00:06:20,870 You have to use the literal string terraform, 160 00:06:20,870 --> 00:06:23,060 dash, and then the name of the provider, 161 00:06:23,060 --> 00:06:25,400 so that would be something like AWS, 162 00:06:25,400 --> 00:06:26,940 Google, Kubernetes, 163 00:06:26,940 --> 00:06:28,260 something like that. 164 00:06:28,260 --> 00:06:30,296 And then another dash, 165 00:06:30,296 --> 00:06:32,180 and then the name, and the name can be 166 00:06:32,180 --> 00:06:33,760 whatever makes sense to you, 167 00:06:33,760 --> 00:06:36,690 and that can also contain hyphens. 168 00:06:36,690 --> 00:06:38,900 But the first few fields 169 00:06:38,900 --> 00:06:40,850 will actually be parsed out 170 00:06:40,850 --> 00:06:42,810 by the registry, okay? 171 00:06:42,810 --> 00:06:43,810 So you have to keep that in mind 172 00:06:43,810 --> 00:06:45,490 when you're creating your modules. 173 00:06:45,490 --> 00:06:50,490 If you don't plan on publishing these to registry 174 00:06:50,980 --> 00:06:53,480 then you can name them however you like. 175 00:06:53,480 --> 00:06:56,360 Most people leave off the Terraform part 176 00:06:56,360 --> 00:06:58,230 and sometimes they leave off the provider part. 177 00:06:58,230 --> 00:06:59,360 A module layout. 178 00:06:59,360 --> 00:07:01,810 So again, your modules can be laid out 179 00:07:01,810 --> 00:07:02,700 anyway that you like, 180 00:07:02,700 --> 00:07:03,830 that's valid Terraform, 181 00:07:03,830 --> 00:07:05,080 but this is the convention 182 00:07:05,080 --> 00:07:06,660 and this is also required 183 00:07:06,660 --> 00:07:09,510 for the module registries. 184 00:07:09,510 --> 00:07:11,850 So, by convention, 185 00:07:11,850 --> 00:07:14,230 the entry point is called main.tf. 186 00:07:14,230 --> 00:07:16,960 Also by convention, the input variables 187 00:07:16,960 --> 00:07:18,840 are stored in variables.tf, 188 00:07:18,840 --> 00:07:22,120 and the outputs are stores in outputs.tf. 189 00:07:22,120 --> 00:07:24,070 If you have any submodules 190 00:07:24,070 --> 00:07:25,770 those should go into a directory 191 00:07:25,770 --> 00:07:26,603 named modules, 192 00:07:28,930 --> 00:07:31,160 and then within there there're subdirectories 193 00:07:31,160 --> 00:07:32,233 for each submodule. 194 00:07:33,150 --> 00:07:37,060 And then those follow the same pattern recursively. 195 00:07:37,060 --> 00:07:39,520 By convention, there is also an examples directory 196 00:07:39,520 --> 00:07:41,640 and this is used, also this is broken out 197 00:07:41,640 --> 00:07:42,650 by the module registry. 198 00:07:42,650 --> 00:07:44,550 But I highly encourage you 199 00:07:44,550 --> 00:07:46,410 to create the examples directory, 200 00:07:46,410 --> 00:07:48,110 and it's very, very useful to have that 201 00:07:48,110 --> 00:07:49,500 during your development process 202 00:07:49,500 --> 00:07:51,200 because it gives you a little piece of, 203 00:07:51,200 --> 00:07:53,250 it gives you a root module that you can use 204 00:07:53,250 --> 00:07:55,020 to call your own Terraform. 205 00:07:55,020 --> 00:07:58,280 Additionally, a README file is required 206 00:07:58,280 --> 00:08:00,610 if you want to publish this to a registry. 207 00:08:00,610 --> 00:08:02,600 It's highly recommended anyway. 208 00:08:02,600 --> 00:08:05,400 By convention, submodules don't get README files, 209 00:08:05,400 --> 00:08:07,260 and that's actually how Terraform tells 210 00:08:07,260 --> 00:08:09,790 whether something is intended to be 211 00:08:09,790 --> 00:08:10,630 a private module. 212 00:08:10,630 --> 00:08:13,550 So include README and LICENSE methods 213 00:08:13,550 --> 00:08:17,040 going into the public repository. 214 00:08:17,040 --> 00:08:18,910 A LICENSE file is required. 215 00:08:18,910 --> 00:08:21,810 You can get the language for those 216 00:08:21,810 --> 00:08:23,990 from GitHub or online or anywhere else 217 00:08:23,990 --> 00:08:25,330 to paste in there. 218 00:08:25,330 --> 00:08:27,630 So modules follow the exact same format 219 00:08:27,630 --> 00:08:29,480 as the root module. 220 00:08:29,480 --> 00:08:30,600 There's a few differences 221 00:08:30,600 --> 00:08:31,930 that you need to be aware of. 222 00:08:31,930 --> 00:08:34,390 Like the root module, variables are used 223 00:08:34,390 --> 00:08:36,560 to pass parameters into a module, 224 00:08:36,560 --> 00:08:38,740 and output is used to return 225 00:08:38,740 --> 00:08:40,700 values from a module. 226 00:08:40,700 --> 00:08:42,500 But unlike the root module, 227 00:08:42,500 --> 00:08:45,260 variables that don't have a default defined 228 00:08:45,260 --> 00:08:46,390 are required. 229 00:08:46,390 --> 00:08:48,740 So it won't prompt you. 230 00:08:48,740 --> 00:08:51,690 In the root module, if you don't define a variable 231 00:08:51,690 --> 00:08:54,040 then Terraform, we saw Terraform 232 00:08:54,040 --> 00:08:55,520 prompting you for the value. 233 00:08:55,520 --> 00:08:56,730 It's just simply an error 234 00:08:56,730 --> 00:08:58,200 if you are calling a module 235 00:08:58,200 --> 00:09:01,100 and one of its required input values 236 00:09:01,100 --> 00:09:02,410 is specified. 237 00:09:02,410 --> 00:09:05,090 And then the outputs are slightly different as well. 238 00:09:05,090 --> 00:09:09,070 So the outputs don't get printed out at the end, 239 00:09:09,070 --> 00:09:10,510 the way they do in the root module. 240 00:09:10,510 --> 00:09:14,080 The outputs are fed back 241 00:09:14,080 --> 00:09:15,130 to the root module 242 00:09:16,040 --> 00:09:18,670 as the values of the module, 243 00:09:18,670 --> 00:09:19,503 and we'll see this. 244 00:09:19,503 --> 00:09:21,070 It's a little bit confusing to explain, 245 00:09:21,070 --> 00:09:22,700 but we'll see this in action 246 00:09:22,700 --> 00:09:24,950 when we actually go through some module code. 247 00:09:24,950 --> 00:09:27,030 So this is the HCL syntax 248 00:09:27,030 --> 00:09:30,140 for using a module. 249 00:09:30,140 --> 00:09:32,030 So it's a little bit different 250 00:09:32,030 --> 00:09:36,840 than a resource specification. 251 00:09:36,840 --> 00:09:39,350 The syntax is simply the word module 252 00:09:39,350 --> 00:09:40,410 and then the label, 253 00:09:40,410 --> 00:09:44,030 and then within the specification 254 00:09:44,030 --> 00:09:47,490 a required parameter is source, 255 00:09:47,490 --> 00:09:50,560 and the source can be a couple 256 00:09:50,560 --> 00:09:52,723 of different syntaxes. 257 00:09:54,460 --> 00:09:57,790 The first one is just a filesystem path. 258 00:09:57,790 --> 00:10:00,160 So Terraform will attempt to resolve that 259 00:10:00,160 --> 00:10:02,010 into a filesystem path, 260 00:10:02,010 --> 00:10:03,730 and you can use relative directories 261 00:10:03,730 --> 00:10:07,020 like dot-dot for one directory above, 262 00:10:07,020 --> 00:10:09,740 that's really common in using your examples. 263 00:10:09,740 --> 00:10:12,330 A Terraform registry URL, 264 00:10:12,330 --> 00:10:14,380 which is not a full URL, 265 00:10:14,380 --> 00:10:18,690 it's username and then the name hashed 266 00:10:18,690 --> 00:10:21,400 including the provider, and I'll show you 267 00:10:21,400 --> 00:10:23,860 in the registry what that actually looks like. 268 00:10:23,860 --> 00:10:25,600 So if you look here you can see 269 00:10:25,600 --> 00:10:28,560 that it gives you a little example 270 00:10:28,560 --> 00:10:30,730 including this into your code, 271 00:10:30,730 --> 00:10:34,410 and this is what the actual string looks like 272 00:10:34,410 --> 00:10:35,480 to be included in your code. 273 00:10:35,480 --> 00:10:37,400 You can also include a version 274 00:10:37,400 --> 00:10:38,570 if you're using a registry. 275 00:10:38,570 --> 00:10:41,760 And then lastly, you can include a link 276 00:10:41,760 --> 00:10:43,260 to your SCM Repo. 277 00:10:43,260 --> 00:10:46,010 And Terraform supports 278 00:10:46,010 --> 00:10:48,513 a number of different SCMs directly, 279 00:10:49,370 --> 00:10:51,680 GitHub being one of them, 280 00:10:51,680 --> 00:10:53,880 as opposed to just RawGit. 281 00:10:53,880 --> 00:10:55,440 You could also use the RawGit provider 282 00:10:55,440 --> 00:10:58,240 with GitHub, but the GitHub gives you 283 00:10:58,240 --> 00:10:59,280 a little bit of a shortcut. 284 00:10:59,280 --> 00:11:01,657 You don't have to give it the full SSH path. 285 00:11:01,657 --> 00:11:04,230 But if you're using some other git provider 286 00:11:04,230 --> 00:11:05,330 you can still use that. 287 00:11:05,330 --> 00:11:08,543 It also supports Bitbucket, Subversion, 288 00:11:08,543 --> 00:11:10,870 and possibly some others. 289 00:11:10,870 --> 00:11:12,900 Also GitLinks and I think 290 00:11:12,900 --> 00:11:15,140 other SCMs as well. 291 00:11:15,140 --> 00:11:17,710 You can also specify a reference 292 00:11:17,710 --> 00:11:20,210 or a branch number or a tag as well. 293 00:11:20,210 --> 00:11:22,640 So you can do fully reproducible builds 294 00:11:22,640 --> 00:11:23,920 using that method. 295 00:11:23,920 --> 00:11:25,910 This is just a little example 296 00:11:25,910 --> 00:11:28,910 of what a module would look like in action, 297 00:11:28,910 --> 00:11:30,090 and we're gonna go through this 298 00:11:30,090 --> 00:11:33,110 in more detail when we get there, 299 00:11:33,110 --> 00:11:35,830 but this top part defines the module itself. 300 00:11:35,830 --> 00:11:37,850 So this would be in your module file. 301 00:11:37,850 --> 00:11:38,683 Okay? 302 00:11:38,683 --> 00:11:41,220 So this is just a really quick trivial module, 303 00:11:41,220 --> 00:11:45,190 showing you how to accept parameters 304 00:11:45,190 --> 00:11:47,460 and how to output values, 305 00:11:47,460 --> 00:11:49,740 and then it shows you in the main.tf 306 00:11:49,740 --> 00:11:51,700 down below how to call that. 307 00:11:51,700 --> 00:11:52,840 Okay? 308 00:11:52,840 --> 00:11:56,295 And we'll go and see some concrete examples here 309 00:11:56,295 --> 00:11:58,003 in the next section.